From 3ec672afe97f68ca863632980309b6684b5fcf49 Mon Sep 17 00:00:00 2001 From: binary1248 Date: Tue, 31 Mar 2015 05:41:23 +0200 Subject: [PATCH] Removed XCB dependencies (EWMH, ICCCM, Keysyms, Util), added XCB libraries to FindSFML.cmake, fixed checking for X11 library checking for XRandR instead. --- cmake/Modules/FindSFML.cmake | 23 +- src/SFML/Window/CMakeLists.txt | 10 +- src/SFML/Window/Unix/Display.cpp | 231 +++++++ src/SFML/Window/Unix/Display.hpp | 23 + src/SFML/Window/Unix/InputImpl.cpp | 240 ++++--- src/SFML/Window/Unix/WindowImplX11.cpp | 874 ++++++++++++------------- src/SFML/Window/Unix/WindowImplX11.hpp | 73 ++- 7 files changed, 843 insertions(+), 631 deletions(-) diff --git a/cmake/Modules/FindSFML.cmake b/cmake/Modules/FindSFML.cmake index 7aafc74c..d1766b32 100644 --- a/cmake/Modules/FindSFML.cmake +++ b/cmake/Modules/FindSFML.cmake @@ -281,22 +281,25 @@ if(SFML_STATIC_LIBRARIES) if(NOT ${FIND_SFML_WINDOW_COMPONENT} EQUAL -1) # find libraries - if(FIND_SFML_OS_LINUX) + if(FIND_SFML_OS_LINUX OR FIND_SFML_OS_FREEBSD) find_sfml_dependency(X11_LIBRARY "X11" X11) - find_sfml_dependency(XRANDR_LIBRARY "Xrandr" Xrandr) - find_sfml_dependency(UDEV_LIBRARIES "UDev" udev) + 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) + endif() + + if(FIND_SFML_OS_LINUX) + find_sfml_dependency(UDEV_LIBRARIES "UDev" udev libudev) endif() # update the list if(FIND_SFML_OS_WINDOWS) set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "opengl32" "winmm" "gdi32") - elseif(FIND_SFML_OS_LINUX OR FIND_SFML_OS_FREEBSD) - set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "GL" ${X11_LIBRARY} ${XRANDR_LIBRARY}) - if(FIND_SFML_OS_FREEBSD) - set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "usbhid") - else() - set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} ${UDEV_LIBRARIES}) - endif() + 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}) + 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") 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/src/SFML/Window/CMakeLists.txt b/src/SFML/Window/CMakeLists.txt index e39fcd3c..386c0778 100644 --- a/src/SFML/Window/CMakeLists.txt +++ b/src/SFML/Window/CMakeLists.txt @@ -190,8 +190,8 @@ endif() # find external libraries if(SFML_OS_LINUX OR SFML_OS_FREEBSD) find_package(X11 REQUIRED) - if(NOT X11_Xrandr_FOUND) - message(FATAL_ERROR "Xrandr library not found") + if(NOT X11_FOUND) + message(FATAL_ERROR "X11 library not found") endif() include_directories(${X11_INCLUDE_DIR}) endif() @@ -199,7 +199,7 @@ 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 icccm image randr util ewmh keysyms REQUIRED) + find_package(XCB COMPONENTS xlib_xcb image randr REQUIRED) if(NOT LIBXCB_FOUND) message(FATAL_ERROR "Xcb library not found") endif() @@ -224,9 +224,9 @@ endif() if(SFML_OS_WINDOWS) list(APPEND WINDOW_EXT_LIBS winmm gdi32) elseif(SFML_OS_LINUX) - list(APPEND WINDOW_EXT_LIBS ${LIBXCB_LIBRARIES} ${UDEV_LIBRARIES}) + list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${LIBXCB_LIBRARIES} ${UDEV_LIBRARIES}) elseif(SFML_OS_FREEBSD) - list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${X11_Xrandr_LIB} ${LIBXCB_LIBRARIES} usbhid) + list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${LIBXCB_LIBRARIES} 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 969e01cc..e537224c 100644 --- a/src/SFML/Window/Unix/Display.cpp +++ b/src/SFML/Window/Unix/Display.cpp @@ -27,8 +27,12 @@ //////////////////////////////////////////////////////////// #include #include +#include +#include #include #include +#include +#include namespace @@ -36,6 +40,182 @@ namespace // The shared display and its reference counter Display* sharedDisplay = NULL; unsigned int referenceCount = 0; + + typedef std::map AtomMap; + AtomMap atoms; + + bool mapBuilt = false; + xcb_keycode_t firstKeycode = 255; + xcb_keycode_t lastKeycode = 0; + + // We use a simple array instead of a map => constant time lookup + // xcb_keycode_t can only contain 256 distinct values + xcb_keysym_t keysymMap[256]; + + xcb_keysym_t keysymToLower(xcb_keysym_t keysym) + { + switch(keysym >> 8) + { + // Latin 1 + case 0: + { + if ((keysym >= XK_A) && (keysym <= XK_Z)) + return keysym + (XK_a - XK_A); + else if ((keysym >= XK_Agrave) && (keysym <= XK_Odiaeresis)) + return keysym + (XK_agrave - XK_Agrave); + else if ((keysym >= XK_Ooblique) && (keysym <= XK_Thorn)) + return keysym + (XK_oslash - XK_Ooblique); + break; + } + + // Latin 2 + case 1: + { + if (keysym == XK_Aogonek) + return XK_aogonek; + else if (keysym >= XK_Lstroke && keysym <= XK_Sacute) + return keysym + (XK_lstroke - XK_Lstroke); + else if (keysym >= XK_Scaron && keysym <= XK_Zacute) + return keysym + (XK_scaron - XK_Scaron); + else if (keysym >= XK_Zcaron && keysym <= XK_Zabovedot) + return keysym + (XK_zcaron - XK_Zcaron); + else if (keysym >= XK_Racute && keysym <= XK_Tcedilla) + return keysym + (XK_racute - XK_Racute); + break; + } + + // Latin 3 + case 2: + { + if (keysym >= XK_Hstroke && keysym <= XK_Hcircumflex) + return keysym + (XK_hstroke - XK_Hstroke); + else if (keysym >= XK_Gbreve && keysym <= XK_Jcircumflex) + return keysym + (XK_gbreve - XK_Gbreve); + else if (keysym >= XK_Cabovedot && keysym <= XK_Scircumflex) + return keysym + (XK_cabovedot - XK_Cabovedot); + break; + } + + // Latin 4 + case 3: + { + if (keysym >= XK_Rcedilla && keysym <= XK_Tslash) + return keysym + (XK_rcedilla - XK_Rcedilla); + else if (keysym == XK_ENG) + return XK_eng; + else if (keysym >= XK_Amacron && keysym <= XK_Umacron) + return keysym + (XK_amacron - XK_Amacron); + break; + } + + // Cyrillic + case 6: + { + if (keysym >= XK_Serbian_DJE && keysym <= XK_Serbian_DZE) + return keysym - (XK_Serbian_DJE - XK_Serbian_dje); + else if (keysym >= XK_Cyrillic_YU && keysym <= XK_Cyrillic_HARDSIGN) + return keysym - (XK_Cyrillic_YU - XK_Cyrillic_yu); + break; + } + + // Greek + case 7: + { + if (keysym >= XK_Greek_ALPHAaccent && keysym <= XK_Greek_OMEGAaccent) + return keysym + (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); + else if (keysym >= XK_Greek_ALPHA && keysym <= XK_Greek_OMEGA) + return keysym + (XK_Greek_alpha - XK_Greek_ALPHA); + break; + } + + // Armenian + case 0x14: + { + if (keysym >= XK_Armenian_AYB && keysym <= XK_Armenian_fe) { + return (keysym | 1); + } + break; + } + + default: + { + break; + } + } + + return keysym; + } + + void buildMap() + { + // Open a connection with the X server + xcb_connection_t* connection = sf::priv::OpenConnection(); + + firstKeycode = xcb_get_setup(connection)->min_keycode; + lastKeycode = xcb_get_setup(connection)->max_keycode; + + sf::priv::ScopedXcbPtr error(NULL); + + sf::priv::ScopedXcbPtr keyboardMapping(xcb_get_keyboard_mapping_reply( + connection, + xcb_get_keyboard_mapping( + connection, + firstKeycode, + lastKeycode - firstKeycode + 1 + ), + &error + )); + + sf::priv::CloseConnection(connection); + + if (error || !keyboardMapping) + { + sf::err() << "Failed to get keyboard mapping" << std::endl; + return; + } + + uint8_t keysymsPerKeycode = keyboardMapping->keysyms_per_keycode; + + if (!keysymsPerKeycode) + { + sf::err() << "Error: No keysyms per keycode" << std::endl; + return; + } + + const xcb_keysym_t* keysyms = xcb_get_keyboard_mapping_keysyms(keyboardMapping.get()); + + if (!keysyms) + { + sf::err() << "Failed to get keyboard mapping keysyms" << std::endl; + return; + } + + xcb_keycode_t range = lastKeycode - firstKeycode + 1; + + std::fill(keysymMap, keysymMap + 256, XK_VoidSymbol); + + for (xcb_keycode_t i = firstKeycode; ; ++i) + { + const xcb_keysym_t* keysym = &keysyms[(i - firstKeycode) * keysymsPerKeycode]; + + if ((keysymsPerKeycode == 1) || (keysym[1] == XCB_NO_SYMBOL)) + { + keysymMap[i] = keysymToLower(keysym[0]); + + if (i == lastKeycode) + break; + + continue; + } + + keysymMap[i] = keysym[0]; + + if (i == lastKeycode) + break; + } + + mapBuilt = true; + } } namespace sf @@ -80,6 +260,7 @@ void CloseDisplay(Display* display) XCloseDisplay(display); } + //////////////////////////////////////////////////////////// void CloseConnection(xcb_connection_t* connection) { @@ -87,6 +268,7 @@ void CloseConnection(xcb_connection_t* connection) return CloseDisplay(sharedDisplay); } + //////////////////////////////////////////////////////////// xcb_screen_t* XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr) { @@ -101,6 +283,7 @@ xcb_screen_t* XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr) return NULL; } + //////////////////////////////////////////////////////////// xcb_screen_t* XCBDefaultScreen(xcb_connection_t* connection) { @@ -108,6 +291,7 @@ xcb_screen_t* XCBDefaultScreen(xcb_connection_t* connection) return XCBScreenOfDisplay(connection, XDefaultScreen(sharedDisplay)); } + //////////////////////////////////////////////////////////// xcb_window_t XCBDefaultRootWindow(xcb_connection_t* connection) { @@ -118,6 +302,53 @@ xcb_window_t XCBDefaultRootWindow(xcb_connection_t* connection) return 0; } + +//////////////////////////////////////////////////////////// +xcb_atom_t getAtom(const std::string& name, bool onlyIfExists) +{ + AtomMap::const_iterator iter = atoms.find(name); + + if (iter != atoms.end()) + return iter->second; + + ScopedXcbPtr error(NULL); + + xcb_connection_t* connection = OpenConnection(); + + ScopedXcbPtr reply(xcb_intern_atom_reply( + connection, + xcb_intern_atom( + connection, + onlyIfExists, + name.size(), + name.c_str() + ), + &error + )); + + CloseConnection(connection); + + if (error || !reply) + { + err() << "Failed to get " << name << " atom." << std::endl; + return XCB_ATOM_NONE; + } + + atoms[name] = reply->atom; + + return reply->atom; +} + + +//////////////////////////////////////////////////////////// +const xcb_keysym_t* getKeysymMap() +{ + if (!mapBuilt) + buildMap(); + + return keysymMap; +} + } // namespace priv } // namespace sf diff --git a/src/SFML/Window/Unix/Display.hpp b/src/SFML/Window/Unix/Display.hpp index 469f0720..1cda4a7e 100644 --- a/src/SFML/Window/Unix/Display.hpp +++ b/src/SFML/Window/Unix/Display.hpp @@ -29,6 +29,7 @@ // Headers //////////////////////////////////////////////////////////// #include +#include namespace sf @@ -104,6 +105,28 @@ xcb_screen_t* XCBDefaultScreen(xcb_connection_t* connection); //////////////////////////////////////////////////////////// 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 +/// +//////////////////////////////////////////////////////////// +xcb_atom_t getAtom(const std::string& name, bool onlyIfExists = false); + +//////////////////////////////////////////////////////////// +/// \brief Get the keycode to keysym map +/// +/// Contains 255 values. Use the keycode as the index +/// into the array to retrieve its keysym. +/// +/// \return Keycode to keysym map +/// +//////////////////////////////////////////////////////////// +const xcb_keysym_t* getKeysymMap(); + } // namespace priv } // namespace sf diff --git a/src/SFML/Window/Unix/InputImpl.cpp b/src/SFML/Window/Unix/InputImpl.cpp index 63fdb4fb..8817165e 100644 --- a/src/SFML/Window/Unix/InputImpl.cpp +++ b/src/SFML/Window/Unix/InputImpl.cpp @@ -30,8 +30,7 @@ #include #include #include -#include -#include +#include #include #include @@ -45,138 +44,125 @@ namespace // We use a simple array instead of a map => constant time lookup xcb_keycode_t keycodeMap[sf::Keyboard::KeyCount]; - xcb_keycode_t getKeycode(xcb_key_symbols_t* keySymbols, xcb_keysym_t keysym) + xcb_keycode_t getKeycode(xcb_keysym_t keysym) { - // keycodes is actually a vector of keycodes - // Since we only care about the unmodified keycode, - // we simply return the first one - sf::priv::ScopedXcbPtr keycodes(xcb_key_symbols_get_keycode(keySymbols, keysym)); + const xcb_keysym_t* keysymMap = sf::priv::getKeysymMap(); - if (keycodes) - return *keycodes.get(); + for (xcb_keycode_t i = 0; ; ++i) + { + if (keysymMap[i] == keysym) + return i; - return 0; + if (i == 255) + break; + } + + return 255; } void buildMap() { - // Open a connection with the X server - xcb_connection_t* connection = sf::priv::OpenConnection(); - - xcb_key_symbols_t* keySymbols = xcb_key_symbols_alloc(connection); - - if (!keySymbols) - { - sf::err() << "Failed to allocate key symbols" << std::endl; - return; - } - - keycodeMap[sf::Keyboard::A] = getKeycode(keySymbols, XK_A); - keycodeMap[sf::Keyboard::B] = getKeycode(keySymbols, XK_B); - keycodeMap[sf::Keyboard::C] = getKeycode(keySymbols, XK_C); - keycodeMap[sf::Keyboard::D] = getKeycode(keySymbols, XK_D); - keycodeMap[sf::Keyboard::E] = getKeycode(keySymbols, XK_E); - keycodeMap[sf::Keyboard::F] = getKeycode(keySymbols, XK_F); - keycodeMap[sf::Keyboard::G] = getKeycode(keySymbols, XK_G); - keycodeMap[sf::Keyboard::H] = getKeycode(keySymbols, XK_H); - keycodeMap[sf::Keyboard::I] = getKeycode(keySymbols, XK_I); - keycodeMap[sf::Keyboard::J] = getKeycode(keySymbols, XK_J); - keycodeMap[sf::Keyboard::K] = getKeycode(keySymbols, XK_K); - keycodeMap[sf::Keyboard::L] = getKeycode(keySymbols, XK_L); - keycodeMap[sf::Keyboard::M] = getKeycode(keySymbols, XK_M); - keycodeMap[sf::Keyboard::N] = getKeycode(keySymbols, XK_N); - keycodeMap[sf::Keyboard::O] = getKeycode(keySymbols, XK_O); - keycodeMap[sf::Keyboard::P] = getKeycode(keySymbols, XK_P); - keycodeMap[sf::Keyboard::Q] = getKeycode(keySymbols, XK_Q); - keycodeMap[sf::Keyboard::R] = getKeycode(keySymbols, XK_R); - keycodeMap[sf::Keyboard::S] = getKeycode(keySymbols, XK_S); - keycodeMap[sf::Keyboard::T] = getKeycode(keySymbols, XK_T); - keycodeMap[sf::Keyboard::U] = getKeycode(keySymbols, XK_U); - keycodeMap[sf::Keyboard::V] = getKeycode(keySymbols, XK_V); - keycodeMap[sf::Keyboard::W] = getKeycode(keySymbols, XK_W); - keycodeMap[sf::Keyboard::X] = getKeycode(keySymbols, XK_X); - keycodeMap[sf::Keyboard::Y] = getKeycode(keySymbols, XK_Y); - keycodeMap[sf::Keyboard::Z] = getKeycode(keySymbols, XK_Z); - keycodeMap[sf::Keyboard::Num0] = getKeycode(keySymbols, XK_0); - keycodeMap[sf::Keyboard::Num1] = getKeycode(keySymbols, XK_1); - keycodeMap[sf::Keyboard::Num2] = getKeycode(keySymbols, XK_2); - keycodeMap[sf::Keyboard::Num3] = getKeycode(keySymbols, XK_3); - keycodeMap[sf::Keyboard::Num4] = getKeycode(keySymbols, XK_4); - keycodeMap[sf::Keyboard::Num5] = getKeycode(keySymbols, XK_5); - keycodeMap[sf::Keyboard::Num6] = getKeycode(keySymbols, XK_6); - keycodeMap[sf::Keyboard::Num7] = getKeycode(keySymbols, XK_7); - keycodeMap[sf::Keyboard::Num8] = getKeycode(keySymbols, XK_8); - keycodeMap[sf::Keyboard::Num9] = getKeycode(keySymbols, XK_9); - keycodeMap[sf::Keyboard::Escape] = getKeycode(keySymbols, XK_Escape); - keycodeMap[sf::Keyboard::LControl] = getKeycode(keySymbols, XK_Control_L); - keycodeMap[sf::Keyboard::LShift] = getKeycode(keySymbols, XK_Shift_L); - keycodeMap[sf::Keyboard::LAlt] = getKeycode(keySymbols, XK_Alt_L); - keycodeMap[sf::Keyboard::LSystem] = getKeycode(keySymbols, XK_Super_L); - keycodeMap[sf::Keyboard::RControl] = getKeycode(keySymbols, XK_Control_R); - keycodeMap[sf::Keyboard::RShift] = getKeycode(keySymbols, XK_Shift_R); - keycodeMap[sf::Keyboard::RAlt] = getKeycode(keySymbols, XK_Alt_R); - keycodeMap[sf::Keyboard::RSystem] = getKeycode(keySymbols, XK_Super_R); - keycodeMap[sf::Keyboard::Menu] = getKeycode(keySymbols, XK_Menu); - keycodeMap[sf::Keyboard::LBracket] = getKeycode(keySymbols, XK_bracketleft); - keycodeMap[sf::Keyboard::RBracket] = getKeycode(keySymbols, XK_bracketright); - keycodeMap[sf::Keyboard::SemiColon] = getKeycode(keySymbols, XK_semicolon); - keycodeMap[sf::Keyboard::Comma] = getKeycode(keySymbols, XK_comma); - keycodeMap[sf::Keyboard::Period] = getKeycode(keySymbols, XK_period); - keycodeMap[sf::Keyboard::Quote] = getKeycode(keySymbols, XK_apostrophe); - keycodeMap[sf::Keyboard::Slash] = getKeycode(keySymbols, XK_slash); - keycodeMap[sf::Keyboard::BackSlash] = getKeycode(keySymbols, XK_backslash); - keycodeMap[sf::Keyboard::Tilde] = getKeycode(keySymbols, XK_grave); - keycodeMap[sf::Keyboard::Equal] = getKeycode(keySymbols, XK_equal); - keycodeMap[sf::Keyboard::Dash] = getKeycode(keySymbols, XK_minus); - keycodeMap[sf::Keyboard::Space] = getKeycode(keySymbols, XK_space); - keycodeMap[sf::Keyboard::Return] = getKeycode(keySymbols, XK_Return); - keycodeMap[sf::Keyboard::BackSpace] = getKeycode(keySymbols, XK_BackSpace); - keycodeMap[sf::Keyboard::Tab] = getKeycode(keySymbols, XK_Tab); - keycodeMap[sf::Keyboard::PageUp] = getKeycode(keySymbols, XK_Prior); - keycodeMap[sf::Keyboard::PageDown] = getKeycode(keySymbols, XK_Next); - keycodeMap[sf::Keyboard::End] = getKeycode(keySymbols, XK_End); - keycodeMap[sf::Keyboard::Home] = getKeycode(keySymbols, XK_Home); - keycodeMap[sf::Keyboard::Insert] = getKeycode(keySymbols, XK_Insert); - keycodeMap[sf::Keyboard::Delete] = getKeycode(keySymbols, XK_Delete); - keycodeMap[sf::Keyboard::Add] = getKeycode(keySymbols, XK_KP_Add); - keycodeMap[sf::Keyboard::Subtract] = getKeycode(keySymbols, XK_KP_Subtract); - keycodeMap[sf::Keyboard::Multiply] = getKeycode(keySymbols, XK_KP_Multiply); - keycodeMap[sf::Keyboard::Divide] = getKeycode(keySymbols, XK_KP_Divide); - keycodeMap[sf::Keyboard::Left] = getKeycode(keySymbols, XK_Left); - keycodeMap[sf::Keyboard::Right] = getKeycode(keySymbols, XK_Right); - keycodeMap[sf::Keyboard::Up] = getKeycode(keySymbols, XK_Up); - keycodeMap[sf::Keyboard::Down] = getKeycode(keySymbols, XK_Down); - keycodeMap[sf::Keyboard::Numpad0] = getKeycode(keySymbols, XK_KP_0); - keycodeMap[sf::Keyboard::Numpad1] = getKeycode(keySymbols, XK_KP_1); - keycodeMap[sf::Keyboard::Numpad2] = getKeycode(keySymbols, XK_KP_2); - keycodeMap[sf::Keyboard::Numpad3] = getKeycode(keySymbols, XK_KP_3); - keycodeMap[sf::Keyboard::Numpad4] = getKeycode(keySymbols, XK_KP_4); - keycodeMap[sf::Keyboard::Numpad5] = getKeycode(keySymbols, XK_KP_5); - keycodeMap[sf::Keyboard::Numpad6] = getKeycode(keySymbols, XK_KP_6); - keycodeMap[sf::Keyboard::Numpad7] = getKeycode(keySymbols, XK_KP_7); - keycodeMap[sf::Keyboard::Numpad8] = getKeycode(keySymbols, XK_KP_8); - keycodeMap[sf::Keyboard::Numpad9] = getKeycode(keySymbols, XK_KP_9); - keycodeMap[sf::Keyboard::F1] = getKeycode(keySymbols, XK_F1); - keycodeMap[sf::Keyboard::F2] = getKeycode(keySymbols, XK_F2); - keycodeMap[sf::Keyboard::F3] = getKeycode(keySymbols, XK_F3); - keycodeMap[sf::Keyboard::F4] = getKeycode(keySymbols, XK_F4); - keycodeMap[sf::Keyboard::F5] = getKeycode(keySymbols, XK_F5); - keycodeMap[sf::Keyboard::F6] = getKeycode(keySymbols, XK_F6); - keycodeMap[sf::Keyboard::F7] = getKeycode(keySymbols, XK_F7); - keycodeMap[sf::Keyboard::F8] = getKeycode(keySymbols, XK_F8); - keycodeMap[sf::Keyboard::F9] = getKeycode(keySymbols, XK_F9); - keycodeMap[sf::Keyboard::F10] = getKeycode(keySymbols, XK_F10); - keycodeMap[sf::Keyboard::F11] = getKeycode(keySymbols, XK_F11); - keycodeMap[sf::Keyboard::F12] = getKeycode(keySymbols, XK_F12); - keycodeMap[sf::Keyboard::F13] = getKeycode(keySymbols, XK_F13); - keycodeMap[sf::Keyboard::F14] = getKeycode(keySymbols, XK_F14); - keycodeMap[sf::Keyboard::F15] = getKeycode(keySymbols, XK_F15); - keycodeMap[sf::Keyboard::Pause] = getKeycode(keySymbols, XK_Pause); - - xcb_key_symbols_free(keySymbols); - - // Close the connection with the X server - sf::priv::CloseConnection(connection); + keycodeMap[sf::Keyboard::A] = getKeycode(XK_a); + keycodeMap[sf::Keyboard::B] = getKeycode(XK_b); + keycodeMap[sf::Keyboard::C] = getKeycode(XK_c); + keycodeMap[sf::Keyboard::D] = getKeycode(XK_d); + keycodeMap[sf::Keyboard::E] = getKeycode(XK_e); + keycodeMap[sf::Keyboard::F] = getKeycode(XK_f); + keycodeMap[sf::Keyboard::G] = getKeycode(XK_g); + keycodeMap[sf::Keyboard::H] = getKeycode(XK_h); + keycodeMap[sf::Keyboard::I] = getKeycode(XK_i); + keycodeMap[sf::Keyboard::J] = getKeycode(XK_j); + keycodeMap[sf::Keyboard::K] = getKeycode(XK_k); + keycodeMap[sf::Keyboard::L] = getKeycode(XK_l); + keycodeMap[sf::Keyboard::M] = getKeycode(XK_m); + keycodeMap[sf::Keyboard::N] = getKeycode(XK_n); + keycodeMap[sf::Keyboard::O] = getKeycode(XK_o); + keycodeMap[sf::Keyboard::P] = getKeycode(XK_p); + keycodeMap[sf::Keyboard::Q] = getKeycode(XK_q); + keycodeMap[sf::Keyboard::R] = getKeycode(XK_r); + keycodeMap[sf::Keyboard::S] = getKeycode(XK_s); + keycodeMap[sf::Keyboard::T] = getKeycode(XK_t); + keycodeMap[sf::Keyboard::U] = getKeycode(XK_u); + keycodeMap[sf::Keyboard::V] = getKeycode(XK_v); + keycodeMap[sf::Keyboard::W] = getKeycode(XK_w); + keycodeMap[sf::Keyboard::X] = getKeycode(XK_x); + keycodeMap[sf::Keyboard::Y] = getKeycode(XK_y); + keycodeMap[sf::Keyboard::Z] = getKeycode(XK_z); + keycodeMap[sf::Keyboard::Num0] = getKeycode(XK_0); + keycodeMap[sf::Keyboard::Num1] = getKeycode(XK_1); + keycodeMap[sf::Keyboard::Num2] = getKeycode(XK_2); + keycodeMap[sf::Keyboard::Num3] = getKeycode(XK_3); + keycodeMap[sf::Keyboard::Num4] = getKeycode(XK_4); + keycodeMap[sf::Keyboard::Num5] = getKeycode(XK_5); + keycodeMap[sf::Keyboard::Num6] = getKeycode(XK_6); + keycodeMap[sf::Keyboard::Num7] = getKeycode(XK_7); + keycodeMap[sf::Keyboard::Num8] = getKeycode(XK_8); + keycodeMap[sf::Keyboard::Num9] = getKeycode(XK_9); + keycodeMap[sf::Keyboard::Escape] = getKeycode(XK_Escape); + keycodeMap[sf::Keyboard::LControl] = getKeycode(XK_Control_L); + keycodeMap[sf::Keyboard::LShift] = getKeycode(XK_Shift_L); + keycodeMap[sf::Keyboard::LAlt] = getKeycode(XK_Alt_L); + keycodeMap[sf::Keyboard::LSystem] = getKeycode(XK_Super_L); + keycodeMap[sf::Keyboard::RControl] = getKeycode(XK_Control_R); + keycodeMap[sf::Keyboard::RShift] = getKeycode(XK_Shift_R); + keycodeMap[sf::Keyboard::RAlt] = getKeycode(XK_Alt_R); + keycodeMap[sf::Keyboard::RSystem] = getKeycode(XK_Super_R); + keycodeMap[sf::Keyboard::Menu] = getKeycode(XK_Menu); + keycodeMap[sf::Keyboard::LBracket] = getKeycode(XK_bracketleft); + keycodeMap[sf::Keyboard::RBracket] = getKeycode(XK_bracketright); + keycodeMap[sf::Keyboard::SemiColon] = getKeycode(XK_semicolon); + keycodeMap[sf::Keyboard::Comma] = getKeycode(XK_comma); + keycodeMap[sf::Keyboard::Period] = getKeycode(XK_period); + keycodeMap[sf::Keyboard::Quote] = getKeycode(XK_apostrophe); + keycodeMap[sf::Keyboard::Slash] = getKeycode(XK_slash); + keycodeMap[sf::Keyboard::BackSlash] = getKeycode(XK_backslash); + keycodeMap[sf::Keyboard::Tilde] = getKeycode(XK_grave); + keycodeMap[sf::Keyboard::Equal] = getKeycode(XK_equal); + keycodeMap[sf::Keyboard::Dash] = getKeycode(XK_minus); + keycodeMap[sf::Keyboard::Space] = getKeycode(XK_space); + keycodeMap[sf::Keyboard::Return] = getKeycode(XK_Return); + keycodeMap[sf::Keyboard::BackSpace] = getKeycode(XK_BackSpace); + keycodeMap[sf::Keyboard::Tab] = getKeycode(XK_Tab); + keycodeMap[sf::Keyboard::PageUp] = getKeycode(XK_Prior); + keycodeMap[sf::Keyboard::PageDown] = getKeycode(XK_Next); + keycodeMap[sf::Keyboard::End] = getKeycode(XK_End); + keycodeMap[sf::Keyboard::Home] = getKeycode(XK_Home); + keycodeMap[sf::Keyboard::Insert] = getKeycode(XK_Insert); + keycodeMap[sf::Keyboard::Delete] = getKeycode(XK_Delete); + keycodeMap[sf::Keyboard::Add] = getKeycode(XK_KP_Add); + keycodeMap[sf::Keyboard::Subtract] = getKeycode(XK_KP_Subtract); + keycodeMap[sf::Keyboard::Multiply] = getKeycode(XK_KP_Multiply); + keycodeMap[sf::Keyboard::Divide] = getKeycode(XK_KP_Divide); + keycodeMap[sf::Keyboard::Left] = getKeycode(XK_Left); + keycodeMap[sf::Keyboard::Right] = getKeycode(XK_Right); + keycodeMap[sf::Keyboard::Up] = getKeycode(XK_Up); + keycodeMap[sf::Keyboard::Down] = getKeycode(XK_Down); + keycodeMap[sf::Keyboard::Numpad0] = getKeycode(XK_KP_0); + keycodeMap[sf::Keyboard::Numpad1] = getKeycode(XK_KP_1); + keycodeMap[sf::Keyboard::Numpad2] = getKeycode(XK_KP_2); + keycodeMap[sf::Keyboard::Numpad3] = getKeycode(XK_KP_3); + keycodeMap[sf::Keyboard::Numpad4] = getKeycode(XK_KP_4); + keycodeMap[sf::Keyboard::Numpad5] = getKeycode(XK_KP_5); + keycodeMap[sf::Keyboard::Numpad6] = getKeycode(XK_KP_6); + keycodeMap[sf::Keyboard::Numpad7] = getKeycode(XK_KP_7); + keycodeMap[sf::Keyboard::Numpad8] = getKeycode(XK_KP_8); + keycodeMap[sf::Keyboard::Numpad9] = getKeycode(XK_KP_9); + keycodeMap[sf::Keyboard::F1] = getKeycode(XK_F1); + keycodeMap[sf::Keyboard::F2] = getKeycode(XK_F2); + keycodeMap[sf::Keyboard::F3] = getKeycode(XK_F3); + keycodeMap[sf::Keyboard::F4] = getKeycode(XK_F4); + keycodeMap[sf::Keyboard::F5] = getKeycode(XK_F5); + keycodeMap[sf::Keyboard::F6] = getKeycode(XK_F6); + keycodeMap[sf::Keyboard::F7] = getKeycode(XK_F7); + keycodeMap[sf::Keyboard::F8] = getKeycode(XK_F8); + keycodeMap[sf::Keyboard::F9] = getKeycode(XK_F9); + keycodeMap[sf::Keyboard::F10] = getKeycode(XK_F10); + keycodeMap[sf::Keyboard::F11] = getKeycode(XK_F11); + keycodeMap[sf::Keyboard::F12] = getKeycode(XK_F12); + keycodeMap[sf::Keyboard::F13] = getKeycode(XK_F13); + keycodeMap[sf::Keyboard::F14] = getKeycode(XK_F14); + keycodeMap[sf::Keyboard::F15] = getKeycode(XK_F15); + keycodeMap[sf::Keyboard::Pause] = getKeycode(XK_Pause); mapBuilt = true; } diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index 7814563c..212c9d34 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -67,7 +66,14 @@ namespace sf::priv::WindowImplX11* fullscreenWindow = NULL; std::vector allWindows; sf::Mutex allWindowsMutex; - unsigned long eventMask = XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_PRESS | + + bool mapBuilt = false; + + // We use a simple array instead of a map => constant time lookup + // xcb_keycode_t can only contain 256 distinct values + sf::Keyboard::Key sfKeyMap[256]; + + 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 | @@ -119,68 +125,70 @@ namespace checked = true; xcb_connection_t* connection = sf::priv::OpenConnection(); - xcb_ewmh_connection_t ewmhConnection; + + xcb_atom_t netSupportingWmCheck = sf::priv::getAtom("_NET_SUPPORTING_WM_CHECK", true); + xcb_atom_t netSupported = sf::priv::getAtom("_NET_SUPPORTED", true); + + if (!netSupportingWmCheck || !netSupported) + return false; sf::priv::ScopedXcbPtr error(NULL); - uint8_t result = xcb_ewmh_init_atoms_replies( - &ewmhConnection, - xcb_ewmh_init_atoms( + sf::priv::ScopedXcbPtr rootSupportingWindow(xcb_get_property_reply( + connection, + xcb_get_property( connection, - &ewmhConnection + 0, + sf::priv::XCBDefaultRootWindow(connection), + netSupportingWmCheck, + XCB_ATOM_WINDOW, + 0, + 1 ), &error - ); + )); - if (!result || error) + if (!rootSupportingWindow || rootSupportingWindow->length != 1) { - xcb_ewmh_connection_wipe(&ewmhConnection); sf::priv::CloseConnection(connection); return false; } - xcb_window_t rootWindow; + xcb_window_t* rootWindow = reinterpret_cast(xcb_get_property_value(rootSupportingWindow.get())); - result = xcb_ewmh_get_supporting_wm_check_reply( - &ewmhConnection, - xcb_ewmh_get_supporting_wm_check( - &ewmhConnection, - sf::priv::XCBDefaultRootWindow(connection) - ), - &rootWindow, - &error - ); - - if (!result || error) - { - xcb_ewmh_connection_wipe(&ewmhConnection); - sf::priv::CloseConnection(connection); + if (!rootWindow) return false; - } - xcb_window_t childWindow; - - result = xcb_ewmh_get_supporting_wm_check_reply( - &ewmhConnection, - xcb_ewmh_get_supporting_wm_check( - &ewmhConnection, - rootWindow + sf::priv::ScopedXcbPtr childSupportingWindow(xcb_get_property_reply( + connection, + xcb_get_property( + connection, + 0, + *rootWindow, + netSupportingWmCheck, + XCB_ATOM_WINDOW, + 0, + 1 ), - &childWindow, &error - ); + )); - xcb_ewmh_connection_wipe(&ewmhConnection); sf::priv::CloseConnection(connection); - if (!result || error) + if (!childSupportingWindow || childSupportingWindow->length != 1) + return false; + + xcb_window_t* childWindow = reinterpret_cast(xcb_get_property_value(childSupportingWindow.get())); + + if (!childWindow) return false; // Conforming window managers should return the same window for both queries - if (rootWindow != childWindow) + if (*rootWindow != *childWindow) return false; ewmhSupported = true; + return true; } @@ -300,6 +308,143 @@ namespace sf::err() << "Unhandled event type: " << (static_cast(type) & ~0x80) << std::endl << "Report this to the SFML maintainers if possible" << std::endl; } + + xcb_keysym_t getKeysymFromKeycode(xcb_keycode_t keycode) + { + return sf::priv::getKeysymMap()[keycode]; + } + + sf::Keyboard::Key keysymToSF(xcb_keysym_t symbol) + { + switch (symbol) + { + case XK_Shift_L: return sf::Keyboard::LShift; + case XK_Shift_R: return sf::Keyboard::RShift; + case XK_Control_L: return sf::Keyboard::LControl; + case XK_Control_R: return sf::Keyboard::RControl; + case XK_Alt_L: return sf::Keyboard::LAlt; + case XK_Alt_R: return sf::Keyboard::RAlt; + case XK_Super_L: return sf::Keyboard::LSystem; + case XK_Super_R: return sf::Keyboard::RSystem; + case XK_Menu: return sf::Keyboard::Menu; + case XK_Escape: return sf::Keyboard::Escape; + case XK_semicolon: return sf::Keyboard::SemiColon; + case XK_slash: return sf::Keyboard::Slash; + case XK_equal: return sf::Keyboard::Equal; + case XK_minus: return sf::Keyboard::Dash; + case XK_bracketleft: return sf::Keyboard::LBracket; + case XK_bracketright: return sf::Keyboard::RBracket; + case XK_comma: return sf::Keyboard::Comma; + case XK_period: return sf::Keyboard::Period; + case XK_apostrophe: return sf::Keyboard::Quote; + case XK_backslash: return sf::Keyboard::BackSlash; + case XK_grave: return sf::Keyboard::Tilde; + case XK_space: return sf::Keyboard::Space; + case XK_Return: return sf::Keyboard::Return; + case XK_KP_Enter: return sf::Keyboard::Return; + case XK_BackSpace: return sf::Keyboard::BackSpace; + case XK_Tab: return sf::Keyboard::Tab; + case XK_Prior: return sf::Keyboard::PageUp; + case XK_Next: return sf::Keyboard::PageDown; + case XK_End: return sf::Keyboard::End; + case XK_Home: return sf::Keyboard::Home; + case XK_Insert: return sf::Keyboard::Insert; + case XK_Delete: return sf::Keyboard::Delete; + case XK_KP_Add: return sf::Keyboard::Add; + case XK_KP_Subtract: return sf::Keyboard::Subtract; + case XK_KP_Multiply: return sf::Keyboard::Multiply; + case XK_KP_Divide: return sf::Keyboard::Divide; + case XK_Pause: return sf::Keyboard::Pause; + case XK_F1: return sf::Keyboard::F1; + case XK_F2: return sf::Keyboard::F2; + case XK_F3: return sf::Keyboard::F3; + case XK_F4: return sf::Keyboard::F4; + case XK_F5: return sf::Keyboard::F5; + case XK_F6: return sf::Keyboard::F6; + case XK_F7: return sf::Keyboard::F7; + case XK_F8: return sf::Keyboard::F8; + case XK_F9: return sf::Keyboard::F9; + case XK_F10: return sf::Keyboard::F10; + case XK_F11: return sf::Keyboard::F11; + case XK_F12: return sf::Keyboard::F12; + case XK_F13: return sf::Keyboard::F13; + case XK_F14: return sf::Keyboard::F14; + case XK_F15: return sf::Keyboard::F15; + case XK_Left: return sf::Keyboard::Left; + case XK_Right: return sf::Keyboard::Right; + case XK_Up: return sf::Keyboard::Up; + case XK_Down: return sf::Keyboard::Down; + case XK_KP_0: return sf::Keyboard::Numpad0; + case XK_KP_1: return sf::Keyboard::Numpad1; + case XK_KP_2: return sf::Keyboard::Numpad2; + case XK_KP_3: return sf::Keyboard::Numpad3; + case XK_KP_4: return sf::Keyboard::Numpad4; + case XK_KP_5: return sf::Keyboard::Numpad5; + case XK_KP_6: return sf::Keyboard::Numpad6; + case XK_KP_7: return sf::Keyboard::Numpad7; + case XK_KP_8: return sf::Keyboard::Numpad8; + case XK_KP_9: return sf::Keyboard::Numpad9; + case XK_a: return sf::Keyboard::A; + case XK_b: return sf::Keyboard::B; + case XK_c: return sf::Keyboard::C; + case XK_d: return sf::Keyboard::D; + case XK_e: return sf::Keyboard::E; + case XK_f: return sf::Keyboard::F; + case XK_g: return sf::Keyboard::G; + case XK_h: return sf::Keyboard::H; + case XK_i: return sf::Keyboard::I; + case XK_j: return sf::Keyboard::J; + case XK_k: return sf::Keyboard::K; + case XK_l: return sf::Keyboard::L; + case XK_m: return sf::Keyboard::M; + case XK_n: return sf::Keyboard::N; + case XK_o: return sf::Keyboard::O; + case XK_p: return sf::Keyboard::P; + case XK_q: return sf::Keyboard::Q; + case XK_r: return sf::Keyboard::R; + case XK_s: return sf::Keyboard::S; + case XK_t: return sf::Keyboard::T; + case XK_u: return sf::Keyboard::U; + case XK_v: return sf::Keyboard::V; + case XK_w: return sf::Keyboard::W; + case XK_x: return sf::Keyboard::X; + case XK_y: return sf::Keyboard::Y; + case XK_z: return sf::Keyboard::Z; + case XK_0: return sf::Keyboard::Num0; + case XK_1: return sf::Keyboard::Num1; + case XK_2: return sf::Keyboard::Num2; + case XK_3: return sf::Keyboard::Num3; + case XK_4: return sf::Keyboard::Num4; + case XK_5: return sf::Keyboard::Num5; + case XK_6: return sf::Keyboard::Num6; + case XK_7: return sf::Keyboard::Num7; + case XK_8: return sf::Keyboard::Num8; + case XK_9: return sf::Keyboard::Num9; + } + + return sf::Keyboard::Unknown; + } + + void buildMap() + { + for (xcb_keycode_t i = 0; ; ++i) + { + sfKeyMap[i] = keysymToSF(getKeysymFromKeycode(i)); + + if (i == 255) + break; + } + + mapBuilt = true; + } + + sf::Keyboard::Key keycodeToSF(xcb_keycode_t keycode) + { + if (!mapBuilt) + buildMap(); + + return sfKeyMap[keycode]; + } } @@ -312,10 +457,7 @@ WindowImplX11::WindowImplX11(WindowHandle handle) : m_window (0), m_inputMethod (NULL), m_inputContext (NULL), -m_keySymbols (NULL), m_isExternal (true), -m_atomWmProtocols(0), -m_atomClose (0), m_hiddenCursor (0), m_keyRepeat (true), m_previousSize (-1, -1), @@ -335,22 +477,7 @@ m_fullscreen (false) } // Make sure to check for EWMH support before we do anything - if (ewmhSupported()) - { - ScopedXcbPtr error(NULL); - - uint8_t result = xcb_ewmh_init_atoms_replies( - &m_ewmhConnection, - xcb_ewmh_init_atoms( - m_connection, - &m_ewmhConnection - ), - &error - ); - - if (!result || error) - err() << "Failed to initialize EWMH atoms" << std::endl; - } + ewmhSupported(); m_screen = XCBDefaultScreen(m_connection); XSetEventQueueOwner(m_display, XCBOwnsEventQueue); @@ -384,10 +511,7 @@ WindowImplX11::WindowImplX11(VideoMode mode, const String& title, unsigned long m_window (0), m_inputMethod (NULL), m_inputContext (NULL), -m_keySymbols (NULL), m_isExternal (false), -m_atomWmProtocols(0), -m_atomClose (0), m_hiddenCursor (0), m_keyRepeat (true), m_previousSize (-1, -1), @@ -407,22 +531,7 @@ m_fullscreen ((style & Style::Fullscreen) != 0) } // Make sure to check for EWMH support before we do anything - if (ewmhSupported()) - { - ScopedXcbPtr error(NULL); - - uint8_t result = xcb_ewmh_init_atoms_replies( - &m_ewmhConnection, - xcb_ewmh_init_atoms( - m_connection, - &m_ewmhConnection - ), - &error - ); - - if (!result || error) - err() << "Failed to initialize EWMH atoms" << std::endl; - } + ewmhSupported(); m_screen = XCBDefaultScreen(m_connection); XSetEventQueueOwner(m_display, XCBOwnsEventQueue); @@ -471,27 +580,31 @@ m_fullscreen ((style & Style::Fullscreen) != 0) setProtocols(); // Set the WM initial state to the normal state - xcb_icccm_wm_hints_t hints; + WMHints hints; std::memset(&hints, 0, sizeof(hints)); - xcb_icccm_wm_hints_set_normal(&hints); - xcb_icccm_set_wm_hints(m_connection, m_window, &hints); - - xcb_size_hints_t sizeHints; - std::memset(&sizeHints, 0, sizeof(sizeHints)); + hints.initial_state = 1; + hints.flags |= 1 << 1; + setWMHints(hints); // Set the window's style (tell the window manager to change our window's decorations and functions according to the requested style) setMotifHints(style); + WMSizeHints sizeHints; + std::memset(&sizeHints, 0, sizeof(sizeHints)); + // This is a hack to force some windows managers to disable resizing if (!(style & Style::Resize)) { m_useSizeHints = true; - xcb_icccm_size_hints_set_min_size(&sizeHints, width, height); - xcb_icccm_size_hints_set_max_size(&sizeHints, width, height); + sizeHints.flags |= ((1 << 4) | (1 << 5)); + sizeHints.min_width = width; + sizeHints.max_width = width; + sizeHints.min_height = height; + sizeHints.max_height = height; } // Set the WM hints of the normal state - xcb_icccm_set_wm_normal_hints(m_connection, m_window, &sizeHints); + setWMSizeHints(sizeHints); // Set the window's WM class (this can be used by window managers) // The WM_CLASS property actually consists of 2 parts, @@ -508,7 +621,8 @@ m_fullscreen ((style & Style::Fullscreen) != 0) windowClass += title.toAnsiString(); // We add 1 to the size of the string to include the null at the end - xcb_icccm_set_wm_class_checked(m_connection, m_window, windowClass.size() + 1, windowClass.c_str()); + 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; // Set the window's name setTitle(title); @@ -539,7 +653,6 @@ WindowImplX11::~WindowImplX11() // Destroy the input context if (m_inputContext) XDestroyIC(m_inputContext); - // Destroy the window if (m_window && !m_isExternal) { @@ -547,17 +660,10 @@ WindowImplX11::~WindowImplX11() xcb_flush(m_connection); } - // Free key symbols - if (m_keySymbols) - xcb_key_symbols_free(m_keySymbols); - // Close the input method if (m_inputMethod) XCloseIM(m_inputMethod); - // Clean up the EWMH connection - xcb_ewmh_connection_wipe(&m_ewmhConnection); - // Close the connection with the X server CloseDisplay(m_display); @@ -737,22 +843,16 @@ 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 ) { - xcb_size_hints_t sizeHints; + WMSizeHints sizeHints; std::memset(&sizeHints, 0, sizeof(sizeHints)); - xcb_icccm_size_hints_set_min_size(&sizeHints, size.x, size.y); - xcb_icccm_size_hints_set_max_size(&sizeHints, size.x, size.y); - ScopedXcbPtr configureWindowError(xcb_request_check( - m_connection, - xcb_icccm_set_wm_normal_hints( - m_connection, - m_window, - &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; - if (configureWindowError) - err() << "Failed to set window size hints" << std::endl; + setWMSizeHints(sizeHints); } uint32_t values[] = {size.x, size.y}; @@ -778,66 +878,36 @@ void WindowImplX11::setSize(const Vector2u& size) void WindowImplX11::setTitle(const String& title) { // XCB takes UTF-8-encoded strings. + xcb_atom_t utf8StringType = getAtom("UTF8_STRING"); + + if (!utf8StringType) + utf8StringType = XCB_ATOM_STRING; + std::string utf8String; Utf<32>::toUtf8(title.begin(), title.end(), std::back_inserter(utf8String)); - ScopedXcbPtr wmNameError(xcb_request_check( - m_connection, - xcb_icccm_set_wm_name_checked( - m_connection, - m_window, - XCB_ATOM_STRING, - sizeof(std::basic_string::value_type) * 8, - utf8String.length(), - utf8String.c_str() - ) - )); - - if (wmNameError) + if (!changeWindowProperty(XCB_ATOM_WM_NAME, utf8StringType, 8, utf8String.length(), utf8String.c_str())) err() << "Failed to set window title" << std::endl; - ScopedXcbPtr wmIconNameError(xcb_request_check( - m_connection, - xcb_icccm_set_wm_icon_name_checked( - m_connection, - m_window, - XCB_ATOM_STRING, - sizeof(std::basic_string::value_type) * 8, - utf8String.length(), - utf8String.c_str() - ) - )); - - if (wmIconNameError) + if (!changeWindowProperty(XCB_ATOM_WM_ICON_NAME, utf8StringType, 8, utf8String.length(), utf8String.c_str())) err() << "Failed to set WM_ICON_NAME property" << std::endl; if (ewmhSupported()) { - ScopedXcbPtr ewmhNameError(xcb_request_check( - m_connection, - xcb_ewmh_set_wm_name_checked( - &m_ewmhConnection, - m_window, - utf8String.length(), - utf8String.c_str() - ) - )); + xcb_atom_t netWmName = getAtom("_NET_WM_NAME", true); + xcb_atom_t netWmIconName = getAtom("_NET_WM_ICON_NAME", true); - if (ewmhNameError) - err() << "Failed to set _NET_WM_NAME property" << std::endl; + if (utf8StringType && netWmName) + { + if (!changeWindowProperty(netWmName, utf8StringType, 8, utf8String.length(), utf8String.c_str())) + err() << "Failed to set _NET_WM_NAME property" << std::endl; + } - ScopedXcbPtr ewmhIconNameError(xcb_request_check( - m_connection, - xcb_ewmh_set_wm_icon_name_checked( - &m_ewmhConnection, - m_window, - utf8String.length(), - utf8String.c_str() - ) - )); - - if (ewmhIconNameError) - err() << "Failed to set _NET_WM_ICON_NAME property" << std::endl; + if (utf8StringType && netWmName) + { + 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); @@ -969,25 +1039,13 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8 ); // Send our new icon to the window through the WMHints - xcb_icccm_wm_hints_t hints; + WMHints hints; std::memset(&hints, 0, sizeof(hints)); - xcb_icccm_wm_hints_set_icon_pixmap(&hints, iconPixmap); - xcb_icccm_wm_hints_set_icon_mask(&hints, maskPixmap); + hints.flags |= ((1 << 2) | (1 << 5)); + hints.icon_pixmap = iconPixmap; + hints.icon_mask = maskPixmap; - ScopedXcbPtr setWmHintsError(xcb_request_check( - m_connection, - xcb_icccm_set_wm_hints( - m_connection, - m_window, - &hints - ) - )); - - if (setWmHintsError) - { - err() << "Failed to set the window's icon (icccm_set_wm_hints): "; - err() << "Error code " << static_cast(setWmHintsError->error_code) << std::endl; - } + setWMHints(hints); xcb_flush(m_connection); @@ -1090,6 +1148,8 @@ 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( @@ -1098,10 +1158,10 @@ void WindowImplX11::requestFocus() m_connection, m_window ), - NULL + &error )); - if (!attributes) + if (error || !attributes) { err() << "Failed to check if window is viewable while requesting focus" << std::endl; return; // error getting attribute @@ -1118,23 +1178,30 @@ void WindowImplX11::requestFocus() else { // Get current WM hints. - xcb_icccm_wm_hints_t hints; - std::memset(&hints, 0, sizeof(hints)); - - xcb_icccm_get_wm_hints_reply( + ScopedXcbPtr hintsReply(xcb_get_property_reply( m_connection, - xcb_icccm_get_wm_hints_unchecked( - m_connection, - m_window - ), - &hints, - NULL - ); + xcb_get_property(m_connection, 0, m_window, XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 0, 9), + &error + )); + + 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. - xcb_icccm_wm_hints_set_urgency(&hints); - xcb_icccm_set_wm_hints_checked(m_connection, m_window, &hints); + hints->flags |= (1 << 8); + setWMHints(*hints); } } @@ -1162,25 +1229,38 @@ bool WindowImplX11::hasFocus() const //////////////////////////////////////////////////////////// void WindowImplX11::grabFocus() { + xcb_atom_t netActiveWindow = XCB_ATOM_NONE; + if (ewmhSupported()) + netActiveWindow = getAtom("_NET_ACTIVE_WINDOW"); + + if (netActiveWindow) { + xcb_client_message_event_t 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 + ScopedXcbPtr activeWindowError(xcb_request_check( m_connection, - xcb_ewmh_request_change_active_window( - &m_ewmhConnection, - XDefaultScreen(m_display), - m_window, - XCB_EWMH_CLIENT_SOURCE_TYPE_NORMAL, - XCB_CURRENT_TIME, - None + xcb_send_event_checked( + m_connection, + 0, + XCBDefaultRootWindow(m_connection), + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, + reinterpret_cast(&event) ) )); if (activeWindowError) - { - err() << "Failed to change active window (request_change_active_window)" << std::endl; - return; - } + err() << "Setting fullscreen failed, could not send \"_NET_ACTIVE_WINDOW\" event" << std::endl; } else { @@ -1360,58 +1440,52 @@ void WindowImplX11::switchToFullscreen() if (ewmhSupported()) { - // Create atom for _NET_WM_BYPASS_COMPOSITOR. - static const std::string netWmStateBypassCompositor = "_NET_WM_BYPASS_COMPOSITOR"; - ScopedXcbPtr compReply(xcb_intern_atom_reply( - m_connection, - xcb_intern_atom( - m_connection, - False, - netWmStateBypassCompositor.size(), - netWmStateBypassCompositor.c_str() - ), - 0 - )); + xcb_atom_t netWmBypassCompositor = getAtom("_NET_WM_BYPASS_COMPOSITOR"); - static const Uint32 bypassCompositor = 1; + if (netWmBypassCompositor) + { + static const Uint32 bypassCompositor = 1; - // Disable compositor. - ScopedXcbPtr compositorError(xcb_request_check( - m_connection, - xcb_change_property_checked( - m_connection, - XCB_PROP_MODE_REPLACE, - m_window, - compReply->atom, - XCB_ATOM_CARDINAL, - 32, - 1, - &bypassCompositor - ) - )); + // 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; + } - // Not being able to bypass the compositor is not a fatal error - if (compositorError) - err() << "xcb_change_property failed, unable to set _NET_WM_BYPASS_COMPOSITOR" << std::endl; + xcb_atom_t netWmState = getAtom("_NET_WM_STATE", true); + xcb_atom_t netWmStateFullscreen = getAtom("_NET_WM_STATE_FULLSCREEN", true); + + if (!netWmState || !netWmStateFullscreen) + { + err() << "Setting fullscreen failed. Could not get required atoms" << std::endl; + return; + } + + xcb_client_message_event_t 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 ScopedXcbPtr wmStateError(xcb_request_check( m_connection, - xcb_ewmh_request_change_wm_state( - &m_ewmhConnection, - XDefaultScreen(m_display), - m_window, - XCB_EWMH_WM_STATE_ADD, - m_ewmhConnection._NET_WM_STATE_FULLSCREEN, + xcb_send_event_checked( + m_connection, 0, - XCB_EWMH_CLIENT_SOURCE_TYPE_NORMAL + XCBDefaultRootWindow(m_connection), + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, + reinterpret_cast(&event) ) )); if (wmStateError) - { - err() << "Setting fullscreen failed, could not change WM state" << std::endl; - return; - } + err() << "Setting fullscreen failed. Could not send \"_NET_WM_STATE\" event" << std::endl; } } @@ -1419,83 +1493,48 @@ void WindowImplX11::switchToFullscreen() //////////////////////////////////////////////////////////// void WindowImplX11::setProtocols() { - ScopedXcbPtr error(NULL); + xcb_atom_t wmProtocols = getAtom("WM_PROTOCOLS"); + xcb_atom_t wmDeleteWindow = getAtom("WM_DELETE_WINDOW"); - // Get the atom for setting the window protocols we support - static const std::string WM_PROTOCOLS_NAME = "WM_PROTOCOLS"; - ScopedXcbPtr protocolsAtomReply(xcb_intern_atom_reply( - m_connection, - xcb_intern_atom( - m_connection, - 0, - WM_PROTOCOLS_NAME.size(), - WM_PROTOCOLS_NAME.c_str() - ), - &error - )); - - if (error || !protocolsAtomReply) + if (!wmProtocols) { err() << "Failed to request WM_PROTOCOLS atom." << std::endl; return; } - m_atomWmProtocols = protocolsAtomReply->atom; - std::vector atoms; - // Get the atom for registering the close event - static const std::string WM_DELETE_WINDOW_NAME = "WM_DELETE_WINDOW"; - ScopedXcbPtr deleteWindowAtomReply(xcb_intern_atom_reply( - m_connection, - xcb_intern_atom( - m_connection, - 0, - WM_DELETE_WINDOW_NAME.size(), - WM_DELETE_WINDOW_NAME.c_str() - ), - &error - )); - - if (!error && deleteWindowAtomReply) + if (wmDeleteWindow) { - atoms.push_back(deleteWindowAtomReply->atom); - m_atomClose = deleteWindowAtomReply->atom; + atoms.push_back(wmDeleteWindow); } else { err() << "Failed to request WM_DELETE_WINDOW atom." << std::endl; } - if (ewmhSupported() && m_ewmhConnection._NET_WM_PING && m_ewmhConnection._NET_WM_PID) - { - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_ewmh_set_wm_pid( - &m_ewmhConnection, - m_window, - getpid() - ) - )); + xcb_atom_t netWmPing = XCB_ATOM_NONE; + xcb_atom_t netWmPid = XCB_ATOM_NONE; - if (!error) - atoms.push_back(m_ewmhConnection._NET_WM_PING); + if (ewmhSupported()) + { + netWmPing = getAtom("_NET_WM_PING", true); + 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); } if (!atoms.empty()) { - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_icccm_set_wm_protocols( - m_connection, - m_window, - protocolsAtomReply->atom, - atoms.size(), - &atoms[0] - ) - )); - - if (error) + if (!changeWindowProperty(wmProtocols, XCB_ATOM_ATOM, 32, atoms.size(), &atoms[0])) err() << "Failed to set window protocols" << std::endl; } else @@ -1542,7 +1581,7 @@ void WindowImplX11::setMotifHints(unsigned long style) static const unsigned long MWM_FUNC_MAXIMIZE = 1 << 4; static const unsigned long MWM_FUNC_CLOSE = 1 << 5; - struct WMHints + struct MotifWMHints { uint32_t flags; uint32_t functions; @@ -1551,7 +1590,7 @@ void WindowImplX11::setMotifHints(unsigned long style) uint32_t state; }; - WMHints hints; + MotifWMHints hints; hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; hints.decorations = 0; hints.functions = 0; @@ -1578,21 +1617,7 @@ void WindowImplX11::setMotifHints(unsigned long style) } } - ScopedXcbPtr propertyError(xcb_request_check( - m_connection, - xcb_change_property_checked( - m_connection, - XCB_PROP_MODE_REPLACE, - m_window, - hintsAtomReply->atom, - hintsAtomReply->atom, - sizeof(hints.flags) * 8, - sizeof(hints) / sizeof(hints.flags), - reinterpret_cast(&hints) - ) - )); - - if (propertyError) + if (!changeWindowProperty(hintsAtomReply->atom, hintsAtomReply->atom, 32, 5, &hints)) err() << "xcb_change_property failed, could not set window hints" << std::endl; } else @@ -1602,6 +1627,43 @@ void WindowImplX11::setMotifHints(unsigned long style) } +//////////////////////////////////////////////////////////// +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() { @@ -1629,12 +1691,6 @@ 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; - // Allocate our key symbols - m_keySymbols = xcb_key_symbols_alloc(m_connection); - - if (!m_keySymbols) - err() << "Failed to allocate key symbols" << std::endl; - // Show the window setVisible(true); @@ -1754,40 +1810,32 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent) pushEvent(event); // If the window has been previously marked urgent (notification) as a result of a focus request, undo that - xcb_icccm_wm_hints_t hints; - ScopedXcbPtr error(NULL); - uint8_t result = xcb_icccm_get_wm_hints_reply( + ScopedXcbPtr hintsReply(xcb_get_property_reply( m_connection, - xcb_icccm_get_wm_hints_unchecked( - m_connection, - m_window - ), - &hints, + xcb_get_property(m_connection, 0, m_window, XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 0, 9), &error - ); + )); - if (!result || error) + if (error || !hintsReply) + { + err() << "Failed to get WM hints in XCB_FOCUS_IN" << std::endl; + break; + } + + 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 &= ~XCB_ICCCM_WM_HINT_X_URGENCY; + hints->flags &= ~(1 << 8); - ScopedXcbPtr setWmHintsError(xcb_request_check( - m_connection, - xcb_icccm_set_wm_hints_checked( - m_connection, - m_window, - &hints - ) - )); - - if (setWmHintsError) - err() << "Failed to set WM hints in XCB_FOCUS_IN" << std::endl; + setWMHints(*hints); break; } @@ -1831,17 +1879,22 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent) xcb_client_message_event_t* e = reinterpret_cast(windowEvent); + static xcb_atom_t wmProtocols = getAtom("WM_PROTOCOLS"); + // Handle window manager protocol messages we support - if (e->type == m_atomWmProtocols) + if (e->type == wmProtocols) { - if ((e->format == 32) && (e->data.data32[0]) == static_cast(m_atomClose)) + static xcb_atom_t wmDeleteWindow = getAtom("WM_DELETE_WINDOW"); + static xcb_atom_t netWmPing = ewmhSupported() ? getAtom("_NET_WM_PING", true) : XCB_ATOM_NONE; + + if ((e->format == 32) && (e->data.data32[0]) == static_cast(wmDeleteWindow)) { // Handle the WM_DELETE_WINDOW message Event event; event.type = Event::Closed; pushEvent(event); } - else if (ewmhSupported() && (e->format == 32) && (e->data.data32[0]) == static_cast(m_ewmhConnection._NET_WM_PING)) + else if (netWmPing && (e->format == 32) && (e->data.data32[0]) == static_cast(netWmPing)) { // Handle the _NET_WM_PING message, send pong back to WM to show that we are responsive e->window = XCBDefaultRootWindow(m_connection); @@ -1872,15 +1925,11 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent) xcb_key_press_event_t* e = reinterpret_cast(windowEvent); - // Get the keysym of the key that has been pressed - // We don't pass e->state as the last parameter because we want the unmodified keysym - xcb_keysym_t symbol = xcb_key_press_lookup_keysym(m_keySymbols, e, 0); - // Fill the event parameters // TODO: if modifiers are wrong, use XGetModifierMapping to retrieve the actual modifiers mapping Event event; event.type = Event::KeyPressed; - event.key.code = keysymToSF(symbol); + event.key.code = keycodeToSF(e->detail); event.key.alt = e->state & XCB_MOD_MASK_1; event.key.control = e->state & XCB_MOD_MASK_CONTROL; event.key.shift = e->state & XCB_MOD_MASK_SHIFT; @@ -1951,14 +2000,10 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent) xcb_key_release_event_t* e = reinterpret_cast(windowEvent); - // Get the keysym of the key that has been pressed - // We don't pass e->state as the last parameter because we want the unmodified keysym - xcb_keysym_t symbol = xcb_key_release_lookup_keysym(m_keySymbols, e, 0); - // Fill the event parameters Event event; event.type = Event::KeyReleased; - event.key.code = keysymToSF(symbol); + event.key.code = keycodeToSF(e->detail); event.key.alt = e->state & XCB_MOD_MASK_1; event.key.control = e->state & XCB_MOD_MASK_CONTROL; event.key.shift = e->state & XCB_MOD_MASK_SHIFT; @@ -2215,7 +2260,7 @@ bool WindowImplX11::passEvent(xcb_generic_event_t* windowEvent, xcb_window_t win if (allWindows.size() == 1) return false; - for (std::vector::iterator i = allWindows.begin(); i != allWindows.end(); ++i) + for (std::vector::iterator i = allWindows.begin(); i != allWindows.end(); ++i) { if ((*i)->m_window == window) { @@ -2228,123 +2273,6 @@ bool WindowImplX11::passEvent(xcb_generic_event_t* windowEvent, xcb_window_t win return false; } - -//////////////////////////////////////////////////////////// -Keyboard::Key WindowImplX11::keysymToSF(xcb_keysym_t symbol) -{ - // First convert to uppercase (to avoid dealing with two different keysyms for the same key) - KeySym lower, key; - XConvertCase(symbol, &lower, &key); - - switch (key) - { - case XK_Shift_L: return Keyboard::LShift; - case XK_Shift_R: return Keyboard::RShift; - case XK_Control_L: return Keyboard::LControl; - case XK_Control_R: return Keyboard::RControl; - case XK_Alt_L: return Keyboard::LAlt; - case XK_Alt_R: return Keyboard::RAlt; - case XK_Super_L: return Keyboard::LSystem; - case XK_Super_R: return Keyboard::RSystem; - case XK_Menu: return Keyboard::Menu; - case XK_Escape: return Keyboard::Escape; - case XK_semicolon: return Keyboard::SemiColon; - case XK_slash: return Keyboard::Slash; - case XK_equal: return Keyboard::Equal; - case XK_minus: return Keyboard::Dash; - case XK_bracketleft: return Keyboard::LBracket; - case XK_bracketright: return Keyboard::RBracket; - case XK_comma: return Keyboard::Comma; - case XK_period: return Keyboard::Period; - case XK_apostrophe: return Keyboard::Quote; - case XK_backslash: return Keyboard::BackSlash; - case XK_grave: return Keyboard::Tilde; - case XK_space: return Keyboard::Space; - case XK_Return: return Keyboard::Return; - case XK_KP_Enter: return Keyboard::Return; - case XK_BackSpace: return Keyboard::BackSpace; - case XK_Tab: return Keyboard::Tab; - case XK_Prior: return Keyboard::PageUp; - case XK_Next: return Keyboard::PageDown; - case XK_End: return Keyboard::End; - case XK_Home: return Keyboard::Home; - case XK_Insert: return Keyboard::Insert; - case XK_Delete: return Keyboard::Delete; - case XK_KP_Add: return Keyboard::Add; - case XK_KP_Subtract: return Keyboard::Subtract; - case XK_KP_Multiply: return Keyboard::Multiply; - case XK_KP_Divide: return Keyboard::Divide; - case XK_Pause: return Keyboard::Pause; - case XK_F1: return Keyboard::F1; - case XK_F2: return Keyboard::F2; - case XK_F3: return Keyboard::F3; - case XK_F4: return Keyboard::F4; - case XK_F5: return Keyboard::F5; - case XK_F6: return Keyboard::F6; - case XK_F7: return Keyboard::F7; - case XK_F8: return Keyboard::F8; - case XK_F9: return Keyboard::F9; - case XK_F10: return Keyboard::F10; - case XK_F11: return Keyboard::F11; - case XK_F12: return Keyboard::F12; - case XK_F13: return Keyboard::F13; - case XK_F14: return Keyboard::F14; - case XK_F15: return Keyboard::F15; - case XK_Left: return Keyboard::Left; - case XK_Right: return Keyboard::Right; - case XK_Up: return Keyboard::Up; - case XK_Down: return Keyboard::Down; - case XK_KP_0: return Keyboard::Numpad0; - case XK_KP_1: return Keyboard::Numpad1; - case XK_KP_2: return Keyboard::Numpad2; - case XK_KP_3: return Keyboard::Numpad3; - case XK_KP_4: return Keyboard::Numpad4; - case XK_KP_5: return Keyboard::Numpad5; - case XK_KP_6: return Keyboard::Numpad6; - case XK_KP_7: return Keyboard::Numpad7; - case XK_KP_8: return Keyboard::Numpad8; - case XK_KP_9: return Keyboard::Numpad9; - case XK_A: return Keyboard::A; - case XK_Z: return Keyboard::Z; - case XK_E: return Keyboard::E; - case XK_R: return Keyboard::R; - case XK_T: return Keyboard::T; - case XK_Y: return Keyboard::Y; - case XK_U: return Keyboard::U; - case XK_I: return Keyboard::I; - case XK_O: return Keyboard::O; - case XK_P: return Keyboard::P; - case XK_Q: return Keyboard::Q; - case XK_S: return Keyboard::S; - case XK_D: return Keyboard::D; - case XK_F: return Keyboard::F; - case XK_G: return Keyboard::G; - case XK_H: return Keyboard::H; - case XK_J: return Keyboard::J; - case XK_K: return Keyboard::K; - case XK_L: return Keyboard::L; - case XK_M: return Keyboard::M; - case XK_W: return Keyboard::W; - case XK_X: return Keyboard::X; - case XK_C: return Keyboard::C; - case XK_V: return Keyboard::V; - case XK_B: return Keyboard::B; - case XK_N: return Keyboard::N; - case XK_0: return Keyboard::Num0; - case XK_1: return Keyboard::Num1; - case XK_2: return Keyboard::Num2; - case XK_3: return Keyboard::Num3; - case XK_4: return Keyboard::Num4; - case XK_5: return Keyboard::Num5; - case XK_6: return Keyboard::Num6; - case XK_7: return Keyboard::Num7; - case XK_8: return Keyboard::Num8; - case XK_9: return Keyboard::Num9; - } - - return Keyboard::Unknown; -} - } // namespace priv } // namespace sf diff --git a/src/SFML/Window/Unix/WindowImplX11.hpp b/src/SFML/Window/Unix/WindowImplX11.hpp index 65427907..2e31fbf5 100644 --- a/src/SFML/Window/Unix/WindowImplX11.hpp +++ b/src/SFML/Window/Unix/WindowImplX11.hpp @@ -32,8 +32,6 @@ #include #include #include -#include -#include #include #include @@ -182,6 +180,33 @@ 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 /// @@ -220,6 +245,36 @@ private: //////////////////////////////////////////////////////////// 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); + //////////////////////////////////////////////////////////// /// \brief Do some common initializations after the window has been created /// @@ -259,31 +314,17 @@ private: //////////////////////////////////////////////////////////// bool passEvent(xcb_generic_event_t* windowEvent, xcb_window_t window); - //////////////////////////////////////////////////////////// - /// \brief Convert a X11 keysym to SFML key code - /// - /// \param symbol Key symbol to convert - /// - /// \return Corresponding SFML key code - /// - //////////////////////////////////////////////////////////// - static Keyboard::Key keysymToSF(xcb_keysym_t symbol); - //////////////////////////////////////////////////////////// // 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_ewmh_connection_t m_ewmhConnection; ///< xcb EWMH 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 - xcb_key_symbols_t* m_keySymbols; ///< Symbols used to look up keysyms std::deque m_xcbEvents; ///< Events that were received in another window's loop bool m_isExternal; ///< Tell whether the window has been created externally or by SFML - Atom m_atomWmProtocols; ///< Atom used to identify WM protocol messages - Atom m_atomClose; ///< Atom used to identify the close event 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?