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
if(SFML_OS_WINDOWS)
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})
if(SFML_OS_FREEBSD)
list(APPEND WINDOW_EXT_LIBS usbhid)
endif()
elseif(SFML_OS_FREEBSD)
list(APPEND WINDOW_EXT_LIBS ${LIBXCB_LIBRARIES} usbhid)
elseif(SFML_OS_MACOSX)
list(APPEND WINDOW_EXT_LIBS "-framework Foundation -framework AppKit -framework IOKit -framework Carbon")
elseif(SFML_OS_IOS)

View File

@ -101,6 +101,23 @@ xcb_screen_t* XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr)
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 sf

View File

@ -60,7 +60,7 @@ xcb_connection_t* OpenConnection();
////////////////////////////////////////////////////////////
/// \brief Release a reference to the shared display
///
/// \param Display to release
/// \param display Display to release
///
////////////////////////////////////////////////////////////
void CloseDisplay(Display* display);
@ -68,7 +68,7 @@ void CloseDisplay(Display* 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);
@ -76,13 +76,34 @@ void CloseConnection(xcb_connection_t* connection);
////////////////////////////////////////////////////////////
/// \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
///
////////////////////////////////////////////////////////////
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 sf

View File

@ -189,16 +189,15 @@ void InputImpl::setVirtualKeyboardVisible(bool /*visible*/)
bool InputImpl::isMouseButtonPressed(Mouse::Button button)
{
// Open a connection with the X server
Display* display = OpenDisplay();
xcb_connection_t* connection = XGetXCBConnection(display);
xcb_connection_t* connection = OpenConnection();
// 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;
free(pointer);
// Close the connection with the X server
CloseDisplay(display);
CloseConnection(connection);
switch (button)
{
@ -216,13 +215,12 @@ bool InputImpl::isMouseButtonPressed(Mouse::Button button)
Vector2i InputImpl::getMousePosition()
{
// Open a connection with the X server
Display* display = OpenDisplay();
xcb_connection_t* connection = XGetXCBConnection(display);
xcb_connection_t* connection = OpenConnection();
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
CloseDisplay(display);
CloseConnection(connection);
// Prepare result.
Vector2i result(pointer->root_x, pointer->root_y);
@ -263,14 +261,13 @@ Vector2i InputImpl::getMousePosition(const Window& relativeTo)
void InputImpl::setMousePosition(const Vector2i& position)
{
// Open a connection with the X server
Display* display = OpenDisplay();
xcb_connection_t* connection = XGetXCBConnection(display);
xcb_connection_t* connection = OpenConnection();
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);
// 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;
// Open a connection with the X server
Display* display = OpenDisplay();
xcb_connection_t* connection = XGetXCBConnection(display);
xcb_connection_t* connection = OpenConnection();
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
xcb_query_extension_cookie_t cookie = xcb_query_extension(connection, 5, "RANDR");
// Get the current configuration
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
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)
if (!error)
{
// Get the current configuration
xcb_generic_error_t* errors;
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 available screen sizes
xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config);
if (sizes && (config->nSizes > 0))
{
// Get the available screen sizes
xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config);
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))
{
// 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)
{
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
if (std::find(modes.begin(), modes.end(), mode) == modes.end())
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);
}
}
}
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
{
// 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;
// Failed to get the screen configuration
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
CloseDisplay(display);
// Free the configuration instance
free(error);
free(config);
}
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;
// 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;
}
free(randr_ext);
// Close the connection with the X server
CloseConnection(connection);
return modes;
}
@ -118,59 +126,68 @@ VideoMode VideoModeImpl::getDesktopMode()
VideoMode desktopMode;
// Open a connection with the X server
Display* display = OpenDisplay();
xcb_connection_t* connection = XGetXCBConnection(display);
if (display)
xcb_connection_t* connection = OpenConnection();
// 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");
// Retrieve the default screen
xcb_screen_t* screen = XCBScreenOfDisplay(connection, DefaultScreen(display));
// Get the current configuration
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
);
// 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)
if (!error)
{
// Get the current configuration
xcb_generic_error_t* errors;
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 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);
xcb_randr_screen_size_t* sizes= xcb_randr_get_screen_info_sizes(config);
if (sizes && (nbSizes > 0))
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);
// Get the available screen sizes
int nbSizes = xcb_randr_get_screen_info_sizes_length(config);
xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config);
if (sizes && (nbSizes > 0))
desktopMode = VideoMode(sizes[currentMode].width, sizes[currentMode].height, screen->root_depth);
}
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;
// Failed to get the screen configuration
err() << "Failed to retrieve the screen configuration while trying to get the desktop video modes" << std::endl;
}
free(randr_ext);
// Close the connection with the X server
CloseDisplay(display);
// Free the configuration instance
free(error);
free(config);
}
else
{
// 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;
// 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;
}
free(randr_ext);
// Close the connection with the X server
CloseConnection(connection);
return desktopMode;
}

View File

@ -35,6 +35,8 @@
#include <xcb/xcb_image.h>
#include <xcb/xcb_util.h>
#include <xcb/randr.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <libgen.h>
#include <cstring>
@ -65,18 +67,22 @@ namespace
EnterWindowMask | LeaveWindowMask;
// Find the name of the current executable
void findExecutableName(char* buffer, std::size_t bufferSize)
std::string findExecutableName()
{
//Default fallback name
const char* executableName = "sfml";
std::size_t length = readlink("/proc/self/exe", buffer, bufferSize);
if ((length > 0) && (length < bufferSize))
{
// Remove the path to keep the executable name only
buffer[length] = '\0';
executableName = basename(buffer);
struct stat linkStat;
if (!lstat("/proc/self/exe", &linkStat)) {
std::vector<char> buffer(0, linkStat.st_size + 1);
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';
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
m_display = OpenDisplay();
XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
m_connection = XGetXCBConnection(m_display);
if (!m_connection)
@ -109,10 +114,8 @@ m_useSizeHints(false)
return;
}
// Get connection info.
const xcb_setup_t* setup = xcb_get_setup(m_connection);
xcb_screen_iterator_t screenIter = xcb_setup_roots_iterator(setup);
m_screen = screenIter.data;
m_screen = XCBDefaultScreen(m_connection);
XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
// Save the window handle
m_window = handle;
@ -122,10 +125,12 @@ m_useSizeHints(false)
// Make sure the window is listening to all the required events
const uint32_t value_list[] = {static_cast<uint32_t>(eventMask)};
xcb_change_window_attributes(m_connection,
m_window,
XCB_CW_EVENT_MASK,
value_list);
xcb_change_window_attributes(
m_connection,
m_window,
XCB_CW_EVENT_MASK,
value_list
);
// Do some common initializations
initialize();
@ -148,32 +153,21 @@ m_useSizeHints(false)
{
// Open a connection with the X server
m_display = OpenDisplay();
XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
m_connection = XGetXCBConnection(m_display);
if (!m_connection)
{
err() << "Failed cast Display object to an XCB connection object" << std::endl;
return;
}
// Get connection info.
const xcb_setup_t* setup = xcb_get_setup(m_connection);
xcb_screen_iterator_t screenIter = xcb_setup_roots_iterator(setup);
m_screen = screenIter.data;
m_screen = XCBDefaultScreen(m_connection);
XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
// Compute position and size
int left, top;
bool fullscreen = (style & Style::Fullscreen) != 0;
if (!fullscreen)
{
left = (m_screen->width_in_pixels - mode.width) / 2;
top = (m_screen->height_in_pixels - mode.height) / 2;
}
else
{
left = 0;
top = 0;
}
int left = fullscreen ? 0 : (m_screen->width_in_pixels - mode.width) / 2;
int top = fullscreen ? 0 : (m_screen->height_in_pixels - mode.height) / 2;
int width = mode.width;
int height = mode.height;
@ -187,20 +181,23 @@ m_useSizeHints(false)
// Create the window
m_window = xcb_generate_id(m_connection);
xcb_void_cookie_t cookie = xcb_create_window_checked(
m_connection,
XCB_COPY_FROM_PARENT,
m_window,
m_screen->root,
left, top,
width, height,
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
XCB_COPY_FROM_PARENT,
XCB_CW_EVENT_MASK | XCB_CW_OVERRIDE_REDIRECT,
value_list);
xcb_generic_error_t* errptr = xcb_request_check(
m_connection,
xcb_create_window_checked(
m_connection,
XCB_COPY_FROM_PARENT,
m_window,
m_screen->root,
left, top,
width, height,
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
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);
free(errptr);
@ -213,19 +210,18 @@ m_useSizeHints(false)
// Set the window's name
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)
{
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(
m_connection,
hintsAtomRequest,
xcb_intern_atom(
m_connection,
0,
MOTIF_WM_HINTS.size(),
MOTIF_WM_HINTS.c_str()
),
NULL
);
@ -279,9 +275,16 @@ m_useSizeHints(false)
hints.functions |= MWM_FUNC_CLOSE;
}
const unsigned char* ptr = reinterpret_cast<const unsigned char*>(&hints);
xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window,
hintsAtomReply->atom, XCB_ATOM_WM_HINTS, 32, 5, ptr);
xcb_change_property(
m_connection,
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);
}
@ -299,9 +302,8 @@ m_useSizeHints(false)
}
// Set the window's WM class (this can be used by window managers)
char windowClass[512];
findExecutableName(windowClass, sizeof(windowClass));
xcb_icccm_set_wm_class_checked(m_connection, m_window, std::strlen(windowClass), windowClass);
std::string windowClass = findExecutableName();
xcb_icccm_set_wm_class_checked(m_connection, m_window, windowClass.size(), windowClass.c_str());
// Do some common initializations
initialize();
@ -309,8 +311,26 @@ m_useSizeHints(false)
// In fullscreen mode, we must grab keyboard and mouse inputs
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_keyboard(m_connection, True, m_window, XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
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_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 nextWindow = topLevelWindow;
xcb_query_tree_cookie_t treeCookie;
xcb_query_tree_reply_t* treeReply = NULL;
// 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;
treeCookie = xcb_query_tree(m_connection, topLevelWindow);
treeReply = xcb_query_tree_reply(m_connection, treeCookie, NULL);
treeReply = xcb_query_tree_reply(m_connection, xcb_query_tree(m_connection, topLevelWindow), NULL);
nextWindow = treeReply->parent;
free(treeReply);
}
xcb_get_geometry_cookie_t geometryCookie = xcb_get_geometry(m_connection, topLevelWindow);
xcb_get_geometry_reply_t* geometryReply = xcb_get_geometry_reply(m_connection, geometryCookie, NULL);
xcb_get_geometry_reply_t* geometryReply = xcb_get_geometry_reply(
m_connection,
xcb_get_geometry(
m_connection,
topLevelWindow
),
NULL
);
sf::Vector2i result(geometryReply->x, geometryReply->y);
free(geometryReply);
@ -480,9 +504,12 @@ void WindowImplX11::setSize(const Vector2u& size)
}
uint32_t values[] = {size.x, size.y};
xcb_configure_window(m_connection, m_window,
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
values);
xcb_configure_window(
m_connection,
m_window,
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
values
);
xcb_flush(m_connection);
}
@ -497,9 +524,16 @@ void WindowImplX11::setTitle(const String& title)
std::back_inserter( utf8String )
);
xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window,
XCB_ATOM_WM_NAME, XCB_ATOM_STRING,
8, utf8String.length(), utf8String.c_str());
xcb_change_property(
m_connection,
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);
}
@ -519,17 +553,38 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8
// Create the icon pixmap
xcb_pixmap_t iconPixmap = xcb_generate_id(m_connection);
xcb_create_pixmap(m_connection, m_screen->root_depth, iconPixmap, m_screen->root,
width, height);
xcb_create_pixmap(
m_connection,
m_screen->root_depth,
iconPixmap,
m_screen->root,
width,
height
);
xcb_gcontext_t iconGC = xcb_generate_id(m_connection);
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,
width, height, 0, 0, 0, m_screen->root_depth, sizeof(iconPixels), iconPixels);
xcb_generic_error_t* errptr = xcb_request_check(
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_generic_error_t* errptr = xcb_request_check(m_connection, cookie);
if (errptr)
{
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
xcb_icccm_wm_hints_t hints;
@ -613,10 +679,14 @@ void WindowImplX11::requestFocus()
// Check if window is viewable (not on other desktop, ...)
// 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(m_connection,
attribCookie,
NULL);
xcb_get_window_attributes_reply_t* attributes = xcb_get_window_attributes_reply(
m_connection,
xcb_get_window_attributes(
m_connection,
m_window
),
NULL
);
if (!attributes)
{
sf::err() << "Failed to check if window is viewable while requesting focus" << std::endl;
@ -637,9 +707,16 @@ void WindowImplX11::requestFocus()
else
{
// 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_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
// different from Xlib where XAllocWMHints() has to be called.
@ -652,13 +729,18 @@ void WindowImplX11::requestFocus()
////////////////////////////////////////////////////////////
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(m_connection, cookie, NULL);
xcb_get_input_focus_reply_t* reply = xcb_get_input_focus_reply(
m_connection,
xcb_get_input_focus_unchecked(
m_connection
),
NULL
);
bool focussed = (reply->focus == m_window);
bool focused = (reply->focus == m_window);
free(reply);
return focussed;
return focused;
}
@ -666,17 +748,31 @@ bool WindowImplX11::hasFocus() const
void WindowImplX11::switchToFullscreen(const VideoMode& mode)
{
// Check if the XRandR extension is present
xcb_query_extension_reply_t* randr_ext =
xcb_query_extension_reply(m_connection, xcb_query_extension(m_connection, 5, "RANDR"), NULL);
static const std::string RANDR = "RANDR";
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)
{
// Get the current configuration
xcb_generic_error_t* errors;
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);
if (! errors)
xcb_generic_error_t* error;
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
),
&error
);
if (!error)
{
// Save the current video mode before we switch to fullscreen
m_oldVideoMode = config->sizeID;
@ -688,14 +784,19 @@ void WindowImplX11::switchToFullscreen(const VideoMode& mode)
// Search a matching size
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
xcb_randr_set_screen_config(m_connection,
m_screen->root,
config->timestamp,
config->config_timestamp,
i, config->rotation, config->rate);
xcb_randr_set_screen_config(
m_connection,
m_screen->root,
config->timestamp,
config->config_timestamp,
i,
config->rotation,
config->rate
);
// Set "this" as the current fullscreen window
fullscreenWindow = this;
@ -709,14 +810,17 @@ void WindowImplX11::switchToFullscreen(const VideoMode& mode)
// Failed to get the screen configuration
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);
}
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;
}
free(randr_ext);
}
@ -726,30 +830,26 @@ void WindowImplX11::initialize()
{
// Get the atoms for registering the close event
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(
m_connection,
deleteWindowAtomRequest,
xcb_intern_atom(
m_connection,
0,
WM_DELETE_WINDOW_NAME.size(),
WM_DELETE_WINDOW_NAME.c_str()
),
NULL
);
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(
m_connection,
protocolsAtomRequest,
xcb_intern_atom(
m_connection,
0,
WM_PROTOCOLS_NAME.size(),
WM_PROTOCOLS_NAME.c_str()
),
NULL
);
@ -776,18 +876,25 @@ void WindowImplX11::initialize()
// Create the input context
m_inputMethod = XOpenIM(m_display, NULL, NULL, NULL);
if (m_inputMethod)
{
m_inputContext = XCreateIC(m_inputMethod,
XNClientWindow, m_window,
XNFocusWindow, m_window,
XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
(void*)NULL);
m_inputContext = XCreateIC(
m_inputMethod,
XNClientWindow,
m_window,
XNFocusWindow,
m_window,
XNInputStyle,
XIMPreeditNothing | XIMStatusNothing,
reinterpret_cast<void*>(NULL)
);
}
else
{
m_inputContext = NULL;
}
if (!m_inputContext)
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);
// 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,
0, 0, 0, // Fore color
0, 0, 0, // Back color
0, 0);
xcb_create_cursor(
m_connection,
m_hiddenCursor,
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
xcb_free_pixmap(m_connection, cursorPixmap);
@ -832,23 +945,33 @@ void WindowImplX11::cleanup()
if (fullscreenWindow == this)
{
// 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(
m_connection, xcb_randr_get_screen_info(m_connection, m_screen->root), &errors);
if (!errors)
m_connection,
xcb_randr_get_screen_info(
m_connection,
m_screen->root
),
&error
);
if (!error)
{
// Reset the video mode
xcb_randr_set_screen_config(m_connection,
m_screen->root,
CurrentTime,
config->config_timestamp,
m_oldVideoMode,
config->rotation, config->rate);
// Free the configuration instance
free(config);
xcb_randr_set_screen_config(
m_connection,
m_screen->root,
CurrentTime,
config->config_timestamp,
m_oldVideoMode,
config->rotation,
config->rate
);
}
free(errors);
// Free the configuration instance
free(error);
free(config);
// Reset the fullscreen window
fullscreenWindow = NULL;
@ -885,9 +1008,16 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
pushEvent(event);
// 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_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
hints.flags &= ~XUrgencyHint;
@ -949,8 +1079,8 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
XEvent fake_event;
fake_event.type = KeyPress;
fake_event.xany.display = m_display;
fake_event.xany.window = e->event;
fake_event.xkey.state = e->state;
fake_event.xany.window = e->event;
fake_event.xkey.state = e->state;
fake_event.xkey.keycode = e->detail;
XLookupString(&fake_event.xkey, buffer, sizeof(buffer), &symbol, &keyboard);
@ -974,7 +1104,16 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
{
Status status;
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)
{
Uint32 unicode = 0;
@ -1019,7 +1158,7 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
// has to be converted to an XEvent
XKeyEvent fake_event;
fake_event.display = m_display;
fake_event.state = e->state;
fake_event.state = e->state;
fake_event.keycode = e->detail;
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?
xcb_button_t button = e->detail;
if ((button == XCB_BUTTON_INDEX_1) || (button == XCB_BUTTON_INDEX_2)
|| (button == XCB_BUTTON_INDEX_3) || (button == 8) || (button == 9))
if ((button == XCB_BUTTON_INDEX_1) ||
(button == XCB_BUTTON_INDEX_2) ||
(button == XCB_BUTTON_INDEX_3) ||
(button == 8) ||
(button == 9))
{
Event event;
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_t button = e->detail;
if ((button == XCB_BUTTON_INDEX_1) || (button == XCB_BUTTON_INDEX_2)
|| (button == XCB_BUTTON_INDEX_3) || (button == 8) || (button == 9))
if ((button == XCB_BUTTON_INDEX_1) ||
(button == XCB_BUTTON_INDEX_2) ||
(button == XCB_BUTTON_INDEX_3) ||
(button == 8) ||
(button == 9))
{
Event event;
event.type = Event::MouseButtonReleased;