Refactored Unix Window implementation.

This commit is contained in:
binary1248 2015-03-06 16:11:56 +01:00 committed by Lukas Dürrenberger
parent b758f9a1dd
commit b2b35d0a43
6 changed files with 456 additions and 260 deletions

View File

@ -217,11 +217,10 @@ endif()
# build the list of external libraries to link # build the list of external libraries to link
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 OR SFML_OS_FREEBSD) elseif(SFML_OS_LINUX)
list(APPEND WINDOW_EXT_LIBS ${LIBXCB_LIBRARIES} ${UDEV_LIBRARIES}) list(APPEND WINDOW_EXT_LIBS ${LIBXCB_LIBRARIES} ${UDEV_LIBRARIES})
if(SFML_OS_FREEBSD) elseif(SFML_OS_FREEBSD)
list(APPEND WINDOW_EXT_LIBS usbhid) list(APPEND WINDOW_EXT_LIBS ${LIBXCB_LIBRARIES} usbhid)
endif()
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

@ -101,6 +101,23 @@ xcb_screen_t* XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr)
return NULL; 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;
}
} // namespace priv } // namespace priv
} // namespace sf } // namespace sf

View File

@ -60,7 +60,7 @@ xcb_connection_t* OpenConnection();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Release a reference to the shared display /// \brief Release a reference to the shared display
/// ///
/// \param Display to release /// \param display Display to release
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void CloseDisplay(Display* display); void CloseDisplay(Display* display);
@ -68,7 +68,7 @@ void CloseDisplay(Display* display);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Release a reference to the shared display /// \brief Release a reference to the shared display
/// ///
/// \param Connection of display to release /// \param connection Connection of display to release
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void CloseConnection(xcb_connection_t* connection); void CloseConnection(xcb_connection_t* connection);
@ -76,13 +76,34 @@ void CloseConnection(xcb_connection_t* connection);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Get screen of a display by index (equivalent to XScreenOfDisplay) /// \brief Get screen of a display by index (equivalent to XScreenOfDisplay)
/// ///
/// \param The index of the screen /// \param connection Connection of display
/// \param screen_nbr The index of the screen
/// ///
/// \return Pointer to the screen /// \return Pointer to the screen
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
xcb_screen_t* XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr); 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);
} // namespace priv } // namespace priv
} // namespace sf } // namespace sf

View File

@ -189,16 +189,15 @@ 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
Display* display = OpenDisplay(); xcb_connection_t* connection = OpenConnection();
xcb_connection_t* connection = XGetXCBConnection(display);
// Get pointer mask // Get pointer mask
xcb_query_pointer_reply_t* pointer = xcb_query_pointer_reply(connection, xcb_query_pointer(connection, XDefaultRootWindow(display)), NULL); xcb_query_pointer_reply_t* pointer = xcb_query_pointer_reply(connection, xcb_query_pointer(connection, XCBDefaultRootWindow(connection)), NULL);
uint16_t mask = pointer->mask; uint16_t mask = pointer->mask;
free(pointer); free(pointer);
// Close the connection with the X server // Close the connection with the X server
CloseDisplay(display); CloseConnection(connection);
switch (button) switch (button)
{ {
@ -216,13 +215,12 @@ 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
Display* display = OpenDisplay(); xcb_connection_t* connection = OpenConnection();
xcb_connection_t* connection = XGetXCBConnection(display);
xcb_query_pointer_reply_t* pointer = xcb_query_pointer_reply(connection, xcb_query_pointer(connection, XDefaultRootWindow(display)), NULL); xcb_query_pointer_reply_t* pointer = xcb_query_pointer_reply(connection, xcb_query_pointer(connection, XCBDefaultRootWindow(connection)), NULL);
// Close the connection with the X server // Close the connection with the X server
CloseDisplay(display); CloseConnection(connection);
// Prepare result. // Prepare result.
Vector2i result(pointer->root_x, pointer->root_y); Vector2i result(pointer->root_x, pointer->root_y);
@ -263,14 +261,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
Display* display = OpenDisplay(); xcb_connection_t* connection = OpenConnection();
xcb_connection_t* connection = XGetXCBConnection(display);
xcb_warp_pointer(connection, None, XDefaultRootWindow(display), 0, 0, 0, 0, position.x, position.y); xcb_warp_pointer(connection, None, XCBDefaultRootWindow(connection), 0, 0, 0, 0, position.x, position.y);
xcb_flush(connection); xcb_flush(connection);
// Close the connection with the X server // Close the connection with the X server
CloseDisplay(display); CloseConnection(connection);
} }

View File

@ -42,72 +42,80 @@ 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
Display* display = OpenDisplay(); xcb_connection_t* connection = OpenConnection();
xcb_connection_t* connection = XGetXCBConnection(display);
if (display) // Retrieve the default screen
xcb_screen_t* screen = XCBDefaultScreen(connection);
// Check if the XRandR extension is present
static const std::string RANDR = "RANDR";
xcb_query_extension_reply_t* randr_ext = xcb_query_extension_reply(
connection,
xcb_query_extension(
connection,
RANDR.size(),
RANDR.c_str()
),
NULL
);
if (randr_ext->present)
{ {
// Check if the XRandR extension is present // Get the current configuration
xcb_query_extension_cookie_t cookie = xcb_query_extension(connection, 5, "RANDR"); xcb_generic_error_t* error;
xcb_randr_get_screen_info_reply_t* config = xcb_randr_get_screen_info_reply(
connection,
xcb_randr_get_screen_info(
connection,
screen->root
),
&error
);
// Retrieve the default screen if (!error)
xcb_screen_t* screen = XCBScreenOfDisplay(connection, DefaultScreen(display));
// Check if the XRandR extension is present
xcb_query_extension_reply_t* randr_ext = xcb_query_extension_reply(connection, cookie, NULL);
if (randr_ext->present)
{ {
// Get the current configuration // Get the available screen sizes
xcb_generic_error_t* errors; xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config);
xcb_randr_get_screen_info_reply_t* config = xcb_randr_get_screen_info_reply( if (sizes && (config->nSizes > 0))
connection, xcb_randr_get_screen_info(connection, screen->root), &errors);
if (! errors)
{ {
// Get the available screen sizes // Get the list of supported depths
xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config); xcb_depth_iterator_t iter = xcb_screen_allowed_depths_iterator(screen);
if (sizes && (config->nSizes > 0)) // Combine depths and sizes to fill the array of supported modes
for (; iter.rem; xcb_depth_next(&iter))
{ {
// Get the list of supported depths for (int j = 0; j < config->nSizes; ++j)
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) // Convert to VideoMode
{ VideoMode mode(sizes[j].width, sizes[j].height, iter.data->depth);
// Convert to VideoMode
VideoMode mode(sizes[j].width, sizes[j].height, iter.data->depth);
// Add it only if it is not already in the array // Add it only if it is not already in the array
if (std::find(modes.begin(), modes.end(), mode) == modes.end()) if (std::find(modes.begin(), modes.end(), mode) == modes.end())
modes.push_back(mode); modes.push_back(mode);
}
} }
} }
} }
else
{
// Failed to get the screen configuration
err() << "Failed to retrieve the screen configuration while trying to get the supported video modes" << std::endl;
}
// Free the configuration instance
free(errors);
free(config);
} }
else else
{ {
// XRandr extension is not supported: we cannot get the video modes // Failed to get the screen configuration
err() << "Failed to use the XRandR extension while trying to get the supported video modes" << std::endl; err() << "Failed to retrieve the screen configuration while trying to get the supported video modes" << std::endl;
} }
free(randr_ext);
// Close the connection with the X server // Free the configuration instance
CloseDisplay(display); free(error);
free(config);
} }
else else
{ {
// We couldn't connect to the X server // XRandr extension is not supported: we cannot get the video modes
err() << "Failed to connect to the X server while trying to get the supported video modes" << std::endl; err() << "Failed to use the XRandR extension while trying to get the supported video modes" << std::endl;
} }
free(randr_ext);
// Close the connection with the X server
CloseConnection(connection);
return modes; return modes;
} }
@ -118,59 +126,68 @@ VideoMode VideoModeImpl::getDesktopMode()
VideoMode desktopMode; VideoMode desktopMode;
// Open a connection with the X server // Open a connection with the X server
Display* display = OpenDisplay(); xcb_connection_t* connection = OpenConnection();
xcb_connection_t* connection = XGetXCBConnection(display);
if (display) // Retrieve the default screen
xcb_screen_t* screen = XCBDefaultScreen(connection);
// Check if the XRandR extension is present
static const std::string RANDR = "RANDR";
xcb_query_extension_reply_t* randr_ext = xcb_query_extension_reply(
connection,
xcb_query_extension(
connection,
RANDR.size(),
RANDR.c_str()
),
NULL
);
if (randr_ext->present)
{ {
xcb_query_extension_cookie_t cookie = xcb_query_extension(connection, 5, "RANDR"); // Get the current configuration
// Retrieve the default screen xcb_generic_error_t* error;
xcb_screen_t* screen = XCBScreenOfDisplay(connection, DefaultScreen(display)); xcb_randr_get_screen_info_reply_t* config = xcb_randr_get_screen_info_reply(
connection,
xcb_randr_get_screen_info(
connection,
screen->root
),
&error
);
// Check if the XRandR extension is present if (!error)
xcb_query_extension_reply_t* randr_ext = xcb_query_extension_reply(connection, cookie, NULL);
if (randr_ext->present)
{ {
// Get the current configuration // Get the current video mode
xcb_generic_error_t* errors; xcb_randr_mode_t currentMode = config->sizeID;
xcb_randr_get_screen_info_reply_t* config =
xcb_randr_get_screen_info_reply(
connection, xcb_randr_get_screen_info(connection, screen->root), &errors);
if (! errors)
{
// Get the current video mode
xcb_randr_mode_t currentMode = config->sizeID;
// Get the available screen sizes // Get the available screen sizes
int nbSizes = xcb_randr_get_screen_info_sizes_length(config); int nbSizes = xcb_randr_get_screen_info_sizes_length(config);
xcb_randr_screen_size_t* sizes= xcb_randr_get_screen_info_sizes(config); xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config);
if (sizes && (nbSizes > 0)) if (sizes && (nbSizes > 0))
desktopMode = VideoMode(sizes[currentMode].width, sizes[currentMode].height, screen->root_depth); desktopMode = VideoMode(sizes[currentMode].width, sizes[currentMode].height, screen->root_depth);
}
else
{
// Failed to get the screen configuration
err() << "Failed to retrieve the screen configuration while trying to get the desktop video modes" << std::endl;
}
// Free the configuration instance
free(errors);
free(config);
} }
else else
{ {
// XRandr extension is not supported: we cannot get the video modes // Failed to get the screen configuration
err() << "Failed to use the XRandR extension while trying to get the desktop video modes" << std::endl; err() << "Failed to retrieve the screen configuration while trying to get the desktop video modes" << std::endl;
} }
free(randr_ext); // Free the configuration instance
// Close the connection with the X server free(error);
CloseDisplay(display); free(config);
} }
else else
{ {
// We couldn't connect to the X server // XRandr extension is not supported: we cannot get the video modes
err() << "Failed to connect to the X server while trying to get the desktop video modes" << std::endl; err() << "Failed to use the XRandR extension while trying to get the desktop video modes" << std::endl;
} }
free(randr_ext);
// Close the connection with the X server
CloseConnection(connection);
return desktopMode; return desktopMode;
} }

View File

@ -35,6 +35,8 @@
#include <xcb/xcb_image.h> #include <xcb/xcb_image.h>
#include <xcb/xcb_util.h> #include <xcb/xcb_util.h>
#include <xcb/randr.h> #include <xcb/randr.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <libgen.h> #include <libgen.h>
#include <cstring> #include <cstring>
@ -65,18 +67,22 @@ namespace
EnterWindowMask | LeaveWindowMask; EnterWindowMask | LeaveWindowMask;
// Find the name of the current executable // Find the name of the current executable
void findExecutableName(char* buffer, std::size_t bufferSize) std::string findExecutableName()
{ {
//Default fallback name struct stat linkStat;
const char* executableName = "sfml"; if (!lstat("/proc/self/exe", &linkStat)) {
std::size_t length = readlink("/proc/self/exe", buffer, bufferSize); std::vector<char> buffer(0, linkStat.st_size + 1);
if ((length > 0) && (length < bufferSize)) std::size_t length = readlink("/proc/self/exe", &buffer[0], buffer.size());
{ if ((length > 0) && (length < buffer.size()))
// Remove the path to keep the executable name only {
buffer[length] = '\0'; // Remove the path to keep the executable name only
executableName = basename(buffer); buffer[length] = '\0';
return basename(&buffer[0]);
}
} }
std::memmove(buffer, executableName, std::strlen(executableName) + 1);
//Default fallback name
return "sfml";
} }
} }
@ -100,7 +106,6 @@ m_useSizeHints(false)
{ {
// Open a connection with the X server // Open a connection with the X server
m_display = OpenDisplay(); m_display = OpenDisplay();
XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
m_connection = XGetXCBConnection(m_display); m_connection = XGetXCBConnection(m_display);
if (!m_connection) if (!m_connection)
@ -109,10 +114,8 @@ m_useSizeHints(false)
return; return;
} }
// Get connection info. m_screen = XCBDefaultScreen(m_connection);
const xcb_setup_t* setup = xcb_get_setup(m_connection); XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
xcb_screen_iterator_t screenIter = xcb_setup_roots_iterator(setup);
m_screen = screenIter.data;
// Save the window handle // Save the window handle
m_window = handle; m_window = handle;
@ -122,10 +125,12 @@ m_useSizeHints(false)
// Make sure the window is listening to all the required events // Make sure the window is listening to all the required events
const uint32_t value_list[] = {static_cast<uint32_t>(eventMask)}; const uint32_t value_list[] = {static_cast<uint32_t>(eventMask)};
xcb_change_window_attributes(m_connection, xcb_change_window_attributes(
m_window, m_connection,
XCB_CW_EVENT_MASK, m_window,
value_list); XCB_CW_EVENT_MASK,
value_list
);
// Do some common initializations // Do some common initializations
initialize(); initialize();
@ -148,32 +153,21 @@ m_useSizeHints(false)
{ {
// Open a connection with the X server // Open a connection with the X server
m_display = OpenDisplay(); m_display = OpenDisplay();
XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
m_connection = XGetXCBConnection(m_display); m_connection = XGetXCBConnection(m_display);
if (!m_connection) if (!m_connection)
{ {
err() << "Failed cast Display object to an XCB connection object" << std::endl; err() << "Failed cast Display object to an XCB connection object" << std::endl;
return; return;
} }
// Get connection info. m_screen = XCBDefaultScreen(m_connection);
const xcb_setup_t* setup = xcb_get_setup(m_connection); XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
xcb_screen_iterator_t screenIter = xcb_setup_roots_iterator(setup);
m_screen = screenIter.data;
// Compute position and size // Compute position and size
int left, top;
bool fullscreen = (style & Style::Fullscreen) != 0; bool fullscreen = (style & Style::Fullscreen) != 0;
if (!fullscreen) int left = fullscreen ? 0 : (m_screen->width_in_pixels - mode.width) / 2;
{ int top = fullscreen ? 0 : (m_screen->height_in_pixels - mode.height) / 2;
left = (m_screen->width_in_pixels - mode.width) / 2;
top = (m_screen->height_in_pixels - mode.height) / 2;
}
else
{
left = 0;
top = 0;
}
int width = mode.width; int width = mode.width;
int height = mode.height; int height = mode.height;
@ -187,20 +181,23 @@ m_useSizeHints(false)
// Create the window // Create the window
m_window = xcb_generate_id(m_connection); m_window = xcb_generate_id(m_connection);
xcb_void_cookie_t cookie = xcb_create_window_checked( xcb_generic_error_t* errptr = xcb_request_check(
m_connection, m_connection,
XCB_COPY_FROM_PARENT, xcb_create_window_checked(
m_window, m_connection,
m_screen->root, XCB_COPY_FROM_PARENT,
left, top, m_window,
width, height, m_screen->root,
0, left, top,
XCB_WINDOW_CLASS_INPUT_OUTPUT, width, height,
XCB_COPY_FROM_PARENT, 0,
XCB_CW_EVENT_MASK | XCB_CW_OVERRIDE_REDIRECT, XCB_WINDOW_CLASS_INPUT_OUTPUT,
value_list); XCB_COPY_FROM_PARENT,
XCB_CW_EVENT_MASK | XCB_CW_OVERRIDE_REDIRECT,
value_list
)
);
xcb_generic_error_t* errptr = xcb_request_check(m_connection, cookie);
bool createWindowFailed = (errptr != NULL); bool createWindowFailed = (errptr != NULL);
free(errptr); free(errptr);
@ -213,19 +210,18 @@ m_useSizeHints(false)
// Set the window's name // Set the window's name
setTitle(title); setTitle(title);
// Set the window's style (tell the windows manager to change our window's decorations and functions according to the requested style) // Set the window's style (tell the window manager to change our window's decorations and functions according to the requested style)
if (!fullscreen) if (!fullscreen)
{ {
static const std::string MOTIF_WM_HINTS = "_MOTIF_WM_HINTS"; static const std::string MOTIF_WM_HINTS = "_MOTIF_WM_HINTS";
xcb_intern_atom_cookie_t hintsAtomRequest = xcb_intern_atom(
m_connection,
0,
MOTIF_WM_HINTS.size(),
MOTIF_WM_HINTS.c_str()
);
xcb_intern_atom_reply_t* hintsAtomReply = xcb_intern_atom_reply( xcb_intern_atom_reply_t* hintsAtomReply = xcb_intern_atom_reply(
m_connection, m_connection,
hintsAtomRequest, xcb_intern_atom(
m_connection,
0,
MOTIF_WM_HINTS.size(),
MOTIF_WM_HINTS.c_str()
),
NULL NULL
); );
@ -279,9 +275,16 @@ m_useSizeHints(false)
hints.functions |= MWM_FUNC_CLOSE; hints.functions |= MWM_FUNC_CLOSE;
} }
const unsigned char* ptr = reinterpret_cast<const unsigned char*>(&hints); xcb_change_property(
xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window, m_connection,
hintsAtomReply->atom, XCB_ATOM_WM_HINTS, 32, 5, ptr); XCB_PROP_MODE_REPLACE,
m_window,
hintsAtomReply->atom,
XCB_ATOM_WM_HINTS,
sizeof(hints.flags) * 8,
sizeof(hints) / sizeof(hints.flags),
reinterpret_cast<const unsigned char*>(&hints)
);
free(hintsAtomReply); free(hintsAtomReply);
} }
@ -299,9 +302,8 @@ m_useSizeHints(false)
} }
// Set the window's WM class (this can be used by window managers) // Set the window's WM class (this can be used by window managers)
char windowClass[512]; std::string windowClass = findExecutableName();
findExecutableName(windowClass, sizeof(windowClass)); xcb_icccm_set_wm_class_checked(m_connection, m_window, windowClass.size(), windowClass.c_str());
xcb_icccm_set_wm_class_checked(m_connection, m_window, std::strlen(windowClass), windowClass);
// Do some common initializations // Do some common initializations
initialize(); initialize();
@ -309,8 +311,26 @@ m_useSizeHints(false)
// In fullscreen mode, we must grab keyboard and mouse inputs // In fullscreen mode, we must grab keyboard and mouse inputs
if (fullscreen) if (fullscreen)
{ {
xcb_grab_pointer(m_connection, True, m_window, 0, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, m_window, XCB_NONE, XCB_CURRENT_TIME); xcb_grab_pointer(
xcb_grab_keyboard(m_connection, True, m_window, XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); m_connection,
True,
m_window,
0,
XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC,
m_window,
XCB_NONE,
XCB_CURRENT_TIME
);
xcb_grab_keyboard(
m_connection,
True,
m_window,
XCB_CURRENT_TIME,
XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC
);
} }
} }
@ -422,7 +442,6 @@ Vector2i WindowImplX11::getPosition() const
{ {
::Window topLevelWindow = m_window; ::Window topLevelWindow = m_window;
::Window nextWindow = topLevelWindow; ::Window nextWindow = topLevelWindow;
xcb_query_tree_cookie_t treeCookie;
xcb_query_tree_reply_t* treeReply = NULL; xcb_query_tree_reply_t* treeReply = NULL;
// Get "top level" window, i.e. the window with the root window as its parent. // Get "top level" window, i.e. the window with the root window as its parent.
@ -430,14 +449,19 @@ Vector2i WindowImplX11::getPosition() const
{ {
topLevelWindow = nextWindow; topLevelWindow = nextWindow;
treeCookie = xcb_query_tree(m_connection, topLevelWindow); treeReply = xcb_query_tree_reply(m_connection, xcb_query_tree(m_connection, topLevelWindow), NULL);
treeReply = xcb_query_tree_reply(m_connection, treeCookie, NULL);
nextWindow = treeReply->parent; nextWindow = treeReply->parent;
free(treeReply); free(treeReply);
} }
xcb_get_geometry_cookie_t geometryCookie = xcb_get_geometry(m_connection, topLevelWindow); xcb_get_geometry_reply_t* geometryReply = xcb_get_geometry_reply(
xcb_get_geometry_reply_t* geometryReply = xcb_get_geometry_reply(m_connection, geometryCookie, NULL); m_connection,
xcb_get_geometry(
m_connection,
topLevelWindow
),
NULL
);
sf::Vector2i result(geometryReply->x, geometryReply->y); sf::Vector2i result(geometryReply->x, geometryReply->y);
free(geometryReply); free(geometryReply);
@ -480,9 +504,12 @@ void WindowImplX11::setSize(const Vector2u& size)
} }
uint32_t values[] = {size.x, size.y}; uint32_t values[] = {size.x, size.y};
xcb_configure_window(m_connection, m_window, xcb_configure_window(
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, m_connection,
values); m_window,
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
values
);
xcb_flush(m_connection); xcb_flush(m_connection);
} }
@ -497,9 +524,16 @@ void WindowImplX11::setTitle(const String& title)
std::back_inserter( utf8String ) std::back_inserter( utf8String )
); );
xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window, xcb_change_property(
XCB_ATOM_WM_NAME, XCB_ATOM_STRING, m_connection,
8, utf8String.length(), utf8String.c_str()); XCB_PROP_MODE_REPLACE,
m_window,
XCB_ATOM_WM_NAME,
XCB_ATOM_STRING,
sizeof(std::basic_string<sf::Uint8>::value_type) * 8,
utf8String.length(),
utf8String.c_str()
);
xcb_flush(m_connection); xcb_flush(m_connection);
} }
@ -519,17 +553,38 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8
// Create the icon pixmap // Create the icon pixmap
xcb_pixmap_t iconPixmap = xcb_generate_id(m_connection); xcb_pixmap_t iconPixmap = xcb_generate_id(m_connection);
xcb_create_pixmap(m_connection, m_screen->root_depth, iconPixmap, m_screen->root, xcb_create_pixmap(
width, height); m_connection,
m_screen->root_depth,
iconPixmap,
m_screen->root,
width,
height
);
xcb_gcontext_t iconGC = xcb_generate_id(m_connection); xcb_gcontext_t iconGC = xcb_generate_id(m_connection);
xcb_create_gc(m_connection, iconGC, iconPixmap, 0, NULL); xcb_create_gc(m_connection, iconGC, iconPixmap, 0, NULL);
xcb_void_cookie_t cookie = xcb_put_image_checked(
m_connection, XCB_IMAGE_FORMAT_Z_PIXMAP, iconPixmap, iconGC, xcb_generic_error_t* errptr = xcb_request_check(
width, height, 0, 0, 0, m_screen->root_depth, sizeof(iconPixels), iconPixels); m_connection,
xcb_put_image_checked(
m_connection,
XCB_IMAGE_FORMAT_Z_PIXMAP,
iconPixmap,
iconGC,
width,
height,
0,
0,
0,
m_screen->root_depth,
sizeof(iconPixels),
iconPixels
)
);
xcb_free_gc(m_connection, iconGC); xcb_free_gc(m_connection, iconGC);
xcb_generic_error_t* errptr = xcb_request_check(m_connection, cookie);
if (errptr) if (errptr)
{ {
err() << "Failed to set the window's icon: Error code " << static_cast<int>(errptr->error_code) << std::endl; err() << "Failed to set the window's icon: Error code " << static_cast<int>(errptr->error_code) << std::endl;
@ -554,7 +609,18 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8
} }
} }
} }
xcb_pixmap_t maskPixmap = xcb_create_pixmap_from_bitmap_data(m_connection, m_window, (Uint8*)&maskPixels[0], width, height, 1, 0, 1, NULL);
xcb_pixmap_t maskPixmap = xcb_create_pixmap_from_bitmap_data(
m_connection,
m_window,
reinterpret_cast<uint8_t*>(&maskPixels[0]),
width,
height,
1,
0,
1,
NULL
);
// Send our new icon to the window through the WMHints // Send our new icon to the window through the WMHints
xcb_icccm_wm_hints_t hints; xcb_icccm_wm_hints_t hints;
@ -613,10 +679,14 @@ void WindowImplX11::requestFocus()
// Check if window is viewable (not on other desktop, ...) // Check if window is viewable (not on other desktop, ...)
// TODO: Check also if minimized // TODO: Check also if minimized
xcb_get_window_attributes_cookie_t attribCookie = xcb_get_window_attributes(m_connection, m_window); xcb_get_window_attributes_reply_t* attributes = xcb_get_window_attributes_reply(
xcb_get_window_attributes_reply_t* attributes = xcb_get_window_attributes_reply(m_connection, m_connection,
attribCookie, xcb_get_window_attributes(
NULL); m_connection,
m_window
),
NULL
);
if (!attributes) if (!attributes)
{ {
sf::err() << "Failed to check if window is viewable while requesting focus" << std::endl; sf::err() << "Failed to check if window is viewable while requesting focus" << std::endl;
@ -637,9 +707,16 @@ void WindowImplX11::requestFocus()
else else
{ {
// Get current WM hints. // Get current WM hints.
xcb_get_property_cookie_t hintsCookie = xcb_icccm_get_wm_hints_unchecked(m_connection, m_window);
xcb_icccm_wm_hints_t hints; xcb_icccm_wm_hints_t hints;
xcb_icccm_get_wm_hints_reply(m_connection, hintsCookie, &hints, NULL); xcb_icccm_get_wm_hints_reply(
m_connection,
xcb_icccm_get_wm_hints_unchecked(
m_connection,
m_window
),
&hints,
NULL
);
// Even if no hints were returned, we can simply set the proper flags we need and go on. This is // Even if no hints were returned, we can simply set the proper flags we need and go on. This is
// different from Xlib where XAllocWMHints() has to be called. // different from Xlib where XAllocWMHints() has to be called.
@ -652,13 +729,18 @@ void WindowImplX11::requestFocus()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool WindowImplX11::hasFocus() const bool WindowImplX11::hasFocus() const
{ {
xcb_get_input_focus_cookie_t cookie = xcb_get_input_focus_unchecked(m_connection); xcb_get_input_focus_reply_t* reply = xcb_get_input_focus_reply(
xcb_get_input_focus_reply_t* reply = xcb_get_input_focus_reply(m_connection, cookie, NULL); m_connection,
xcb_get_input_focus_unchecked(
m_connection
),
NULL
);
bool focussed = (reply->focus == m_window); bool focused = (reply->focus == m_window);
free(reply); free(reply);
return focussed; return focused;
} }
@ -666,17 +748,31 @@ bool WindowImplX11::hasFocus() const
void WindowImplX11::switchToFullscreen(const VideoMode& mode) void WindowImplX11::switchToFullscreen(const VideoMode& mode)
{ {
// Check if the XRandR extension is present // Check if the XRandR extension is present
xcb_query_extension_reply_t* randr_ext = static const std::string RANDR = "RANDR";
xcb_query_extension_reply(m_connection, xcb_query_extension(m_connection, 5, "RANDR"), NULL); xcb_query_extension_reply_t* randr_ext = xcb_query_extension_reply(
m_connection,
xcb_query_extension(
m_connection,
RANDR.size(),
RANDR.c_str()
),
NULL
);
if (randr_ext->present) if (randr_ext->present)
{ {
// Get the current configuration // Get the current configuration
xcb_generic_error_t* errors; xcb_generic_error_t* error;
xcb_randr_get_screen_info_reply_t* config = xcb_randr_get_screen_info_reply_t* config = xcb_randr_get_screen_info_reply(
xcb_randr_get_screen_info_reply(m_connection, m_connection,
xcb_randr_get_screen_info(m_connection, m_screen->root), xcb_randr_get_screen_info(
&errors); m_connection,
if (! errors) m_screen->root
),
&error
);
if (!error)
{ {
// Save the current video mode before we switch to fullscreen // Save the current video mode before we switch to fullscreen
m_oldVideoMode = config->sizeID; m_oldVideoMode = config->sizeID;
@ -688,14 +784,19 @@ void WindowImplX11::switchToFullscreen(const VideoMode& mode)
// Search a matching size // Search a matching size
for (int i = 0; i < config->nSizes; ++i) for (int i = 0; i < config->nSizes; ++i)
{ {
if ((sizes[i].width == static_cast<int>(mode.width)) && (sizes[i].height == static_cast<int>(mode.height))) if ((sizes[i].width == static_cast<int>(mode.width)) &&
(sizes[i].height == static_cast<int>(mode.height)))
{ {
// Switch to fullscreen mode // Switch to fullscreen mode
xcb_randr_set_screen_config(m_connection, xcb_randr_set_screen_config(
m_screen->root, m_connection,
config->timestamp, m_screen->root,
config->config_timestamp, config->timestamp,
i, config->rotation, config->rate); config->config_timestamp,
i,
config->rotation,
config->rate
);
// Set "this" as the current fullscreen window // Set "this" as the current fullscreen window
fullscreenWindow = this; fullscreenWindow = this;
@ -709,14 +810,17 @@ void WindowImplX11::switchToFullscreen(const VideoMode& mode)
// Failed to get the screen configuration // Failed to get the screen configuration
err() << "Failed to get the current screen configuration for fullscreen mode, switching to window mode" << std::endl; err() << "Failed to get the current screen configuration for fullscreen mode, switching to window mode" << std::endl;
} }
free(errors);
// Free the configuration instance
free(error);
free(config); free(config);
} }
else else
{ {
// XRandr extension is not supported: we cannot use fullscreen mode // XRandR extension is not supported: we cannot use fullscreen mode
err() << "Fullscreen is not supported, switching to window mode" << std::endl; err() << "Fullscreen is not supported, switching to window mode" << std::endl;
} }
free(randr_ext); free(randr_ext);
} }
@ -726,30 +830,26 @@ void WindowImplX11::initialize()
{ {
// Get the atoms for registering the close event // Get the atoms for registering the close event
static const std::string WM_DELETE_WINDOW_NAME = "WM_DELETE_WINDOW"; static const std::string WM_DELETE_WINDOW_NAME = "WM_DELETE_WINDOW";
xcb_intern_atom_cookie_t deleteWindowAtomRequest = xcb_intern_atom(
m_connection,
0,
WM_DELETE_WINDOW_NAME.size(),
WM_DELETE_WINDOW_NAME.c_str()
);
xcb_intern_atom_reply_t* deleteWindowAtomReply = xcb_intern_atom_reply( xcb_intern_atom_reply_t* deleteWindowAtomReply = xcb_intern_atom_reply(
m_connection, m_connection,
deleteWindowAtomRequest, xcb_intern_atom(
m_connection,
0,
WM_DELETE_WINDOW_NAME.size(),
WM_DELETE_WINDOW_NAME.c_str()
),
NULL NULL
); );
static const std::string WM_PROTOCOLS_NAME = "WM_PROTOCOLS"; static const std::string WM_PROTOCOLS_NAME = "WM_PROTOCOLS";
xcb_intern_atom_cookie_t protocolsAtomRequest = xcb_intern_atom(
m_connection,
0,
WM_PROTOCOLS_NAME.size(),
WM_PROTOCOLS_NAME.c_str()
);
xcb_intern_atom_reply_t* protocolsAtomReply = xcb_intern_atom_reply( xcb_intern_atom_reply_t* protocolsAtomReply = xcb_intern_atom_reply(
m_connection, m_connection,
protocolsAtomRequest, xcb_intern_atom(
m_connection,
0,
WM_PROTOCOLS_NAME.size(),
WM_PROTOCOLS_NAME.c_str()
),
NULL NULL
); );
@ -776,18 +876,25 @@ void WindowImplX11::initialize()
// Create the input context // Create the input context
m_inputMethod = XOpenIM(m_display, NULL, NULL, NULL); m_inputMethod = XOpenIM(m_display, NULL, NULL, NULL);
if (m_inputMethod) if (m_inputMethod)
{ {
m_inputContext = XCreateIC(m_inputMethod, m_inputContext = XCreateIC(
XNClientWindow, m_window, m_inputMethod,
XNFocusWindow, m_window, XNClientWindow,
XNInputStyle, XIMPreeditNothing | XIMStatusNothing, m_window,
(void*)NULL); XNFocusWindow,
m_window,
XNInputStyle,
XIMPreeditNothing | XIMStatusNothing,
reinterpret_cast<void*>(NULL)
);
} }
else else
{ {
m_inputContext = NULL; m_inputContext = NULL;
} }
if (!m_inputContext) if (!m_inputContext)
err() << "Failed to create input context for window -- TextEntered event won't be able to return unicode" << std::endl; err() << "Failed to create input context for window -- TextEntered event won't be able to return unicode" << std::endl;
@ -815,10 +922,16 @@ void WindowImplX11::createHiddenCursor()
xcb_create_pixmap(m_connection, 1, cursorPixmap, m_window, 1, 1); xcb_create_pixmap(m_connection, 1, cursorPixmap, m_window, 1, 1);
// Create the cursor, using the pixmap as both the shape and the mask of the cursor // Create the cursor, using the pixmap as both the shape and the mask of the cursor
xcb_create_cursor(m_connection, m_hiddenCursor, cursorPixmap, cursorPixmap, xcb_create_cursor(
0, 0, 0, // Fore color m_connection,
0, 0, 0, // Back color m_hiddenCursor,
0, 0); cursorPixmap,
cursorPixmap,
0, 0, 0, // Foreground RGB color
0, 0, 0, // Background RGB color
0, // X
0 // Y
);
// We don't need the pixmap any longer, free it // We don't need the pixmap any longer, free it
xcb_free_pixmap(m_connection, cursorPixmap); xcb_free_pixmap(m_connection, cursorPixmap);
@ -832,23 +945,33 @@ void WindowImplX11::cleanup()
if (fullscreenWindow == this) if (fullscreenWindow == this)
{ {
// Get current screen info // Get current screen info
xcb_generic_error_t* errors; xcb_generic_error_t* error;
xcb_randr_get_screen_info_reply_t* config = xcb_randr_get_screen_info_reply( xcb_randr_get_screen_info_reply_t* config = xcb_randr_get_screen_info_reply(
m_connection, xcb_randr_get_screen_info(m_connection, m_screen->root), &errors); m_connection,
if (!errors) xcb_randr_get_screen_info(
m_connection,
m_screen->root
),
&error
);
if (!error)
{ {
// Reset the video mode // Reset the video mode
xcb_randr_set_screen_config(m_connection, xcb_randr_set_screen_config(
m_screen->root, m_connection,
CurrentTime, m_screen->root,
config->config_timestamp, CurrentTime,
m_oldVideoMode, config->config_timestamp,
config->rotation, config->rate); m_oldVideoMode,
config->rotation,
// Free the configuration instance config->rate
free(config); );
} }
free(errors);
// Free the configuration instance
free(error);
free(config);
// Reset the fullscreen window // Reset the fullscreen window
fullscreenWindow = NULL; fullscreenWindow = NULL;
@ -885,9 +1008,16 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
pushEvent(event); pushEvent(event);
// If the window has been previously marked urgent (notification) as a result of a focus request, undo that // If the window has been previously marked urgent (notification) as a result of a focus request, undo that
xcb_get_property_cookie_t hintsCookie = xcb_icccm_get_wm_hints_unchecked(m_connection, m_window);
xcb_icccm_wm_hints_t hints; xcb_icccm_wm_hints_t hints;
xcb_icccm_get_wm_hints_reply(m_connection, hintsCookie, &hints, NULL); xcb_icccm_get_wm_hints_reply(
m_connection,
xcb_icccm_get_wm_hints_unchecked(
m_connection,
m_window
),
&hints,
NULL
);
// Remove urgency (notification) flag from hints // Remove urgency (notification) flag from hints
hints.flags &= ~XUrgencyHint; hints.flags &= ~XUrgencyHint;
@ -949,8 +1079,8 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
XEvent fake_event; XEvent fake_event;
fake_event.type = KeyPress; fake_event.type = KeyPress;
fake_event.xany.display = m_display; fake_event.xany.display = m_display;
fake_event.xany.window = e->event; fake_event.xany.window = e->event;
fake_event.xkey.state = e->state; fake_event.xkey.state = e->state;
fake_event.xkey.keycode = e->detail; fake_event.xkey.keycode = e->detail;
XLookupString(&fake_event.xkey, buffer, sizeof(buffer), &symbol, &keyboard); XLookupString(&fake_event.xkey, buffer, sizeof(buffer), &symbol, &keyboard);
@ -974,7 +1104,16 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
{ {
Status status; Status status;
Uint8 keyBuffer[16]; Uint8 keyBuffer[16];
int length = Xutf8LookupString(m_inputContext, &fake_event.xkey, reinterpret_cast<char*>(keyBuffer), sizeof(keyBuffer), NULL, &status);
int length = Xutf8LookupString(
m_inputContext,
&fake_event.xkey,
reinterpret_cast<char*>(keyBuffer),
sizeof(keyBuffer),
NULL,
&status
);
if (length > 0) if (length > 0)
{ {
Uint32 unicode = 0; Uint32 unicode = 0;
@ -1019,7 +1158,7 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
// has to be converted to an XEvent // has to be converted to an XEvent
XKeyEvent fake_event; XKeyEvent fake_event;
fake_event.display = m_display; fake_event.display = m_display;
fake_event.state = e->state; fake_event.state = e->state;
fake_event.keycode = e->detail; fake_event.keycode = e->detail;
XLookupString(&fake_event, buffer, 32, &symbol, NULL); XLookupString(&fake_event, buffer, 32, &symbol, NULL);
@ -1043,8 +1182,11 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
// XXX: Why button 8 and 9? // XXX: Why button 8 and 9?
xcb_button_t button = e->detail; xcb_button_t button = e->detail;
if ((button == XCB_BUTTON_INDEX_1) || (button == XCB_BUTTON_INDEX_2) if ((button == XCB_BUTTON_INDEX_1) ||
|| (button == XCB_BUTTON_INDEX_3) || (button == 8) || (button == 9)) (button == XCB_BUTTON_INDEX_2) ||
(button == XCB_BUTTON_INDEX_3) ||
(button == 8) ||
(button == 9))
{ {
Event event; Event event;
event.type = Event::MouseButtonPressed; event.type = Event::MouseButtonPressed;
@ -1069,8 +1211,11 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
xcb_button_release_event_t* e = reinterpret_cast<xcb_button_press_event_t*>(windowEvent); xcb_button_release_event_t* e = reinterpret_cast<xcb_button_press_event_t*>(windowEvent);
xcb_button_t button = e->detail; xcb_button_t button = e->detail;
if ((button == XCB_BUTTON_INDEX_1) || (button == XCB_BUTTON_INDEX_2) if ((button == XCB_BUTTON_INDEX_1) ||
|| (button == XCB_BUTTON_INDEX_3) || (button == 8) || (button == 9)) (button == XCB_BUTTON_INDEX_2) ||
(button == XCB_BUTTON_INDEX_3) ||
(button == 8) ||
(button == 9))
{ {
Event event; Event event;
event.type = Event::MouseButtonReleased; event.type = Event::MouseButtonReleased;