Compare commits

...

16 commits

Author SHA1 Message Date
Lukas Dürrenberger b3e44568df Incremented SFML version number and added changes to the changelog. 2016-11-03 07:50:51 +01:00
Lukas Dürrenberger 303d07976c Added back GlResource::ensureGlContext() for ABI compatibility. 2016-10-28 13:51:40 +02:00
binary1248 b74391cf97 Removed internal OpenGL contexts, reduced the number of temporary contexts that get created during runtime. 2016-10-24 13:51:03 +02:00
Mario Liebisch 6c0b7857f9 Added some simple messaging when trying to build under Cygwin 2016-10-24 13:47:46 +02:00
Mischa Aster Alff 3d7f354d25 Clarify documentation on Rect::contains function bounds 2016-10-24 13:47:38 +02:00
Marco Antognini bc121e9bda Fixed inconsistency between doc and impl on OS X for the grab feature
Patch for #1133 and #1148.
2016-10-24 13:47:29 +02:00
binary1248 555d0c484b Converted Unix Window implementation from XCB back to Xlib. 2016-10-24 13:47:19 +02:00
louis-langholtz eacdafe9d7 Fixes bug #1049: iOS orientation change handling re-scales window size by backingScaleFactor. 2016-10-24 13:46:51 +02:00
Hapaxia 1424fa4dc3 update Window documentation
removed part of the sentence that stated that cursor grabbing is different for fullscreen windows as this is not the case.
2016-10-24 13:46:44 +02:00
binary1248 946dbce6c4 Fixed possible hang when setting visibility if external window sources e.g. Qt don't forward visibility notify events to us. 2016-10-24 13:46:09 +02:00
binary1248 42146ea070 Fixed leak of XVisualInfo objects during GlxContext creation. 2016-10-24 13:46:03 +02:00
Hapax d9056ad5b3 Changed uniform error message
Changed the error message for using uniforms to use the word uniform instead of the word parameter since parameter's deprecation.

A minor text output alteration to keep consistent with the new interface.
2016-10-24 13:45:57 +02:00
James Cowgill fea5d47221 Define SFML_OS_FREEBSD when compiling for kFreeBSD 2016-10-24 13:45:46 +02:00
Dka8 e2c4bca779 UdpSocket.hpp typo in comment for void unbind()
Function  void unbind();
The suggested text by @binary1248
Added "If the socket is not bound to a port, this function has no effect."
2016-10-24 13:45:20 +02:00
Manu343726 cb097ff8d8 Correctly add XCB components if no components are requested
This commit fixes the FindXCB.cmake module for the case no components
are requested. The previous version assigned `XCB_FIND_COMPONENTS`
list to an empty variable name.

I was lucky enough to catch the bug in a corner case where both
`XCB_COMPONENTS` and `XCB_FIND_COMPONENTS` were empty and `set()`
command failed, but note this awesome CMake language supports more annoying
corner cases like `XCB_COMPONENTS` empty and `XCB_FIND_COMPONENTS`
with two elements, which results in the following `set()` invocation:

``` cmake
set(${XCB_FIND_COMPONENTS[0]} ${XCB_FIND_COMPONENTS[1]})
```

So always beware of CMake secret charms...
2016-10-24 13:45:14 +02:00
binary1248 f72888fac3 Fixed not being able to set the window icon properly on some Unix window managers (#1087) and added support for setting the window icon via ICCCM (_NET_WM_ICON). 2016-10-24 13:44:55 +02:00
42 changed files with 1415 additions and 2095 deletions

View file

@ -13,6 +13,9 @@ endmacro()
# determine whether to create a debug or release build # determine whether to create a debug or release build
sfml_set_option(CMAKE_BUILD_TYPE Release STRING "Choose the type of build (Debug or Release)") sfml_set_option(CMAKE_BUILD_TYPE Release STRING "Choose the type of build (Debug or Release)")
# Suppress Cygwin legacy warning
set(CMAKE_LEGACY_CYGWIN_WIN32 0)
# set Android specific options # set Android specific options
# define the minimum API level to be used # define the minimum API level to be used
@ -31,6 +34,8 @@ if(NOT ANDROID_ABI)
set(ANDROID_ABI armeabi-v7a) set(ANDROID_ABI armeabi-v7a)
endif() endif()
#end of Android specific options
# project name # project name
project(SFML) project(SFML)
@ -40,7 +45,7 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake)
# setup version numbers # setup version numbers
set(VERSION_MAJOR 2) set(VERSION_MAJOR 2)
set(VERSION_MINOR 4) set(VERSION_MINOR 4)
set(VERSION_PATCH 0) set(VERSION_PATCH 1)
# add the SFML header path # add the SFML header path
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)

View file

@ -1,3 +1,51 @@
SFML 2.4.1
==========
Also available on the website: http://www.sfml-dev.org/changelog.php#sfml-2.4.1
General
=======
* [kFreeBSD] Define SFML_OS_FREEBSD when compiling for kFreeBSD (#1129)
* [Window] Added some simple messaging when trying to build under Cygwin (#1153)
Window
======
Bugfixes
--------
* Fixed stack overflow on GlContext creation with multiple threads (#989, #1002)
* Adjusted mouse cursor grab documentation (#1133)
* [iOS] Fixed orientation change not rescaling window size properly (#1049, #1050)
* [Linux] Fixed fullscreen issue (#921, #1138)
* [Linux] Switched from XCB back to Xlib for windowing (#1138)
* [Linux] Fixed window icon not showing up on some distros (#1087, #1088)
* [Linux] Fixed an issue where GNOME flags window unresponsive (#1089, #1138)
* [Linux] Fixed leak of XVisualInfo objects during GlxContext creation (#1135)
* [Linux] Fixed possible hang when setting visibility if external window sources (#1136)
* [OS X] Fixed inconsistency between doc and impl on OS X for the grab feature (#1133, #1148, #1150)
* [Windows] Fixed context memory leaks (#1143, #1002)
Graphics
========
Bugfixes
--------
* Adjusted uniform error message (#1131)
* Clarify documentation on Rect::contains function bounds (#1151)
Network
=======
Bugfixes
--------
* Fixed a typo in comment for void unbind() (#1121)
SFML 2.4.0 SFML 2.4.0
========== ==========
@ -115,8 +163,6 @@ Bugfixes
SFML 2.3.2 SFML 2.3.2
========== ==========
@ -152,6 +198,7 @@ Bugfixes
* Secure function against random data return (#935, #942) * Secure function against random data return (#935, #942)
SFML 2.3.1 SFML 2.3.1
========== ==========

View file

@ -27,7 +27,7 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
# don't use the OpenGL ES implementation on Linux # don't use the OpenGL ES implementation on Linux
set(OPENGL_ES 0) set(OPENGL_ES 0)
endif() endif()
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") elseif(CMAKE_SYSTEM_NAME MATCHES "^k?FreeBSD$")
set(SFML_OS_FREEBSD 1) set(SFML_OS_FREEBSD 1)
# don't use the OpenGL ES implementation on FreeBSD # don't use the OpenGL ES implementation on FreeBSD
set(OPENGL_ES 0) set(OPENGL_ES 0)
@ -64,6 +64,10 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Android")
# use the OpenGL ES implementation on Android # use the OpenGL ES implementation on Android
set(OPENGL_ES 1) set(OPENGL_ES 1)
# comparing CMAKE_SYSTEM_NAME with "CYGWIN" generates a false warning depending on the CMake version
# let's avoid it so the actual error is more visible
elseif(${CYGWIN})
message(FATAL_ERROR "Unfortunately SFML doesn't support Cygwin's 'hybrid' status between both Windows and Linux derivatives.\nIf you insist on using the GCC, please use a standalone build of MinGW without the Cygwin environment instead.")
else() else()
message(FATAL_ERROR "Unsupported operating system or environment") message(FATAL_ERROR "Unsupported operating system or environment")
return() return()

View file

@ -285,10 +285,7 @@ if(SFML_STATIC_LIBRARIES)
# find libraries # find libraries
if(FIND_SFML_OS_LINUX OR FIND_SFML_OS_FREEBSD) if(FIND_SFML_OS_LINUX OR FIND_SFML_OS_FREEBSD)
find_sfml_dependency(X11_LIBRARY "X11" X11) find_sfml_dependency(X11_LIBRARY "X11" X11)
find_sfml_dependency(LIBXCB_LIBRARIES "XCB" xcb libxcb) find_sfml_dependency(XRANDR_LIBRARY "Xrandr" Xrandr)
find_sfml_dependency(X11_XCB_LIBRARY "X11-xcb" X11-xcb libX11-xcb)
find_sfml_dependency(XCB_RANDR_LIBRARY "xcb-randr" xcb-randr libxcb-randr)
find_sfml_dependency(XCB_IMAGE_LIBRARY "xcb-image" xcb-image libxcb-image)
endif() endif()
if(FIND_SFML_OS_LINUX) if(FIND_SFML_OS_LINUX)
@ -299,9 +296,9 @@ if(SFML_STATIC_LIBRARIES)
if(FIND_SFML_OS_WINDOWS) if(FIND_SFML_OS_WINDOWS)
set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "opengl32" "winmm" "gdi32") set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "opengl32" "winmm" "gdi32")
elseif(FIND_SFML_OS_LINUX) elseif(FIND_SFML_OS_LINUX)
set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "GL" ${X11_LIBRARY} ${LIBXCB_LIBRARIES} ${X11_XCB_LIBRARY} ${XCB_RANDR_LIBRARY} ${XCB_IMAGE_LIBRARY} ${UDEV_LIBRARIES}) set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "GL" ${X11_LIBRARY} ${XRANDR_LIBRARY} ${UDEV_LIBRARIES})
elseif(FIND_SFML_OS_FREEBSD) elseif(FIND_SFML_OS_FREEBSD)
set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "GL" ${X11_LIBRARY} ${LIBXCB_LIBRARIES} ${X11_XCB_LIBRARY} ${XCB_RANDR_LIBRARY} ${XCB_IMAGE_LIBRARY} "usbhid") set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "GL" ${X11_LIBRARY} ${XRANDR_LIBRARY} "usbhid")
elseif(FIND_SFML_OS_MACOSX) elseif(FIND_SFML_OS_MACOSX)
set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "-framework OpenGL -framework Foundation -framework AppKit -framework IOKit -framework Carbon") set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "-framework OpenGL -framework Foundation -framework AppKit -framework IOKit -framework Carbon")
endif() endif()

View file

@ -1,97 +0,0 @@
# Try to find libxcb
#
#
# Once done this will define:
# LIBXCB_FOUND - True if xcb was found
# LIBXCB_INCLUDE_DIRS - Directories containing the headers
# LIBXCB_LIBRARIES - List of libraries to link to
#
# Also for each requested component:
# LIBXCB_${UPPER_COMPONENT_NAME}_FOUND
# LIBXCB_${UPPER_COMPONENT_NAME}_INCLUDE_DIRS
# LIBXCB_${UPPER_COMPONENT_NAME}_LIBRARIES
include(FindPackageHandleStandardArgs)
IF(NOT WIN32)
IF(LIBXCB_LIBRARIES AND LIBXCB_INCLUDE_DIR)
set(XCB_FIND_QUIETLY TRUE)
ENDIF()
# Find xcb
FIND_PATH(LIBXCB_INCLUDE_DIR xcb/xcb.h)
FIND_LIBRARY(LIBXCB_LIBRARY NAMES xcb libxcb)
# Add xcb info to LIBXCB_LIBRARIES and LIBXCB_INCLUDE_DIRS
SET(LIBXCB_LIBRARIES ${LIBXCB_LIBRARY})
SET(LIBXCB_INCLUDE_DIRS ${LIBXCB_INCLUDE_DIR})
find_package_handle_standard_args(LIBXCB DEFAULT_MSG
LIBXCB_LIBRARY LIBXCB_INCLUDE_DIR)
mark_as_advanced(LIBXCB_LIBRARY LIBXCB_INCLUDE_DIR)
# Check whether we should search for XLIB_XCB
set(FIND_XLIB_XCB FALSE)
FOREACH(XCB_COMPONENT ${XCB_FIND_COMPONENTS})
# Generate upper string of the component name
string(TOUPPER ${XCB_COMPONENT} XCB_COMPONENT_UPPER)
IF(${XCB_COMPONENT_UPPER} MATCHES "XLIB_XCB")
set(FIND_XLIB_XCB TRUE)
ELSE()
# XCB_COMPONENTS is generated to be a copy of XCB_FIND_COMPONENTS
# without XLIB_XCB (for later component search)
set(XCB_COMPONENTS ${XCB_COMPONENTS} ${XCB_COMPONENT})
ENDIF()
ENDFOREACH()
# Find XLIB_XCB if requested
IF(FIND_XLIB_XCB)
FIND_PATH(XLIB_XCB_INCLUDE_DIR X11/Xlib-xcb.h)
FIND_LIBRARY(XLIB_XCB_LIBRARY NAMES X11-xcb libX11-xcb)
SET(XLIB_XCB_LIBRARIES ${XLIB_XCB_LIBRARY})
SET(XLIB_XCB_INCLUDE_DIRS ${XLIB_XCB_INCLUDE_DIR})
find_package_handle_standard_args(XLIB_XCB DEFAULT_MSG
XLIB_XCB_LIBRARY LIBXCB_INCLUDE_DIR)
mark_as_advanced(XLIB_XCB_LIBRARY XLIB_XCB_INCLUDE_DIR)
# Add xlib_xcb info to LIBXCB_LIBRARIES and LIBXCB_INCLUDE_DIRS
set(LIBXCB_LIBRARIES ${LIBXCB_LIBRARIES} ${XLIB_XCB_LIBRARIES})
set(LIBXCB_INCLUDE_DIRS ${LIBXCB_INCLUDE_DIRS} ${XLIB_XCB_INCLUDE_DIR})
if(NOT XLIB_XCB_FOUND)
message(FATAL_ERROR "XlibXcb library not found")
endif()
ELSE()
# Add component name to the component list
set(${XCB_COMPONENTS} ${XCB_FIND_COMPONENTS})
ENDIF()
# Loop through requested xcb components (does not contain xlib_xcb)
FOREACH(XCB_COMPONENT ${XCB_COMPONENTS})
# Generate lower and upper string of the component name
string(TOLOWER ${XCB_COMPONENT} XCB_COMPONENT_LOWER)
string(TOUPPER ${XCB_COMPONENT} XCB_COMPONENT_UPPER)
# Find the specific component
FIND_LIBRARY(LIBXCB_${XCB_COMPONENT_UPPER}_LIBRARY
NAMES libxcb-${XCB_COMPONENT_LOWER} xcb-${XCB_COMPONENT_LOWER})
find_package_handle_standard_args(LIBXCB_${XCB_COMPONENT_UPPER} DEFAULT_MSG
LIBXCB_${XCB_COMPONENT_UPPER}_LIBRARY LIBXCB_INCLUDE_DIR)
mark_as_advanced(LIBXCB_${XCB_COMPONENT_UPPER}_LIBRARY)
# Append the component's library path to LIBXCB_LIBRARIES
set(LIBXCB_LIBRARIES ${LIBXCB_LIBRARIES} ${LIBXCB_${XCB_COMPONENT_UPPER}_LIBRARY})
if(NOT LIBXCB_${XCB_COMPONENT_UPPER}_FOUND)
message(FATAL_ERROR "xcb-${XCB_COMPONENT_LOWER} not found")
endif()
ENDFOREACH()
endif()

View file

@ -5,7 +5,7 @@
#include <SFML/Window.hpp> #include <SFML/Window.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <SFML/OpenGL.hpp> #include <SFML/OpenGL.hpp>
#include <X11/Xlib-xcb.h> #include <X11/Xlib.h>
#include <iostream> #include <iostream>
#include <cmath> #include <cmath>
@ -133,77 +133,46 @@ int main()
if (!display) if (!display)
return EXIT_FAILURE; return EXIT_FAILURE;
// Get the XCB connection for the opened display. // Get the default screen
xcb_connection_t* xcbConnection = XGetXCBConnection(display); int screen = DefaultScreen(display);
if (!xcbConnection) // Let's create the main window
{ XSetWindowAttributes attributes;
sf::err() << "Failed to get the XCB connection for opened display." << std::endl; attributes.background_pixel = BlackPixel(display, screen);
attributes.event_mask = KeyPressMask;
Window window = XCreateWindow(display, RootWindow(display, screen),
0, 0, 650, 330, 0,
DefaultDepth(display, screen),
InputOutput,
DefaultVisual(display, screen),
CWBackPixel | CWEventMask, &attributes);
if (!window)
return EXIT_FAILURE; return EXIT_FAILURE;
}
// Get XCB screen. // Set the window's name
const xcb_setup_t* xcbSetup = xcb_get_setup(xcbConnection); XStoreName(display, window , "SFML Window");
xcb_screen_iterator_t xcbScreenIter = xcb_setup_roots_iterator(xcbSetup);
xcb_screen_t* screen = xcbScreenIter.data;
if (!screen) // Let's create the windows which will serve as containers for our SFML views
{ Window view1 = XCreateWindow(display, window,
sf::err() << "Failed to get the XCB screen." << std::endl; 10, 10, 310, 310, 0,
return EXIT_FAILURE; DefaultDepth(display, screen),
} InputOutput,
DefaultVisual(display, screen),
0, NULL);
Window view2 = XCreateWindow(display, window,
330, 10, 310, 310, 0,
DefaultDepth(display, screen),
InputOutput,
DefaultVisual(display, screen),
0, NULL);
// Generate the XCB window IDs. // Show our windows
xcb_window_t rootWindowId = xcb_generate_id(xcbConnection); XMapWindow(display, window);
xcb_window_t view1WindowId = xcb_generate_id(xcbConnection); XFlush(display);
xcb_window_t view2WindowId = xcb_generate_id(xcbConnection);
// Create the root window with a black background.
uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
uint32_t attributes[2] = {screen->black_pixel, XCB_EVENT_MASK_KEY_PRESS};
xcb_create_window(xcbConnection,
XCB_COPY_FROM_PARENT,
rootWindowId,
screen->root,
0, 0, 650, 330,
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual,
mask, attributes);
// Create windows for the SFML views.
xcb_create_window(xcbConnection,
XCB_COPY_FROM_PARENT,
view1WindowId,
rootWindowId,
10, 10, 310, 310,
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual,
mask, attributes);
xcb_create_window(xcbConnection,
XCB_COPY_FROM_PARENT,
view2WindowId,
rootWindowId,
330, 10, 310, 310,
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual,
mask, attributes);
// Map windows to screen.
xcb_map_window(xcbConnection, rootWindowId);
xcb_map_window(xcbConnection, view1WindowId);
xcb_map_window(xcbConnection, view2WindowId);
// Flush commands.
xcb_flush(xcbConnection);
// Create our SFML views // Create our SFML views
sf::Window sfmlView1(view1WindowId); sf::Window sfmlView1(view1);
sf::Window sfmlView2(view2WindowId); sf::Window sfmlView2(view2);
// Create a clock for measuring elapsed time // Create a clock for measuring elapsed time
sf::Clock clock; sf::Clock clock;
@ -214,13 +183,22 @@ int main()
// Start the event loop // Start the event loop
bool running = true; bool running = true;
xcb_generic_event_t* event = NULL;
while (running) while (running)
{ {
while ((event = xcb_poll_for_event(xcbConnection))) while (XPending(display))
{ {
running = false; // Get the next pending event
XEvent event;
XNextEvent(display, &event);
// Process it
switch (event.type)
{
// Any key is pressed: quit
case KeyPress:
running = false;
break;
}
} }
// Draw something into our views // Draw something into our views
@ -232,5 +210,8 @@ int main()
sfmlView2.display(); sfmlView2.display();
} }
// Close the display
XCloseDisplay(display);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View file

@ -31,7 +31,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#define SFML_VERSION_MAJOR 2 #define SFML_VERSION_MAJOR 2
#define SFML_VERSION_MINOR 4 #define SFML_VERSION_MINOR 4
#define SFML_VERSION_PATCH 0 #define SFML_VERSION_PATCH 1
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View file

@ -95,6 +95,9 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Check if a point is inside the rectangle's area /// \brief Check if a point is inside the rectangle's area
/// ///
/// This check is non-inclusive. If the point lies on the
/// edge of the rectangle, this function will return false.
///
/// \param x X coordinate of the point to test /// \param x X coordinate of the point to test
/// \param y Y coordinate of the point to test /// \param y Y coordinate of the point to test
/// ///
@ -108,6 +111,9 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Check if a point is inside the rectangle's area /// \brief Check if a point is inside the rectangle's area
/// ///
/// This check is non-inclusive. If the point lies on the
/// edge of the rectangle, this function will return false.
///
/// \param point Point to test /// \param point Point to test
/// ///
/// \return True if the point is inside, false otherwise /// \return True if the point is inside, false otherwise

View file

@ -95,9 +95,11 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Unbind the socket from the local port to which it is bound /// \brief Unbind the socket from the local port to which it is bound
/// ///
/// The port that the socket was previously using is immediately /// The port that the socket was previously bound to is immediately
/// available after this function is called. If the /// made available to the operating system after this function is called.
/// socket is not bound to a port, this function has no effect. /// This means that a subsequent call to bind() will be able to re-bind
/// the port if no other process has done so in the mean time.
/// If the socket is not bound to a port, this function has no effect.
/// ///
/// \see bind /// \see bind
/// ///

View file

@ -29,10 +29,14 @@
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Window/Export.hpp> #include <SFML/Window/Export.hpp>
#include <SFML/System/NonCopyable.hpp>
namespace sf namespace sf
{ {
class Context;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Base class for classes that require an OpenGL context /// \brief Base class for classes that require an OpenGL context
/// ///
@ -54,10 +58,33 @@ protected:
~GlResource(); ~GlResource();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Make sure that a valid OpenGL context exists in the current thread /// \brief Empty function for ABI compatibility, use acquireTransientContext instead
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
static void ensureGlContext(); static void ensureGlContext();
////////////////////////////////////////////////////////////
/// \brief RAII helper class to temporarily lock an available context for use
///
////////////////////////////////////////////////////////////
class SFML_WINDOW_API TransientContextLock : NonCopyable
{
public:
////////////////////////////////////////////////////////////
/// \brief Default constructor
///
////////////////////////////////////////////////////////////
TransientContextLock();
////////////////////////////////////////////////////////////
/// \brief Destructor
///
////////////////////////////////////////////////////////////
~TransientContextLock();
private:
Context* m_context; ///< Temporary context, in case we needed to create one
};
}; };
} // namespace sf } // namespace sf

View file

@ -354,9 +354,7 @@ public:
/// If set, grabs the mouse cursor inside this window's client /// If set, grabs the mouse cursor inside this window's client
/// area so it may no longer be moved outside its bounds. /// area so it may no longer be moved outside its bounds.
/// Note that grabbing is only active while the window has /// Note that grabbing is only active while the window has
/// focus and calling this function for fullscreen windows /// focus.
/// won't have any effect (fullscreen windows always grab the
/// cursor).
/// ///
/// \param grabbed True to enable, false to disable /// \param grabbed True to enable, false to disable
/// ///

View file

@ -645,10 +645,6 @@ Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold, f
// Delete the FT glyph // Delete the FT glyph
FT_Done_Glyph(glyphDesc); FT_Done_Glyph(glyphDesc);
// Force an OpenGL flush, so that the font's texture will appear updated
// in all contexts immediately (solves problems in multi-threaded apps)
glCheck(glFlush());
// Done :) // Done :)
return glyph; return glyph;
} }

View file

@ -29,6 +29,14 @@
#include <SFML/Window/Context.hpp> #include <SFML/Window/Context.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#if !defined(GL_MAJOR_VERSION)
#define GL_MAJOR_VERSION 0x821B
#endif
#if !defined(GL_MINOR_VERSION)
#define GL_MINOR_VERSION 0x821C
#endif
namespace sf namespace sf
{ {
@ -41,22 +49,41 @@ void ensureExtensionsInit()
static bool initialized = false; static bool initialized = false;
if (!initialized) if (!initialized)
{ {
const Context* context = Context::getActiveContext(); initialized = true;
if (!context)
return;
sfogl_LoadFunctions(); sfogl_LoadFunctions();
ContextSettings settings = context->getSettings(); // Retrieve the context version number
int majorVersion = 0;
int minorVersion = 0;
if ((settings.majorVersion < 1) || ((settings.majorVersion == 1) && (settings.minorVersion < 1))) // Try the new way first
glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
glGetIntegerv(GL_MINOR_VERSION, &minorVersion);
if (glGetError() == GL_INVALID_ENUM)
{
// Try the old way
const GLubyte* version = glGetString(GL_VERSION);
if (version)
{
// The beginning of the returned string is "major.minor" (this is standard)
majorVersion = version[0] - '0';
minorVersion = version[2] - '0';
}
else
{
// Can't get the version number, assume 1.1
majorVersion = 1;
minorVersion = 1;
}
}
if ((majorVersion < 1) || ((majorVersion == 1) && (minorVersion < 1)))
{ {
err() << "sfml-graphics requires support for OpenGL 1.1 or greater" << std::endl; err() << "sfml-graphics requires support for OpenGL 1.1 or greater" << std::endl;
err() << "Ensure that hardware acceleration is enabled if available" << std::endl; err() << "Ensure that hardware acceleration is enabled if available" << std::endl;
} }
initialized = true;
} }
#endif #endif
} }

View file

@ -48,7 +48,7 @@ m_depthBuffer(0)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
RenderTextureImplFBO::~RenderTextureImplFBO() RenderTextureImplFBO::~RenderTextureImplFBO()
{ {
ensureGlContext(); m_context->setActive(true);
// Destroy the depth buffer // Destroy the depth buffer
if (m_depthBuffer) if (m_depthBuffer)
@ -72,7 +72,7 @@ RenderTextureImplFBO::~RenderTextureImplFBO()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool RenderTextureImplFBO::isAvailable() bool RenderTextureImplFBO::isAvailable()
{ {
ensureGlContext(); TransientContextLock lock;
// Make sure that extensions are initialized // Make sure that extensions are initialized
priv::ensureExtensionsInit(); priv::ensureExtensionsInit();

View file

@ -56,7 +56,8 @@
namespace namespace
{ {
sf::Mutex mutex; sf::Mutex maxTextureUnitsMutex;
sf::Mutex isAvailableMutex;
GLint checkMaxTextureUnits() GLint checkMaxTextureUnits()
{ {
@ -70,7 +71,7 @@ namespace
GLint getMaxTextureUnits() GLint getMaxTextureUnits()
{ {
// TODO: Remove this lock when it becomes unnecessary in C++11 // TODO: Remove this lock when it becomes unnecessary in C++11
sf::Lock lock(mutex); sf::Lock lock(maxTextureUnitsMutex);
static GLint maxUnits = checkMaxTextureUnits(); static GLint maxUnits = checkMaxTextureUnits();
@ -116,53 +117,6 @@ namespace
return success; return success;
} }
bool checkShadersAvailable()
{
// Create a temporary context in case the user checks
// before a GlResource is created, thus initializing
// the shared context
if (!sf::Context::getActiveContext())
{
sf::Context context;
// Make sure that extensions are initialized
sf::priv::ensureExtensionsInit();
bool available = GLEXT_multitexture &&
GLEXT_shading_language_100 &&
GLEXT_shader_objects &&
GLEXT_vertex_shader &&
GLEXT_fragment_shader;
return available;
}
// Make sure that extensions are initialized
sf::priv::ensureExtensionsInit();
bool available = GLEXT_multitexture &&
GLEXT_shading_language_100 &&
GLEXT_shader_objects &&
GLEXT_vertex_shader &&
GLEXT_fragment_shader;
return available;
}
bool checkGeometryShadersAvailable()
{
// Create a temporary context in case the user checks
// before a GlResource is created, thus initializing
// the shared context
sf::Context context;
// Make sure that extensions are initialized
sf::priv::ensureExtensionsInit();
bool available = checkShadersAvailable() && GLEXT_geometry_shader4;
return available;
}
// Transforms an array of 2D vectors into a contiguous array of scalars // Transforms an array of 2D vectors into a contiguous array of scalars
template <typename T> template <typename T>
std::vector<T> flatten(const sf::Vector2<T>* vectorArray, std::size_t length) std::vector<T> flatten(const sf::Vector2<T>* vectorArray, std::size_t length)
@ -236,8 +190,6 @@ struct Shader::UniformBinder : private NonCopyable
{ {
if (currentProgram) if (currentProgram)
{ {
ensureGlContext();
// Enable program object // Enable program object
glCheck(savedProgram = GLEXT_glGetHandle(GLEXT_GL_PROGRAM_OBJECT)); glCheck(savedProgram = GLEXT_glGetHandle(GLEXT_GL_PROGRAM_OBJECT));
if (currentProgram != savedProgram) if (currentProgram != savedProgram)
@ -259,9 +211,10 @@ struct Shader::UniformBinder : private NonCopyable
glCheck(GLEXT_glUseProgramObject(savedProgram)); glCheck(GLEXT_glUseProgramObject(savedProgram));
} }
GLEXT_GLhandle savedProgram; ///< Handle to the previously active program object TransientContextLock lock; ///< Lock to keep context active while uniform is bound
GLEXT_GLhandle currentProgram; ///< Handle to the program object of the modified sf::Shader instance GLEXT_GLhandle savedProgram; ///< Handle to the previously active program object
GLint location; ///< Uniform location, used by the surrounding sf::Shader code GLEXT_GLhandle currentProgram; ///< Handle to the program object of the modified sf::Shader instance
GLint location; ///< Uniform location, used by the surrounding sf::Shader code
}; };
@ -278,7 +231,7 @@ m_uniforms ()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Shader::~Shader() Shader::~Shader()
{ {
ensureGlContext(); TransientContextLock lock;
// Destroy effect program // Destroy effect program
if (m_shaderProgram) if (m_shaderProgram)
@ -592,7 +545,7 @@ void Shader::setUniform(const std::string& name, const Texture& texture)
{ {
if (m_shaderProgram) if (m_shaderProgram)
{ {
ensureGlContext(); TransientContextLock lock;
// Find the location of the variable in the shader // Find the location of the variable in the shader
int location = getUniformLocation(name); int location = getUniformLocation(name);
@ -627,7 +580,7 @@ void Shader::setUniform(const std::string& name, CurrentTextureType)
{ {
if (m_shaderProgram) if (m_shaderProgram)
{ {
ensureGlContext(); TransientContextLock lock;
// Find the location of the variable in the shader // Find the location of the variable in the shader
m_currentTexture = getUniformLocation(name); m_currentTexture = getUniformLocation(name);
@ -787,7 +740,7 @@ unsigned int Shader::getNativeHandle() const
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Shader::bind(const Shader* shader) void Shader::bind(const Shader* shader)
{ {
ensureGlContext(); TransientContextLock lock;
// Make sure that we can use shaders // Make sure that we can use shaders
if (!isAvailable()) if (!isAvailable())
@ -820,10 +773,26 @@ void Shader::bind(const Shader* shader)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool Shader::isAvailable() bool Shader::isAvailable()
{ {
// TODO: Remove this lock when it becomes unnecessary in C++11 Lock lock(isAvailableMutex);
Lock lock(mutex);
static bool available = checkShadersAvailable(); static bool checked = false;
static bool available = false;
if (!checked)
{
checked = true;
TransientContextLock contextLock;
// Make sure that extensions are initialized
sf::priv::ensureExtensionsInit();
available = GLEXT_multitexture &&
GLEXT_shading_language_100 &&
GLEXT_shader_objects &&
GLEXT_vertex_shader &&
GLEXT_fragment_shader;
}
return available; return available;
} }
@ -832,10 +801,22 @@ bool Shader::isAvailable()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool Shader::isGeometryAvailable() bool Shader::isGeometryAvailable()
{ {
// TODO: Remove this lock when it becomes unnecessary in C++11 Lock lock(isAvailableMutex);
Lock lock(mutex);
static bool available = checkGeometryShadersAvailable(); static bool checked = false;
static bool available = false;
if (!checked)
{
checked = true;
TransientContextLock contextLock;
// Make sure that extensions are initialized
sf::priv::ensureExtensionsInit();
available = isAvailable() && GLEXT_geometry_shader4;
}
return available; return available;
} }
@ -844,7 +825,7 @@ bool Shader::isGeometryAvailable()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool Shader::compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode) bool Shader::compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode)
{ {
ensureGlContext(); TransientContextLock lock;
// First make sure that we can use shaders // First make sure that we can use shaders
if (!isAvailable()) if (!isAvailable())
@ -1022,7 +1003,7 @@ int Shader::getUniformLocation(const std::string& name)
m_uniforms.insert(std::make_pair(name, location)); m_uniforms.insert(std::make_pair(name, location));
if (location == -1) if (location == -1)
err() << "Parameter \"" << name << "\" not found in shader" << std::endl; err() << "Uniform \"" << name << "\" not found in shader" << std::endl;
return location; return location;
} }

View file

@ -40,39 +40,19 @@
namespace namespace
{ {
sf::Mutex mutex; sf::Mutex idMutex;
sf::Mutex maximumSizeMutex;
// Thread-safe unique identifier generator, // Thread-safe unique identifier generator,
// is used for states cache (see RenderTarget) // is used for states cache (see RenderTarget)
sf::Uint64 getUniqueId() sf::Uint64 getUniqueId()
{ {
sf::Lock lock(mutex); sf::Lock lock(idMutex);
static sf::Uint64 id = 1; // start at 1, zero is "no texture" static sf::Uint64 id = 1; // start at 1, zero is "no texture"
return id++; return id++;
} }
unsigned int checkMaximumTextureSize()
{
// Create a temporary context in case the user queries
// the size before a GlResource is created, thus
// initializing the shared context
if (!sf::Context::getActiveContext())
{
sf::Context context;
GLint size;
glCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size));
return static_cast<unsigned int>(size);
}
GLint size;
glCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size));
return static_cast<unsigned int>(size);
}
} }
@ -118,7 +98,7 @@ Texture::~Texture()
// Destroy the OpenGL texture // Destroy the OpenGL texture
if (m_texture) if (m_texture)
{ {
ensureGlContext(); TransientContextLock lock;
GLuint texture = static_cast<GLuint>(m_texture); GLuint texture = static_cast<GLuint>(m_texture);
glCheck(glDeleteTextures(1, &texture)); glCheck(glDeleteTextures(1, &texture));
@ -157,7 +137,7 @@ bool Texture::create(unsigned int width, unsigned int height)
m_pixelsFlipped = false; m_pixelsFlipped = false;
m_fboAttachment = false; m_fboAttachment = false;
ensureGlContext(); TransientContextLock lock;
// Create the OpenGL texture if it doesn't exist yet // Create the OpenGL texture if it doesn't exist yet
if (!m_texture) if (!m_texture)
@ -265,10 +245,6 @@ bool Texture::loadFromImage(const Image& image, const IntRect& area)
{ {
update(image); update(image);
// Force an OpenGL flush, so that the texture will appear updated
// in all contexts immediately (solves problems in multi-threaded apps)
glCheck(glFlush());
return true; return true;
} }
else else
@ -290,6 +266,8 @@ bool Texture::loadFromImage(const Image& image, const IntRect& area)
// Create the texture and upload the pixels // Create the texture and upload the pixels
if (create(rectangle.width, rectangle.height)) if (create(rectangle.width, rectangle.height))
{ {
TransientContextLock lock;
// Make sure that the current texture binding will be preserved // Make sure that the current texture binding will be preserved
priv::TextureSaver save; priv::TextureSaver save;
@ -333,7 +311,7 @@ Image Texture::copyToImage() const
if (!m_texture) if (!m_texture)
return Image(); return Image();
ensureGlContext(); TransientContextLock lock;
// Make sure that the current texture binding will be preserved // Make sure that the current texture binding will be preserved
priv::TextureSaver save; priv::TextureSaver save;
@ -424,7 +402,7 @@ void Texture::update(const Uint8* pixels, unsigned int width, unsigned int heigh
if (pixels && m_texture) if (pixels && m_texture)
{ {
ensureGlContext(); TransientContextLock lock;
// Make sure that the current texture binding will be preserved // Make sure that the current texture binding will be preserved
priv::TextureSaver save; priv::TextureSaver save;
@ -436,6 +414,10 @@ void Texture::update(const Uint8* pixels, unsigned int width, unsigned int heigh
m_hasMipmap = false; m_hasMipmap = false;
m_pixelsFlipped = false; m_pixelsFlipped = false;
m_cacheId = getUniqueId(); m_cacheId = getUniqueId();
// Force an OpenGL flush, so that the texture data will appear updated
// in all contexts immediately (solves problems in multi-threaded apps)
glCheck(glFlush());
} }
} }
@ -470,6 +452,8 @@ void Texture::update(const Window& window, unsigned int x, unsigned int y)
if (m_texture && window.setActive(true)) if (m_texture && window.setActive(true))
{ {
TransientContextLock lock;
// Make sure that the current texture binding will be preserved // Make sure that the current texture binding will be preserved
priv::TextureSaver save; priv::TextureSaver save;
@ -480,6 +464,10 @@ void Texture::update(const Window& window, unsigned int x, unsigned int y)
m_hasMipmap = false; m_hasMipmap = false;
m_pixelsFlipped = true; m_pixelsFlipped = true;
m_cacheId = getUniqueId(); m_cacheId = getUniqueId();
// Force an OpenGL flush, so that the texture will appear updated
// in all contexts immediately (solves problems in multi-threaded apps)
glCheck(glFlush());
} }
} }
@ -493,7 +481,7 @@ void Texture::setSmooth(bool smooth)
if (m_texture) if (m_texture)
{ {
ensureGlContext(); TransientContextLock lock;
// Make sure that the current texture binding will be preserved // Make sure that the current texture binding will be preserved
priv::TextureSaver save; priv::TextureSaver save;
@ -544,7 +532,7 @@ void Texture::setRepeated(bool repeated)
if (m_texture) if (m_texture)
{ {
ensureGlContext(); TransientContextLock lock;
// Make sure that the current texture binding will be preserved // Make sure that the current texture binding will be preserved
priv::TextureSaver save; priv::TextureSaver save;
@ -586,7 +574,7 @@ bool Texture::generateMipmap()
if (!m_texture) if (!m_texture)
return false; return false;
ensureGlContext(); TransientContextLock lock;
// Make sure that extensions are initialized // Make sure that extensions are initialized
priv::ensureExtensionsInit(); priv::ensureExtensionsInit();
@ -613,7 +601,7 @@ void Texture::invalidateMipmap()
if (!m_hasMipmap) if (!m_hasMipmap)
return; return;
ensureGlContext(); TransientContextLock lock;
// Make sure that the current texture binding will be preserved // Make sure that the current texture binding will be preserved
priv::TextureSaver save; priv::TextureSaver save;
@ -628,7 +616,7 @@ void Texture::invalidateMipmap()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Texture::bind(const Texture* texture, CoordinateType coordinateType) void Texture::bind(const Texture* texture, CoordinateType coordinateType)
{ {
ensureGlContext(); TransientContextLock lock;
if (texture && texture->m_texture) if (texture && texture->m_texture)
{ {
@ -684,12 +672,21 @@ void Texture::bind(const Texture* texture, CoordinateType coordinateType)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int Texture::getMaximumSize() unsigned int Texture::getMaximumSize()
{ {
// TODO: Remove this lock when it becomes unnecessary in C++11 Lock lock(maximumSizeMutex);
Lock lock(mutex);
static unsigned int size = checkMaximumTextureSize(); static bool checked = false;
static GLint size = 0;
return size; if (!checked)
{
checked = true;
TransientContextLock lock;
glCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size));
}
return static_cast<unsigned int>(size);
} }
@ -722,7 +719,7 @@ unsigned int Texture::getNativeHandle() const
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int Texture::getValidSize(unsigned int size) unsigned int Texture::getValidSize(unsigned int size)
{ {
ensureGlContext(); TransientContextLock lock;
// Make sure that extensions are initialized // Make sure that extensions are initialized
priv::ensureExtensionsInit(); priv::ensureExtensionsInit();

View file

@ -75,8 +75,6 @@ elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD)
${SRCROOT}/Unix/Display.hpp ${SRCROOT}/Unix/Display.hpp
${SRCROOT}/Unix/InputImpl.cpp ${SRCROOT}/Unix/InputImpl.cpp
${SRCROOT}/Unix/InputImpl.hpp ${SRCROOT}/Unix/InputImpl.hpp
${SRCROOT}/Unix/ScopedXcbPtr.hpp
${SRCROOT}/Unix/ScopedXcbPtr.inl
${SRCROOT}/Unix/SensorImpl.cpp ${SRCROOT}/Unix/SensorImpl.cpp
${SRCROOT}/Unix/SensorImpl.hpp ${SRCROOT}/Unix/SensorImpl.hpp
${SRCROOT}/Unix/VideoModeImpl.cpp ${SRCROOT}/Unix/VideoModeImpl.cpp
@ -200,18 +198,14 @@ if(SFML_OS_LINUX OR SFML_OS_FREEBSD)
if(NOT X11_FOUND) if(NOT X11_FOUND)
message(FATAL_ERROR "X11 library not found") message(FATAL_ERROR "X11 library not found")
endif() endif()
if(NOT X11_Xrandr_FOUND)
message(FATAL_ERROR "Xrandr library not found")
endif()
include_directories(${X11_INCLUDE_DIR}) include_directories(${X11_INCLUDE_DIR})
endif() endif()
if(NOT SFML_OPENGL_ES) if(NOT SFML_OPENGL_ES)
find_package(OpenGL REQUIRED) find_package(OpenGL REQUIRED)
include_directories(${OPENGL_INCLUDE_DIR}) include_directories(${OPENGL_INCLUDE_DIR})
if(SFML_OS_LINUX OR SFML_OS_FREEBSD)
find_package(XCB COMPONENTS xlib_xcb image randr REQUIRED)
if(NOT LIBXCB_FOUND)
message(FATAL_ERROR "Xcb library not found")
endif()
include_directories(${LIBXCB_INCLUDE_DIRS})
endif()
endif() endif()
if(SFML_OPENGL_ES AND SFML_OS_LINUX) if(SFML_OPENGL_ES AND SFML_OS_LINUX)
find_package(EGL REQUIRED) find_package(EGL REQUIRED)
@ -231,9 +225,9 @@ endif()
if(SFML_OS_WINDOWS) if(SFML_OS_WINDOWS)
list(APPEND WINDOW_EXT_LIBS winmm gdi32) list(APPEND WINDOW_EXT_LIBS winmm gdi32)
elseif(SFML_OS_LINUX) elseif(SFML_OS_LINUX)
list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${LIBXCB_LIBRARIES} ${UDEV_LIBRARIES}) list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${X11_Xrandr_LIB} ${UDEV_LIBRARIES})
elseif(SFML_OS_FREEBSD) elseif(SFML_OS_FREEBSD)
list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${LIBXCB_LIBRARIES} usbhid) list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${X11_Xrandr_LIB} usbhid)
elseif(SFML_OS_MACOSX) elseif(SFML_OS_MACOSX)
list(APPEND WINDOW_EXT_LIBS "-framework Foundation -framework AppKit -framework IOKit -framework Carbon") list(APPEND WINDOW_EXT_LIBS "-framework Foundation -framework AppKit -framework IOKit -framework Carbon")
elseif(SFML_OS_IOS) elseif(SFML_OS_IOS)

View file

@ -28,24 +28,6 @@
#include <SFML/Window/Context.hpp> #include <SFML/Window/Context.hpp>
#include <SFML/Window/GlContext.hpp> #include <SFML/Window/GlContext.hpp>
#include <SFML/System/ThreadLocalPtr.hpp> #include <SFML/System/ThreadLocalPtr.hpp>
#include <SFML/OpenGL.hpp>
#include <algorithm>
#include <vector>
#include <string>
#if defined(SFML_SYSTEM_WINDOWS)
typedef const GLubyte* (APIENTRY *glGetStringiFuncType)(GLenum, GLuint);
#else
typedef const GLubyte* (*glGetStringiFuncType)(GLenum, GLuint);
#endif
#if !defined(GL_NUM_EXTENSIONS)
#define GL_NUM_EXTENSIONS 0x821D
#endif
namespace namespace
@ -99,70 +81,16 @@ const Context* Context::getActiveContext()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
GlFunctionPointer Context::getFunction(const char* name) bool Context::isExtensionAvailable(const char* name)
{ {
return priv::GlContext::getFunction(name); return priv::GlContext::isExtensionAvailable(name);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool Context::isExtensionAvailable(const char* name) GlFunctionPointer Context::getFunction(const char* name)
{ {
static std::vector<std::string> extensions; return priv::GlContext::getFunction(name);
static bool loaded = false;
if (!loaded)
{
const Context* context = getActiveContext();
if (!context)
return false;
const char* extensionString = NULL;
if(context->getSettings().majorVersion < 3)
{
// Try to load the < 3.0 way
extensionString = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
do
{
const char* extension = extensionString;
while(*extensionString && (*extensionString != ' '))
extensionString++;
extensions.push_back(std::string(extension, extensionString));
}
while (*extensionString++);
}
else
{
// Try to load the >= 3.0 way
glGetStringiFuncType glGetStringiFunc = NULL;
glGetStringiFunc = reinterpret_cast<glGetStringiFuncType>(getFunction("glGetStringi"));
if (glGetStringiFunc)
{
int numExtensions = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
if (numExtensions)
{
for (unsigned int i = 0; i < static_cast<unsigned int>(numExtensions); ++i)
{
extensionString = reinterpret_cast<const char*>(glGetStringiFunc(GL_EXTENSIONS, i));
extensions.push_back(extensionString);
}
}
}
}
loaded = true;
}
return std::find(extensions.begin(), extensions.end(), name) != extensions.end();
} }

View file

@ -173,9 +173,12 @@ EglContext::~EglContext()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool EglContext::makeCurrent() bool EglContext::makeCurrent(bool current)
{ {
return m_surface != EGL_NO_SURFACE && eglCheck(eglMakeCurrent(m_display, m_surface, m_surface, m_context)); if (current)
return m_surface != EGL_NO_SURFACE && eglCheck(eglMakeCurrent(m_display, m_surface, m_surface, m_context));
return m_surface != EGL_NO_SURFACE && eglCheck(eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
} }
@ -209,6 +212,9 @@ void EglContext::createContext(EglContext* shared)
else else
toShared = EGL_NO_CONTEXT; toShared = EGL_NO_CONTEXT;
if (toShared != EGL_NO_CONTEXT)
eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
// Create EGL context // Create EGL context
m_context = eglCheck(eglCreateContext(m_display, m_config, toShared, contextVersion)); m_context = eglCheck(eglCreateContext(m_display, m_config, toShared, contextVersion));
} }

View file

@ -83,10 +83,12 @@ public:
/// \brief Activate the context as the current target /// \brief Activate the context as the current target
/// for rendering /// for rendering
/// ///
/// \param current Whether to make the context current or no longer current
///
/// \return True on success, false if any error happened /// \return True on success, false if any error happened
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
virtual bool makeCurrent(); virtual bool makeCurrent(bool current);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Display what has been rendered to the context so far /// \brief Display what has been rendered to the context so far

View file

@ -31,9 +31,13 @@
#include <SFML/System/Lock.hpp> #include <SFML/System/Lock.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <SFML/OpenGL.hpp> #include <SFML/OpenGL.hpp>
#include <algorithm>
#include <vector>
#include <string>
#include <set> #include <set>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <cassert>
#if !defined(SFML_OPENGL_ES) #if !defined(SFML_OPENGL_ES)
@ -126,6 +130,8 @@ namespace
// AMD drivers have issues with internal synchronization // AMD drivers have issues with internal synchronization
// We need to make sure that no operating system context // We need to make sure that no operating system context
// or pixel format operations are performed simultaneously // or pixel format operations are performed simultaneously
// This mutex is also used to protect the shared context
// from being locked on multiple threads
sf::Mutex mutex; sf::Mutex mutex;
// This per-thread variable holds the current context for each thread // This per-thread variable holds the current context for each thread
@ -134,35 +140,12 @@ namespace
// The hidden, inactive context that will be shared with all other contexts // The hidden, inactive context that will be shared with all other contexts
ContextType* sharedContext = NULL; ContextType* sharedContext = NULL;
// Internal contexts // This per-thread variable is set to point to the shared context
sf::ThreadLocalPtr<sf::Context> internalContext(NULL); // if we had to acquire it when a TransientContextLock was required
std::set<sf::Context*> internalContexts; sf::ThreadLocalPtr<sf::priv::GlContext> currentSharedContext(NULL);
sf::Mutex internalContextsMutex;
// Check if the internal context of the current thread is valid // Supported OpenGL extensions
bool hasInternalContext() std::vector<std::string> extensions;
{
// The internal context can be null...
if (!internalContext)
return false;
// ... or non-null but deleted from the list of internal contexts
sf::Lock lock(internalContextsMutex);
return internalContexts.find(internalContext) != internalContexts.end();
}
// Retrieve the internal context for the current thread
sf::Context* getInternalContext()
{
if (!hasInternalContext())
{
internalContext = new sf::Context;
sf::Lock lock(internalContextsMutex);
internalContexts.insert(internalContext);
}
return internalContext;
}
} }
@ -182,9 +165,53 @@ void GlContext::globalInit()
sharedContext = new ContextType(NULL); sharedContext = new ContextType(NULL);
sharedContext->initialize(ContextSettings()); sharedContext->initialize(ContextSettings());
// This call makes sure that: // Load our extensions vector
// - the shared context is inactive (it must never be) extensions.clear();
// - another valid context is activated in the current thread
// Check whether a >= 3.0 context is available
int majorVersion = 0;
glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
if (glGetError() == GL_INVALID_ENUM)
{
// Try to load the < 3.0 way
const char* extensionString = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
do
{
const char* extension = extensionString;
while(*extensionString && (*extensionString != ' '))
extensionString++;
extensions.push_back(std::string(extension, extensionString));
}
while (*extensionString++);
}
else
{
// Try to load the >= 3.0 way
glGetStringiFuncType glGetStringiFunc = NULL;
glGetStringiFunc = reinterpret_cast<glGetStringiFuncType>(getFunction("glGetStringi"));
if (glGetStringiFunc)
{
int numExtensions = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
if (numExtensions)
{
for (unsigned int i = 0; i < static_cast<unsigned int>(numExtensions); ++i)
{
const char* extensionString = reinterpret_cast<const char*>(glGetStringiFunc(GL_EXTENSIONS, i));
extensions.push_back(extensionString);
}
}
}
}
// Deactivate the shared context so that others can activate it when necessary
sharedContext->setActive(false); sharedContext->setActive(false);
} }
@ -200,31 +227,59 @@ void GlContext::globalCleanup()
// Destroy the shared context // Destroy the shared context
delete sharedContext; delete sharedContext;
sharedContext = NULL; sharedContext = NULL;
// Destroy the internal contexts
Lock internalContextsLock(internalContextsMutex);
for (std::set<Context*>::iterator it = internalContexts.begin(); it != internalContexts.end(); ++it)
delete *it;
internalContexts.clear();
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void GlContext::ensureContext() void GlContext::acquireTransientContext()
{ {
// If there's no active context on the current thread, activate an internal one // If a capable context is already active on this thread
if (!currentContext) // there is no need to use the shared context for the operation
getInternalContext()->setActive(true); if (currentContext)
{
currentSharedContext = NULL;
return;
}
mutex.lock();
currentSharedContext = sharedContext;
sharedContext->setActive(true);
}
////////////////////////////////////////////////////////////
void GlContext::releaseTransientContext()
{
if (!currentSharedContext)
return;
sharedContext->setActive(false);
mutex.unlock();
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
GlContext* GlContext::create() GlContext* GlContext::create()
{ {
// Make sure that there's an active context (context creation may need extensions, and thus a valid context)
assert(sharedContext != NULL);
Lock lock(mutex); Lock lock(mutex);
// Create the context GlContext* context = NULL;
GlContext* context = new ContextType(sharedContext);
// We don't use acquireTransientContext here since we have
// to ensure we have exclusive access to the shared context
// in order to make sure it is not active during context creation
{
sharedContext->setActive(true);
// Create the context
context = new ContextType(sharedContext);
sharedContext->setActive(false);
}
context->initialize(ContextSettings()); context->initialize(ContextSettings());
return context; return context;
@ -235,12 +290,24 @@ GlContext* GlContext::create()
GlContext* GlContext::create(const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel) GlContext* GlContext::create(const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel)
{ {
// Make sure that there's an active context (context creation may need extensions, and thus a valid context) // Make sure that there's an active context (context creation may need extensions, and thus a valid context)
ensureContext(); assert(sharedContext != NULL);
Lock lock(mutex); Lock lock(mutex);
// Create the context GlContext* context = NULL;
GlContext* context = new ContextType(sharedContext, settings, owner, bitsPerPixel);
// We don't use acquireTransientContext here since we have
// to ensure we have exclusive access to the shared context
// in order to make sure it is not active during context creation
{
sharedContext->setActive(true);
// Create the context
context = new ContextType(sharedContext, settings, owner, bitsPerPixel);
sharedContext->setActive(false);
}
context->initialize(settings); context->initialize(settings);
context->checkSettings(settings); context->checkSettings(settings);
@ -252,12 +319,24 @@ GlContext* GlContext::create(const ContextSettings& settings, const WindowImpl*
GlContext* GlContext::create(const ContextSettings& settings, unsigned int width, unsigned int height) GlContext* GlContext::create(const ContextSettings& settings, unsigned int width, unsigned int height)
{ {
// Make sure that there's an active context (context creation may need extensions, and thus a valid context) // Make sure that there's an active context (context creation may need extensions, and thus a valid context)
ensureContext(); assert(sharedContext != NULL);
Lock lock(mutex); Lock lock(mutex);
// Create the context GlContext* context = NULL;
GlContext* context = new ContextType(sharedContext, settings, width, height);
// We don't use acquireTransientContext here since we have
// to ensure we have exclusive access to the shared context
// in order to make sure it is not active during context creation
{
sharedContext->setActive(true);
// Create the context
context = new ContextType(sharedContext, settings, width, height);
sharedContext->setActive(false);
}
context->initialize(settings); context->initialize(settings);
context->checkSettings(settings); context->checkSettings(settings);
@ -265,6 +344,13 @@ GlContext* GlContext::create(const ContextSettings& settings, unsigned int width
} }
////////////////////////////////////////////////////////////
bool GlContext::isExtensionAvailable(const char* name)
{
return std::find(extensions.begin(), extensions.end(), name) != extensions.end();
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
GlFunctionPointer GlContext::getFunction(const char* name) GlFunctionPointer GlContext::getFunction(const char* name)
{ {
@ -287,7 +373,10 @@ GlContext::~GlContext()
{ {
// Deactivate the context before killing it, unless we're inside Cleanup() // Deactivate the context before killing it, unless we're inside Cleanup()
if (sharedContext) if (sharedContext)
setActive(false); {
if (this == currentContext)
currentContext = NULL;
}
} }
@ -308,7 +397,7 @@ bool GlContext::setActive(bool active)
Lock lock(mutex); Lock lock(mutex);
// Activate the context // Activate the context
if (makeCurrent()) if (makeCurrent(true))
{ {
// Set it as the new current context for this thread // Set it as the new current context for this thread
currentContext = this; currentContext = this;
@ -329,9 +418,18 @@ bool GlContext::setActive(bool active)
{ {
if (this == currentContext) if (this == currentContext)
{ {
// To deactivate the context, we actually activate another one so that we make Lock lock(mutex);
// sure that there is always an active context for subsequent graphics operations
return getInternalContext()->setActive(true); // Deactivate the context
if (makeCurrent(false))
{
currentContext = NULL;
return true;
}
else
{
return false;
}
} }
else else
{ {

View file

@ -73,10 +73,16 @@ public:
static void globalCleanup(); static void globalCleanup();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Ensures that an OpenGL context is active in the current thread /// \brief Acquires a context for short-term use on the current thread
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
static void ensureContext(); static void acquireTransientContext();
////////////////////////////////////////////////////////////
/// \brief Releases a context after short-term use on the current thread
///
////////////////////////////////////////////////////////////
static void releaseTransientContext();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Create a new context, not associated to a window /// \brief Create a new context, not associated to a window
@ -120,6 +126,16 @@ public:
static GlContext* create(const ContextSettings& settings, unsigned int width, unsigned int height); static GlContext* create(const ContextSettings& settings, unsigned int width, unsigned int height);
public: public:
////////////////////////////////////////////////////////////
/// \brief Check whether a given OpenGL extension is available
///
/// \param name Name of the extension to check for
///
/// \return True if available, false if unavailable
///
////////////////////////////////////////////////////////////
static bool isExtensionAvailable(const char* name);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Get the address of an OpenGL function /// \brief Get the address of an OpenGL function
/// ///
@ -197,10 +213,12 @@ protected:
/// \brief Activate the context as the current target /// \brief Activate the context as the current target
/// for rendering /// for rendering
/// ///
/// \param current Whether to make the context current or no longer current
///
/// \return True on success, false if any error happened /// \return True on success, false if any error happened
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
virtual bool makeCurrent() = 0; virtual bool makeCurrent(bool current) = 0;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Evaluate a pixel format configuration /// \brief Evaluate a pixel format configuration

View file

@ -27,6 +27,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Window/GlResource.hpp> #include <SFML/Window/GlResource.hpp>
#include <SFML/Window/GlContext.hpp> #include <SFML/Window/GlContext.hpp>
#include <SFML/Window/Context.hpp>
#include <SFML/System/Mutex.hpp> #include <SFML/System/Mutex.hpp>
#include <SFML/System/Lock.hpp> #include <SFML/System/Lock.hpp>
@ -44,20 +45,15 @@ namespace sf
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
GlResource::GlResource() GlResource::GlResource()
{ {
{ // Protect from concurrent access
// Protect from concurrent access Lock lock(mutex);
Lock lock(mutex);
// If this is the very first resource, trigger the global context initialization // If this is the very first resource, trigger the global context initialization
if (count == 0) if (count == 0)
priv::GlContext::globalInit(); priv::GlContext::globalInit();
// Increment the resources counter // Increment the resources counter
count++; count++;
}
// Now make sure that there is an active OpenGL context in the current thread
priv::GlContext::ensureContext();
} }
@ -79,7 +75,36 @@ GlResource::~GlResource()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void GlResource::ensureGlContext() void GlResource::ensureGlContext()
{ {
priv::GlContext::ensureContext(); // Empty function for ABI compatibility, use acquireTransientContext instead
}
////////////////////////////////////////////////////////////
GlResource::TransientContextLock::TransientContextLock() :
m_context(0)
{
Lock lock(mutex);
if (count == 0)
{
m_context = new Context;
return;
}
priv::GlContext::acquireTransientContext();
}
////////////////////////////////////////////////////////////
GlResource::TransientContextLock::~TransientContextLock()
{
if (m_context)
{
delete m_context;
return;
}
priv::GlContext::releaseTransientContext();
} }
} // namespace sf } // namespace sf

View file

@ -137,10 +137,12 @@ protected:
/// \brief Activate the context as the current target /// \brief Activate the context as the current target
/// for rendering /// for rendering
/// ///
/// \param current Whether to make the context current or no longer current
///
/// \return True on success, false if any error happened /// \return True on success, false if any error happened
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
virtual bool makeCurrent(); virtual bool makeCurrent(bool current);
private: private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View file

@ -104,6 +104,10 @@ m_window(0)
SFContext::~SFContext() SFContext::~SFContext()
{ {
[m_context clearDrawable]; [m_context clearDrawable];
if (m_context == [NSOpenGLContext currentContext])
[NSOpenGLContext clearCurrentContext];
[m_context release]; [m_context release];
[m_view release]; // Might be nil but we don't care. [m_view release]; // Might be nil but we don't care.
@ -124,10 +128,18 @@ GlFunctionPointer SFContext::getFunction(const char* name)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool SFContext::makeCurrent() bool SFContext::makeCurrent(bool current)
{ {
[m_context makeCurrentContext]; if (current)
return m_context == [NSOpenGLContext currentContext]; // Should be true. {
[m_context makeCurrentContext];
return m_context == [NSOpenGLContext currentContext]; // Should be true.
}
else
{
[NSOpenGLContext clearCurrentContext];
return m_context != [NSOpenGLContext currentContext]; // Should be true.
}
} }
@ -257,6 +269,17 @@ void SFContext::createContext(SFContext* shared,
// Use the shared context if one is given. // Use the shared context if one is given.
NSOpenGLContext* sharedContext = shared != NULL ? shared->m_context : nil; NSOpenGLContext* sharedContext = shared != NULL ? shared->m_context : nil;
if (sharedContext != nil)
{
[NSOpenGLContext clearCurrentContext];
if (sharedContext == [NSOpenGLContext currentContext])
{
sf::err() << "Failed to deactivate shared context before sharing" << std::endl;
return;
}
}
// Create the context. // Create the context.
m_context = [[NSOpenGLContext alloc] initWithFormat:pixFmt m_context = [[NSOpenGLContext alloc] initWithFormat:pixFmt
shareContext:sharedContext]; shareContext:sharedContext];

View file

@ -230,7 +230,7 @@
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
-(BOOL)isCursorCurrentlyGrabbed -(BOOL)isCursorCurrentlyGrabbed
{ {
return [[self window] isKeyWindow] && (m_cursorGrabbed || m_fullscreen); return [[self window] isKeyWindow] && m_cursorGrabbed;
} }

View file

@ -70,8 +70,7 @@
/// \brief Check whether the cursor is grabbed or not /// \brief Check whether the cursor is grabbed or not
/// ///
/// The cursor is grabbed if the window is active (key) and /// The cursor is grabbed if the window is active (key) and
/// either it is in fullscreen mode or the user wants to /// the user wants to grab it.
/// grab it.
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
-(BOOL)isCursorCurrentlyGrabbed; -(BOOL)isCursorCurrentlyGrabbed;

View file

@ -26,10 +26,12 @@
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <SFML/System/Mutex.hpp>
#include <SFML/System/Lock.hpp>
#include <SFML/Window/Unix/Display.hpp> #include <SFML/Window/Unix/Display.hpp>
#include <SFML/Window/Unix/ScopedXcbPtr.hpp>
#include <X11/keysym.h> #include <X11/keysym.h>
#include <cassert> #include <cassert>
#include <cstdlib>
#include <map> #include <map>
@ -38,8 +40,9 @@ namespace
// The shared display and its reference counter // The shared display and its reference counter
Display* sharedDisplay = NULL; Display* sharedDisplay = NULL;
unsigned int referenceCount = 0; unsigned int referenceCount = 0;
sf::Mutex mutex;
typedef std::map<std::string, xcb_atom_t> AtomMap; typedef std::map<std::string, Atom> AtomMap;
AtomMap atoms; AtomMap atoms;
} }
@ -50,6 +53,8 @@ namespace priv
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Display* OpenDisplay() Display* OpenDisplay()
{ {
Lock lock(mutex);
if (referenceCount == 0) if (referenceCount == 0)
{ {
sharedDisplay = XOpenDisplay(NULL); sharedDisplay = XOpenDisplay(NULL);
@ -68,16 +73,11 @@ Display* OpenDisplay()
} }
////////////////////////////////////////////////////////////
xcb_connection_t* OpenConnection()
{
return XGetXCBConnection(OpenDisplay());
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void CloseDisplay(Display* display) void CloseDisplay(Display* display)
{ {
Lock lock(mutex);
assert(display == sharedDisplay); assert(display == sharedDisplay);
referenceCount--; referenceCount--;
@ -87,81 +87,22 @@ void CloseDisplay(Display* display)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void CloseConnection(xcb_connection_t* connection) Atom getAtom(const std::string& name, bool onlyIfExists)
{
assert(connection == XGetXCBConnection(sharedDisplay));
return CloseDisplay(sharedDisplay);
}
////////////////////////////////////////////////////////////
xcb_screen_t* XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr)
{
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(connection));
for (; iter.rem; --screen_nbr, xcb_screen_next (&iter))
{
if (screen_nbr == 0)
return iter.data;
}
return NULL;
}
////////////////////////////////////////////////////////////
xcb_screen_t* XCBDefaultScreen(xcb_connection_t* connection)
{
assert(connection == XGetXCBConnection(sharedDisplay));
return XCBScreenOfDisplay(connection, XDefaultScreen(sharedDisplay));
}
////////////////////////////////////////////////////////////
xcb_window_t XCBDefaultRootWindow(xcb_connection_t* connection)
{
assert(connection == XGetXCBConnection(sharedDisplay));
xcb_screen_t* screen = XCBScreenOfDisplay(connection, XDefaultScreen(sharedDisplay));
if (screen)
return screen->root;
return 0;
}
////////////////////////////////////////////////////////////
xcb_atom_t getAtom(const std::string& name, bool onlyIfExists)
{ {
AtomMap::const_iterator iter = atoms.find(name); AtomMap::const_iterator iter = atoms.find(name);
if (iter != atoms.end()) if (iter != atoms.end())
return iter->second; return iter->second;
ScopedXcbPtr<xcb_generic_error_t> error(NULL); Display* display = OpenDisplay();
xcb_connection_t* connection = OpenConnection(); Atom atom = XInternAtom(display, name.c_str(), onlyIfExists ? True : False);
ScopedXcbPtr<xcb_intern_atom_reply_t> reply(xcb_intern_atom_reply( CloseDisplay(display);
connection,
xcb_intern_atom(
connection,
onlyIfExists,
name.size(),
name.c_str()
),
&error
));
CloseConnection(connection); atoms[name] = atom;
if (error || !reply) return atom;
{
err() << "Failed to get " << name << " atom." << std::endl;
return XCB_ATOM_NONE;
}
atoms[name] = reply->atom;
return reply->atom;
} }
} // namespace priv } // namespace priv

View file

@ -28,7 +28,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <X11/Xlib-xcb.h> #include <X11/Xlib.h>
#include <string> #include <string>
@ -47,17 +47,6 @@ namespace priv
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Display* OpenDisplay(); Display* OpenDisplay();
////////////////////////////////////////////////////////////
/// \brief Get the xcb connection of the shared Display
///
/// This function increments the reference count of the display,
/// it must be matched with a call to CloseConnection.
///
/// \return Pointer to the shared connection
///
////////////////////////////////////////////////////////////
xcb_connection_t* OpenConnection();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Release a reference to the shared display /// \brief Release a reference to the shared display
/// ///
@ -66,55 +55,16 @@ xcb_connection_t* OpenConnection();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void CloseDisplay(Display* display); void CloseDisplay(Display* display);
////////////////////////////////////////////////////////////
/// \brief Release a reference to the shared display
///
/// \param connection Connection of display to release
///
////////////////////////////////////////////////////////////
void CloseConnection(xcb_connection_t* connection);
////////////////////////////////////////////////////////////
/// \brief Get screen of a display by index (equivalent to XScreenOfDisplay)
///
/// \param connection Connection of display
/// \param screen_nbr The index of the screen
///
/// \return Pointer to the screen
///
////////////////////////////////////////////////////////////
xcb_screen_t* XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr);
////////////////////////////////////////////////////////////
/// \brief Get default screen of a display (equivalent to XDefaultScreen)
///
/// \param connection Connection of display
///
/// \return Pointer to the default screen of the display
///
////////////////////////////////////////////////////////////
xcb_screen_t* XCBDefaultScreen(xcb_connection_t* connection);
////////////////////////////////////////////////////////////
/// \brief Get default root window of a display (equivalent to XDefaultRootWindow)
///
/// \param connection Connection of display
///
/// \return Root window of the display
///
////////////////////////////////////////////////////////////
xcb_window_t XCBDefaultRootWindow(xcb_connection_t* connection);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Get the atom with the specified name /// \brief Get the atom with the specified name
/// ///
/// \param name Name of the atom /// \param name Name of the atom
/// \param onlyIfExists Don't try to create the atom if it doesn't already exist /// \param onlyIfExists Don't try to create the atom if it doesn't already exist
/// ///
/// \return Atom if it exists or XCB_ATOM_NONE (0) if it doesn't /// \return Atom if it exists or None (0) if it doesn't
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
xcb_atom_t getAtom(const std::string& name, bool onlyIfExists = false); Atom getAtom(const std::string& name, bool onlyIfExists = false);
} // namespace priv } // namespace priv

View file

@ -194,8 +194,8 @@ GlxContext::~GlxContext()
// Destroy the window if we own it // Destroy the window if we own it
if (m_window && m_ownsWindow) if (m_window && m_ownsWindow)
{ {
xcb_destroy_window(m_connection, m_window); XDestroyWindow(m_display, m_window);
xcb_flush(m_connection); XFlush(m_display);
} }
// Close the connection with the X server // Close the connection with the X server
@ -211,7 +211,7 @@ GlFunctionPointer GlxContext::getFunction(const char* name)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool GlxContext::makeCurrent() bool GlxContext::makeCurrent(bool current)
{ {
if (!m_context) if (!m_context)
return false; return false;
@ -222,13 +222,20 @@ bool GlxContext::makeCurrent()
bool result = false; bool result = false;
if (m_pbuffer) if (current)
{ {
result = glXMakeContextCurrent(m_display, m_pbuffer, m_pbuffer, m_context); if (m_pbuffer)
{
result = glXMakeContextCurrent(m_display, m_pbuffer, m_pbuffer, m_context);
}
else if (m_window)
{
result = glXMakeCurrent(m_display, m_window, m_context);
}
} }
else if (m_window) else
{ {
result = glXMakeCurrent(m_display, m_window, m_context); result = glXMakeCurrent(m_display, None, NULL);
} }
#if defined(GLX_DEBUGGING) #if defined(GLX_DEBUGGING)
@ -444,7 +451,6 @@ void GlxContext::updateSettingsFromWindow()
void GlxContext::createSurface(GlxContext* shared, unsigned int width, unsigned int height, unsigned int bitsPerPixel) void GlxContext::createSurface(GlxContext* shared, unsigned int width, unsigned int height, unsigned int bitsPerPixel)
{ {
m_display = OpenDisplay(); m_display = OpenDisplay();
m_connection = XGetXCBConnection(m_display);
// Choose the visual according to the context settings // Choose the visual according to the context settings
XVisualInfo visualInfo = selectBestVisual(m_display, bitsPerPixel, m_settings); XVisualInfo visualInfo = selectBestVisual(m_display, bitsPerPixel, m_settings);
@ -482,8 +488,11 @@ void GlxContext::createSurface(GlxContext* shared, unsigned int width, unsigned
if (visual->visualid == visualInfo.visualid) if (visual->visualid == visualInfo.visualid)
{ {
config = &configs[i]; config = &configs[i];
XFree(visual);
break; break;
} }
XFree(visual);
} }
if (config) if (config)
@ -510,28 +519,22 @@ void GlxContext::createSurface(GlxContext* shared, unsigned int width, unsigned
} }
// If pbuffers are not available we use a hidden window as the off-screen surface to draw to // If pbuffers are not available we use a hidden window as the off-screen surface to draw to
xcb_screen_t* screen = XCBScreenOfDisplay(m_connection, DefaultScreen(m_display)); int screen = DefaultScreen(m_display);
// Define the window attributes // Define the window attributes
xcb_colormap_t colormap = xcb_generate_id(m_connection); XSetWindowAttributes attributes;
xcb_create_colormap(m_connection, XCB_COLORMAP_ALLOC_NONE, colormap, screen->root, visualInfo.visualid); attributes.colormap = XCreateColormap(m_display, RootWindow(m_display, screen), visualInfo.visual, AllocNone);
const uint32_t value_list[] = {colormap};
// Create a dummy window (disabled and hidden) m_window = XCreateWindow(m_display,
m_window = xcb_generate_id(m_connection); RootWindow(m_display, screen),
xcb_create_window( 0, 0,
m_connection, width, height,
static_cast<uint8_t>(visualInfo.depth), 0,
m_window, DefaultDepth(m_display, screen),
screen->root, InputOutput,
0, 0, visualInfo.visual,
width, height, CWColormap,
0, &attributes);
XCB_WINDOW_CLASS_INPUT_OUTPUT,
visualInfo.visualid,
XCB_CW_COLORMAP,
value_list
);
m_ownsWindow = true; m_ownsWindow = true;
@ -543,7 +546,6 @@ void GlxContext::createSurface(GlxContext* shared, unsigned int width, unsigned
void GlxContext::createSurface(::Window window) void GlxContext::createSurface(::Window window)
{ {
m_display = OpenDisplay(); m_display = OpenDisplay();
m_connection = XGetXCBConnection(m_display);
// A window already exists, so just use it // A window already exists, so just use it
m_window = window; m_window = window;
@ -640,8 +642,11 @@ void GlxContext::createContext(GlxContext* shared)
if (visual->visualid == visualInfo->visualid) if (visual->visualid == visualInfo->visualid)
{ {
config = &configs[i]; config = &configs[i];
XFree(visual);
break; break;
} }
XFree(visual);
} }
if (!config) if (!config)
@ -688,6 +693,15 @@ void GlxContext::createContext(GlxContext* shared)
// On an error, glXCreateContextAttribsARB will return 0 anyway // On an error, glXCreateContextAttribsARB will return 0 anyway
GlxErrorHandler handler(m_display); GlxErrorHandler handler(m_display);
if (toShare)
{
if (!glXMakeCurrent(m_display, None, NULL))
{
err() << "Failed to deactivate shared context before sharing" << std::endl;
return;
}
}
// Create the context // Create the context
m_context = glXCreateContextAttribsARB(m_display, *config, toShare, true, &attributes[0]); m_context = glXCreateContextAttribsARB(m_display, *config, toShare, true, &attributes[0]);
@ -734,6 +748,15 @@ void GlxContext::createContext(GlxContext* shared)
GlxErrorHandler handler(m_display); GlxErrorHandler handler(m_display);
#endif #endif
if (toShare)
{
if (!glXMakeCurrent(m_display, None, NULL))
{
err() << "Failed to deactivate shared context before sharing" << std::endl;
return;
}
}
// Create the context, using the target window's visual // Create the context, using the target window's visual
m_context = glXCreateContext(m_display, visualInfo, toShare, true); m_context = glXCreateContext(m_display, visualInfo, toShare, true);

View file

@ -30,7 +30,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Window/GlContext.hpp> #include <SFML/Window/GlContext.hpp>
#include <SFML/Window/Unix/GlxExtensions.hpp> #include <SFML/Window/Unix/GlxExtensions.hpp>
#include <X11/Xlib-xcb.h> #include <X11/Xlib.h>
namespace sf namespace sf
@ -94,10 +94,12 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Activate the context as the current target for rendering /// \brief Activate the context as the current target for rendering
/// ///
/// \param current Whether to make the context current or no longer current
///
/// \return True on success, false if any error happened /// \return True on success, false if any error happened
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
virtual bool makeCurrent(); virtual bool makeCurrent(bool current);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Display what has been rendered to the context so far /// \brief Display what has been rendered to the context so far
@ -178,7 +180,6 @@ private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
::Display* m_display; ///< Connection to the X server ::Display* m_display; ///< Connection to the X server
::Window m_window; ///< Window to which the context is attached ::Window m_window; ///< Window to which the context is attached
xcb_connection_t* m_connection; ///< Pointer to the xcb connection
GLXContext m_context; ///< OpenGL context GLXContext m_context; ///< OpenGL context
GLXPbuffer m_pbuffer; ///< GLX pbuffer ID if one was created GLXPbuffer m_pbuffer; ///< GLX pbuffer ID if one was created
bool m_ownsWindow; ///< Do we own the window associated to the context? bool m_ownsWindow; ///< Do we own the window associated to the context?

View file

@ -28,9 +28,8 @@
#include <SFML/Window/Window.hpp> // important to be included first (conflict with None) #include <SFML/Window/Window.hpp> // important to be included first (conflict with None)
#include <SFML/Window/Unix/InputImpl.hpp> #include <SFML/Window/Unix/InputImpl.hpp>
#include <SFML/Window/Unix/Display.hpp> #include <SFML/Window/Unix/Display.hpp>
#include <SFML/Window/Unix/ScopedXcbPtr.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <xcb/xcb.h> #include <X11/Xlib.h>
#include <X11/keysym.h> #include <X11/keysym.h>
@ -157,36 +156,26 @@ bool InputImpl::isKeyPressed(Keyboard::Key key)
Display* display = OpenDisplay(); Display* display = OpenDisplay();
// Convert to keycode // Convert to keycode
xcb_keycode_t keycode = XKeysymToKeycode(display, keysym); KeyCode keycode = XKeysymToKeycode(display, keysym);
if (keycode != 0)
CloseDisplay(display);
ScopedXcbPtr<xcb_generic_error_t> error(NULL);
// Open a connection with the X server
xcb_connection_t* connection = OpenConnection();
// Get the whole keyboard state
ScopedXcbPtr<xcb_query_keymap_reply_t> keymap(
xcb_query_keymap_reply(
connection,
xcb_query_keymap(connection),
&error
)
);
// Close the connection with the X server
CloseConnection(connection);
if (error)
{ {
err() << "Failed to query keymap" << std::endl; // Get the whole keyboard state
char keys[32];
XQueryKeymap(display, keys);
// Close the connection with the X server
CloseDisplay(display);
// Check our keycode
return (keys[keycode / 8] & (1 << (keycode % 8))) != 0;
}
else
{
// Close the connection with the X server
CloseDisplay(display);
return false; return false;
} }
// Check our keycode
return (keymap->keys[keycode / 8] & (1 << (keycode % 8))) != 0;
} }
@ -201,43 +190,30 @@ void InputImpl::setVirtualKeyboardVisible(bool /*visible*/)
bool InputImpl::isMouseButtonPressed(Mouse::Button button) bool InputImpl::isMouseButtonPressed(Mouse::Button button)
{ {
// Open a connection with the X server // Open a connection with the X server
xcb_connection_t* connection = OpenConnection(); Display* display = OpenDisplay();
ScopedXcbPtr<xcb_generic_error_t> error(NULL); // we don't care about these but they are required
::Window root, child;
int wx, wy;
int gx, gy;
// Get pointer mask unsigned int buttons = 0;
ScopedXcbPtr<xcb_query_pointer_reply_t> pointer( XQueryPointer(display, DefaultRootWindow(display), &root, &child, &gx, &gy, &wx, &wy, &buttons);
xcb_query_pointer_reply(
connection,
xcb_query_pointer(
connection,
XCBDefaultRootWindow(connection)
),
&error
)
);
// Close the connection with the X server // Close the connection with the X server
CloseConnection(connection); CloseDisplay(display);
if (error)
{
err() << "Failed to query pointer" << std::endl;
return false;
}
uint16_t buttons = pointer->mask;
switch (button) switch (button)
{ {
case Mouse::Left: return buttons & XCB_BUTTON_MASK_1; case Mouse::Left: return buttons & Button1Mask;
case Mouse::Right: return buttons & XCB_BUTTON_MASK_3; case Mouse::Right: return buttons & Button3Mask;
case Mouse::Middle: return buttons & XCB_BUTTON_MASK_2; case Mouse::Middle: return buttons & Button2Mask;
case Mouse::XButton1: return false; // not supported by X case Mouse::XButton1: return false; // not supported by X
case Mouse::XButton2: return false; // not supported by X case Mouse::XButton2: return false; // not supported by X
default: return false; default: return false;
} }
return false;
} }
@ -245,32 +221,21 @@ bool InputImpl::isMouseButtonPressed(Mouse::Button button)
Vector2i InputImpl::getMousePosition() Vector2i InputImpl::getMousePosition()
{ {
// Open a connection with the X server // Open a connection with the X server
xcb_connection_t* connection = OpenConnection(); Display* display = OpenDisplay();
ScopedXcbPtr<xcb_generic_error_t> error(NULL); // we don't care about these but they are required
::Window root, child;
int x, y;
unsigned int buttons;
ScopedXcbPtr<xcb_query_pointer_reply_t> pointer( int gx = 0;
xcb_query_pointer_reply( int gy = 0;
connection, XQueryPointer(display, DefaultRootWindow(display), &root, &child, &gx, &gy, &x, &y, &buttons);
xcb_query_pointer(
connection,
XCBDefaultRootWindow(connection)
),
&error
)
);
// Close the connection with the X server // Close the connection with the X server
CloseConnection(connection); CloseDisplay(display);
if (error) return Vector2i(gx, gy);
{
err() << "Failed to query pointer" << std::endl;
return Vector2i(0, 0);
}
return Vector2i(pointer->root_x, pointer->root_y);
} }
@ -281,32 +246,21 @@ Vector2i InputImpl::getMousePosition(const Window& relativeTo)
if (handle) if (handle)
{ {
// Open a connection with the X server // Open a connection with the X server
xcb_connection_t* connection = OpenConnection(); Display* display = OpenDisplay();
ScopedXcbPtr<xcb_generic_error_t> error(NULL); // we don't care about these but they are required
::Window root, child;
int gx, gy;
unsigned int buttons;
ScopedXcbPtr<xcb_query_pointer_reply_t> pointer( int x = 0;
xcb_query_pointer_reply( int y = 0;
connection, XQueryPointer(display, handle, &root, &child, &gx, &gy, &x, &y, &buttons);
xcb_query_pointer(
connection,
handle
),
&error
)
);
// Close the connection with the X server // Close the connection with the X server
CloseConnection(connection); CloseDisplay(display);
if (error) return Vector2i(x, y);
{
err() << "Failed to query pointer" << std::endl;
return Vector2i(0, 0);
}
return Vector2i(pointer->win_x, pointer->win_y);
} }
else else
{ {
@ -319,27 +273,13 @@ Vector2i InputImpl::getMousePosition(const Window& relativeTo)
void InputImpl::setMousePosition(const Vector2i& position) void InputImpl::setMousePosition(const Vector2i& position)
{ {
// Open a connection with the X server // Open a connection with the X server
xcb_connection_t* connection = OpenConnection(); Display* display = OpenDisplay();
ScopedXcbPtr<xcb_generic_error_t> error(xcb_request_check( XWarpPointer(display, None, DefaultRootWindow(display), 0, 0, 0, 0, position.x, position.y);
connection, XFlush(display);
xcb_warp_pointer(
connection,
None, // Source window
XCBDefaultRootWindow(connection), // Destination window
0, 0, // Source position
0, 0, // Source size
position.x, position.y // Destination position
)
));
if (error)
err() << "Failed to set mouse position" << std::endl;
xcb_flush(connection);
// Close the connection with the X server // Close the connection with the X server
CloseConnection(connection); CloseDisplay(display);
} }
@ -347,31 +287,17 @@ void InputImpl::setMousePosition(const Vector2i& position)
void InputImpl::setMousePosition(const Vector2i& position, const Window& relativeTo) void InputImpl::setMousePosition(const Vector2i& position, const Window& relativeTo)
{ {
// Open a connection with the X server // Open a connection with the X server
xcb_connection_t* connection = OpenConnection(); Display* display = OpenDisplay();
WindowHandle handle = relativeTo.getSystemHandle(); WindowHandle handle = relativeTo.getSystemHandle();
if (handle) if (handle)
{ {
ScopedXcbPtr<xcb_generic_error_t> error(xcb_request_check( XWarpPointer(display, None, handle, 0, 0, 0, 0, position.x, position.y);
connection, XFlush(display);
xcb_warp_pointer(
connection,
None, // Source window
handle, // Destination window
0, 0, // Source position
0, 0, // Source size
position.x, position.y // Destination position
)
));
if (error)
err() << "Failed to set mouse position" << std::endl;
xcb_flush(connection);
} }
// Close the connection with the X server // Close the connection with the X server
CloseConnection(connection); CloseDisplay(display);
} }

View file

@ -1,102 +0,0 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org)
//
// 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 SFML_SCOPEDXCBPTR_HPP
#define SFML_SCOPEDXCBPTR_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <cstdlib>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief Scoped pointer that frees memory returned in XCB replies
///
////////////////////////////////////////////////////////////
template<typename T>
class ScopedXcbPtr
{
public:
////////////////////////////////////////////////////////////
/// \brief Constructor
///
/// \param pointer Pointer value to store
///
////////////////////////////////////////////////////////////
ScopedXcbPtr(T* pointer);
////////////////////////////////////////////////////////////
/// \brief Destructor, calls std::free() on the stored pointer
///
////////////////////////////////////////////////////////////
~ScopedXcbPtr();
////////////////////////////////////////////////////////////
/// \brief Structure dereference operator
///
/// \return Stored pointer
///
////////////////////////////////////////////////////////////
T* operator ->() const;
////////////////////////////////////////////////////////////
/// \brief Address operator.
///
/// \return Address of the stored pointer
///
////////////////////////////////////////////////////////////
T** operator &();
////////////////////////////////////////////////////////////
/// \brief Check if stored pointer is valid
///
/// \return true if stored pointer is valid
///
////////////////////////////////////////////////////////////
operator bool() const;
////////////////////////////////////////////////////////////
/// \brief Retrieve the stored pointer.
///
/// \return The stored pointer
///
////////////////////////////////////////////////////////////
T* get() const;
private:
T* m_pointer; ///< Stored pointer
};
#include <SFML/Window/Unix/ScopedXcbPtr.inl>
} // namespace priv
} // namespace sf
#endif // SFML_SCOPEDXCBPTR_HPP

View file

@ -1,72 +0,0 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org)
//
// 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.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
template <typename T>
inline ScopedXcbPtr<T>::ScopedXcbPtr(T* pointer) :
m_pointer(pointer)
{
}
////////////////////////////////////////////////////////////
template <typename T>
inline ScopedXcbPtr<T>::~ScopedXcbPtr()
{
std::free(m_pointer);
}
////////////////////////////////////////////////////////////
template <typename T>
inline T* ScopedXcbPtr<T>::operator ->() const
{
return m_pointer;
}
////////////////////////////////////////////////////////////
template <typename T>
inline T** ScopedXcbPtr<T>::operator &()
{
return &m_pointer;
}
////////////////////////////////////////////////////////////
template <typename T>
inline ScopedXcbPtr<T>::operator bool() const
{
return m_pointer != NULL;
}
////////////////////////////////////////////////////////////
template <typename T>
inline T* ScopedXcbPtr<T>::get() const
{
return m_pointer;
}

View file

@ -27,9 +27,9 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Window/VideoModeImpl.hpp> #include <SFML/Window/VideoModeImpl.hpp>
#include <SFML/Window/Unix/Display.hpp> #include <SFML/Window/Unix/Display.hpp>
#include <SFML/Window/Unix/ScopedXcbPtr.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <xcb/randr.h> #include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
#include <algorithm> #include <algorithm>
@ -43,95 +43,78 @@ std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
std::vector<VideoMode> modes; std::vector<VideoMode> modes;
// Open a connection with the X server // Open a connection with the X server
xcb_connection_t* connection = OpenConnection(); Display* display = OpenDisplay();
if (display)
// Retrieve the default screen
xcb_screen_t* screen = XCBDefaultScreen(connection);
ScopedXcbPtr<xcb_generic_error_t> error(NULL);
const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(connection, &xcb_randr_id);
if (!randrExt || !randrExt->present)
{ {
// Randr extension is not supported: we cannot get the video modes // Retrieve the default screen number
err() << "Failed to use the RandR extension while trying to get the supported video modes" << std::endl; int screen = DefaultScreen(display);
// Close the connection with the X server // Check if the XRandR extension is present
CloseConnection(connection); int version;
if (XQueryExtension(display, "RANDR", &version, &version, &version))
return modes;
}
// Load RandR and check its version
ScopedXcbPtr<xcb_randr_query_version_reply_t> randrVersion(xcb_randr_query_version_reply(
connection,
xcb_randr_query_version(
connection,
1,
1
),
&error
));
if (error)
{
err() << "Failed to load the RandR extension while trying to get the supported video modes" << std::endl;
// Close the connection with the X server
CloseConnection(connection);
return modes;
}
// Get the current configuration
ScopedXcbPtr<xcb_randr_get_screen_info_reply_t> config(xcb_randr_get_screen_info_reply(
connection,
xcb_randr_get_screen_info(
connection,
screen->root
),
&error
));
if (error)
{
// Failed to get the screen configuration
err() << "Failed to retrieve the screen configuration while trying to get the supported video modes" << std::endl;
// Close the connection with the X server
CloseConnection(connection);
return modes;
}
// Get the available screen sizes
xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config.get());
if (sizes && (config->nSizes > 0))
{
// Get the list of supported depths
xcb_depth_iterator_t iter = xcb_screen_allowed_depths_iterator(screen);
// Combine depths and sizes to fill the array of supported modes
for (; iter.rem; xcb_depth_next(&iter))
{ {
for (int j = 0; j < config->nSizes; ++j) // Get the current configuration
XRRScreenConfiguration* config = XRRGetScreenInfo(display, RootWindow(display, screen));
if (config)
{ {
// Convert to VideoMode // Get the available screen sizes
VideoMode mode(sizes[j].width, sizes[j].height, iter.data->depth); int nbSizes;
XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes);
if (sizes && (nbSizes > 0))
{
// Get the list of supported depths
int nbDepths = 0;
int* depths = XListDepths(display, screen, &nbDepths);
if (depths && (nbDepths > 0))
{
// Combine depths and sizes to fill the array of supported modes
for (int i = 0; i < nbDepths; ++i)
{
for (int j = 0; j < nbSizes; ++j)
{
// Convert to VideoMode
VideoMode mode(sizes[j].width, sizes[j].height, depths[i]);
if (config->rotation == XCB_RANDR_ROTATION_ROTATE_90 || Rotation currentRotation;
config->rotation == XCB_RANDR_ROTATION_ROTATE_270) XRRConfigRotations(config, &currentRotation);
std::swap(mode.width, mode.height);
// Add it only if it is not already in the array if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270)
if (std::find(modes.begin(), modes.end(), mode) == modes.end()) std::swap(mode.width, mode.height);
modes.push_back(mode);
// Add it only if it is not already in the array
if (std::find(modes.begin(), modes.end(), mode) == modes.end())
modes.push_back(mode);
}
}
// Free the array of depths
XFree(depths);
}
}
// Free the configuration instance
XRRFreeScreenConfigInfo(config);
}
else
{
// Failed to get the screen configuration
err() << "Failed to retrieve the screen configuration while trying to get the supported video modes" << std::endl;
} }
} }
} else
{
// XRandr extension is not supported: we cannot get the video modes
err() << "Failed to use the XRandR extension while trying to get the supported video modes" << std::endl;
}
// Close the connection with the X server // Close the connection with the X server
CloseConnection(connection); CloseDisplay(display);
}
else
{
// We couldn't connect to the X server
err() << "Failed to connect to the X server while trying to get the supported video modes" << std::endl;
}
return modes; return modes;
} }
@ -143,91 +126,62 @@ VideoMode VideoModeImpl::getDesktopMode()
VideoMode desktopMode; VideoMode desktopMode;
// Open a connection with the X server // Open a connection with the X server
xcb_connection_t* connection = OpenConnection(); Display* display = OpenDisplay();
if (display)
// Retrieve the default screen
xcb_screen_t* screen = XCBDefaultScreen(connection);
ScopedXcbPtr<xcb_generic_error_t> error(NULL);
// Check if the RandR extension is present
const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(connection, &xcb_randr_id);
if (!randrExt || !randrExt->present)
{ {
// Randr extension is not supported: we cannot get the video modes // Retrieve the default screen number
err() << "Failed to use the RandR extension while trying to get the desktop video mode" << std::endl; int screen = DefaultScreen(display);
// Check if the XRandR extension is present
int version;
if (XQueryExtension(display, "RANDR", &version, &version, &version))
{
// Get the current configuration
XRRScreenConfiguration* config = XRRGetScreenInfo(display, RootWindow(display, screen));
if (config)
{
// Get the current video mode
Rotation currentRotation;
int currentMode = XRRConfigCurrentConfiguration(config, &currentRotation);
// Get the available screen sizes
int nbSizes;
XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes);
if (sizes && (nbSizes > 0))
{
desktopMode = VideoMode(sizes[currentMode].width, sizes[currentMode].height, DefaultDepth(display, screen));
Rotation currentRotation;
XRRConfigRotations(config, &currentRotation);
if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270)
std::swap(desktopMode.width, desktopMode.height);
}
// Free the configuration instance
XRRFreeScreenConfigInfo(config);
}
else
{
// Failed to get the screen configuration
err() << "Failed to retrieve the screen configuration while trying to get the desktop video modes" << std::endl;
}
}
else
{
// XRandr extension is not supported: we cannot get the video modes
err() << "Failed to use the XRandR extension while trying to get the desktop video modes" << std::endl;
}
// Close the connection with the X server // Close the connection with the X server
CloseConnection(connection); CloseDisplay(display);
return desktopMode;
}
// Load RandR and check its version
ScopedXcbPtr<xcb_randr_query_version_reply_t> randrVersion(xcb_randr_query_version_reply(
connection,
xcb_randr_query_version(
connection,
1,
1
),
&error
));
if (error)
{
err() << "Failed to load the RandR extension while trying to get the desktop video mode" << std::endl;
// Close the connection with the X server
CloseConnection(connection);
return desktopMode;
}
// Get the current configuration
ScopedXcbPtr<xcb_randr_get_screen_info_reply_t> config(xcb_randr_get_screen_info_reply(
connection,
xcb_randr_get_screen_info(
connection,
screen->root
),
&error
));
if (error)
{
// Failed to get the screen configuration
err() << "Failed to retrieve the screen configuration while trying to get the desktop video mode" << std::endl;
// Close the connection with the X server
CloseConnection(connection);
return desktopMode;
}
// Get the current video mode
xcb_randr_mode_t currentMode = config->sizeID;
// Get the available screen sizes
int nbSizes = xcb_randr_get_screen_info_sizes_length(config.get());
xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config.get());
if (sizes && (nbSizes > 0))
{
desktopMode = VideoMode(sizes[currentMode].width, sizes[currentMode].height, screen->root_depth);
if (config->rotation == XCB_RANDR_ROTATION_ROTATE_90 ||
config->rotation == XCB_RANDR_ROTATION_ROTATE_270)
std::swap(desktopMode.width, desktopMode.height);
} }
else else
{ {
err() << "Failed to retrieve any screen sizes while trying to get the desktop video mode" << std::endl; // We couldn't connect to the X server
err() << "Failed to connect to the X server while trying to get the desktop video modes" << std::endl;
} }
// Close the connection with the X server
CloseConnection(connection);
return desktopMode; return desktopMode;
} }

File diff suppressed because it is too large Load diff

View file

@ -31,8 +31,7 @@
#include <SFML/Window/Event.hpp> #include <SFML/Window/Event.hpp>
#include <SFML/Window/WindowImpl.hpp> #include <SFML/Window/WindowImpl.hpp>
#include <SFML/System/String.hpp> #include <SFML/System/String.hpp>
#include <X11/Xlib-xcb.h> #include <X11/Xlib.h>
#include <xcb/randr.h>
#include <deque> #include <deque>
@ -188,33 +187,6 @@ protected:
private: private:
struct WMHints
{
int32_t flags;
uint32_t input;
int32_t initial_state;
xcb_pixmap_t icon_pixmap;
xcb_window_t icon_window;
int32_t icon_x;
int32_t icon_y;
xcb_pixmap_t icon_mask;
xcb_window_t window_group;
};
struct WMSizeHints
{
uint32_t flags;
int32_t x, y;
int32_t width, height;
int32_t min_width, min_height;
int32_t max_width, max_height;
int32_t width_inc, height_inc;
int32_t min_aspect_num, min_aspect_den;
int32_t max_aspect_num, max_aspect_den;
int32_t base_width, base_height;
uint32_t win_gravity;
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Request the WM to make the current window active /// \brief Request the WM to make the current window active
/// ///
@ -248,40 +220,12 @@ private:
void setProtocols(); void setProtocols();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Set Motif WM hints /// \brief Update the last time we received user input
///
/// \param time Last time we received user input
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void setMotifHints(unsigned long style); void updateLastInputTime(::Time time);
////////////////////////////////////////////////////////////
/// \brief Set WM hints
///
/// \param hints Hints
///
////////////////////////////////////////////////////////////
void setWMHints(const WMHints& hints);
////////////////////////////////////////////////////////////
/// \brief Set WM size hints
///
/// \param hints Size hints
///
////////////////////////////////////////////////////////////
void setWMSizeHints(const WMSizeHints& hints);
////////////////////////////////////////////////////////////
/// \brief Change a XCB window property
///
/// \param property Property to change
/// \param type Type of the property
/// \param format Format of the property
/// \param length Length of the new value
/// \param data The new value of the property
///
/// \return True if successful, false if unsuccessful
///
////////////////////////////////////////////////////////////
bool changeWindowProperty(xcb_atom_t property, xcb_atom_t type, uint8_t format, uint32_t length, const void* data);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Do some common initializations after the window has been created /// \brief Do some common initializations after the window has been created
@ -314,21 +258,23 @@ private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
xcb_window_t m_window; ///< xcb identifier defining our window ::Window m_window; ///< X identifier defining our window
::Display* m_display; ///< Pointer to the display ::Display* m_display; ///< Pointer to the display
xcb_connection_t* m_connection; ///< Pointer to the xcb connection int m_screen; ///< Screen identifier
xcb_screen_t* m_screen; ///< Screen identifier XIM m_inputMethod; ///< Input method linked to the X display
XIM m_inputMethod; ///< Input method linked to the X display XIC m_inputContext; ///< Input context used to get unicode input in our window
XIC m_inputContext; ///< Input context used to get unicode input in our window bool m_isExternal; ///< Tell whether the window has been created externally or by SFML
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
xcb_randr_get_screen_info_reply_t m_oldVideoMode; ///< Video mode in use before we switch to fullscreen Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hidding, we must create a transparent one
Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hidding, we must create a transparent one bool m_keyRepeat; ///< Is the KeyRepeat feature enabled?
bool m_keyRepeat; ///< Is the KeyRepeat feature enabled? Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only)
Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only) bool m_useSizeHints; ///< Is the size of the window fixed with size hints?
bool m_useSizeHints; ///< Is the size of the window fixed with size hints? bool m_fullscreen; ///< Is the window in fullscreen?
bool m_fullscreen; ///< Is the window in fullscreen? bool m_cursorGrabbed; ///< Is the mouse cursor trapped?
bool m_cursorGrabbed; ///< Is the mouse cursor trapped? bool m_windowMapped; ///< Has the window been mapped by the window manager?
bool m_windowMapped; ///< Has the window been mapped by the window manager? Pixmap m_iconPixmap; ///< The current icon pixmap if in use
Pixmap m_iconMaskPixmap; ///< The current icon mask pixmap if in use
::Time m_lastInputTime; ///< Last time we received user input
}; };
} // namespace priv } // namespace priv

View file

@ -200,9 +200,9 @@ GlFunctionPointer WglContext::getFunction(const char* name)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool WglContext::makeCurrent() bool WglContext::makeCurrent(bool current)
{ {
return m_deviceContext && m_context && wglMakeCurrent(m_deviceContext, m_context); return m_deviceContext && m_context && wglMakeCurrent(current ? m_deviceContext : NULL, current ? m_context : NULL);
} }
@ -599,6 +599,18 @@ void WglContext::createContext(WglContext* shared)
attributes.push_back(0); attributes.push_back(0);
attributes.push_back(0); attributes.push_back(0);
if (sharedContext)
{
static Mutex mutex;
Lock lock(mutex);
if (!wglMakeCurrent(NULL, NULL))
{
err() << "Failed to deactivate shared context before sharing: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
return;
}
}
// Create the context // Create the context
m_context = wglCreateContextAttribsARB(m_deviceContext, sharedContext, &attributes[0]); m_context = wglCreateContextAttribsARB(m_deviceContext, sharedContext, &attributes[0]);
} }
@ -657,6 +669,12 @@ void WglContext::createContext(WglContext* shared)
static Mutex mutex; static Mutex mutex;
Lock lock(mutex); Lock lock(mutex);
if (!wglMakeCurrent(NULL, NULL))
{
err() << "Failed to deactivate shared context before sharing: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
return;
}
if (!wglShareLists(sharedContext, m_context)) if (!wglShareLists(sharedContext, m_context))
err() << "Failed to share the OpenGL context: " << getErrorString(GetLastError()).toAnsiString() << std::endl; err() << "Failed to share the OpenGL context: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
} }

View file

@ -93,10 +93,12 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Activate the context as the current target for rendering /// \brief Activate the context as the current target for rendering
/// ///
/// \param current Whether to make the context current or no longer current
///
/// \return True on success, false if any error happened /// \return True on success, false if any error happened
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
virtual bool makeCurrent(); virtual bool makeCurrent(bool current);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Display what has been rendered to the context so far /// \brief Display what has been rendered to the context so far

View file

@ -126,10 +126,12 @@ protected:
/// \brief Activate the context as the current target /// \brief Activate the context as the current target
/// for rendering /// for rendering
/// ///
/// \param current Whether to make the context current or no longer current
///
/// \return True on success, false if any error happened /// \return True on success, false if any error happened
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
virtual bool makeCurrent(); virtual bool makeCurrent(bool current);
private: private:

View file

@ -107,6 +107,9 @@ EaglContext::~EaglContext()
// Restore the previous context // Restore the previous context
[EAGLContext setCurrentContext:previousContext]; [EAGLContext setCurrentContext:previousContext];
if (m_context == [EAGLContext currentContext])
[EAGLContext setCurrentContext:nil];
} }
} }
@ -167,9 +170,12 @@ void EaglContext::recreateRenderBuffers(SFView* glView)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool EaglContext::makeCurrent() bool EaglContext::makeCurrent(bool current)
{ {
return [EAGLContext setCurrentContext:m_context]; if (current)
return [EAGLContext setCurrentContext:m_context];
return [EAGLContext setCurrentContext:nil];
} }
@ -215,12 +221,18 @@ void EaglContext::createContext(EaglContext* shared,
// Create the context // Create the context
if (shared) if (shared)
{
[EAGLContext setCurrentContext:nil];
m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 sharegroup:[shared->m_context sharegroup]]; m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 sharegroup:[shared->m_context sharegroup]];
}
else else
{
m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
}
// Activate it // Activate it
makeCurrent(); makeCurrent(true);
// Create the framebuffer (this is the only allowed drawable on iOS) // Create the framebuffer (this is the only allowed drawable on iOS)
glGenFramebuffersOES(1, &m_framebuffer); glGenFramebuffersOES(1, &m_framebuffer);
@ -230,6 +242,9 @@ void EaglContext::createContext(EaglContext* shared,
// Attach the context to the GL view for future updates // Attach the context to the GL view for future updates
window->getGlView().context = this; window->getGlView().context = this;
// Deactivate it
makeCurrent(false);
} }
} // namespace priv } // namespace priv

View file

@ -214,8 +214,8 @@ namespace
// Send a Resized event to the current window // Send a Resized event to the current window
sf::Event event; sf::Event event;
event.type = sf::Event::Resized; event.type = sf::Event::Resized;
event.size.width = size.x * backingScaleFactor; event.size.width = size.x;
event.size.height = size.y * backingScaleFactor; event.size.height = size.y;
sfWindow->forwardEvent(event); sfWindow->forwardEvent(event);
} }
} }