From 9996b7abb6c6e216dc40d527b0339c89880709c5 Mon Sep 17 00:00:00 2001 From: binary1248 Date: Sun, 14 Aug 2016 02:52:49 +0200 Subject: [PATCH] Converted Unix Window implementation from XCB back to Xlib. --- cmake/Modules/FindSFML.cmake | 9 +- cmake/Modules/FindXCB.cmake | 97 -- examples/X11/X11.cpp | 119 +- src/SFML/Window/CMakeLists.txt | 16 +- src/SFML/Window/Unix/Display.cpp | 82 +- src/SFML/Window/Unix/Display.hpp | 56 +- src/SFML/Window/Unix/GlxContext.cpp | 38 +- src/SFML/Window/Unix/GlxContext.hpp | 3 +- src/SFML/Window/Unix/InputImpl.cpp | 190 +-- src/SFML/Window/Unix/ScopedXcbPtr.hpp | 102 -- src/SFML/Window/Unix/ScopedXcbPtr.inl | 72 -- src/SFML/Window/Unix/VideoModeImpl.cpp | 272 ++--- src/SFML/Window/Unix/WindowImplX11.cpp | 1535 +++++++++--------------- src/SFML/Window/Unix/WindowImplX11.hpp | 100 +- 14 files changed, 831 insertions(+), 1860 deletions(-) delete mode 100644 cmake/Modules/FindXCB.cmake delete mode 100644 src/SFML/Window/Unix/ScopedXcbPtr.hpp delete mode 100644 src/SFML/Window/Unix/ScopedXcbPtr.inl diff --git a/cmake/Modules/FindSFML.cmake b/cmake/Modules/FindSFML.cmake index fdea1eb2..fe84c961 100644 --- a/cmake/Modules/FindSFML.cmake +++ b/cmake/Modules/FindSFML.cmake @@ -285,10 +285,7 @@ if(SFML_STATIC_LIBRARIES) # find libraries if(FIND_SFML_OS_LINUX OR FIND_SFML_OS_FREEBSD) find_sfml_dependency(X11_LIBRARY "X11" X11) - find_sfml_dependency(LIBXCB_LIBRARIES "XCB" xcb libxcb) - 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) + find_sfml_dependency(XRANDR_LIBRARY "Xrandr" Xrandr) endif() if(FIND_SFML_OS_LINUX) @@ -299,9 +296,9 @@ if(SFML_STATIC_LIBRARIES) if(FIND_SFML_OS_WINDOWS) set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "opengl32" "winmm" "gdi32") 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) - 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) set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "-framework OpenGL -framework Foundation -framework AppKit -framework IOKit -framework Carbon") endif() diff --git a/cmake/Modules/FindXCB.cmake b/cmake/Modules/FindXCB.cmake deleted file mode 100644 index 4915f723..00000000 --- a/cmake/Modules/FindXCB.cmake +++ /dev/null @@ -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() diff --git a/examples/X11/X11.cpp b/examples/X11/X11.cpp index 2c2419b7..746bf075 100644 --- a/examples/X11/X11.cpp +++ b/examples/X11/X11.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include @@ -133,77 +133,46 @@ int main() if (!display) return EXIT_FAILURE; - // Get the XCB connection for the opened display. - xcb_connection_t* xcbConnection = XGetXCBConnection(display); + // Get the default screen + int screen = DefaultScreen(display); - if (!xcbConnection) - { - sf::err() << "Failed to get the XCB connection for opened display." << std::endl; + // Let's create the main window + XSetWindowAttributes attributes; + 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; - } - // Get XCB screen. - const xcb_setup_t* xcbSetup = xcb_get_setup(xcbConnection); - xcb_screen_iterator_t xcbScreenIter = xcb_setup_roots_iterator(xcbSetup); - xcb_screen_t* screen = xcbScreenIter.data; + // Set the window's name + XStoreName(display, window , "SFML Window"); - if (!screen) - { - sf::err() << "Failed to get the XCB screen." << std::endl; - return EXIT_FAILURE; - } + // Let's create the windows which will serve as containers for our SFML views + Window view1 = XCreateWindow(display, window, + 10, 10, 310, 310, 0, + 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. - xcb_window_t rootWindowId = xcb_generate_id(xcbConnection); - xcb_window_t view1WindowId = xcb_generate_id(xcbConnection); - 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); + // Show our windows + XMapWindow(display, window); + XFlush(display); // Create our SFML views - sf::Window sfmlView1(view1WindowId); - sf::Window sfmlView2(view2WindowId); + sf::Window sfmlView1(view1); + sf::Window sfmlView2(view2); // Create a clock for measuring elapsed time sf::Clock clock; @@ -214,13 +183,22 @@ int main() // Start the event loop bool running = true; - xcb_generic_event_t* event = NULL; - 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 @@ -232,5 +210,8 @@ int main() sfmlView2.display(); } + // Close the display + XCloseDisplay(display); + return EXIT_SUCCESS; } diff --git a/src/SFML/Window/CMakeLists.txt b/src/SFML/Window/CMakeLists.txt index 231dee8f..a887766e 100644 --- a/src/SFML/Window/CMakeLists.txt +++ b/src/SFML/Window/CMakeLists.txt @@ -75,8 +75,6 @@ elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD) ${SRCROOT}/Unix/Display.hpp ${SRCROOT}/Unix/InputImpl.cpp ${SRCROOT}/Unix/InputImpl.hpp - ${SRCROOT}/Unix/ScopedXcbPtr.hpp - ${SRCROOT}/Unix/ScopedXcbPtr.inl ${SRCROOT}/Unix/SensorImpl.cpp ${SRCROOT}/Unix/SensorImpl.hpp ${SRCROOT}/Unix/VideoModeImpl.cpp @@ -200,18 +198,14 @@ if(SFML_OS_LINUX OR SFML_OS_FREEBSD) if(NOT X11_FOUND) message(FATAL_ERROR "X11 library not found") endif() + if(NOT X11_Xrandr_FOUND) + message(FATAL_ERROR "Xrandr library not found") + endif() include_directories(${X11_INCLUDE_DIR}) endif() if(NOT SFML_OPENGL_ES) find_package(OpenGL REQUIRED) 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() if(SFML_OPENGL_ES AND SFML_OS_LINUX) find_package(EGL REQUIRED) @@ -231,9 +225,9 @@ endif() if(SFML_OS_WINDOWS) list(APPEND WINDOW_EXT_LIBS winmm gdi32) 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) - 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) list(APPEND WINDOW_EXT_LIBS "-framework Foundation -framework AppKit -framework IOKit -framework Carbon") elseif(SFML_OS_IOS) diff --git a/src/SFML/Window/Unix/Display.cpp b/src/SFML/Window/Unix/Display.cpp index a078b975..fce86015 100644 --- a/src/SFML/Window/Unix/Display.cpp +++ b/src/SFML/Window/Unix/Display.cpp @@ -27,9 +27,9 @@ //////////////////////////////////////////////////////////// #include #include -#include #include #include +#include #include @@ -39,7 +39,7 @@ namespace Display* sharedDisplay = NULL; unsigned int referenceCount = 0; - typedef std::map AtomMap; + typedef std::map AtomMap; AtomMap atoms; } @@ -68,13 +68,6 @@ Display* OpenDisplay() } -//////////////////////////////////////////////////////////// -xcb_connection_t* OpenConnection() -{ - return XGetXCBConnection(OpenDisplay()); -} - - //////////////////////////////////////////////////////////// void CloseDisplay(Display* display) { @@ -87,81 +80,22 @@ void CloseDisplay(Display* display) //////////////////////////////////////////////////////////// -void CloseConnection(xcb_connection_t* connection) -{ - 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) +Atom getAtom(const std::string& name, bool onlyIfExists) { AtomMap::const_iterator iter = atoms.find(name); if (iter != atoms.end()) return iter->second; - ScopedXcbPtr error(NULL); + Display* display = OpenDisplay(); - xcb_connection_t* connection = OpenConnection(); + Atom atom = XInternAtom(display, name.c_str(), onlyIfExists ? True : False); - ScopedXcbPtr reply(xcb_intern_atom_reply( - connection, - xcb_intern_atom( - connection, - onlyIfExists, - name.size(), - name.c_str() - ), - &error - )); + CloseDisplay(display); - CloseConnection(connection); + atoms[name] = atom; - if (error || !reply) - { - err() << "Failed to get " << name << " atom." << std::endl; - return XCB_ATOM_NONE; - } - - atoms[name] = reply->atom; - - return reply->atom; + return atom; } } // namespace priv diff --git a/src/SFML/Window/Unix/Display.hpp b/src/SFML/Window/Unix/Display.hpp index 2743678c..f0eb3020 100644 --- a/src/SFML/Window/Unix/Display.hpp +++ b/src/SFML/Window/Unix/Display.hpp @@ -28,7 +28,7 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#include +#include #include @@ -47,17 +47,6 @@ namespace priv //////////////////////////////////////////////////////////// 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 /// @@ -66,55 +55,16 @@ xcb_connection_t* OpenConnection(); //////////////////////////////////////////////////////////// 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 /// /// \param name Name of the atom /// \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 diff --git a/src/SFML/Window/Unix/GlxContext.cpp b/src/SFML/Window/Unix/GlxContext.cpp index 4d4d8312..8b4711d4 100644 --- a/src/SFML/Window/Unix/GlxContext.cpp +++ b/src/SFML/Window/Unix/GlxContext.cpp @@ -194,8 +194,8 @@ GlxContext::~GlxContext() // Destroy the window if we own it if (m_window && m_ownsWindow) { - xcb_destroy_window(m_connection, m_window); - xcb_flush(m_connection); + XDestroyWindow(m_display, m_window); + XFlush(m_display); } // Close the connection with the X server @@ -444,7 +444,6 @@ void GlxContext::updateSettingsFromWindow() void GlxContext::createSurface(GlxContext* shared, unsigned int width, unsigned int height, unsigned int bitsPerPixel) { m_display = OpenDisplay(); - m_connection = XGetXCBConnection(m_display); // Choose the visual according to the context settings XVisualInfo visualInfo = selectBestVisual(m_display, bitsPerPixel, m_settings); @@ -513,28 +512,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 - xcb_screen_t* screen = XCBScreenOfDisplay(m_connection, DefaultScreen(m_display)); + int screen = DefaultScreen(m_display); // Define the window attributes - xcb_colormap_t colormap = xcb_generate_id(m_connection); - xcb_create_colormap(m_connection, XCB_COLORMAP_ALLOC_NONE, colormap, screen->root, visualInfo.visualid); - const uint32_t value_list[] = {colormap}; + XSetWindowAttributes attributes; + attributes.colormap = XCreateColormap(m_display, RootWindow(m_display, screen), visualInfo.visual, AllocNone); - // Create a dummy window (disabled and hidden) - m_window = xcb_generate_id(m_connection); - xcb_create_window( - m_connection, - static_cast(visualInfo.depth), - m_window, - screen->root, - 0, 0, - width, height, - 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - visualInfo.visualid, - XCB_CW_COLORMAP, - value_list - ); + m_window = XCreateWindow(m_display, + RootWindow(m_display, screen), + 0, 0, + width, height, + 0, + DefaultDepth(m_display, screen), + InputOutput, + visualInfo.visual, + CWColormap, + &attributes); m_ownsWindow = true; @@ -546,7 +539,6 @@ void GlxContext::createSurface(GlxContext* shared, unsigned int width, unsigned void GlxContext::createSurface(::Window window) { m_display = OpenDisplay(); - m_connection = XGetXCBConnection(m_display); // A window already exists, so just use it m_window = window; diff --git a/src/SFML/Window/Unix/GlxContext.hpp b/src/SFML/Window/Unix/GlxContext.hpp index 4a9444f2..959c3299 100644 --- a/src/SFML/Window/Unix/GlxContext.hpp +++ b/src/SFML/Window/Unix/GlxContext.hpp @@ -30,7 +30,7 @@ //////////////////////////////////////////////////////////// #include #include -#include +#include namespace sf @@ -178,7 +178,6 @@ private: //////////////////////////////////////////////////////////// ::Display* m_display; ///< Connection to the X server ::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 GLXPbuffer m_pbuffer; ///< GLX pbuffer ID if one was created bool m_ownsWindow; ///< Do we own the window associated to the context? diff --git a/src/SFML/Window/Unix/InputImpl.cpp b/src/SFML/Window/Unix/InputImpl.cpp index ad62cd50..90cae1a2 100644 --- a/src/SFML/Window/Unix/InputImpl.cpp +++ b/src/SFML/Window/Unix/InputImpl.cpp @@ -28,9 +28,8 @@ #include // important to be included first (conflict with None) #include #include -#include #include -#include +#include #include @@ -157,36 +156,26 @@ bool InputImpl::isKeyPressed(Keyboard::Key key) Display* display = OpenDisplay(); // Convert to keycode - xcb_keycode_t keycode = XKeysymToKeycode(display, keysym); - - CloseDisplay(display); - - ScopedXcbPtr error(NULL); - - // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); - - // Get the whole keyboard state - ScopedXcbPtr keymap( - xcb_query_keymap_reply( - connection, - xcb_query_keymap(connection), - &error - ) - ); - - // Close the connection with the X server - CloseConnection(connection); - - if (error) + KeyCode keycode = XKeysymToKeycode(display, keysym); + if (keycode != 0) { - 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; } - - // 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) { // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); + Display* display = OpenDisplay(); - ScopedXcbPtr error(NULL); + // we don't care about these but they are required + ::Window root, child; + int wx, wy; + int gx, gy; - // Get pointer mask - ScopedXcbPtr pointer( - xcb_query_pointer_reply( - connection, - xcb_query_pointer( - connection, - XCBDefaultRootWindow(connection) - ), - &error - ) - ); + unsigned int buttons = 0; + XQueryPointer(display, DefaultRootWindow(display), &root, &child, &gx, &gy, &wx, &wy, &buttons); // Close the connection with the X server - CloseConnection(connection); - - if (error) - { - err() << "Failed to query pointer" << std::endl; - - return false; - } - - uint16_t buttons = pointer->mask; + CloseDisplay(display); switch (button) { - case Mouse::Left: return buttons & XCB_BUTTON_MASK_1; - case Mouse::Right: return buttons & XCB_BUTTON_MASK_3; - case Mouse::Middle: return buttons & XCB_BUTTON_MASK_2; + case Mouse::Left: return buttons & Button1Mask; + case Mouse::Right: return buttons & Button3Mask; + case Mouse::Middle: return buttons & Button2Mask; case Mouse::XButton1: return false; // not supported by X case Mouse::XButton2: return false; // not supported by X default: return false; } + + return false; } @@ -245,32 +221,21 @@ bool InputImpl::isMouseButtonPressed(Mouse::Button button) Vector2i InputImpl::getMousePosition() { // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); + Display* display = OpenDisplay(); - ScopedXcbPtr error(NULL); + // we don't care about these but they are required + ::Window root, child; + int x, y; + unsigned int buttons; - ScopedXcbPtr pointer( - xcb_query_pointer_reply( - connection, - xcb_query_pointer( - connection, - XCBDefaultRootWindow(connection) - ), - &error - ) - ); + int gx = 0; + int gy = 0; + XQueryPointer(display, DefaultRootWindow(display), &root, &child, &gx, &gy, &x, &y, &buttons); // Close the connection with the X server - CloseConnection(connection); + CloseDisplay(display); - if (error) - { - err() << "Failed to query pointer" << std::endl; - - return Vector2i(0, 0); - } - - return Vector2i(pointer->root_x, pointer->root_y); + return Vector2i(gx, gy); } @@ -281,32 +246,21 @@ Vector2i InputImpl::getMousePosition(const Window& relativeTo) if (handle) { // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); + Display* display = OpenDisplay(); - ScopedXcbPtr error(NULL); + // we don't care about these but they are required + ::Window root, child; + int gx, gy; + unsigned int buttons; - ScopedXcbPtr pointer( - xcb_query_pointer_reply( - connection, - xcb_query_pointer( - connection, - handle - ), - &error - ) - ); + int x = 0; + int y = 0; + XQueryPointer(display, handle, &root, &child, &gx, &gy, &x, &y, &buttons); // Close the connection with the X server - CloseConnection(connection); + CloseDisplay(display); - if (error) - { - err() << "Failed to query pointer" << std::endl; - - return Vector2i(0, 0); - } - - return Vector2i(pointer->win_x, pointer->win_y); + return Vector2i(x, y); } else { @@ -319,27 +273,13 @@ Vector2i InputImpl::getMousePosition(const Window& relativeTo) void InputImpl::setMousePosition(const Vector2i& position) { // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); + Display* display = OpenDisplay(); - ScopedXcbPtr error(xcb_request_check( - connection, - 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); + XWarpPointer(display, None, DefaultRootWindow(display), 0, 0, 0, 0, position.x, position.y); + XFlush(display); // 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) { // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); + Display* display = OpenDisplay(); WindowHandle handle = relativeTo.getSystemHandle(); if (handle) { - ScopedXcbPtr error(xcb_request_check( - connection, - 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); + XWarpPointer(display, None, handle, 0, 0, 0, 0, position.x, position.y); + XFlush(display); } // Close the connection with the X server - CloseConnection(connection); + CloseDisplay(display); } diff --git a/src/SFML/Window/Unix/ScopedXcbPtr.hpp b/src/SFML/Window/Unix/ScopedXcbPtr.hpp deleted file mode 100644 index f610d81d..00000000 --- a/src/SFML/Window/Unix/ScopedXcbPtr.hpp +++ /dev/null @@ -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 - - -namespace sf -{ -namespace priv -{ -//////////////////////////////////////////////////////////// -/// \brief Scoped pointer that frees memory returned in XCB replies -/// -//////////////////////////////////////////////////////////// -template -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 - -} // namespace priv - -} // namespace sf - -#endif // SFML_SCOPEDXCBPTR_HPP diff --git a/src/SFML/Window/Unix/ScopedXcbPtr.inl b/src/SFML/Window/Unix/ScopedXcbPtr.inl deleted file mode 100644 index 5869d916..00000000 --- a/src/SFML/Window/Unix/ScopedXcbPtr.inl +++ /dev/null @@ -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 -inline ScopedXcbPtr::ScopedXcbPtr(T* pointer) : -m_pointer(pointer) -{ - -} - - -//////////////////////////////////////////////////////////// -template -inline ScopedXcbPtr::~ScopedXcbPtr() -{ - std::free(m_pointer); -} - - -//////////////////////////////////////////////////////////// -template -inline T* ScopedXcbPtr::operator ->() const -{ - return m_pointer; -} - - -//////////////////////////////////////////////////////////// -template -inline T** ScopedXcbPtr::operator &() -{ - return &m_pointer; -} - - -//////////////////////////////////////////////////////////// -template -inline ScopedXcbPtr::operator bool() const -{ - return m_pointer != NULL; -} - - -//////////////////////////////////////////////////////////// -template -inline T* ScopedXcbPtr::get() const -{ - return m_pointer; -} diff --git a/src/SFML/Window/Unix/VideoModeImpl.cpp b/src/SFML/Window/Unix/VideoModeImpl.cpp index f95d3232..cd78c548 100644 --- a/src/SFML/Window/Unix/VideoModeImpl.cpp +++ b/src/SFML/Window/Unix/VideoModeImpl.cpp @@ -27,9 +27,9 @@ //////////////////////////////////////////////////////////// #include #include -#include #include -#include +#include +#include #include @@ -43,95 +43,78 @@ std::vector VideoModeImpl::getFullscreenModes() std::vector modes; // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); - - // Retrieve the default screen - xcb_screen_t* screen = XCBDefaultScreen(connection); - - ScopedXcbPtr error(NULL); - - const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(connection, &xcb_randr_id); - - if (!randrExt || !randrExt->present) + Display* display = OpenDisplay(); + if (display) { - // Randr extension is not supported: we cannot get the video modes - err() << "Failed to use the RandR extension while trying to get the supported video modes" << std::endl; + // Retrieve the default screen number + int screen = DefaultScreen(display); - // Close the connection with the X server - CloseConnection(connection); - - return modes; - } - - // Load RandR and check its version - ScopedXcbPtr 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 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)) + // Check if the XRandR extension is present + int version; + if (XQueryExtension(display, "RANDR", &version, &version, &version)) { - for (int j = 0; j < config->nSizes; ++j) + // Get the current configuration + XRRScreenConfiguration* config = XRRGetScreenInfo(display, RootWindow(display, screen)); + if (config) { - // Convert to VideoMode - VideoMode mode(sizes[j].width, sizes[j].height, iter.data->depth); + // Get the available screen sizes + 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 || - config->rotation == XCB_RANDR_ROTATION_ROTATE_270) - std::swap(mode.width, mode.height); + Rotation currentRotation; + XRRConfigRotations(config, ¤tRotation); - // 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); + if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270) + std::swap(mode.width, mode.height); + + // 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 - CloseConnection(connection); + // Close the connection with the X server + 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; } @@ -143,91 +126,62 @@ VideoMode VideoModeImpl::getDesktopMode() VideoMode desktopMode; // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); - - // Retrieve the default screen - xcb_screen_t* screen = XCBDefaultScreen(connection); - - ScopedXcbPtr 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) + Display* display = OpenDisplay(); + if (display) { - // Randr extension is not supported: we cannot get the video modes - err() << "Failed to use the RandR extension while trying to get the desktop video mode" << std::endl; + // Retrieve the default screen number + 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, ¤tRotation); + + // 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, ¤tRotation); + + 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 - CloseConnection(connection); - - return desktopMode; - } - - // Load RandR and check its version - ScopedXcbPtr 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 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); + CloseDisplay(display); } 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; } diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index 9e7fca76..530bea50 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -29,15 +29,16 @@ #include #include #include -#include #include #include #include #include #include -#include -#include #include +#include +#include +#include +#include #include #include #include @@ -66,12 +67,12 @@ namespace sf::Mutex allWindowsMutex; sf::String windowManagerName; - static const unsigned long eventMask = XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_PRESS | - XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION | - XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_KEY_PRESS | - XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | - XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | - XCB_EVENT_MASK_VISIBILITY_CHANGE; + static const unsigned long eventMask = FocusChangeMask | ButtonPressMask | + ButtonReleaseMask | ButtonMotionMask | + PointerMotionMask | KeyPressMask | + KeyReleaseMask | StructureNotifyMask | + EnterWindowMask | LeaveWindowMask | + VisibilityChangeMask | PropertyChangeMask; static const unsigned int maxTrialsCount = 5; @@ -127,76 +128,88 @@ namespace checked = true; - xcb_connection_t* connection = sf::priv::OpenConnection(); - - xcb_atom_t netSupportingWmCheck = sf::priv::getAtom("_NET_SUPPORTING_WM_CHECK", true); - xcb_atom_t netSupported = sf::priv::getAtom("_NET_SUPPORTED", true); + Atom netSupportingWmCheck = sf::priv::getAtom("_NET_SUPPORTING_WM_CHECK", true); + Atom netSupported = sf::priv::getAtom("_NET_SUPPORTED", true); if (!netSupportingWmCheck || !netSupported) return false; - sf::priv::ScopedXcbPtr error(NULL); + ::Display* display = sf::priv::OpenDisplay(); - sf::priv::ScopedXcbPtr rootSupportingWindow(xcb_get_property_reply( - connection, - xcb_get_property( - connection, - 0, - sf::priv::XCBDefaultRootWindow(connection), - netSupportingWmCheck, - XCB_ATOM_WINDOW, - 0, - 1 - ), - &error - )); + Atom actualType; + int actualFormat; + unsigned long numItems; + unsigned long numBytes; + unsigned char* data; - if (!rootSupportingWindow || rootSupportingWindow->length != 1) + int result = XGetWindowProperty(display, + DefaultRootWindow(display), + netSupportingWmCheck, + 0, + 1, + False, + XA_WINDOW, + &actualType, + &actualFormat, + &numItems, + &numBytes, + &data); + + if (result != Success || actualType != XA_WINDOW || numItems != 1) { - sf::priv::CloseConnection(connection); + if(result == Success) + XFree(data); + + sf::priv::CloseDisplay(display); return false; } - xcb_window_t* rootWindow = reinterpret_cast(xcb_get_property_value(rootSupportingWindow.get())); + ::Window rootWindow = *reinterpret_cast< ::Window* >(data); + + XFree(data); if (!rootWindow) { - sf::priv::CloseConnection(connection); + sf::priv::CloseDisplay(display); return false; } - sf::priv::ScopedXcbPtr childSupportingWindow(xcb_get_property_reply( - connection, - xcb_get_property( - connection, - 0, - *rootWindow, - netSupportingWmCheck, - XCB_ATOM_WINDOW, - 0, - 1 - ), - &error - )); + result = XGetWindowProperty(display, + rootWindow, + netSupportingWmCheck, + 0, + 1, + False, + XA_WINDOW, + &actualType, + &actualFormat, + &numItems, + &numBytes, + &data); - if (!childSupportingWindow || childSupportingWindow->length != 1) + if (result != Success || actualType != XA_WINDOW || numItems != 1) { - sf::priv::CloseConnection(connection); + if(result == Success) + XFree(data); + + sf::priv::CloseDisplay(display); return false; } - xcb_window_t* childWindow = reinterpret_cast(xcb_get_property_value(childSupportingWindow.get())); + ::Window childWindow = *reinterpret_cast< ::Window* >(data); + + XFree(data); if (!childWindow) { - sf::priv::CloseConnection(connection); + sf::priv::CloseDisplay(display); return false; } // Conforming window managers should return the same window for both queries - if (*rootWindow != *childWindow) + if (rootWindow != childWindow) { - sf::priv::CloseConnection(connection); + sf::priv::CloseDisplay(display); return false; } @@ -204,45 +217,51 @@ namespace // We try to get the name of the window manager // for window manager specific workarounds - xcb_atom_t netWmName = sf::priv::getAtom("_NET_WM_NAME", true); - xcb_atom_t utf8StringType = sf::priv::getAtom("UTF8_STRING"); - - if (!utf8StringType) - utf8StringType = XCB_ATOM_STRING; + Atom netWmName = sf::priv::getAtom("_NET_WM_NAME", true); if (!netWmName) { - sf::priv::CloseConnection(connection); + sf::priv::CloseDisplay(display); return true; } - sf::priv::ScopedXcbPtr wmName(xcb_get_property_reply( - connection, - xcb_get_property( - connection, - 0, - *childWindow, - netWmName, - utf8StringType, - 0, - 0x7fffffff - ), - &error - )); + Atom utf8StringType = sf::priv::getAtom("UTF8_STRING"); - sf::priv::CloseConnection(connection); + if (!utf8StringType) + utf8StringType = XA_STRING; - // It seems the wm name string reply is not necessarily - // null-terminated. The work around is to get its actual - // length to build a proper string - const char* begin = reinterpret_cast(xcb_get_property_value(wmName.get())); - const char* end = begin + xcb_get_property_value_length(wmName.get()); - windowManagerName = sf::String::fromUtf8(begin, end); + result = XGetWindowProperty(display, + rootWindow, + netWmName, + 0, + 0x7fffffff, + False, + utf8StringType, + &actualType, + &actualFormat, + &numItems, + &numBytes, + &data); + + if (actualType && numItems) + { + // It seems the wm name string reply is not necessarily + // null-terminated. The work around is to get its actual + // length to build a proper string + const char* begin = reinterpret_cast(data); + const char* end = begin + numItems; + windowManagerName = sf::String::fromUtf8(begin, end); + } + + if(result == Success) + XFree(data); + + sf::priv::CloseDisplay(display); return true; } - sf::Keyboard::Key keysymToSF(xcb_keysym_t symbol) + sf::Keyboard::Key keysymToSF(KeySym symbol) { switch (symbol) { @@ -362,10 +381,11 @@ namespace priv //////////////////////////////////////////////////////////// WindowImplX11::WindowImplX11(WindowHandle handle) : m_window (0), -m_screen (NULL), +m_screen (0), m_inputMethod (NULL), m_inputContext (NULL), m_isExternal (true), +m_oldVideoMode (0), m_hiddenCursor (0), m_keyRepeat (true), m_previousSize (-1, -1), @@ -374,24 +394,16 @@ m_fullscreen (false), m_cursorGrabbed (false), m_windowMapped (false), m_iconPixmap (0), -m_iconMaskPixmap (0) +m_iconMaskPixmap (0), +m_lastInputTime (0) { // Open a connection with the X server m_display = OpenDisplay(); - m_connection = XGetXCBConnection(m_display); - - std::memset(&m_oldVideoMode, 0, sizeof(m_oldVideoMode)); - - if (!m_connection) - { - err() << "Failed cast Display object to an XCB connection object" << std::endl; - return; - } // Make sure to check for EWMH support before we do anything ewmhSupported(); - m_screen = XCBDefaultScreen(m_connection); + m_screen = DefaultScreen(m_display); // Save the window handle m_window = handle; @@ -399,14 +411,10 @@ m_iconMaskPixmap (0) if (m_window) { // Make sure the window is listening to all the required events - const uint32_t value_list[] = {static_cast(eventMask)}; + XSetWindowAttributes attributes; + attributes.event_mask = eventMask; - xcb_change_window_attributes( - m_connection, - m_window, - XCB_CW_EVENT_MASK, - value_list - ); + XChangeWindowAttributes(m_display, m_window, CWEventMask, &attributes); // Set the WM protocols setProtocols(); @@ -420,10 +428,11 @@ m_iconMaskPixmap (0) //////////////////////////////////////////////////////////// WindowImplX11::WindowImplX11(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings) : m_window (0), -m_screen (NULL), +m_screen (0), m_inputMethod (NULL), m_inputContext (NULL), m_isExternal (false), +m_oldVideoMode (0), m_hiddenCursor (0), m_keyRepeat (true), m_previousSize (-1, -1), @@ -432,28 +441,20 @@ m_fullscreen ((style & Style::Fullscreen) != 0), m_cursorGrabbed (m_fullscreen), m_windowMapped (false), m_iconPixmap (0), -m_iconMaskPixmap (0) +m_iconMaskPixmap (0), +m_lastInputTime (0) { // Open a connection with the X server m_display = OpenDisplay(); - m_connection = XGetXCBConnection(m_display); - - std::memset(&m_oldVideoMode, 0, sizeof(m_oldVideoMode)); - - if (!m_connection) - { - err() << "Failed cast Display object to an XCB connection object" << std::endl; - return; - } // Make sure to check for EWMH support before we do anything ewmhSupported(); - m_screen = XCBDefaultScreen(m_connection); + m_screen = DefaultScreen(m_display); // Compute position and size - int left = m_fullscreen ? 0 : (m_screen->width_in_pixels - mode.width) / 2; - int top = m_fullscreen ? 0 : (m_screen->height_in_pixels - mode.height) / 2; + int left = m_fullscreen ? 0 : (DisplayWidth(m_display, m_screen) - mode.width) / 2; + int top = m_fullscreen ? 0 : (DisplayHeight(m_display, m_screen) - mode.height) / 2; int width = mode.width; int height = mode.height; @@ -461,31 +462,23 @@ m_iconMaskPixmap (0) XVisualInfo visualInfo = ContextType::selectBestVisual(m_display, mode.bitsPerPixel, settings); // Define the window attributes - xcb_colormap_t colormap = xcb_generate_id(m_connection); - xcb_create_colormap(m_connection, XCB_COLORMAP_ALLOC_NONE, colormap, m_screen->root, visualInfo.visualid); - const uint32_t value_list[] = {m_fullscreen && !ewmhSupported(), static_cast(eventMask), colormap}; + XSetWindowAttributes attributes; + attributes.colormap = XCreateColormap(m_display, DefaultRootWindow(m_display), visualInfo.visual, AllocNone); + attributes.event_mask = eventMask; + attributes.override_redirect = (m_fullscreen && !ewmhSupported()) ? True : False; - // Create the window - m_window = xcb_generate_id(m_connection); + m_window = XCreateWindow(m_display, + DefaultRootWindow(m_display), + left, top, + width, height, + 0, + visualInfo.depth, + InputOutput, + visualInfo.visual, + CWEventMask | CWOverrideRedirect | CWColormap, + &attributes); - ScopedXcbPtr errptr(xcb_request_check( - m_connection, - xcb_create_window_checked( - m_connection, - static_cast(visualInfo.depth), - m_window, - m_screen->root, - left, top, - width, height, - 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - visualInfo.visualid, - XCB_CW_EVENT_MASK | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_COLORMAP, - value_list - ) - )); - - if (errptr) + if (!m_window) { err() << "Failed to create window" << std::endl; return; @@ -495,54 +488,113 @@ m_iconMaskPixmap (0) setProtocols(); // Set the WM initial state to the normal state - WMHints hints; - std::memset(&hints, 0, sizeof(hints)); - hints.initial_state = 1; - hints.flags |= 1 << 1; - setWMHints(hints); + XWMHints* hints = XAllocWMHints(); + hints->flags = StateHint; + hints->initial_state = NormalState; + XSetWMHints(m_display, m_window, hints); + XFree(hints); // If not in fullscreen, set the window's style (tell the window manager to // change our window's decorations and functions according to the requested style) if (!m_fullscreen) - setMotifHints(style); - - WMSizeHints sizeHints; - std::memset(&sizeHints, 0, sizeof(sizeHints)); - - // This is a hack to force some windows managers to disable resizing - // Fullscreen is bugged on Openbox. Unless size hints are set, there - // will be a region of the window that is off-screen. We try to workaround - // this by setting size hints even in fullscreen just for Openbox. - if ((!m_fullscreen || (windowManagerName == "Openbox")) && !(style & Style::Resize)) { - m_useSizeHints = true; - sizeHints.flags |= ((1 << 4) | (1 << 5)); - sizeHints.min_width = width; - sizeHints.max_width = width; - sizeHints.min_height = height; - sizeHints.max_height = height; + Atom WMHintsAtom = getAtom("_MOTIF_WM_HINTS", false); + if (WMHintsAtom) + { + static const unsigned long MWM_HINTS_FUNCTIONS = 1 << 0; + static const unsigned long MWM_HINTS_DECORATIONS = 1 << 1; + + //static const unsigned long MWM_DECOR_ALL = 1 << 0; + static const unsigned long MWM_DECOR_BORDER = 1 << 1; + static const unsigned long MWM_DECOR_RESIZEH = 1 << 2; + static const unsigned long MWM_DECOR_TITLE = 1 << 3; + static const unsigned long MWM_DECOR_MENU = 1 << 4; + static const unsigned long MWM_DECOR_MINIMIZE = 1 << 5; + static const unsigned long MWM_DECOR_MAXIMIZE = 1 << 6; + + //static const unsigned long MWM_FUNC_ALL = 1 << 0; + static const unsigned long MWM_FUNC_RESIZE = 1 << 1; + static const unsigned long MWM_FUNC_MOVE = 1 << 2; + static const unsigned long MWM_FUNC_MINIMIZE = 1 << 3; + static const unsigned long MWM_FUNC_MAXIMIZE = 1 << 4; + static const unsigned long MWM_FUNC_CLOSE = 1 << 5; + + struct WMHints + { + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long inputMode; + unsigned long state; + }; + + WMHints hints; + std::memset(&hints, 0, sizeof(hints)); + hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; + hints.decorations = 0; + hints.functions = 0; + + if (style & Style::Titlebar) + { + hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU; + hints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE; + } + if (style & Style::Resize) + { + hints.decorations |= MWM_DECOR_MAXIMIZE | MWM_DECOR_RESIZEH; + hints.functions |= MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE; + } + if (style & Style::Close) + { + hints.decorations |= 0; + hints.functions |= MWM_FUNC_CLOSE; + } + + XChangeProperty(m_display, + m_window, + WMHintsAtom, + WMHintsAtom, + 32, + PropModeReplace, + reinterpret_cast(&hints), + 5); + } } - // Set the WM hints of the normal state - setWMSizeHints(sizeHints); + // This is a hack to force some windows managers to disable resizing + if (!(style & Style::Resize)) + { + m_useSizeHints = true; + XSizeHints* sizeHints = XAllocSizeHints(); + sizeHints->flags = PMinSize | PMaxSize; + sizeHints->min_width = sizeHints->max_width = width; + sizeHints->min_height = sizeHints->max_height = height; + XSetWMNormalHints(m_display, m_window, sizeHints); + XFree(sizeHints); + } // Set the window's WM class (this can be used by window managers) - // The WM_CLASS property actually consists of 2 parts, - // the instance name and the class name both of which should be - // null terminated strings. - // The instance name should be something unique to this invokation + XClassHint* hint = XAllocClassHint(); + + // The instance name should be something unique to this invocation // of the application but is rarely if ever used these days. // For simplicity, we retrieve it via the base executable name. + std::string executableName = findExecutableName(); + std::vector windowInstance(executableName.size() + 1, 0); + std::copy(executableName.begin(), executableName.end(), windowInstance.begin()); + hint->res_name = &windowInstance[0]; + // The class name identifies a class of windows that // "are of the same type". We simply use the initial window name as // the class name. - std::string windowClass = findExecutableName(); - windowClass += '\0'; // Important to separate instance from class - windowClass += title.toAnsiString(); + std::string ansiTitle = title.toAnsiString(); + std::vector windowClass(ansiTitle.size() + 1, 0); + std::copy(ansiTitle.begin(), ansiTitle.end(), windowClass.begin()); + hint->res_class = &windowClass[0]; - // We add 1 to the size of the string to include the null at the end - if (!changeWindowProperty(XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, windowClass.size() + 1, windowClass.c_str())) - sf::err() << "Failed to set WM_CLASS property" << std::endl; + XSetClassHint(m_display, m_window, hint); + + XFree(hint); // Set the window's name setTitle(title); @@ -567,53 +619,26 @@ WindowImplX11::~WindowImplX11() cleanup(); // Destroy icon pixmap - if (m_iconPixmap) - { - ScopedXcbPtr freePixmapError(xcb_request_check( - m_connection, - xcb_free_pixmap_checked( - m_connection, - m_iconPixmap - ) - )); - - if (freePixmapError) - { - err() << "Failed to free icon pixmap: "; - err() << "Error code " << static_cast(freePixmapError->error_code) << std::endl; - } - } + if(m_iconPixmap) + XFreePixmap(m_display, m_iconPixmap); // Destroy icon mask pixmap - if (m_iconMaskPixmap) - { - ScopedXcbPtr freePixmapMaskError(xcb_request_check( - m_connection, - xcb_free_pixmap_checked( - m_connection, - m_iconMaskPixmap - ) - )); - - if (freePixmapMaskError) - { - err() << "Failed to free icon mask pixmap: "; - err() << "Error code " << static_cast(freePixmapMaskError->error_code) << std::endl; - } - } + if(m_iconMaskPixmap) + XFreePixmap(m_display, m_iconMaskPixmap); // Destroy the cursor if (m_hiddenCursor) - xcb_free_cursor(m_connection, m_hiddenCursor); + XFreeCursor(m_display, m_hiddenCursor); // Destroy the input context if (m_inputContext) XDestroyIC(m_inputContext); + // Destroy the window if (m_window && !m_isExternal) { - xcb_destroy_window(m_connection, m_window); - xcb_flush(m_connection); + XDestroyWindow(m_display, m_window); + XFlush(m_display); } // Close the input method @@ -650,70 +675,31 @@ void WindowImplX11::processEvents() //////////////////////////////////////////////////////////// Vector2i WindowImplX11::getPosition() const { - ::Window topLevelWindow = m_window; - ::Window nextWindow = topLevelWindow; + ::Window root, child; + int localX, localY, x, y; + unsigned int width, height, border, depth; - ScopedXcbPtr error(NULL); + XGetGeometry(m_display, m_window, &root, &localX, &localY, &width, &height, &border, &depth); + XTranslateCoordinates(m_display, m_window, root, localX, localY, &x, &y, &child); - // Get "top level" window, i.e. the window with the root window as its parent. - while (nextWindow != m_screen->root) - { - topLevelWindow = nextWindow; - - ScopedXcbPtr treeReply(xcb_query_tree_reply( - m_connection, - xcb_query_tree( - m_connection, - topLevelWindow - ), - &error - )); - - if (error) - { - err() << "Failed to get window position (query_tree)" << std::endl; - return Vector2i(0, 0); - } - - nextWindow = treeReply->parent; - } - - ScopedXcbPtr geometryReply(xcb_get_geometry_reply( - m_connection, - xcb_get_geometry( - m_connection, - topLevelWindow - ), - &error - )); - - if (error) - { - err() << "Failed to get window position (get_geometry)" << std::endl; - return Vector2i(0, 0); - } - - return Vector2i(geometryReply->x, geometryReply->y); + return Vector2i(x, y); } //////////////////////////////////////////////////////////// void WindowImplX11::setPosition(const Vector2i& position) { - uint32_t values[] = {static_cast(position.x), static_cast(position.y)}; - xcb_configure_window(m_connection, m_window, - XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, - values); - xcb_flush(m_connection); + XMoveWindow(m_display, m_window, position.x, position.y); + XFlush(m_display); } //////////////////////////////////////////////////////////// Vector2u WindowImplX11::getSize() const { - ScopedXcbPtr reply(xcb_get_geometry_reply(m_connection, xcb_get_geometry(m_connection, m_window), NULL)); - - return Vector2u(reply->width, reply->height); + XWindowAttributes attributes; + XGetWindowAttributes(m_display, m_window, &attributes); + return Vector2u(attributes.width, attributes.height); } @@ -721,84 +707,74 @@ Vector2u WindowImplX11::getSize() const void WindowImplX11::setSize(const Vector2u& size) { // If resizing is disable for the window we have to update the size hints (required by some window managers). - if( m_useSizeHints ) { - WMSizeHints sizeHints; - std::memset(&sizeHints, 0, sizeof(sizeHints)); - - sizeHints.flags |= (1 << 4 | 1 << 5); - sizeHints.min_width = size.x; - sizeHints.max_width = size.x; - sizeHints.min_height = size.y; - sizeHints.max_height = size.y; - - setWMSizeHints(sizeHints); + if (m_useSizeHints) + { + XSizeHints* sizeHints = XAllocSizeHints(); + sizeHints->flags = PMinSize | PMaxSize; + sizeHints->min_width = sizeHints->max_width = size.x; + sizeHints->min_height = sizeHints->max_height = size.y; + XSetWMNormalHints(m_display, m_window, sizeHints); + XFree(sizeHints); } - uint32_t values[] = {size.x, size.y}; - - ScopedXcbPtr configureWindowError(xcb_request_check( - m_connection, - xcb_configure_window( - m_connection, - m_window, - XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, - values - ) - )); - - if (configureWindowError) - err() << "Failed to set window size" << std::endl; - - xcb_flush(m_connection); + XResizeWindow(m_display, m_window, size.x, size.y); + XFlush(m_display); } //////////////////////////////////////////////////////////// void WindowImplX11::setTitle(const String& title) { - // XCB takes UTF-8-encoded strings. - xcb_atom_t utf8StringType = getAtom("UTF8_STRING"); + // Bare X11 has no Unicode window title support. + // There is however an option to tell the window manager your Unicode title via hints. - if (!utf8StringType) - utf8StringType = XCB_ATOM_STRING; + // Convert to UTF-8 encoding. + std::basic_string utf8Title; + Utf32::toUtf8(title.begin(), title.end(), std::back_inserter(utf8Title)); - std::string utf8String; - Utf<32>::toUtf8(title.begin(), title.end(), std::back_inserter(utf8String)); + Atom useUtf8 = getAtom("UTF8_STRING", false); - if (!changeWindowProperty(XCB_ATOM_WM_NAME, utf8StringType, 8, utf8String.length(), utf8String.c_str())) - err() << "Failed to set window title" << std::endl; + // Set the _NET_WM_NAME atom, which specifies a UTF-8 encoded window title. + Atom wmName = getAtom("_NET_WM_NAME", false); + XChangeProperty(m_display, m_window, wmName, useUtf8, 8, + PropModeReplace, utf8Title.c_str(), utf8Title.size()); - if (!changeWindowProperty(XCB_ATOM_WM_ICON_NAME, utf8StringType, 8, utf8String.length(), utf8String.c_str())) - err() << "Failed to set WM_ICON_NAME property" << std::endl; + // Set the _NET_WM_ICON_NAME atom, which specifies a UTF-8 encoded window title. + Atom wmIconName = getAtom("_NET_WM_ICON_NAME", false); + XChangeProperty(m_display, m_window, wmIconName, useUtf8, 8, + PropModeReplace, utf8Title.c_str(), utf8Title.size()); - if (ewmhSupported()) - { - xcb_atom_t netWmName = getAtom("_NET_WM_NAME", true); - xcb_atom_t netWmIconName = getAtom("_NET_WM_ICON_NAME", true); - - if (utf8StringType && netWmName) - { - if (!changeWindowProperty(netWmName, utf8StringType, 8, utf8String.length(), utf8String.c_str())) - err() << "Failed to set _NET_WM_NAME property" << std::endl; - } - - if (utf8StringType && netWmIconName) - { - if (!changeWindowProperty(netWmIconName, utf8StringType, 8, utf8String.length(), utf8String.c_str())) - err() << "Failed to set _NET_WM_ICON_NAME property" << std::endl; - } - } - - xcb_flush(m_connection); + // Set the non-Unicode title as a fallback for window managers who don't support _NET_WM_NAME. + #ifdef X_HAVE_UTF8_STRING + Xutf8SetWMProperties(m_display, + m_window, + title.toAnsiString().c_str(), + title.toAnsiString().c_str(), + NULL, + 0, + NULL, + NULL, + NULL); + #else + XmbSetWMProperties(m_display, + m_window, + title.toAnsiString().c_str(), + title.toAnsiString().c_str(), + NULL, + 0, + NULL, + NULL, + NULL); + #endif } //////////////////////////////////////////////////////////// void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8* pixels) { - // X11 and ICCCM want BGRA pixels: swap red and blue channels - // ICCCM also wants the first 2 unsigned 32-bit values to be width and height - Uint8 iconPixels[8 + width * height * 4]; + // X11 wants BGRA pixels: swap red and blue channels + // Note: this memory will be freed by XDestroyImage + Uint8* iconPixels = static_cast(std::malloc(width * height * 4)); for (std::size_t i = 0; i < width * height; ++i) { iconPixels[8 + i * 4 + 0] = pixels[i * 4 + 2]; @@ -807,69 +783,29 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8 iconPixels[8 + i * 4 + 3] = pixels[i * 4 + 3]; } - reinterpret_cast(iconPixels)[0] = width; - reinterpret_cast(iconPixels)[1] = height; - - if (m_iconPixmap) - { - ScopedXcbPtr freePixmapError(xcb_request_check( - m_connection, - xcb_free_pixmap_checked( - m_connection, - m_iconPixmap - ) - )); - - if (freePixmapError) - { - err() << "Failed to free icon pixmap: "; - err() << "Error code " << static_cast(freePixmapError->error_code) << std::endl; - } - - m_iconPixmap = 0; - } - - if (m_iconMaskPixmap) - { - ScopedXcbPtr freePixmapMaskError(xcb_request_check( - m_connection, - xcb_free_pixmap_checked( - m_connection, - m_iconMaskPixmap - ) - )); - - if (freePixmapMaskError) - { - err() << "Failed to free icon mask pixmap: "; - err() << "Error code " << static_cast(freePixmapMaskError->error_code) << std::endl; - } - - m_iconMaskPixmap = 0; - } - // Create the icon pixmap - m_iconPixmap = xcb_generate_id(m_connection); - - ScopedXcbPtr createPixmapError(xcb_request_check( - m_connection, - xcb_create_pixmap_checked( - m_connection, - m_screen->root_depth, - m_iconPixmap, - m_screen->root, - width, - height - ) - )); - - if (createPixmapError) + Visual* defVisual = DefaultVisual(m_display, m_screen); + unsigned int defDepth = DefaultDepth(m_display, m_screen); + XImage* iconImage = XCreateImage(m_display, defVisual, defDepth, ZPixmap, 0, (char*)iconPixels, width, height, 32, 0); + if (!iconImage) { - err() << "Failed to set the window's icon (create_pixmap): "; - err() << "Error code " << static_cast(createPixmapError->error_code) << std::endl; + err() << "Failed to set the window's icon" << std::endl; return; } + if(m_iconPixmap) + XFreePixmap(m_display, m_iconPixmap); + + if(m_iconMaskPixmap) + XFreePixmap(m_display, m_iconMaskPixmap); + + m_iconPixmap = XCreatePixmap(m_display, RootWindow(m_display, m_screen), width, height, defDepth); + XGCValues values; + GC iconGC = XCreateGC(m_display, m_iconPixmap, 0, &values); + XPutImage(m_display, m_iconPixmap, iconGC, iconImage, 0, 0, 0, 0, width, height); + XFreeGC(m_display, iconGC); + XDestroyImage(iconImage); + // Create the mask pixmap (must have 1 bit depth) std::size_t pitch = (width + 7) / 8; std::vector maskPixels(pitch * height, 0); @@ -887,99 +823,42 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8 } } } - - m_iconMaskPixmap = xcb_create_pixmap_from_bitmap_data( - m_connection, - m_window, - reinterpret_cast(&maskPixels[0]), - width, - height, - 1, - 0, - 1, - NULL - ); - - if (!m_iconMaskPixmap) - { - err() << "Failed to set the window's icon (create_pixmap_from_bitmap_data)" << std::endl; - return; - } - - xcb_gcontext_t iconGC = xcb_generate_id(m_connection); - - ScopedXcbPtr createGcError(xcb_request_check( - m_connection, - xcb_create_gc( - m_connection, - iconGC, - m_iconPixmap, - 0, - NULL - ) - )); - - if (createGcError) - { - err() << "Failed to set the window's icon (create_gc): "; - err() << "Error code " << static_cast(createGcError->error_code) << std::endl; - return; - } - - ScopedXcbPtr putImageError(xcb_request_check( - m_connection, - xcb_put_image_checked( - m_connection, - XCB_IMAGE_FORMAT_Z_PIXMAP, - m_iconPixmap, - iconGC, - width, - height, - 0, - 0, - 0, - m_screen->root_depth, - width * height * 4, - iconPixels + 8 - ) - )); - - ScopedXcbPtr freeGcError(xcb_request_check( - m_connection, - xcb_free_gc( - m_connection, - iconGC - ) - )); - - if (freeGcError) - { - err() << "Failed to free icon GC: "; - err() << "Error code " << static_cast(freeGcError->error_code) << std::endl; - } - - if (putImageError) - { - err() << "Failed to set the window's icon (put_image): "; - err() << "Error code " << static_cast(putImageError->error_code) << std::endl; - return; - } + m_iconMaskPixmap = XCreatePixmapFromBitmapData(m_display, m_window, (char*)&maskPixels[0], width, height, 1, 0, 1); // Send our new icon to the window through the WMHints - WMHints hints; - std::memset(&hints, 0, sizeof(hints)); - hints.flags |= ((1 << 2) | (1 << 5)); - hints.icon_pixmap = m_iconPixmap; - hints.icon_mask = m_iconMaskPixmap; + XWMHints* hints = XAllocWMHints(); + hints->flags = IconPixmapHint | IconMaskHint; + hints->icon_pixmap = m_iconPixmap; + hints->icon_mask = m_iconMaskPixmap; + XSetWMHints(m_display, m_window, hints); + XFree(hints); - setWMHints(hints); + // ICCCM wants BGRA pixels: swap red and blue channels + // ICCCM also wants the first 2 unsigned 32-bit values to be width and height + std::vector icccmIconPixels(8 + width * height * 4, 0); + for (std::size_t i = 0; i < width * height; ++i) + { + icccmIconPixels[8 + i * 4 + 0] = pixels[i * 4 + 2]; + icccmIconPixels[8 + i * 4 + 1] = pixels[i * 4 + 1]; + icccmIconPixels[8 + i * 4 + 2] = pixels[i * 4 + 0]; + icccmIconPixels[8 + i * 4 + 3] = pixels[i * 4 + 3]; + } - xcb_atom_t netWmIcon = getAtom("_NET_WM_ICON"); + reinterpret_cast(&icccmIconPixels[0])[0] = width; + reinterpret_cast(&icccmIconPixels[0])[1] = height; - if (!changeWindowProperty(netWmIcon, XCB_ATOM_CARDINAL, 32, 2 + width * height, iconPixels)) - err() << "Failed to set the window's icon (changeWindowProperty)" << std::endl; + Atom netWmIcon = getAtom("_NET_WM_ICON"); - xcb_flush(m_connection); + XChangeProperty(m_display, + m_window, + netWmIcon, + XA_CARDINAL, + 32, + PropModeReplace, + reinterpret_cast(&icccmIconPixels[0]), + 2 + width * height); + + XFlush(m_display); } @@ -988,18 +867,9 @@ void WindowImplX11::setVisible(bool visible) { if (visible) { - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_map_window( - m_connection, - m_window - ) - )); + XMapWindow(m_display, m_window); - if (error) - err() << "Failed to change window visibility" << std::endl; - - xcb_flush(m_connection); + XFlush(m_display); // Before continuing, make sure the WM has // internally marked the window as viewable @@ -1008,18 +878,9 @@ void WindowImplX11::setVisible(bool visible) } else { - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_unmap_window( - m_connection, - m_window - ) - )); + XUnmapWindow(m_display, m_window); - if (error) - err() << "Failed to change window visibility" << std::endl; - - xcb_flush(m_connection); + XFlush(m_display); // Before continuing, make sure the WM has // internally marked the window as unviewable @@ -1032,22 +893,8 @@ void WindowImplX11::setVisible(bool visible) //////////////////////////////////////////////////////////// void WindowImplX11::setMouseCursorVisible(bool visible) { - const uint32_t values = visible ? XCB_NONE : m_hiddenCursor; - - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_change_window_attributes( - m_connection, - m_window, - XCB_CW_CURSOR, - &values - ) - )); - - if (error) - err() << "Failed to change mouse cursor visibility" << std::endl; - - xcb_flush(m_connection); + XDefineCursor(m_display, m_window, visible ? None : m_hiddenCursor); + XFlush(m_display); } @@ -1063,25 +910,9 @@ void WindowImplX11::setMouseCursorGrabbed(bool grabbed) // Try multiple times to grab the cursor for (unsigned int trial = 0; trial < maxTrialsCount; ++trial) { - sf::priv::ScopedXcbPtr error(NULL); + int result = XGrabPointer(m_display, m_window, True, None, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime); - sf::priv::ScopedXcbPtr grabPointerReply(xcb_grab_pointer_reply( - m_connection, - xcb_grab_pointer( - m_connection, - true, - m_window, - XCB_NONE, - XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC, - m_window, - XCB_NONE, - XCB_CURRENT_TIME - ), - &error - )); - - if (!error && grabPointerReply && (grabPointerReply->status == XCB_GRAB_STATUS_SUCCESS)) + if (result == GrabSuccess) { m_cursorGrabbed = true; break; @@ -1096,22 +927,7 @@ void WindowImplX11::setMouseCursorGrabbed(bool grabbed) } else { - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_ungrab_pointer_checked( - m_connection, - XCB_CURRENT_TIME - ) - )); - - if (!error) - { - m_cursorGrabbed = false; - } - else - { - err() << "Failed to ungrab mouse cursor" << std::endl; - } + XUngrabPointer(m_display, CurrentTime); } } @@ -1143,26 +959,16 @@ void WindowImplX11::requestFocus() } } - ScopedXcbPtr error(NULL); - // Check if window is viewable (not on other desktop, ...) // TODO: Check also if minimized - ScopedXcbPtr attributes(xcb_get_window_attributes_reply( - m_connection, - xcb_get_window_attributes( - m_connection, - m_window - ), - &error - )); - - if (error || !attributes) + XWindowAttributes attributes; + if (XGetWindowAttributes(m_display, m_window, &attributes) == 0) { - 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; return; // error getting attribute } - bool windowViewable = (attributes->map_state == XCB_MAP_STATE_VIEWABLE); + bool windowViewable = (attributes.map_state == IsViewable); if (sfmlWindowFocused && windowViewable) { @@ -1172,31 +978,16 @@ void WindowImplX11::requestFocus() } else { - // Get current WM hints. - ScopedXcbPtr hintsReply(xcb_get_property_reply( - m_connection, - xcb_get_property(m_connection, 0, m_window, XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 0, 9), - &error - )); + // Otherwise: display urgency hint (flashing application logo) + // Ensure WM hints exist, allocate if necessary + XWMHints* hints = XGetWMHints(m_display, m_window); + if (hints == NULL) + hints = XAllocWMHints(); - if (error || !hintsReply) - { - err() << "Failed to get WM hints while requesting focus" << std::endl; - return; - } - - WMHints* hints = reinterpret_cast(xcb_get_property_value(hintsReply.get())); - - if (!hints) - { - err() << "Failed to get WM hints while requesting focus" << std::endl; - return; - } - - // 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. - hints->flags |= (1 << 8); - setWMHints(*hints); + // Add urgency (notification) flag to hints + hints->flags |= XUrgencyHint; + XSetWMHints(m_display, m_window, hints); + XFree(hints); } } @@ -1204,91 +995,59 @@ void WindowImplX11::requestFocus() //////////////////////////////////////////////////////////// bool WindowImplX11::hasFocus() const { - ScopedXcbPtr error(NULL); + ::Window focusedWindow = 0; + int revertToReturn = 0; + XGetInputFocus(m_display, &focusedWindow, &revertToReturn); - ScopedXcbPtr reply(xcb_get_input_focus_reply( - m_connection, - xcb_get_input_focus_unchecked( - m_connection - ), - &error - )); - - if (error) - err() << "Failed to check if window has focus" << std::endl; - - return (reply->focus == m_window); + return (m_window == focusedWindow); } //////////////////////////////////////////////////////////// void WindowImplX11::grabFocus() { - xcb_atom_t netActiveWindow = XCB_ATOM_NONE; + Atom netActiveWindow = None; if (ewmhSupported()) netActiveWindow = getAtom("_NET_ACTIVE_WINDOW"); + // Only try to grab focus if the window is mapped + XWindowAttributes attr; + + XGetWindowAttributes(m_display, m_window, &attr); + + if (attr.map_state == IsUnmapped) + return; + if (netActiveWindow) { - xcb_client_message_event_t event; + XEvent event; std::memset(&event, 0, sizeof(event)); - event.response_type = XCB_CLIENT_MESSAGE; - event.window = m_window; - event.format = 32; - event.sequence = 0; - event.type = netActiveWindow; - event.data.data32[0] = 1; // Normal application - event.data.data32[1] = XCB_CURRENT_TIME; - event.data.data32[2] = 0; // We don't know the currently active window + event.type = ClientMessage; + event.xclient.window = m_window; + event.xclient.format = 32; + event.xclient.message_type = netActiveWindow; + event.xclient.data.l[0] = 1; // Normal application + event.xclient.data.l[1] = m_lastInputTime; + event.xclient.data.l[2] = 0; // We don't know the currently active window - ScopedXcbPtr activeWindowError(xcb_request_check( - m_connection, - xcb_send_event_checked( - m_connection, - 0, - XCBDefaultRootWindow(m_connection), - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, - reinterpret_cast(&event) - ) - )); + int result = XSendEvent(m_display, + DefaultRootWindow(m_display), + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); - if (activeWindowError) + XFlush(m_display); + + if (!result) err() << "Setting fullscreen failed, could not send \"_NET_ACTIVE_WINDOW\" event" << std::endl; } else { - ScopedXcbPtr setInputFocusError(xcb_request_check( - m_connection, - xcb_set_input_focus( - m_connection, - XCB_INPUT_FOCUS_POINTER_ROOT, - m_window, - XCB_CURRENT_TIME - ) - )); - - if (setInputFocusError) - { - err() << "Failed to change active window (set_input_focus)" << std::endl; - return; - } - - const uint32_t values[] = {XCB_STACK_MODE_ABOVE}; - - ScopedXcbPtr configureWindowError(xcb_request_check( - m_connection, - xcb_configure_window( - m_connection, - m_window, - XCB_CONFIG_WINDOW_STACK_MODE, - values - ) - )); - - if (configureWindowError) - err() << "Failed to change active window (configure_window)" << std::endl; + XRaiseWindow(m_display, m_window); + XSetInputFocus(m_display, m_window, RevertToPointerRoot, CurrentTime); + XFlush(m_display); } } @@ -1300,46 +1059,19 @@ void WindowImplX11::setVideoMode(const VideoMode& mode) if (mode == VideoMode::getDesktopMode()) return; - ScopedXcbPtr error(NULL); - - // Check if the RandR extension is present - const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(m_connection, &xcb_randr_id); - - if (!randrExt || !randrExt->present) + // Check if the XRandR extension is present + int version; + if (!XQueryExtension(m_display, "RANDR", &version, &version, &version)) { - // RandR 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; return; } - // Load RandR and check its version - ScopedXcbPtr randrVersion(xcb_randr_query_version_reply( - m_connection, - xcb_randr_query_version( - m_connection, - 1, - 1 - ), - &error - )); - - if (error) - { - err() << "Failed to load RandR, switching to window mode" << std::endl; - return; - } - // Get the current configuration - ScopedXcbPtr config(xcb_randr_get_screen_info_reply( - m_connection, - xcb_randr_get_screen_info( - m_connection, - m_screen->root - ), - &error - )); + XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen)); - if (error || !config) + if (!config) { // Failed to get the screen configuration err() << "Failed to get the current screen configuration for fullscreen mode, switching to window mode" << std::endl; @@ -1347,52 +1079,34 @@ void WindowImplX11::setVideoMode(const VideoMode& mode) } // Save the current video mode before we switch to fullscreen - m_oldVideoMode = *config.get(); + Rotation currentRotation; + m_oldVideoMode = XRRConfigCurrentConfiguration(config, ¤tRotation); // Get the available screen sizes - xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config.get()); - - if (!sizes || !config->nSizes) - { - err() << "Failed to get the fullscreen sizes, switching to window mode" << std::endl; - return; - } + int nbSizes; + XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes); // Search for a matching size - for (int i = 0; i < config->nSizes; ++i) + for (int i = 0; (sizes && i < nbSizes); ++i) { - if (config->rotation == XCB_RANDR_ROTATION_ROTATE_90 || - config->rotation == XCB_RANDR_ROTATION_ROTATE_270) + XRRConfigRotations(config, ¤tRotation); + + if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270) std::swap(sizes[i].height, sizes[i].width); - if ((sizes[i].width == static_cast(mode.width)) && - (sizes[i].height == static_cast(mode.height))) + if ((sizes[i].width == static_cast(mode.width)) && (sizes[i].height == static_cast(mode.height))) { // Switch to fullscreen mode - ScopedXcbPtr setScreenConfig(xcb_randr_set_screen_config_reply( - m_connection, - xcb_randr_set_screen_config( - m_connection, - config->root, - XCB_CURRENT_TIME, - config->config_timestamp, - i, - config->rotation, - config->rate - ), - &error - )); - - if (error) - err() << "Failed to set new screen configuration" << std::endl; + XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), i, currentRotation, CurrentTime); // Set "this" as the current fullscreen window fullscreenWindow = this; - return; + break; } } - err() << "Failed to find matching fullscreen size, switching to window mode" << std::endl; + // Free the configuration instance + XRRFreeScreenConfigInfo(config); } @@ -1402,25 +1116,19 @@ void WindowImplX11::resetVideoMode() if (fullscreenWindow == this) { // Get current screen info - ScopedXcbPtr error(NULL); + XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen)); + if (config) + { + // Get the current rotation + Rotation currentRotation; + XRRConfigCurrentConfiguration(config, ¤tRotation); - // Reset the video mode - ScopedXcbPtr setScreenConfig(xcb_randr_set_screen_config_reply( - m_connection, - xcb_randr_set_screen_config( - m_connection, - m_oldVideoMode.root, - XCB_CURRENT_TIME, - m_oldVideoMode.config_timestamp, - m_oldVideoMode.sizeID, - m_oldVideoMode.rotation, - m_oldVideoMode.rate - ), - &error - )); + // Reset the video mode + XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), m_oldVideoMode, currentRotation, CurrentTime); - if (error) - err() << "Failed to reset old screen configuration" << std::endl; + // Free the configuration instance + XRRFreeScreenConfigInfo(config); + } // Reset the fullscreen window fullscreenWindow = NULL; @@ -1435,19 +1143,24 @@ void WindowImplX11::switchToFullscreen() if (ewmhSupported()) { - xcb_atom_t netWmBypassCompositor = getAtom("_NET_WM_BYPASS_COMPOSITOR"); + Atom netWmBypassCompositor = getAtom("_NET_WM_BYPASS_COMPOSITOR"); if (netWmBypassCompositor) { static const Uint32 bypassCompositor = 1; - // Not being able to bypass the compositor is not a fatal error - if (!changeWindowProperty(netWmBypassCompositor, XCB_ATOM_CARDINAL, 32, 1, &bypassCompositor)) - err() << "xcb_change_property failed, unable to set _NET_WM_BYPASS_COMPOSITOR" << std::endl; + XChangeProperty(m_display, + m_window, + netWmBypassCompositor, + XA_CARDINAL, + 32, + PropModeReplace, + reinterpret_cast(&bypassCompositor), + 1); } - xcb_atom_t netWmState = getAtom("_NET_WM_STATE", true); - xcb_atom_t netWmStateFullscreen = getAtom("_NET_WM_STATE_FULLSCREEN", true); + Atom netWmState = getAtom("_NET_WM_STATE", true); + Atom netWmStateFullscreen = getAtom("_NET_WM_STATE_FULLSCREEN", true); if (!netWmState || !netWmStateFullscreen) { @@ -1455,32 +1168,26 @@ void WindowImplX11::switchToFullscreen() return; } - xcb_client_message_event_t event; + XEvent event; std::memset(&event, 0, sizeof(event)); - event.response_type = XCB_CLIENT_MESSAGE; - event.window = m_window; - event.format = 32; - event.sequence = 0; - event.type = netWmState; - event.data.data32[0] = 1; // _NET_WM_STATE_ADD - event.data.data32[1] = netWmStateFullscreen; - event.data.data32[2] = 0; // No second property - event.data.data32[3] = 1; // Normal window + event.type = ClientMessage; + event.xclient.window = m_window; + event.xclient.format = 32; + event.xclient.message_type = netWmState; + event.xclient.data.l[0] = 1; // _NET_WM_STATE_ADD + event.xclient.data.l[1] = netWmStateFullscreen; + event.xclient.data.l[2] = 0; // No second property + event.xclient.data.l[3] = 1; // Normal window - ScopedXcbPtr wmStateError(xcb_request_check( - m_connection, - xcb_send_event_checked( - m_connection, - 0, - XCBDefaultRootWindow(m_connection), - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, - reinterpret_cast(&event) - ) - )); + int result = XSendEvent(m_display, + DefaultRootWindow(m_display), + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); - if (wmStateError) - err() << "Setting fullscreen failed. Could not send \"_NET_WM_STATE\" event" << std::endl; + if (!result) + err() << "Setting fullscreen failed, could not send \"_NET_WM_STATE\" event" << std::endl; } } @@ -1488,8 +1195,8 @@ void WindowImplX11::switchToFullscreen() //////////////////////////////////////////////////////////// void WindowImplX11::setProtocols() { - xcb_atom_t wmProtocols = getAtom("WM_PROTOCOLS"); - xcb_atom_t wmDeleteWindow = getAtom("WM_DELETE_WINDOW"); + Atom wmProtocols = getAtom("WM_PROTOCOLS"); + Atom wmDeleteWindow = getAtom("WM_DELETE_WINDOW"); if (!wmProtocols) { @@ -1497,7 +1204,7 @@ void WindowImplX11::setProtocols() return; } - std::vector atoms; + std::vector atoms; if (wmDeleteWindow) { @@ -1508,8 +1215,8 @@ void WindowImplX11::setProtocols() err() << "Failed to request WM_DELETE_WINDOW atom." << std::endl; } - xcb_atom_t netWmPing = XCB_ATOM_NONE; - xcb_atom_t netWmPid = XCB_ATOM_NONE; + Atom netWmPing = None; + Atom netWmPid = None; if (ewmhSupported()) { @@ -1517,20 +1224,32 @@ void WindowImplX11::setProtocols() netWmPid = getAtom("_NET_WM_PID", true); } - ScopedXcbPtr error(NULL); - if (netWmPing && netWmPid) { uint32_t pid = getpid(); - if (changeWindowProperty(netWmPid, XCB_ATOM_CARDINAL, 32, 1, &pid)) - atoms.push_back(netWmPing); + XChangeProperty(m_display, + m_window, + netWmPid, + XA_CARDINAL, + 32, + PropModeReplace, + reinterpret_cast(&pid), + 1); + + atoms.push_back(netWmPing); } if (!atoms.empty()) { - if (!changeWindowProperty(wmProtocols, XCB_ATOM_ATOM, 32, atoms.size(), &atoms[0])) - err() << "Failed to set window protocols" << std::endl; + XChangeProperty(m_display, + m_window, + wmProtocols, + XA_ATOM, + 32, + PropModeReplace, + reinterpret_cast(&atoms[0]), + atoms.size()); } else { @@ -1539,122 +1258,6 @@ void WindowImplX11::setProtocols() } -//////////////////////////////////////////////////////////// -void WindowImplX11::setMotifHints(unsigned long style) -{ - ScopedXcbPtr error(NULL); - - static const std::string MOTIF_WM_HINTS = "_MOTIF_WM_HINTS"; - ScopedXcbPtr hintsAtomReply(xcb_intern_atom_reply( - m_connection, - xcb_intern_atom( - m_connection, - 0, - MOTIF_WM_HINTS.size(), - MOTIF_WM_HINTS.c_str() - ), - &error - )); - - if (!error && hintsAtomReply) - { - static const unsigned long MWM_HINTS_FUNCTIONS = 1 << 0; - static const unsigned long MWM_HINTS_DECORATIONS = 1 << 1; - - //static const unsigned long MWM_DECOR_ALL = 1 << 0; - static const unsigned long MWM_DECOR_BORDER = 1 << 1; - static const unsigned long MWM_DECOR_RESIZEH = 1 << 2; - static const unsigned long MWM_DECOR_TITLE = 1 << 3; - static const unsigned long MWM_DECOR_MENU = 1 << 4; - static const unsigned long MWM_DECOR_MINIMIZE = 1 << 5; - static const unsigned long MWM_DECOR_MAXIMIZE = 1 << 6; - - //static const unsigned long MWM_FUNC_ALL = 1 << 0; - static const unsigned long MWM_FUNC_RESIZE = 1 << 1; - static const unsigned long MWM_FUNC_MOVE = 1 << 2; - static const unsigned long MWM_FUNC_MINIMIZE = 1 << 3; - static const unsigned long MWM_FUNC_MAXIMIZE = 1 << 4; - static const unsigned long MWM_FUNC_CLOSE = 1 << 5; - - struct MotifWMHints - { - uint32_t flags; - uint32_t functions; - uint32_t decorations; - int32_t inputMode; - uint32_t state; - }; - - MotifWMHints hints; - hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; - hints.decorations = 0; - hints.functions = 0; - hints.inputMode = 0; - hints.state = 0; - - if (style & Style::Titlebar) - { - hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU; - hints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE; - } - if (style & Style::Resize) - { - hints.decorations |= MWM_DECOR_MAXIMIZE | MWM_DECOR_RESIZEH; - hints.functions |= MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE; - } - if (style & Style::Close) - { - hints.decorations |= 0; - hints.functions |= MWM_FUNC_CLOSE; - } - - if (!changeWindowProperty(hintsAtomReply->atom, hintsAtomReply->atom, 32, 5, &hints)) - err() << "xcb_change_property failed, could not set window hints" << std::endl; - } - else - { - err() << "Failed to request _MOTIF_WM_HINTS atom." << std::endl; - } -} - - -//////////////////////////////////////////////////////////// -void WindowImplX11::setWMHints(const WMHints& hints) -{ - if (!changeWindowProperty(XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 32, sizeof(hints) / 4, &hints)) - sf::err() << "Failed to set WM_HINTS property" << std::endl; -} - - -//////////////////////////////////////////////////////////// -void WindowImplX11::setWMSizeHints(const WMSizeHints& hints) -{ - if (!changeWindowProperty(XCB_ATOM_WM_NORMAL_HINTS, XCB_ATOM_WM_SIZE_HINTS, 32, sizeof(hints) / 4, &hints)) - sf::err() << "Failed to set XCB_ATOM_WM_NORMAL_HINTS property" << std::endl; -} - - -//////////////////////////////////////////////////////////// -bool WindowImplX11::changeWindowProperty(xcb_atom_t property, xcb_atom_t type, uint8_t format, uint32_t length, const void* data) -{ - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_change_property_checked( - m_connection, - XCB_PROP_MODE_REPLACE, - m_window, - property, - type, - format, - length, - data - ) - )); - - return !error; -} - - //////////////////////////////////////////////////////////// void WindowImplX11::initialize() { @@ -1663,16 +1266,14 @@ void WindowImplX11::initialize() if (m_inputMethod) { - m_inputContext = XCreateIC( - m_inputMethod, - XNClientWindow, - m_window, - XNFocusWindow, - m_window, - XNInputStyle, - XIMPreeditNothing | XIMStatusNothing, - reinterpret_cast(NULL) - ); + m_inputContext = XCreateIC(m_inputMethod, + XNClientWindow, + m_window, + XNFocusWindow, + m_window, + XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + reinterpret_cast(NULL)); } else { @@ -1682,6 +1283,21 @@ void WindowImplX11::initialize() if (!m_inputContext) err() << "Failed to create input context for window -- TextEntered event won't be able to return unicode" << std::endl; + Atom wmWindowType = getAtom("_NET_WM_WINDOW_TYPE", false); + Atom wmWindowTypeNormal = getAtom("_NET_WM_WINDOW_TYPE_NORMAL", false); + + if (wmWindowType && wmWindowTypeNormal) + { + XChangeProperty(m_display, + m_window, + wmWindowType, + XA_ATOM, + 32, + PropModeReplace, + reinterpret_cast(&wmWindowTypeNormal), + 1); + } + // Show the window setVisible(true); @@ -1692,7 +1308,7 @@ void WindowImplX11::initialize() createHiddenCursor(); // Flush the commands queue - xcb_flush(m_connection); + XFlush(m_display); // Add this window to the global list of windows (required for focus request) Lock lock(allWindowsMutex); @@ -1700,61 +1316,47 @@ void WindowImplX11::initialize() } +//////////////////////////////////////////////////////////// +void WindowImplX11::updateLastInputTime(::Time time) +{ + if (time && (time != m_lastInputTime)) + { + Atom netWmUserTime = getAtom("_NET_WM_USER_TIME", true); + + if(netWmUserTime) + { + XChangeProperty(m_display, + m_window, + netWmUserTime, + XA_CARDINAL, + 32, + PropModeReplace, + reinterpret_cast(&time), + 1); + } + + m_lastInputTime = time; + } +} + + //////////////////////////////////////////////////////////// void WindowImplX11::createHiddenCursor() { - xcb_pixmap_t cursorPixmap = xcb_generate_id(m_connection); - // Create the cursor's pixmap (1x1 pixels) - ScopedXcbPtr createPixmapError(xcb_request_check( - m_connection, - xcb_create_pixmap( - m_connection, - 1, - cursorPixmap, - m_window, - 1, - 1 - ) - )); - - if (createPixmapError) - { - err() << "Failed to create pixmap for hidden cursor" << std::endl; - return; - } - - m_hiddenCursor = xcb_generate_id(m_connection); + Pixmap cursorPixmap = XCreatePixmap(m_display, m_window, 1, 1, 1); + GC graphicsContext = XCreateGC(m_display, cursorPixmap, 0, NULL); + XDrawPoint(m_display, cursorPixmap, graphicsContext, 0, 0); + XFreeGC(m_display, graphicsContext); // Create the cursor, using the pixmap as both the shape and the mask of the cursor - ScopedXcbPtr createCursorError(xcb_request_check( - m_connection, - 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 - ) - )); - - if (createCursorError) - err() << "Failed to create hidden cursor" << std::endl; + XColor color; + color.flags = DoRed | DoGreen | DoBlue; + color.red = color.blue = color.green = 0; + m_hiddenCursor = XCreatePixmapCursor(m_display, cursorPixmap, cursorPixmap, &color, &color, 0, 0); // We don't need the pixmap any longer, free it - ScopedXcbPtr freePixmapError(xcb_request_check( - m_connection, - xcb_free_pixmap( - m_connection, - cursorPixmap - ) - )); - - if (freePixmapError) - err() << "Failed to free pixmap for hidden cursor" << std::endl; + XFreePixmap(m_display, cursorPixmap); } @@ -1831,25 +1433,9 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) // Try multiple times to grab the cursor for (unsigned int trial = 0; trial < maxTrialsCount; ++trial) { - sf::priv::ScopedXcbPtr error(NULL); + int result = XGrabPointer(m_display, m_window, True, None, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime); - sf::priv::ScopedXcbPtr grabPointerReply(xcb_grab_pointer_reply( - m_connection, - xcb_grab_pointer( - m_connection, - true, - m_window, - XCB_NONE, - XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC, - m_window, - XCB_NONE, - XCB_CURRENT_TIME - ), - &error - )); - - if (!error && grabPointerReply && (grabPointerReply->status == XCB_GRAB_STATUS_SUCCESS)) + if (result == GrabSuccess) { m_cursorGrabbed = true; break; @@ -1868,33 +1454,15 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) pushEvent(event); // If the window has been previously marked urgent (notification) as a result of a focus request, undo that - ScopedXcbPtr error(NULL); - - ScopedXcbPtr hintsReply(xcb_get_property_reply( - m_connection, - xcb_get_property(m_connection, 0, m_window, XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 0, 9), - &error - )); - - if (error || !hintsReply) + XWMHints* hints = XGetWMHints(m_display, m_window); + if (hints != NULL) { - err() << "Failed to get WM hints in XCB_FOCUS_IN" << std::endl; - break; + // Remove urgency (notification) flag from hints + hints->flags &= ~XUrgencyHint; + XSetWMHints(m_display, m_window, hints); + XFree(hints); } - WMHints* hints = reinterpret_cast(xcb_get_property_value(hintsReply.get())); - - if (!hints) - { - err() << "Failed to get WM hints in XCB_FOCUS_IN" << std::endl; - break; - } - - // Remove urgency (notification) flag from hints - hints->flags &= ~(1 << 8); - - setWMHints(*hints); - break; } @@ -1907,18 +1475,7 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) // Release cursor if (m_cursorGrabbed) - { - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_ungrab_pointer_checked( - m_connection, - XCB_CURRENT_TIME - ) - )); - - if (error) - err() << "Failed to ungrab mouse cursor" << std::endl; - } + XUngrabPointer(m_display, CurrentTime); Event event; event.type = Event::LostFocus; @@ -1947,13 +1504,13 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) // Close event case ClientMessage: { - static xcb_atom_t wmProtocols = getAtom("WM_PROTOCOLS"); + static Atom wmProtocols = getAtom("WM_PROTOCOLS"); // Handle window manager protocol messages we support if (windowEvent.xclient.message_type == wmProtocols) { - static xcb_atom_t wmDeleteWindow = getAtom("WM_DELETE_WINDOW"); - static xcb_atom_t netWmPing = ewmhSupported() ? getAtom("_NET_WM_PING", true) : XCB_ATOM_NONE; + static Atom wmDeleteWindow = getAtom("WM_DELETE_WINDOW"); + static Atom netWmPing = ewmhSupported() ? getAtom("_NET_WM_PING", true) : None; if ((windowEvent.xclient.format == 32) && (windowEvent.xclient.data.l[0]) == static_cast(wmDeleteWindow)) { @@ -1965,9 +1522,9 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) else if (netWmPing && (windowEvent.xclient.format == 32) && (windowEvent.xclient.data.l[0]) == static_cast(netWmPing)) { // Handle the _NET_WM_PING message, send pong back to WM to show that we are responsive - windowEvent.xclient.window = XCBDefaultRootWindow(m_connection); + windowEvent.xclient.window = DefaultRootWindow(m_display); - XSendEvent(m_display, windowEvent.xclient.window, False, SubstructureNotifyMask | SubstructureRedirectMask, &windowEvent); + XSendEvent(m_display, DefaultRootWindow(m_display), False, SubstructureNotifyMask | SubstructureRedirectMask, &windowEvent); } } break; @@ -2045,6 +1602,8 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) } } + updateLastInputTime(windowEvent.xkey.time); + break; } @@ -2102,6 +1661,9 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) } pushEvent(event); } + + updateLastInputTime(windowEvent.xbutton.time); + break; } @@ -2223,6 +1785,15 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) break; } + + // Window property change + case PropertyNotify: + { + if (!m_lastInputTime) + m_lastInputTime = windowEvent.xproperty.time; + + break; + } } return true; diff --git a/src/SFML/Window/Unix/WindowImplX11.hpp b/src/SFML/Window/Unix/WindowImplX11.hpp index 3c31f4e7..fd2295e9 100644 --- a/src/SFML/Window/Unix/WindowImplX11.hpp +++ b/src/SFML/Window/Unix/WindowImplX11.hpp @@ -31,8 +31,7 @@ #include #include #include -#include -#include +#include #include @@ -188,33 +187,6 @@ protected: 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 /// @@ -248,40 +220,12 @@ private: 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); - - //////////////////////////////////////////////////////////// - /// \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); + void updateLastInputTime(::Time time); //////////////////////////////////////////////////////////// /// \brief Do some common initializations after the window has been created @@ -314,23 +258,23 @@ private: //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - xcb_window_t m_window; ///< xcb identifier defining our window - ::Display* m_display; ///< Pointer to the display - xcb_connection_t* m_connection; ///< Pointer to the xcb connection - xcb_screen_t* m_screen; ///< Screen identifier - XIM m_inputMethod; ///< Input method linked to the X display - 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 - 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 - 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) - bool m_useSizeHints; ///< Is the size of the window fixed with size hints? - bool m_fullscreen; ///< Is the window in fullscreen? - bool m_cursorGrabbed; ///< Is the mouse cursor trapped? - bool m_windowMapped; ///< Has the window been mapped by the window manager? - xcb_pixmap_t m_iconPixmap; ///< The current icon pixmap if in use - xcb_pixmap_t m_iconMaskPixmap; ///< The current icon mask pixmap if in use + ::Window m_window; ///< X identifier defining our window + ::Display* m_display; ///< Pointer to the display + int m_screen; ///< Screen identifier + XIM m_inputMethod; ///< Input method linked to the X display + 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 + int 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 + 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) + bool m_useSizeHints; ///< Is the size of the window fixed with size hints? + bool m_fullscreen; ///< Is the window in fullscreen? + bool m_cursorGrabbed; ///< Is the mouse cursor trapped? + 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