From 2983beafe5ebbe4afe0b493c53479fb2600d9f8f Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sat, 24 Nov 2018 17:26:47 +0000 Subject: [PATCH 01/17] Added searching for xcb dependency and set up of compiling the appropriate source file linking to appropriate libs. Added a null Windowing creation of Xcb_Window as a placeholder for where the Xcb functionality will be added. --- CMakeLists.txt | 17 ++++++++++++++++- src/vsg/CMakeLists.txt | 26 ++++++++++++++++---------- src/vsg/viewer/GLFW_Window.cpp | 10 ++++++++++ src/vsg/viewer/Win32_Window.cpp | 9 +++++++++ src/vsg/viewer/Window.cpp | 10 ---------- src/vsg/viewer/Xcb_Window.cpp | 22 ++++++++++++++++++++++ 6 files changed, 73 insertions(+), 21 deletions(-) create mode 100644 src/vsg/viewer/Xcb_Window.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a9b0c96ce..2dc08a402d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,8 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OUTPUT_LIBDIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_LIBDIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_BINDIR}) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/build") + SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "add a postfix, usually d on windows") SET(CMAKE_RELEASE_POSTFIX "" CACHE STRING "add a postfix, usually empty on windows") SET(CMAKE_RELWITHDEBINFO_POSTFIX "rd" CACHE STRING "add a postfix, usually empty on windows") @@ -48,9 +50,22 @@ endif() set(VSG_WARNING_FLAGS ${VSG_WARNING_FLAGS} CACHE STRING "Compiler flags to use." FORCE) add_compile_options(${VSG_WARNING_FLAGS}) -find_package(glfw3) find_package(Vulkan) +if (ANDROID) + # TODO +elseif (WIN32) + # just use native windowing +elseif (APPLE) + find_package(glfw3) +else() + find_package(glfw3) + find_package(PkgConfig) + pkg_check_modules(xcb REQUIRED IMPORTED_TARGET xcb) + option(USE_GLFW "Use GLFW for Windowing" ${GLFW_FOUND}) +endif() + + # create doxygen build target find_package(Doxygen QUIET) diff --git a/src/vsg/CMakeLists.txt b/src/vsg/CMakeLists.txt index 0a4f7f2d5b..12cdc16c8a 100644 --- a/src/vsg/CMakeLists.txt +++ b/src/vsg/CMakeLists.txt @@ -79,10 +79,24 @@ set(SOURCES ) # add platform specific Window implementation -if(WIN32) +# set up library dependancies +set(LIBRARIES PUBLIC Vulkan::Vulkan) + +if (ANDROID) + # TODO +elseif (WIN32) set(SOURCES ${SOURCES} viewer/Win32_Window.cpp) -else() +elseif (APPLE) set(SOURCES ${SOURCES} viewer/GLFW_Window.cpp) + set(LIBRARIES ${LIBRARIES} PRIVATE glfw PkgConfig::xcb) +else() + if (USE_GLFW) + set(SOURCES ${SOURCES} viewer/GLFW_Window.cpp) + set(LIBRARIES ${LIBRARIES} PRIVATE glfw) + else() + set(SOURCES ${SOURCES} viewer/Xcb_Window.cpp) + set(LIBRARIES ${LIBRARIES} PRIVATE PkgConfig::xcb) + endif() endif() @@ -142,14 +156,6 @@ set_property(TARGET vsg PROPERTY CXX_STANDARD 17) target_include_directories(vsg PUBLIC $ $) -# set up library dependancies -set(LIBRARIES PUBLIC Vulkan::Vulkan) - -if(WIN32) - set(LIBRARIES ${LIBRARIES}) -else() - set(LIBRARIES ${LIBRARIES} PRIVATE glfw) -endif() target_link_libraries(vsg ${LIBRARIES}) diff --git a/src/vsg/viewer/GLFW_Window.cpp b/src/vsg/viewer/GLFW_Window.cpp index bb3c147f8a..7335f13aad 100644 --- a/src/vsg/viewer/GLFW_Window.cpp +++ b/src/vsg/viewer/GLFW_Window.cpp @@ -18,6 +18,16 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI using namespace glfw; +namespace vsg +{ + // Provide the Window::create(...) implementation that automatically maps to a GLFW_Window + Window::Result Window::create(const Window::Traits& traits, bool debugLayer, bool apiDumpLayer, vsg::AllocationCallbacks* allocator) + { + ref_ptr window = glfw::GLFW_Window::create(traits.width, traits.height, debugLayer, apiDumpLayer, traits.shareWindow, allocator); + return Result(window); + } +} + vsg::Names glfw::getInstanceExtensions() { uint32_t glfw_count; diff --git a/src/vsg/viewer/Win32_Window.cpp b/src/vsg/viewer/Win32_Window.cpp index 5f5e720b2c..cb3552daa9 100644 --- a/src/vsg/viewer/Win32_Window.cpp +++ b/src/vsg/viewer/Win32_Window.cpp @@ -20,6 +20,15 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI using namespace vsg; using namespace vsgWin32; +namespace vsg +{ + // Provide the Window::create(...) implementation that automatically maps to a GLFW_Window + Window::Result Window::create(const Window::Traits& traits, bool debugLayer, bool apiDumpLayer, vsg::AllocationCallbacks* allocator) + { + ref_ptr window = vsgWin32::Win32_Window::create(traits, debugLayer, apiDumpLayer, allocator); + } +} + namespace vsgWin32 { const std::string kWindowClassName = "vsg_Win32_Window_Class"; diff --git a/src/vsg/viewer/Window.cpp b/src/vsg/viewer/Window.cpp index 252e4dbd33..c26f2a44d9 100644 --- a/src/vsg/viewer/Window.cpp +++ b/src/vsg/viewer/Window.cpp @@ -173,14 +173,4 @@ namespace vsg return create(traits, debugLayer, apiDumpLayer, allocator); } - Window::Result Window::create(const Window::Traits& traits, bool debugLayer, bool apiDumpLayer, vsg::AllocationCallbacks* allocator) - { -#ifdef _WIN32 - ref_ptr window = vsgWin32::Win32_Window::create(traits, debugLayer, apiDumpLayer, allocator); -#else - ref_ptr window = glfw::GLFW_Window::create(traits.width, traits.height, debugLayer, apiDumpLayer, traits.shareWindow, allocator); -#endif - return Result(window); - } - } // namespace vsg diff --git a/src/vsg/viewer/Xcb_Window.cpp b/src/vsg/viewer/Xcb_Window.cpp new file mode 100644 index 0000000000..5bc87272a4 --- /dev/null +++ b/src/vsg/viewer/Xcb_Window.cpp @@ -0,0 +1,22 @@ +/* + +Copyright(c) 2018 Robert Osfield + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + +#include + +namespace vsg +{ + // Provide the Window::create(...) implementation that automatically maps to a Xcb_Window + Window::Result Window::create(const Window::Traits& traits, bool debugLayer, bool apiDumpLayer, vsg::AllocationCallbacks* allocator) + { + return Result("Failed to created Window, no Xcb implementation yet.", VK_ERROR_INVALID_EXTERNAL_HANDLE); + } +} From b8ea5170b90b3442e7b04855996efcc089494d8e Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sat, 24 Nov 2018 17:39:56 +0000 Subject: [PATCH 02/17] Removed unneccessary setting of cmke module path. Added Xcb find to vsgConfig.cmake --- CMakeLists.txt | 2 -- src/vsg/vsgConfig.cmake | 11 ++++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2dc08a402d..423eea5f83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,8 +18,6 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OUTPUT_LIBDIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_LIBDIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_BINDIR}) -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/build") - SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "add a postfix, usually d on windows") SET(CMAKE_RELEASE_POSTFIX "" CACHE STRING "add a postfix, usually empty on windows") SET(CMAKE_RELWITHDEBINFO_POSTFIX "rd" CACHE STRING "add a postfix, usually empty on windows") diff --git a/src/vsg/vsgConfig.cmake b/src/vsg/vsgConfig.cmake index 4211d59203..0a2383e05e 100644 --- a/src/vsg/vsgConfig.cmake +++ b/src/vsg/vsgConfig.cmake @@ -2,8 +2,17 @@ include(CMakeFindDependencyMacro) find_dependency(Vulkan) -if(NOT WIN32) +if (ANDROID) + # TODO +elseif (WIN32) + # just use native windowing +elseif (APPLE) find_dependency(glfw3) +else() + find_dependency(glfw3) + + find_package(PkgConfig) + pkg_check_modules(xcb REQUIRED IMPORTED_TARGET xcb) endif() include("${CMAKE_CURRENT_LIST_DIR}/vsgTargets.cmake") From a84b82059d68681b9e439d4e6d54fa3d05ef3135 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sat, 24 Nov 2018 17:50:31 +0000 Subject: [PATCH 03/17] Set the USE_GLFW to default to OFF. Removed the unneccessary includes from Window.cpp --- CMakeLists.txt | 2 +- src/vsg/viewer/Window.cpp | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 423eea5f83..3269f6c78e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,7 +60,7 @@ else() find_package(glfw3) find_package(PkgConfig) pkg_check_modules(xcb REQUIRED IMPORTED_TARGET xcb) - option(USE_GLFW "Use GLFW for Windowing" ${GLFW_FOUND}) + option(USE_GLFW "Use GLFW for Windowing" OFF) endif() diff --git a/src/vsg/viewer/Window.cpp b/src/vsg/viewer/Window.cpp index c26f2a44d9..0627f1880d 100644 --- a/src/vsg/viewer/Window.cpp +++ b/src/vsg/viewer/Window.cpp @@ -16,12 +16,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include -#ifdef _WIN32 -# include "Win32_Window.h" -#else -# include "GLFW_Window.h" -#endif - namespace vsg { From 8b75f08fbb480b81e2c069c90472bd7d582a8989 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 27 Nov 2018 19:22:06 +0000 Subject: [PATCH 04/17] Experiments with Xcb window creation and basic event handling --- CMakeLists.txt | 2 + include/vsg/viewer/Window.h | 8 +- src/vsg/CMakeLists.txt | 3 +- src/vsg/viewer/Win32_Window.cpp | 8 +- src/vsg/viewer/Xcb_Window.cpp | 374 +++++++++++++++++++++++++++++++- src/vsg/viewer/Xcb_Window.h | 178 +++++++++++++++ src/vsg/vsgConfig.cmake | 1 + 7 files changed, 563 insertions(+), 11 deletions(-) create mode 100644 src/vsg/viewer/Xcb_Window.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3269f6c78e..cc28f36456 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,8 @@ elseif (APPLE) find_package(glfw3) else() find_package(glfw3) + + find_package(X11) find_package(PkgConfig) pkg_check_modules(xcb REQUIRED IMPORTED_TARGET xcb) option(USE_GLFW "Use GLFW for Windowing" OFF) diff --git a/include/vsg/viewer/Window.h b/include/vsg/viewer/Window.h index 055d8718ad..2d7b9e08d8 100644 --- a/include/vsg/viewer/Window.h +++ b/include/vsg/viewer/Window.h @@ -32,13 +32,15 @@ namespace vsg struct Traits { - uint32_t x = 0; - uint32_t y = 0; + uint32_t x = 100; + uint32_t y = 100; uint32_t width = 800; uint32_t height = 600; uint32_t screenNum = 0; - std::string title = "vsg window"; + std::string windowClass = "vsg::Window"; + std::string windowTitle = "vsg window"; + bool decoration = true; Window* shareWindow = nullptr; diff --git a/src/vsg/CMakeLists.txt b/src/vsg/CMakeLists.txt index 12cdc16c8a..eead0a8882 100644 --- a/src/vsg/CMakeLists.txt +++ b/src/vsg/CMakeLists.txt @@ -88,7 +88,7 @@ elseif (WIN32) set(SOURCES ${SOURCES} viewer/Win32_Window.cpp) elseif (APPLE) set(SOURCES ${SOURCES} viewer/GLFW_Window.cpp) - set(LIBRARIES ${LIBRARIES} PRIVATE glfw PkgConfig::xcb) + set(LIBRARIES ${LIBRARIES} PRIVATE glfw) else() if (USE_GLFW) set(SOURCES ${SOURCES} viewer/GLFW_Window.cpp) @@ -96,6 +96,7 @@ else() else() set(SOURCES ${SOURCES} viewer/Xcb_Window.cpp) set(LIBRARIES ${LIBRARIES} PRIVATE PkgConfig::xcb) + set(LIBRARIES ${LIBRARIES} PRIVATE ${X11_LIBRARIES}) endif() endif() diff --git a/src/vsg/viewer/Win32_Window.cpp b/src/vsg/viewer/Win32_Window.cpp index 9e32bcba8f..d25fad9016 100644 --- a/src/vsg/viewer/Win32_Window.cpp +++ b/src/vsg/viewer/Win32_Window.cpp @@ -31,8 +31,6 @@ namespace vsg namespace vsgWin32 { - const std::string kWindowClassName = "vsg_Win32_Window_Class"; - vsg::Names vsgWin32::getInstanceExtensions() { // check the extensions are avaliable first @@ -104,7 +102,7 @@ Win32_Window::Result Win32_Window::create(const Traits& traits, bool debugLayer, wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = 0; wc.lpszMenuName = 0; - wc.lpszClassName = kWindowClassName.c_str(); + wc.lpszClassName = traits.windowClass.c_str(); wc.hIconSm = 0; if (::RegisterClassEx(&wc) == 0) @@ -151,7 +149,7 @@ Win32_Window::Result Win32_Window::create(const Traits& traits, bool debugLayer, if (!::AdjustWindowRectEx(&windowRect, windowStyle, FALSE, extendedStyle)) return Result("Error: vsg::Win32_Window::create(...) failed to create Window, AdjustWindowRectEx failed.", VK_ERROR_INVALID_EXTERNAL_HANDLE); // create the window - hwnd = ::CreateWindowEx(extendedStyle, kWindowClassName.c_str(), traits.title.c_str(), windowStyle, + hwnd = ::CreateWindowEx(extendedStyle, traits.windowClass.c_str(), traits.windowTitle.c_str(), windowStyle, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, NULL, NULL, ::GetModuleHandle(NULL), NULL); @@ -246,7 +244,7 @@ Win32_Window::~Win32_Window() _window = nullptr; // when should we unregister?? - ::UnregisterClass(kWindowClassName.c_str(), ::GetModuleHandle(NULL)); + ::UnregisterClass(traits.windowClass.c_str(), ::GetModuleHandle(NULL)); } } diff --git a/src/vsg/viewer/Xcb_Window.cpp b/src/vsg/viewer/Xcb_Window.cpp index 5bc87272a4..34f9765788 100644 --- a/src/vsg/viewer/Xcb_Window.cpp +++ b/src/vsg/viewer/Xcb_Window.cpp @@ -10,13 +10,383 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ -#include +#include "Xcb_Window.h" + +#include + +#include + +#include + +#include +#include +#include namespace vsg { // Provide the Window::create(...) implementation that automatically maps to a Xcb_Window Window::Result Window::create(const Window::Traits& traits, bool debugLayer, bool apiDumpLayer, vsg::AllocationCallbacks* allocator) { - return Result("Failed to created Window, no Xcb implementation yet.", VK_ERROR_INVALID_EXTERNAL_HANDLE); + return xcb::Xcb_Window::create(traits, debugLayer, apiDumpLayer, allocator); } } + +using namespace vsg; +using namespace xcb; + +// reference +// https://harrylovescode.gitbooks.io/vulkan-api/content/chap04/chap04-linux.html + +vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bool apiDumpLayer, vsg::AllocationCallbacks* allocator) +{ + std::cout<<"Xcb_Window() "<0; --screenNum) xcb_screen_next(&screen_iterator); + settings._screen = screen_iterator.data; + std::cout<<" selected screen "< stateAtoms{ wmFullScreen }; + + xcb_change_property(settings._connection, XCB_PROP_MODE_REPLACE, settings._window, wmState, XCB_ATOM_ATOM, 32, stateAtoms.size(), stateAtoms.data()); + + std::cout<<"Set up full screen"< actionAtoms + { + wmActionFullScreen + }; + + xcb_change_property(settings._connection, XCB_PROP_MODE_REPLACE, settings._window, wmAllowedActions, XCB_ATOM_ATOM, 32, actionAtoms.size(), actionAtoms.data()); + +#endif + + std::cout<<"Create window : "< windows; + windows["main"] = settings._window; + + xcb_query_tree_cookie_t tree_cookie = xcb_query_tree(settings._connection, settings._window); + xcb_query_tree_reply_t* tree_reply = xcb_query_tree_reply(settings._connection, tree_cookie, nullptr); + + xcb_drawable_t root{}; + + if (tree_reply!=nullptr) + { + root = tree_reply->root; + + windows["parent"] = tree_reply->parent; + + std::cout<<"number children = "<children_len<x; + y = geometry_reply->y; + width = geometry_reply->width; + height = geometry_reply->height; + + std::cout<<" geometry_rely : "<dst_x = "<dst_x<<", trans->dst_y = "<dst_y<response_type & ~0x80; + switch(response_type) + { + case(XCB_EXPOSE): + { + auto expose = reinterpret_cast(event); + std::cout<<"expose "<window<<", "<x<<", "<y<<", "<width<<", "<height<(event); + if (client_message->data.data32[0]==settings._wmDeleteWindow) + { + std::cout<<"client message "<data.data32[0]<root_y<<", "<event_x<<", "<event_y<<", state="<state<root_y<<", "<event_x<<", "<event_y<<", state="<state< + +#include + +#include + +namespace xcb +{ + +struct Settings +{ + xcb_connection_t* _connection = nullptr; + xcb_screen_t* _screen = nullptr; + xcb_window_t _window{}; + xcb_atom_t _wmProtocols{}; + xcb_atom_t _wmDeleteWindow{}; +}; + + + // window decoation + struct MotifHints + { + enum Flags : uint32_t + { + FLAGS_FUNCTIONS = 1<<0, + FLAGS_DECORATIONS = 1<<1, + FLAGS_INPUT_MODE = 1<<2, + FLAGS_STATUS = 1<<3, + }; + + enum Functions : uint32_t + { + FUNC_ALL = 1<<0, + FUNC_RESIZE = 1<<1, + FUNC_MOVE = 1<<2, + FUNC_MINIMUMSIZE = 1<<3, + FUNC_MAXIMUMSIZE = 1<<4, + FUNC_CLOSE = 1<<5 + }; + + enum Decorations : uint32_t + { + DECOR_ALL = 1<<0, + DECOR_BORDER = 1<<1, + DECOR_RESIZE = 1<<2, + DECOR_TITLE = 1<<3, + DECOR_MENU = 1<<4, + DECOR_MINIMUMSIZE = 1<<5, + DECOR_MAXIMUMSIZE = 1<<6 + }; + + static MotifHints borderless() + { + MotifHints hints; + hints.flags = FLAGS_DECORATIONS; + return hints; + } + + static MotifHints window(bool resize=true, bool move=true, bool close=true) + { + MotifHints hints; + hints.flags = FLAGS_DECORATIONS | FLAGS_FUNCTIONS; + hints.functions = 0; + if (resize) hints.functions |= FUNC_RESIZE; + if (move) hints.functions |= FUNC_MOVE; + if (close) hints.functions |= FUNC_CLOSE; + hints.decorations = DECOR_ALL; + return hints; + } + + + uint32_t flags{}; + uint32_t functions{}; + uint32_t decorations{}; + int32_t input_mode{}; + uint32_t status{}; + }; + + class AtomRequest + { + public: + AtomRequest(xcb_connection_t* connection, const char* atom_name): + _connection(connection) + { + _cookie = xcb_intern_atom(connection, false, strlen(atom_name), atom_name); + } + + operator xcb_atom_t () + { + if (_connection) + { + xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(_connection, _cookie, nullptr); + if (reply) + { + _atom = reply->atom; + free(reply); + } + _connection = nullptr; + } + return _atom; + } + + xcb_connection_t* _connection{}; + xcb_intern_atom_cookie_t _cookie{}; + xcb_atom_t _atom{}; + }; + + bool getWindowGeometry(xcb_connection_t* connection, xcb_drawable_t window, int32_t& x, int32_t& y, uint32_t& width, uint32_t& height) + { + xcb_get_geometry_cookie_t geometry_cookie = xcb_get_geometry(connection, window); + xcb_query_tree_cookie_t tree_cookie = xcb_query_tree(connection, window); + + xcb_get_geometry_reply_t* geometry_reply = xcb_get_geometry_reply(connection, geometry_cookie, nullptr); + xcb_query_tree_reply_t* tree_reply = xcb_query_tree_reply(connection, tree_cookie, nullptr); + + if (geometry_reply) + { + x = geometry_reply->x; + y = geometry_reply->y; + width = geometry_reply->width; + height = geometry_reply->height; + + if (tree_reply) + { + xcb_translate_coordinates_cookie_t trans_cookie = xcb_translate_coordinates(connection, window, tree_reply->parent, x, y); + xcb_translate_coordinates_reply_t* trans_reply = xcb_translate_coordinates_reply(connection, trans_cookie, nullptr); + if (trans_reply) + { + std::cout<<"trans->dst_x = "<dst_x<<", trans->dst_y = "<dst_y<root, x, y); + trans_reply = xcb_translate_coordinates_reply(connection, trans_cookie, nullptr); + if (trans_reply) + { + std::cout<<"2nd trans->dst_x = "<dst_x<<", trans->dst_y = "<dst_y< Date: Wed, 28 Nov 2018 19:28:34 +0000 Subject: [PATCH 05/17] Added an experimental KeyboardMap class for mapping raw keycodes to key symbols --- src/vsg/viewer/Xcb_Window.cpp | 86 +++++++++- src/vsg/viewer/Xcb_Window.h | 307 +++++++++++++++++++++++++++++++++- 2 files changed, 384 insertions(+), 9 deletions(-) diff --git a/src/vsg/viewer/Xcb_Window.cpp b/src/vsg/viewer/Xcb_Window.cpp index 34f9765788..3c829a2696 100644 --- a/src/vsg/viewer/Xcb_Window.cpp +++ b/src/vsg/viewer/Xcb_Window.cpp @@ -34,6 +34,25 @@ namespace vsg using namespace vsg; using namespace xcb; +KeyboardMap::KeyboardMap() +{ + _modifierMask=0xff; +} + +void KeyboardMap::add(uint16_t keycode, uint16_t modifier, KeySymbol key) +{ + //std::cout<<"Added ["< > combinations) +{ + for(auto [modifier, key] : combinations) + { + add(keycode, modifier, key); + } +} + // reference // https://harrylovescode.gitbooks.io/vulkan-api/content/chap04/chap04-linux.html @@ -66,6 +85,54 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo // get the screeen const xcb_setup_t* setup = xcb_get_setup(settings._connection); + + vsg::ref_ptr keyboard(new KeyboardMap); + + { + std::cout<<" *** stting up : min_keycode="<<(int)(setup->min_keycode)<<", max_keycode="<<(int)(setup->max_keycode)<min_keycode; + xcb_keycode_t max_keycode = setup->max_keycode; + +#if 0 + for(int keycode = min_keycode; keycode <= max_keycode; ++keycode) + { + std::cout<<" keycode = "<<(int)keycode<=32 && keysym[m]<256) std::cout<<" ["<add(keycode, m, static_cast(keysym[m])); + } + } + + free(keyboard_mapping_reply); + } + + + + xcb_screen_iterator_t screen_iterator = xcb_setup_roots_iterator(setup); for (;screenNum>0; --screenNum) xcb_screen_next(&screen_iterator); settings._screen = screen_iterator.data; @@ -282,9 +349,26 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo { auto key_press = reinterpret_cast(event); std::cout<<"key_press = "<detail)<<", time="<time<<", root_x="<root_x<<", root_y"<root_y<<", "<event_x<<", "<event_y<<", state="<state<detail, 0, key_press->state) ); + if (keystr) std::cout<<" looks like " < 0x"<detail, 0, i) ); + if (str) std::cout<<" key "<; + using KeycodeMap = std::map; + + void add(uint16_t keycode, uint16_t modifier, KeySymbol key); + + void add(uint16_t keycode, std::initializer_list > combinations); + + KeySymbol getKeySymbol(uint16_t keycode, uint16_t modifier) + { + auto itr = _keycodeMap.find(KeycodeModifier(keycode, 0)); + if (itr==_keycodeMap.end()) return KeySymbol::KEY_Undefined; + + KeySymbol baseKeySymbol = itr->second; + if (modifier==0) return baseKeySymbol; + + bool shift = (modifier & KeyModifier::MODKEY_Shift)!=0; + uint16_t index = 0; + + if (baseKeySymbol>=KEY_KP_Space && baseKeySymbol<=KEY_KP_Divide) + { + // numeric keypad values + bool numLock = ((modifier & KeyModifier::MODKEY_NumLock)!=0); + index = (numLock && !shift) ? 1 : 0; + } + else + { + bool capsLock = (modifier & KeyModifier::MODKEY_CapsLock)!=0; + index = (capsLock ? !shift : shift) ? 1 : 0; + } + if (index==0) return baseKeySymbol; + + if (auto itr = _keycodeMap.find(KeycodeModifier(keycode, index)); itr!=_keycodeMap.end()) return itr->second; + return KeySymbol::KEY_Undefined; + } + + protected: + KeycodeMap _keycodeMap; + uint16_t _modifierMask; + }; // window decoation From e4c14b5a7273144c5d980778e62fe408ba67fa5e Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 29 Nov 2018 11:13:02 +0000 Subject: [PATCH 06/17] Added initial UI Event classes --- include/vsg/core/ConstVisitor.h | 21 ++- include/vsg/core/Visitor.h | 21 ++- include/vsg/ui/KeyEvent.h | 299 ++++++++++++++++++++++++++++++++ include/vsg/ui/PointerEvent.h | 63 +++++++ include/vsg/ui/UIEvent.h | 35 ++++ src/vsg/core/ConstVisitor.cpp | 36 ++++ src/vsg/core/Visitor.cpp | 37 ++++ src/vsg/viewer/Xcb_Window.cpp | 4 +- src/vsg/viewer/Xcb_Window.h | 281 +++--------------------------- 9 files changed, 537 insertions(+), 260 deletions(-) create mode 100644 include/vsg/ui/KeyEvent.h create mode 100644 include/vsg/ui/PointerEvent.h create mode 100644 include/vsg/ui/UIEvent.h diff --git a/include/vsg/core/ConstVisitor.h b/include/vsg/core/ConstVisitor.h index 9b0867b9ac..a994479a7e 100644 --- a/include/vsg/core/ConstVisitor.h +++ b/include/vsg/core/ConstVisitor.h @@ -20,17 +20,27 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI namespace vsg { - // forward declare nodes + // forward declare nodes classes class Node; class Group; class QuadGroup; class LOD; class StateGroup; + // forward declare vulkan classes class Command; class CommandBuffer; class RenderPass; + // forward declare ui events classes + class UIEvent; + class KeyEvent; + class KeyPressEvent; + class KeyReleaseEvent; + class PointerEvent; + class ButtonPressEvent; + class ButtonReleaseEvent; + class VSG_DECLSPEC ConstVisitor : public Object { public: @@ -107,6 +117,15 @@ namespace vsg virtual void apply(const Command&); virtual void apply(const CommandBuffer&); virtual void apply(const RenderPass&); + + // ui events + virtual void apply(const UIEvent&); + virtual void apply(const KeyEvent&); + virtual void apply(const KeyPressEvent&); + virtual void apply(const KeyReleaseEvent&); + virtual void apply(const PointerEvent&); + virtual void apply(const ButtonPressEvent&); + virtual void apply(const ButtonReleaseEvent&); }; // provide Value<>::accept() implementation diff --git a/include/vsg/core/Visitor.h b/include/vsg/core/Visitor.h index 78baf2bb36..95cf197aee 100644 --- a/include/vsg/core/Visitor.h +++ b/include/vsg/core/Visitor.h @@ -20,17 +20,27 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI namespace vsg { - // forward declare nodes + // forward declare nodes classes class Node; class Group; class QuadGroup; class LOD; class StateGroup; + // forward declare vulkan classes class Command; class CommandBuffer; class RenderPass; + // forward declare ui events classes + class UIEvent; + class KeyEvent; + class KeyPressEvent; + class KeyReleaseEvent; + class PointerEvent; + class ButtonPressEvent; + class ButtonReleaseEvent; + class VSG_DECLSPEC Visitor : public Object { public: @@ -107,6 +117,15 @@ namespace vsg virtual void apply(Command&); virtual void apply(CommandBuffer&); virtual void apply(RenderPass&); + + // ui events + virtual void apply(UIEvent&); + virtual void apply(KeyEvent&); + virtual void apply(KeyPressEvent&); + virtual void apply(KeyReleaseEvent&); + virtual void apply(PointerEvent&); + virtual void apply(ButtonPressEvent&); + virtual void apply(ButtonReleaseEvent&); }; // provide Value<>::accept() implementation diff --git a/include/vsg/ui/KeyEvent.h b/include/vsg/ui/KeyEvent.h new file mode 100644 index 0000000000..97514080ab --- /dev/null +++ b/include/vsg/ui/KeyEvent.h @@ -0,0 +1,299 @@ +#pragma once + +/* + +Copyright(c) 2018 Robert Osfield + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + +#include +#include +#include + +namespace vsg +{ + + enum KeySymbol : uint16_t + { + KEY_Undefined = 0x0, + + KEY_Space = 0x20, + + KEY_a = 'a', + KEY_b = 'b', + KEY_c = 'c', + KEY_d = 'd', + KEY_e = 'e', + KEY_f = 'f', + KEY_g = 'g', + KEY_h = 'h', + KEY_i = 'i', + KEY_j = 'j', + KEY_k = 'k', + KEY_l = 'l', + KEY_m = 'm', + KEY_n = 'n', + KEY_o = 'o', + KEY_p = 'p', + KEY_q = 'q', + KEY_r = 'r', + KEY_s = 's', + KEY_t = 't', + KEY_u = 'u', + KEY_v = 'v', + KEY_w = 'w', + KEY_x = 'x', + KEY_y = 'y', + KEY_z = 'z', + + KEY_A = 'A', + KEY_B = 'B', + KEY_C = 'C', + KEY_D = 'D', + KEY_E = 'E', + KEY_F = 'F', + KEY_G = 'G', + KEY_H = 'H', + KEY_I = 'I', + KEY_J = 'J', + KEY_K = 'K', + KEY_L = 'L', + KEY_M = 'M', + KEY_N = 'N', + KEY_O = 'O', + KEY_P = 'P', + KEY_Q = 'Q', + KEY_R = 'R', + KEY_S = 'S', + KEY_T = 'T', + KEY_U = 'U', + KEY_V = 'V', + KEY_W = 'W', + KEY_X = 'X', + KEY_Y = 'Y', + KEY_Z = 'Z', + + KEY_Exclaim = 0x21, + KEY_Quotedbl = 0x22, + KEY_Hash = 0x23, + KEY_Dollar = 0x24, + KEY_Ampersand = 0x26, + KEY_Quote = 0x27, + KEY_Leftparen = 0x28, + KEY_Rightparen = 0x29, + KEY_Asterisk = 0x2A, + KEY_Plus = 0x2B, + KEY_Comma = 0x2C, + KEY_Minus = 0x2D, + KEY_Period = 0x2E, + KEY_Slash = 0x2F, + KEY_Colon = 0x3A, + KEY_Semicolon = 0x3B, + KEY_Less = 0x3C, + KEY_Equals = 0x3D, + KEY_Greater = 0x3E, + KEY_Question = 0x3F, + KEY_At = 0x40, + KEY_Leftbracket = 0x5B, + KEY_Backslash = 0x5C, + KEY_Rightbracket = 0x5D, + KEY_Caret = 0x5E, + KEY_Underscore = 0x5F, + KEY_Backquote = 0x60, + + KEY_BackSpace = 0xFF08, /* back space, back char */ + KEY_Tab = 0xFF09, + KEY_Linefeed = 0xFF0A, /* Linefeed, LF */ + KEY_Clear = 0xFF0B, + KEY_Return = 0xFF0D, /* Return, enter */ + KEY_Pause = 0xFF13, /* Pause, hold */ + KEY_Scroll_Lock = 0xFF14, + KEY_Sys_Req = 0xFF15, + KEY_Escape = 0xFF1B, + KEY_Delete = 0xFFFF, /* Delete, rubout */ + + + /* Cursor control & motion */ + + KEY_Home = 0xFF50, + KEY_Left = 0xFF51, /* Move left, left arrow */ + KEY_Up = 0xFF52, /* Move up, up arrow */ + KEY_Right = 0xFF53, /* Move right, right arrow */ + KEY_Down = 0xFF54, /* Move down, down arrow */ + KEY_Prior = 0xFF55, /* Prior, previous */ + KEY_Page_Up = 0xFF55, + KEY_Next = 0xFF56, /* Next */ + KEY_Page_Down = 0xFF56, + KEY_End = 0xFF57, /* EOL */ + KEY_Begin = 0xFF58, /* BOL */ + + + /* Misc Functions */ + + KEY_Select = 0xFF60, /* Select, mark */ + KEY_Print = 0xFF61, + KEY_Execute = 0xFF62, /* Execute, run, do */ + KEY_Insert = 0xFF63, /* Insert, insert here */ + KEY_Undo = 0xFF65, /* Undo, oops */ + KEY_Redo = 0xFF66, /* redo, again */ + KEY_Menu = 0xFF67, /* On Windows, this is VK_APPS, the context-menu key */ + KEY_Find = 0xFF68, /* Find, search */ + KEY_Cancel = 0xFF69, /* Cancel, stop, abort, exit */ + KEY_Help = 0xFF6A, /* Help */ + KEY_Break = 0xFF6B, + KEY_Mode_switch = 0xFF7E, /* Character set switch */ + KEY_Script_switch = 0xFF7E, /* Alias for mode_switch */ + KEY_Num_Lock = 0xFF7F, + + /* Keypad Functions, keypad numbers cleverly chosen to map to ascii */ + + KEY_KP_Space = 0xFF80, /* space */ + KEY_KP_Tab = 0xFF89, + KEY_KP_Enter = 0xFF8D, /* enter */ + KEY_KP_F1 = 0xFF91, /* PF1, KP_A, ... */ + KEY_KP_F2 = 0xFF92, + KEY_KP_F3 = 0xFF93, + KEY_KP_F4 = 0xFF94, + KEY_KP_Home = 0xFF95, + KEY_KP_Left = 0xFF96, + KEY_KP_Up = 0xFF97, + KEY_KP_Right = 0xFF98, + KEY_KP_Down = 0xFF99, + KEY_KP_Prior = 0xFF9A, + KEY_KP_Page_Up = 0xFF9A, + KEY_KP_Next = 0xFF9B, + KEY_KP_Page_Down = 0xFF9B, + KEY_KP_End = 0xFF9C, + KEY_KP_Begin = 0xFF9D, + KEY_KP_Insert = 0xFF9E, + KEY_KP_Delete = 0xFF9F, + KEY_KP_Equal = 0xFFBD, /* equals */ + KEY_KP_Multiply = 0xFFAA, + KEY_KP_Add = 0xFFAB, + KEY_KP_Separator = 0xFFAC, /* separator, often comma */ + KEY_KP_Subtract = 0xFFAD, + KEY_KP_Decimal = 0xFFAE, + KEY_KP_Divide = 0xFFAF, + + KEY_KP_0 = 0xFFB0, + KEY_KP_1 = 0xFFB1, + KEY_KP_2 = 0xFFB2, + KEY_KP_3 = 0xFFB3, + KEY_KP_4 = 0xFFB4, + KEY_KP_5 = 0xFFB5, + KEY_KP_6 = 0xFFB6, + KEY_KP_7 = 0xFFB7, + KEY_KP_8 = 0xFFB8, + KEY_KP_9 = 0xFFB9, + + /* + * Auxiliary Functions; note the duplicate definitions for left and right + * function keys; Sun keyboards and a few other manufactures have such + * function key groups on the left and/or right sides of the keyboard. + * We've not found a keyboard with more than 35 function keys total. + */ + + KEY_F1 = 0xFFBE, + KEY_F2 = 0xFFBF, + KEY_F3 = 0xFFC0, + KEY_F4 = 0xFFC1, + KEY_F5 = 0xFFC2, + KEY_F6 = 0xFFC3, + KEY_F7 = 0xFFC4, + KEY_F8 = 0xFFC5, + KEY_F9 = 0xFFC6, + KEY_F10 = 0xFFC7, + KEY_F11 = 0xFFC8, + KEY_F12 = 0xFFC9, + KEY_F13 = 0xFFCA, + KEY_F14 = 0xFFCB, + KEY_F15 = 0xFFCC, + KEY_F16 = 0xFFCD, + KEY_F17 = 0xFFCE, + KEY_F18 = 0xFFCF, + KEY_F19 = 0xFFD0, + KEY_F20 = 0xFFD1, + KEY_F21 = 0xFFD2, + KEY_F22 = 0xFFD3, + KEY_F23 = 0xFFD4, + KEY_F24 = 0xFFD5, + KEY_F25 = 0xFFD6, + KEY_F26 = 0xFFD7, + KEY_F27 = 0xFFD8, + KEY_F28 = 0xFFD9, + KEY_F29 = 0xFFDA, + KEY_F30 = 0xFFDB, + KEY_F31 = 0xFFDC, + KEY_F32 = 0xFFDD, + KEY_F33 = 0xFFDE, + KEY_F34 = 0xFFDF, + KEY_F35 = 0xFFE0, + + /* Modifiers */ + + KEY_Shift_L = 0xFFE1, /* Left shift */ + KEY_Shift_R = 0xFFE2, /* Right shift */ + KEY_Control_L = 0xFFE3, /* Left control */ + KEY_Control_R = 0xFFE4, /* Right control */ + KEY_Caps_Lock = 0xFFE5, /* Caps lock */ + KEY_Shift_Lock = 0xFFE6, /* Shift lock */ + + KEY_Meta_L = 0xFFE7, /* Left meta */ + KEY_Meta_R = 0xFFE8, /* Right meta */ + KEY_Alt_L = 0xFFE9, /* Left alt */ + KEY_Alt_R = 0xFFEA, /* Right alt */ + KEY_Super_L = 0xFFEB, /* Left super */ + KEY_Super_R = 0xFFEC, /* Right super */ + KEY_Hyper_L = 0xFFED, /* Left hyper */ + KEY_Hyper_R = 0xFFEE /* Right hyper */ + }; + + enum KeyModifier : uint16_t + { + MODKEY_Shift = 1, + MODKEY_CapsLock = 2, + MODKEY_Control = 4, + MODKEY_Alt = 8, + MODKEY_NumLock = 16, + MODKEY_Meta = 128 + }; + + class KeyEvent : public Inherit + { + public: + KeyEvent(Window* in_window, time_point in_time, KeySymbol in_keyBase, KeySymbol in_keyModified, KeyModifier in_modifier, uint32_t in_repeatCount=0): + Inherit(in_time), + window(in_window), + keyBase(in_keyBase), + keyModified(in_keyModified), + keyModifier(in_modifier), + repeatCount(in_repeatCount) {} + + observer_ptr window; + KeySymbol keyBase; + KeySymbol keyModified; + KeyModifier keyModifier; + uint32_t repeatCount; + }; + + class KeyPressEvent : public Inherit + { + public: + KeyPressEvent(Window* in_window, time_point in_time, KeySymbol in_keyBase, KeySymbol in_keyModified, KeyModifier in_modifier, uint32_t in_repeatCount=0): + Inherit(in_window, in_time, in_keyBase, in_keyModified, in_modifier, in_repeatCount) {} + }; + + class KeyReleaseEvent : public Inherit + { + public: + KeyReleaseEvent(Window* in_window, time_point in_time, KeySymbol in_keyBase, KeySymbol in_keyModified, KeyModifier in_modifier, uint32_t in_repeatCount=0): + Inherit(in_window, in_time, in_keyBase, in_keyModified, in_modifier, in_repeatCount) {} + }; + +} diff --git a/include/vsg/ui/PointerEvent.h b/include/vsg/ui/PointerEvent.h new file mode 100644 index 0000000000..bbd8f9e1a5 --- /dev/null +++ b/include/vsg/ui/PointerEvent.h @@ -0,0 +1,63 @@ +#pragma once + +/* + +Copyright(c) 2018 Robert Osfield + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + +#include +#include +#include + +namespace vsg +{ + + enum ButtonMask : uint16_t + { + BUTTON_MASK_1 = 256, + BUTTON_MASK_2 = 512, + BUTTON_MASK_3 = 1024, + BUTTON_MASK_4 = 2048, + BUTTON_MASK_5 = 4096 + }; + + // VSG_type_name(vsg::PointerEvent); + + class PointerEvent : public Inherit + { + public: + PointerEvent(Window* in_window, time_point in_time, uint32_t in_x, uint32_t in_y, ButtonMask in_buttonMask): + Inherit(in_time), + window(in_window), + x(in_x), + y(in_y), + buttonMask(in_buttonMask) {} + + observer_ptr window; + uint32_t x; + uint32_t y; + ButtonMask buttonMask; + }; + + class ButtonPressEvent : public Inherit + { + public: + ButtonPressEvent(Window* in_window, time_point in_time, uint32_t in_x, uint32_t in_y, ButtonMask in_buttonMask): + Inherit(in_window, in_time, in_x, in_y, in_buttonMask) {} + }; + + class ButtonReleaseEvent : public Inherit + { + public: + ButtonReleaseEvent(Window* in_window, time_point in_time, uint32_t in_x, uint32_t in_y, ButtonMask in_buttonMask): + Inherit(in_window, in_time, in_x, in_y, in_buttonMask) {} + }; + +} diff --git a/include/vsg/ui/UIEvent.h b/include/vsg/ui/UIEvent.h new file mode 100644 index 0000000000..d58312e0cf --- /dev/null +++ b/include/vsg/ui/UIEvent.h @@ -0,0 +1,35 @@ +#pragma once + +/* + +Copyright(c) 2018 Robert Osfield + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + +#include + +#include + +namespace vsg +{ + + using clock = std::chrono::steady_clock; + using time_point = clock::time_point; + + class UIEvent : public Inherit + { + public: + UIEvent(time_point in_time): + time(in_time) {} + + time_point time; + }; + + +} diff --git a/src/vsg/core/ConstVisitor.cpp b/src/vsg/core/ConstVisitor.cpp index ac26c7db89..31bcd3307b 100644 --- a/src/vsg/core/ConstVisitor.cpp +++ b/src/vsg/core/ConstVisitor.cpp @@ -22,6 +22,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include +#include +#include + using namespace vsg; ConstVisitor::ConstVisitor() @@ -293,3 +296,36 @@ void ConstVisitor::apply(const RenderPass& value) { apply(static_cast(value)); } + +//////////////////////////////////////////////////////////////////////////////// +// +// UI Events +// +void ConstVisitor::apply(const UIEvent& event) +{ + apply(static_cast(event)); +} +void ConstVisitor::apply(const KeyEvent& event) +{ + apply(static_cast(event)); +} +void ConstVisitor::apply(const KeyPressEvent& event) +{ + apply(static_cast(event)); +} +void ConstVisitor::apply(const KeyReleaseEvent& event) +{ + apply(static_cast(event)); +} +void ConstVisitor::apply(const PointerEvent& event) +{ + apply(static_cast(event)); +} +void ConstVisitor::apply(const ButtonPressEvent& event) +{ + apply(static_cast(event)); +} +void ConstVisitor::apply(const ButtonReleaseEvent& event) +{ + apply(static_cast(event)); +} diff --git a/src/vsg/core/Visitor.cpp b/src/vsg/core/Visitor.cpp index 314c336025..302cde840a 100644 --- a/src/vsg/core/Visitor.cpp +++ b/src/vsg/core/Visitor.cpp @@ -22,6 +22,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include +#include +#include + using namespace vsg; Visitor::Visitor() @@ -293,3 +296,37 @@ void Visitor::apply(RenderPass& value) { apply(static_cast(value)); } + +//////////////////////////////////////////////////////////////////////////////// +// +// UI Events +// +void Visitor::apply(UIEvent& event) +{ + apply(static_cast(event)); +} +void Visitor::apply(KeyEvent& event) +{ + apply(static_cast(event)); +} +void Visitor::apply(KeyPressEvent& event) +{ + apply(static_cast(event)); +} +void Visitor::apply(KeyReleaseEvent& event) +{ + apply(static_cast(event)); +} +void Visitor::apply(PointerEvent& event) +{ + apply(static_cast(event)); +} +void Visitor::apply(ButtonPressEvent& event) +{ + apply(static_cast(event)); +} +void Visitor::apply(ButtonReleaseEvent& event) +{ + apply(static_cast(event)); +} + diff --git a/src/vsg/viewer/Xcb_Window.cpp b/src/vsg/viewer/Xcb_Window.cpp index 3c829a2696..d7a21a4cb6 100644 --- a/src/vsg/viewer/Xcb_Window.cpp +++ b/src/vsg/viewer/Xcb_Window.cpp @@ -352,8 +352,8 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo const char* keystr = XKeysymToString( XkbKeycodeToKeysym(x11_display, key_press->detail, 0, key_press->state) ); if (keystr) std::cout<<" looks like " <getKeySymbol(key_press->detail, key_press->state); - if (keySymbol!=xcb::KeySymbol::KEY_Undefined) + vsg::KeySymbol keySymbol = keyboard->getKeySymbol(key_press->detail, key_press->state); + if (keySymbol!=vsg::KEY_Undefined) { if (keySymbol>=32 && keySymbol<255) std::cout<<" keyboard map to : "<<(char)keySymbol<<" 0x"< 0x"< + +Copyright(c) 2018 Robert Osfield + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + #pragma once #include +#include #include @@ -19,250 +32,6 @@ namespace xcb }; - enum KeySymbol : uint16_t - { - KEY_Undefined = 0x0, - - KEY_Space = 0x20, - - KEY_a = 'a', - KEY_b = 'b', - KEY_c = 'c', - KEY_d = 'd', - KEY_e = 'e', - KEY_f = 'f', - KEY_g = 'g', - KEY_h = 'h', - KEY_i = 'i', - KEY_j = 'j', - KEY_k = 'k', - KEY_l = 'l', - KEY_m = 'm', - KEY_n = 'n', - KEY_o = 'o', - KEY_p = 'p', - KEY_q = 'q', - KEY_r = 'r', - KEY_s = 's', - KEY_t = 't', - KEY_u = 'u', - KEY_v = 'v', - KEY_w = 'w', - KEY_x = 'x', - KEY_y = 'y', - KEY_z = 'z', - - KEY_A = 'A', - KEY_B = 'B', - KEY_C = 'C', - KEY_D = 'D', - KEY_E = 'E', - KEY_F = 'F', - KEY_G = 'G', - KEY_H = 'H', - KEY_I = 'I', - KEY_J = 'J', - KEY_K = 'K', - KEY_L = 'L', - KEY_M = 'M', - KEY_N = 'N', - KEY_O = 'O', - KEY_P = 'P', - KEY_Q = 'Q', - KEY_R = 'R', - KEY_S = 'S', - KEY_T = 'T', - KEY_U = 'U', - KEY_V = 'V', - KEY_W = 'W', - KEY_X = 'X', - KEY_Y = 'Y', - KEY_Z = 'Z', - - KEY_Exclaim = 0x21, - KEY_Quotedbl = 0x22, - KEY_Hash = 0x23, - KEY_Dollar = 0x24, - KEY_Ampersand = 0x26, - KEY_Quote = 0x27, - KEY_Leftparen = 0x28, - KEY_Rightparen = 0x29, - KEY_Asterisk = 0x2A, - KEY_Plus = 0x2B, - KEY_Comma = 0x2C, - KEY_Minus = 0x2D, - KEY_Period = 0x2E, - KEY_Slash = 0x2F, - KEY_Colon = 0x3A, - KEY_Semicolon = 0x3B, - KEY_Less = 0x3C, - KEY_Equals = 0x3D, - KEY_Greater = 0x3E, - KEY_Question = 0x3F, - KEY_At = 0x40, - KEY_Leftbracket = 0x5B, - KEY_Backslash = 0x5C, - KEY_Rightbracket = 0x5D, - KEY_Caret = 0x5E, - KEY_Underscore = 0x5F, - KEY_Backquote = 0x60, - - KEY_BackSpace = 0xFF08, /* back space, back char */ - KEY_Tab = 0xFF09, - KEY_Linefeed = 0xFF0A, /* Linefeed, LF */ - KEY_Clear = 0xFF0B, - KEY_Return = 0xFF0D, /* Return, enter */ - KEY_Pause = 0xFF13, /* Pause, hold */ - KEY_Scroll_Lock = 0xFF14, - KEY_Sys_Req = 0xFF15, - KEY_Escape = 0xFF1B, - KEY_Delete = 0xFFFF, /* Delete, rubout */ - - - /* Cursor control & motion */ - - KEY_Home = 0xFF50, - KEY_Left = 0xFF51, /* Move left, left arrow */ - KEY_Up = 0xFF52, /* Move up, up arrow */ - KEY_Right = 0xFF53, /* Move right, right arrow */ - KEY_Down = 0xFF54, /* Move down, down arrow */ - KEY_Prior = 0xFF55, /* Prior, previous */ - KEY_Page_Up = 0xFF55, - KEY_Next = 0xFF56, /* Next */ - KEY_Page_Down = 0xFF56, - KEY_End = 0xFF57, /* EOL */ - KEY_Begin = 0xFF58, /* BOL */ - - - /* Misc Functions */ - - KEY_Select = 0xFF60, /* Select, mark */ - KEY_Print = 0xFF61, - KEY_Execute = 0xFF62, /* Execute, run, do */ - KEY_Insert = 0xFF63, /* Insert, insert here */ - KEY_Undo = 0xFF65, /* Undo, oops */ - KEY_Redo = 0xFF66, /* redo, again */ - KEY_Menu = 0xFF67, /* On Windows, this is VK_APPS, the context-menu key */ - KEY_Find = 0xFF68, /* Find, search */ - KEY_Cancel = 0xFF69, /* Cancel, stop, abort, exit */ - KEY_Help = 0xFF6A, /* Help */ - KEY_Break = 0xFF6B, - KEY_Mode_switch = 0xFF7E, /* Character set switch */ - KEY_Script_switch = 0xFF7E, /* Alias for mode_switch */ - KEY_Num_Lock = 0xFF7F, - - /* Keypad Functions, keypad numbers cleverly chosen to map to ascii */ - - KEY_KP_Space = 0xFF80, /* space */ - KEY_KP_Tab = 0xFF89, - KEY_KP_Enter = 0xFF8D, /* enter */ - KEY_KP_F1 = 0xFF91, /* PF1, KP_A, ... */ - KEY_KP_F2 = 0xFF92, - KEY_KP_F3 = 0xFF93, - KEY_KP_F4 = 0xFF94, - KEY_KP_Home = 0xFF95, - KEY_KP_Left = 0xFF96, - KEY_KP_Up = 0xFF97, - KEY_KP_Right = 0xFF98, - KEY_KP_Down = 0xFF99, - KEY_KP_Prior = 0xFF9A, - KEY_KP_Page_Up = 0xFF9A, - KEY_KP_Next = 0xFF9B, - KEY_KP_Page_Down = 0xFF9B, - KEY_KP_End = 0xFF9C, - KEY_KP_Begin = 0xFF9D, - KEY_KP_Insert = 0xFF9E, - KEY_KP_Delete = 0xFF9F, - KEY_KP_Equal = 0xFFBD, /* equals */ - KEY_KP_Multiply = 0xFFAA, - KEY_KP_Add = 0xFFAB, - KEY_KP_Separator = 0xFFAC, /* separator, often comma */ - KEY_KP_Subtract = 0xFFAD, - KEY_KP_Decimal = 0xFFAE, - KEY_KP_Divide = 0xFFAF, - - KEY_KP_0 = 0xFFB0, - KEY_KP_1 = 0xFFB1, - KEY_KP_2 = 0xFFB2, - KEY_KP_3 = 0xFFB3, - KEY_KP_4 = 0xFFB4, - KEY_KP_5 = 0xFFB5, - KEY_KP_6 = 0xFFB6, - KEY_KP_7 = 0xFFB7, - KEY_KP_8 = 0xFFB8, - KEY_KP_9 = 0xFFB9, - - /* - * Auxiliary Functions; note the duplicate definitions for left and right - * function keys; Sun keyboards and a few other manufactures have such - * function key groups on the left and/or right sides of the keyboard. - * We've not found a keyboard with more than 35 function keys total. - */ - - KEY_F1 = 0xFFBE, - KEY_F2 = 0xFFBF, - KEY_F3 = 0xFFC0, - KEY_F4 = 0xFFC1, - KEY_F5 = 0xFFC2, - KEY_F6 = 0xFFC3, - KEY_F7 = 0xFFC4, - KEY_F8 = 0xFFC5, - KEY_F9 = 0xFFC6, - KEY_F10 = 0xFFC7, - KEY_F11 = 0xFFC8, - KEY_F12 = 0xFFC9, - KEY_F13 = 0xFFCA, - KEY_F14 = 0xFFCB, - KEY_F15 = 0xFFCC, - KEY_F16 = 0xFFCD, - KEY_F17 = 0xFFCE, - KEY_F18 = 0xFFCF, - KEY_F19 = 0xFFD0, - KEY_F20 = 0xFFD1, - KEY_F21 = 0xFFD2, - KEY_F22 = 0xFFD3, - KEY_F23 = 0xFFD4, - KEY_F24 = 0xFFD5, - KEY_F25 = 0xFFD6, - KEY_F26 = 0xFFD7, - KEY_F27 = 0xFFD8, - KEY_F28 = 0xFFD9, - KEY_F29 = 0xFFDA, - KEY_F30 = 0xFFDB, - KEY_F31 = 0xFFDC, - KEY_F32 = 0xFFDD, - KEY_F33 = 0xFFDE, - KEY_F34 = 0xFFDF, - KEY_F35 = 0xFFE0, - - /* Modifiers */ - - KEY_Shift_L = 0xFFE1, /* Left shift */ - KEY_Shift_R = 0xFFE2, /* Right shift */ - KEY_Control_L = 0xFFE3, /* Left control */ - KEY_Control_R = 0xFFE4, /* Right control */ - KEY_Caps_Lock = 0xFFE5, /* Caps lock */ - KEY_Shift_Lock = 0xFFE6, /* Shift lock */ - - KEY_Meta_L = 0xFFE7, /* Left meta */ - KEY_Meta_R = 0xFFE8, /* Right meta */ - KEY_Alt_L = 0xFFE9, /* Left alt */ - KEY_Alt_R = 0xFFEA, /* Right alt */ - KEY_Super_L = 0xFFEB, /* Left super */ - KEY_Super_R = 0xFFEC, /* Right super */ - KEY_Hyper_L = 0xFFED, /* Left hyper */ - KEY_Hyper_R = 0xFFEE /* Right hyper */ - }; - - enum KeyModifier : uint16_t - { - MODKEY_Shift = 1, - MODKEY_CapsLock = 2, - MODKEY_Control = 4, - MODKEY_Alt = 8, - MODKEY_NumLock = 16, - MODKEY_Meta = 128, - }; class KeyboardMap : public vsg::Object { @@ -270,38 +39,38 @@ namespace xcb KeyboardMap(); using KeycodeModifier = std::pair; - using KeycodeMap = std::map; + using KeycodeMap = std::map; - void add(uint16_t keycode, uint16_t modifier, KeySymbol key); + void add(uint16_t keycode, uint16_t modifier, vsg::KeySymbol key); - void add(uint16_t keycode, std::initializer_list > combinations); + void add(uint16_t keycode, std::initializer_list > combinations); - KeySymbol getKeySymbol(uint16_t keycode, uint16_t modifier) + vsg::KeySymbol getKeySymbol(uint16_t keycode, uint16_t modifier) { auto itr = _keycodeMap.find(KeycodeModifier(keycode, 0)); - if (itr==_keycodeMap.end()) return KeySymbol::KEY_Undefined; + if (itr==_keycodeMap.end()) return vsg::KEY_Undefined; - KeySymbol baseKeySymbol = itr->second; + vsg::KeySymbol baseKeySymbol = itr->second; if (modifier==0) return baseKeySymbol; - bool shift = (modifier & KeyModifier::MODKEY_Shift)!=0; + bool shift = (modifier & vsg::MODKEY_Shift)!=0; uint16_t index = 0; - if (baseKeySymbol>=KEY_KP_Space && baseKeySymbol<=KEY_KP_Divide) + if (baseKeySymbol>=vsg::KEY_KP_Space && baseKeySymbol<=vsg::KEY_KP_Divide) { // numeric keypad values - bool numLock = ((modifier & KeyModifier::MODKEY_NumLock)!=0); + bool numLock = ((modifier & vsg::MODKEY_NumLock)!=0); index = (numLock && !shift) ? 1 : 0; } else { - bool capsLock = (modifier & KeyModifier::MODKEY_CapsLock)!=0; + bool capsLock = (modifier & vsg::MODKEY_CapsLock)!=0; index = (capsLock ? !shift : shift) ? 1 : 0; } if (index==0) return baseKeySymbol; - if (auto itr = _keycodeMap.find(KeycodeModifier(keycode, index)); itr!=_keycodeMap.end()) return itr->second; - return KeySymbol::KEY_Undefined; + if (itr = _keycodeMap.find(KeycodeModifier(keycode, index)); itr!=_keycodeMap.end()) return itr->second; + return vsg::KEY_Undefined; } protected: From dc95c5be2415407280d051a7604d95ceae167e56 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 29 Nov 2018 12:25:32 +0000 Subject: [PATCH 07/17] Added test for mapping XCB timestamps to a std::chrono clock time. --- src/vsg/viewer/Xcb_Window.cpp | 39 +++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/vsg/viewer/Xcb_Window.cpp b/src/vsg/viewer/Xcb_Window.cpp index d7a21a4cb6..ece134dfe4 100644 --- a/src/vsg/viewer/Xcb_Window.cpp +++ b/src/vsg/viewer/Xcb_Window.cpp @@ -21,6 +21,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include namespace vsg { @@ -318,8 +319,16 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo bool close = false; + bool first_xcb_time = true; + xcb_timestamp_t first_xcb_timestamp = 0; + vsg::clock::time_point first_xcb_time_point = vsg::clock::now(); + vsg::clock::time_point start_point = first_xcb_time_point; + while(!close) { + using EventQueue = std::list>; + EventQueue events; + xcb_generic_event_t *event; int i=0; while ((event = xcb_poll_for_event(settings._connection)) ) @@ -331,7 +340,7 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo case(XCB_EXPOSE): { auto expose = reinterpret_cast(event); - std::cout<<"expose "<window<<", "<x<<", "<y<<", "<width<<", "<height<window<<", "<x<<", "<y<<", "<width<<", "<height<<", count="<count<(event); + + if (first_xcb_time) + { + first_xcb_time = false; + first_xcb_timestamp = key_press->time; + first_xcb_time_point = vsg::clock::now(); + } + + xcb_timestamp_t relative_event_time = (key_press->time-first_xcb_timestamp); + vsg::clock::time_point event_time = first_xcb_time_point + std::chrono::milliseconds(relative_event_time); + + vsg::KeySymbol keySymbol = keyboard->getKeySymbol(key_press->detail, 0); + vsg::KeySymbol keySymbolModified = keyboard->getKeySymbol(key_press->detail, key_press->state); + events.emplace_back(new vsg::KeyPressEvent(0, event_time, keySymbol, keySymbolModified, KeyModifier(key_press->state), 0)); + + std::cout<<"relative_event_time = "<root_y<<", "<event_x<<", "<event_y<<", state="<state<detail, 0, key_press->state) ); if (keystr) std::cout<<" looks like " <(event); std::cout<<"key_release = "<detail)<<", time="<time<<", root_x="<root_x<<", root_y"<root_y<<", "<event_x<<", "<event_y<<", state="<state<className()<<" time="<(vsg_event->time - start_point).count()<0) std::cout< Date: Thu, 29 Nov 2018 17:59:59 +0000 Subject: [PATCH 08/17] Added setting of the the initial serve xcb_timestamp and start point. Added event print visitor --- src/vsg/viewer/Xcb_Window.cpp | 99 +++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 45 deletions(-) diff --git a/src/vsg/viewer/Xcb_Window.cpp b/src/vsg/viewer/Xcb_Window.cpp index ece134dfe4..86453a1958 100644 --- a/src/vsg/viewer/Xcb_Window.cpp +++ b/src/vsg/viewer/Xcb_Window.cpp @@ -159,7 +159,7 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo { settings._screen->black_pixel, override_redirect, - XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE + XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_PROPERTY_CHANGE }; // ceate window @@ -231,6 +231,27 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo std::cout<<"Create window : "<response_type & ~0x80; + if (response_type==XCB_PROPERTY_NOTIFY) + { + auto propety_notify = reinterpret_cast(event); + first_xcb_time = false; + first_xcb_timestamp = propety_notify->time; + first_xcb_time_point = vsg::clock::now(); + } + free(event); + } + } xcb_map_window(settings._connection, settings._window); @@ -319,11 +340,6 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo bool close = false; - bool first_xcb_time = true; - xcb_timestamp_t first_xcb_timestamp = 0; - vsg::clock::time_point first_xcb_time_point = vsg::clock::now(); - vsg::clock::time_point start_point = first_xcb_time_point; - while(!close) { using EventQueue = std::list>; @@ -358,53 +374,22 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo { auto key_press = reinterpret_cast(event); - if (first_xcb_time) - { - first_xcb_time = false; - first_xcb_timestamp = key_press->time; - first_xcb_time_point = vsg::clock::now(); - } - - xcb_timestamp_t relative_event_time = (key_press->time-first_xcb_timestamp); - vsg::clock::time_point event_time = first_xcb_time_point + std::chrono::milliseconds(relative_event_time); - + vsg::clock::time_point event_time = first_xcb_time_point + std::chrono::milliseconds(key_press->time-first_xcb_timestamp); vsg::KeySymbol keySymbol = keyboard->getKeySymbol(key_press->detail, 0); vsg::KeySymbol keySymbolModified = keyboard->getKeySymbol(key_press->detail, key_press->state); events.emplace_back(new vsg::KeyPressEvent(0, event_time, keySymbol, keySymbolModified, KeyModifier(key_press->state), 0)); - std::cout<<"relative_event_time = "<root_y<<", "<event_x<<", "<event_y<<", state="<state<detail, 0, key_press->state) ); - if (keystr) std::cout<<" looks like " <getKeySymbol(key_press->detail, key_press->state); - if (keySymbol!=vsg::KEY_Undefined) - { - if (keySymbol>=32 && keySymbol<255) std::cout<<" keyboard map to : "<<(char)keySymbol<<" 0x"< 0x"<detail, 0, i) ); - if (str) std::cout<<" key "<(event); - std::cout<<"key_release = "<detail)<<", time="<time<<", root_x="<root_x<<", root_y"<root_y<<", "<event_x<<", "<event_y<<", state="<state<time-first_xcb_timestamp); + vsg::KeySymbol keySymbol = keyboard->getKeySymbol(key_release->detail, 0); + vsg::KeySymbol keySymbolModified = keyboard->getKeySymbol(key_release->detail, key_release->state); + events.emplace_back(new vsg::KeyReleaseEvent(0, event_time, keySymbol, keySymbolModified, KeyModifier(key_release->state), 0)); + break; } default: @@ -416,9 +401,33 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo free(event); } + struct PrintEvents : public vsg::Visitor + { + vsg::clock::time_point start_point; + + PrintEvents(vsg::clock::time_point in_start_point) : start_point(in_start_point) {} + + void apply(vsg::UIEvent& event) + { + std::cout<<"event : "<(event.time - start_point).count()<(keyRelease.time - start_point).count()<<", "<(keyPress.time - start_point).count()<<", "<className()<<" time="<(vsg_event->time - start_point).count()<accept(print); } if (i>0) std::cout< Date: Thu, 29 Nov 2018 18:57:38 +0000 Subject: [PATCH 09/17] Removed the no longer neccessary links to X11 --- CMakeLists.txt | 1 - src/vsg/CMakeLists.txt | 1 - src/vsg/viewer/Xcb_Window.cpp | 6 ------ src/vsg/vsgConfig.cmake | 3 --- 4 files changed, 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cc28f36456..7d9d2e2f28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,7 +59,6 @@ elseif (APPLE) else() find_package(glfw3) - find_package(X11) find_package(PkgConfig) pkg_check_modules(xcb REQUIRED IMPORTED_TARGET xcb) option(USE_GLFW "Use GLFW for Windowing" OFF) diff --git a/src/vsg/CMakeLists.txt b/src/vsg/CMakeLists.txt index eead0a8882..a2da75c25e 100644 --- a/src/vsg/CMakeLists.txt +++ b/src/vsg/CMakeLists.txt @@ -96,7 +96,6 @@ else() else() set(SOURCES ${SOURCES} viewer/Xcb_Window.cpp) set(LIBRARIES ${LIBRARIES} PRIVATE PkgConfig::xcb) - set(LIBRARIES ${LIBRARIES} PRIVATE ${X11_LIBRARIES}) endif() endif() diff --git a/src/vsg/viewer/Xcb_Window.cpp b/src/vsg/viewer/Xcb_Window.cpp index 86453a1958..ae9f1eac95 100644 --- a/src/vsg/viewer/Xcb_Window.cpp +++ b/src/vsg/viewer/Xcb_Window.cpp @@ -16,8 +16,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include -#include - #include #include #include @@ -69,8 +67,6 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo bool fullscreen = false;//true; uint32_t override_redirect = 0; // fullscreen ? 1 : 0; - Display* x11_display = XOpenDisplay(displayName); - // open connection settings._connection = xcb_connect(displayName, &screenNum); if (xcb_connection_has_error(settings._connection)) @@ -483,8 +479,6 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo // close connection xcb_disconnect(settings._connection); - XCloseDisplay(x11_display); - std::cout<<"Disconnect"< Date: Fri, 30 Nov 2018 08:46:42 +0000 Subject: [PATCH 10/17] Moved the window creation into Xcb_Window constructor --- src/vsg/viewer/Xcb_Window.cpp | 136 +++++++++++++++++----------------- src/vsg/viewer/Xcb_Window.h | 21 ++---- 2 files changed, 77 insertions(+), 80 deletions(-) diff --git a/src/vsg/viewer/Xcb_Window.cpp b/src/vsg/viewer/Xcb_Window.cpp index ae9f1eac95..dd9aa14c78 100644 --- a/src/vsg/viewer/Xcb_Window.cpp +++ b/src/vsg/viewer/Xcb_Window.cpp @@ -57,9 +57,17 @@ void KeyboardMap::add(uint16_t keycode, std::initializer_list window(new Xcb_Window(traits, debugLayer, apiDumpLayer, allocator)); + + return Result("Failed to created Window, no Xcb implementation yet.", VK_ERROR_INVALID_EXTERNAL_HANDLE); - Settings settings; +// return window; +} + + +Xcb_Window::Xcb_Window(const Traits& traits, bool debugLayer, bool apiDumpLayer, vsg::AllocationCallbacks* allocator) +{ + std::cout<<"Xcb_Window() "< keyboard(new KeyboardMap); @@ -97,8 +106,8 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo std::cout<<" keycode = "<<(int)keycode< stateAtoms{ wmFullScreen }; - xcb_change_property(settings._connection, XCB_PROP_MODE_REPLACE, settings._window, wmState, XCB_ATOM_ATOM, 32, stateAtoms.size(), stateAtoms.data()); + xcb_change_property(_connection, XCB_PROP_MODE_REPLACE, _window, wmState, XCB_ATOM_ATOM, 32, stateAtoms.size(), stateAtoms.data()); std::cout<<"Set up full screen"< actionAtoms { wmActionFullScreen }; - xcb_change_property(settings._connection, XCB_PROP_MODE_REPLACE, settings._window, wmAllowedActions, XCB_ATOM_ATOM, 32, actionAtoms.size(), actionAtoms.data()); + xcb_change_property(_connection, XCB_PROP_MODE_REPLACE, _window, wmAllowedActions, XCB_ATOM_ATOM, 32, actionAtoms.size(), actionAtoms.data()); #endif @@ -235,7 +244,7 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo // work out the X server timestamp by checking for the property notify events that result for the above xcb_change_property calls. { xcb_generic_event_t *event = nullptr; - while (first_xcb_time && (event = xcb_wait_for_event(settings._connection))) + while (first_xcb_time && (event = xcb_wait_for_event(_connection))) { uint8_t response_type = event->response_type & ~0x80; if (response_type==XCB_PROPERTY_NOTIFY) @@ -250,17 +259,17 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo } - xcb_map_window(settings._connection, settings._window); + xcb_map_window(_connection, _window); #if 0 // reconfigure the window position and size. const uint32_t values[] = { 100, 200, 300, 400 }; - xcb_configure_window (settings._connection, settings._window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); - xcb_flush(settings._connection); + xcb_configure_window (_connection, _window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); + xcb_flush(_connection); #endif - xcb_flush(settings._connection); + xcb_flush(_connection); @@ -278,10 +287,10 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo std::map windows; - windows["main"] = settings._window; + windows["main"] = _window; - xcb_query_tree_cookie_t tree_cookie = xcb_query_tree(settings._connection, settings._window); - xcb_query_tree_reply_t* tree_reply = xcb_query_tree_reply(settings._connection, tree_cookie, nullptr); + xcb_query_tree_cookie_t tree_cookie = xcb_query_tree(_connection, _window); + xcb_query_tree_reply_t* tree_reply = xcb_query_tree_reply(_connection, tree_cookie, nullptr); xcb_drawable_t root{}; @@ -304,7 +313,7 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo int32_t x, y; uint32_t width, height; - xcb_get_geometry_reply_t* geometry_reply = xcb_get_geometry_reply(settings._connection, xcb_get_geometry(settings._connection, window), nullptr); + xcb_get_geometry_reply_t* geometry_reply = xcb_get_geometry_reply(_connection, xcb_get_geometry(_connection, window), nullptr); if (geometry_reply!=nullptr) { x = geometry_reply->x; @@ -314,8 +323,8 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo std::cout<<" geometry_rely : "<dst_x = "<dst_x<<", trans->dst_y = "<dst_y<response_type & ~0x80; @@ -358,10 +367,10 @@ vsg::Window::Result Xcb_Window::create(const Traits& traits, bool debugLayer, bo case XCB_CLIENT_MESSAGE: { auto client_message = reinterpret_cast(event); - if (client_message->data.data32[0]==settings._wmDeleteWindow) + if (client_message->data.data32[0]==_wmDeleteWindow) { std::cout<<"client message "<data.data32[0]< Date: Fri, 30 Nov 2018 09:41:19 +0000 Subject: [PATCH 11/17] Changed the Window::pollEvents() method to Window::pollEvents(Events&) to facilitate getting polled events. --- include/vsg/ui/UIEvent.h | 3 +- include/vsg/viewer/Window.h | 5 +- src/vsg/viewer/GLFW_Window.cpp | 2 +- src/vsg/viewer/GLFW_Window.h | 8 +-- src/vsg/viewer/Viewer.cpp | 3 +- src/vsg/viewer/Win32_Window.cpp | 2 +- src/vsg/viewer/Win32_Window.h | 8 +-- src/vsg/viewer/Xcb_Window.cpp | 96 +++++++++++++++++++++++++-------- src/vsg/viewer/Xcb_Window.h | 7 ++- 9 files changed, 98 insertions(+), 36 deletions(-) diff --git a/include/vsg/ui/UIEvent.h b/include/vsg/ui/UIEvent.h index d58312e0cf..f8fd1d375f 100644 --- a/include/vsg/ui/UIEvent.h +++ b/include/vsg/ui/UIEvent.h @@ -15,6 +15,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include +#include namespace vsg { @@ -31,5 +32,5 @@ namespace vsg time_point time; }; - + using Events = std::list>; } diff --git a/include/vsg/viewer/Window.h b/include/vsg/viewer/Window.h index 2d7b9e08d8..f78b0e0fd8 100644 --- a/include/vsg/viewer/Window.h +++ b/include/vsg/viewer/Window.h @@ -14,6 +14,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include +#include + #include #include #include @@ -21,6 +23,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include + namespace vsg { @@ -53,7 +56,7 @@ namespace vsg virtual bool valid() const { return false; } - virtual bool pollEvents() { return false; } + virtual bool pollEvents(Events& /*events*/) { return false; } virtual bool resized() const { return false; } virtual void resize() {} diff --git a/src/vsg/viewer/GLFW_Window.cpp b/src/vsg/viewer/GLFW_Window.cpp index 7335f13aad..1d20aad733 100644 --- a/src/vsg/viewer/GLFW_Window.cpp +++ b/src/vsg/viewer/GLFW_Window.cpp @@ -173,7 +173,7 @@ GLFW_Window::~GLFW_Window() } } -bool GLFW_Window::pollEvents() +bool GLFW_Window::pollEvents(vsg::Events& /*events*/) { glfwPollEvents(); return false; diff --git a/src/vsg/viewer/GLFW_Window.h b/src/vsg/viewer/GLFW_Window.h index 3010b1fac4..26e34b35f1 100644 --- a/src/vsg/viewer/GLFW_Window.h +++ b/src/vsg/viewer/GLFW_Window.h @@ -34,13 +34,13 @@ class GLFW_Window : public vsg::Window static Result create(uint32_t width, uint32_t height, bool debugLayer=false, bool apiDumpLayer=false, vsg::Window* shareWindow=nullptr, vsg::AllocationCallbacks* allocator=nullptr); - virtual bool valid() const { return _window && !glfwWindowShouldClose(_window); } + bool valid() const override { return _window && !glfwWindowShouldClose(_window); } - virtual bool pollEvents(); + bool pollEvents(vsg::Events& events) override; - virtual bool resized() const; + bool resized() const override; - virtual void resize(); + void resize() override; operator GLFWwindow* () { return _window; } operator const GLFWwindow* () const { return _window; } diff --git a/src/vsg/viewer/Viewer.cpp b/src/vsg/viewer/Viewer.cpp index 37109cd700..85954135e2 100644 --- a/src/vsg/viewer/Viewer.cpp +++ b/src/vsg/viewer/Viewer.cpp @@ -76,9 +76,10 @@ bool Viewer::done() const bool Viewer::pollEvents() { bool result = false; + Events events; for (auto& window : _windows) { - if (window->pollEvents()) result = true; + if (window->pollEvents(events)) result = true; } return result; } diff --git a/src/vsg/viewer/Win32_Window.cpp b/src/vsg/viewer/Win32_Window.cpp index d25fad9016..1b1bf78c0a 100644 --- a/src/vsg/viewer/Win32_Window.cpp +++ b/src/vsg/viewer/Win32_Window.cpp @@ -248,7 +248,7 @@ Win32_Window::~Win32_Window() } } -bool Win32_Window::pollEvents() +bool Win32_Window::pollEvents(vsg::Events& events) { MSG msg; diff --git a/src/vsg/viewer/Win32_Window.h b/src/vsg/viewer/Win32_Window.h index da6506a79f..2a3e0c8515 100644 --- a/src/vsg/viewer/Win32_Window.h +++ b/src/vsg/viewer/Win32_Window.h @@ -35,13 +35,13 @@ namespace vsgWin32 static Result create(const Traits& traits, bool debugLayer = false, bool apiDumpLayer = false, vsg::AllocationCallbacks* allocator = nullptr); - virtual bool valid() const { return _window && !_shouldClose; } + bool valid() const override { return _window && !_shouldClose; } - virtual bool pollEvents(); + bool pollEvents(vsg::Events& events) override; - virtual bool resized() const; + bool resized() const override; - virtual void resize(); + void resize() override; operator HWND () { return _window; } operator const HWND () const { return _window; } diff --git a/src/vsg/viewer/Xcb_Window.cpp b/src/vsg/viewer/Xcb_Window.cpp index dd9aa14c78..39f42a7062 100644 --- a/src/vsg/viewer/Xcb_Window.cpp +++ b/src/vsg/viewer/Xcb_Window.cpp @@ -19,7 +19,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include -#include namespace vsg { @@ -92,7 +91,7 @@ Xcb_Window::Xcb_Window(const Traits& traits, bool debugLayer, bool apiDumpLayer, // get the screeen const xcb_setup_t* setup = xcb_get_setup(_connection); - vsg::ref_ptr keyboard(new KeyboardMap); + _keyboard = new KeyboardMap; { std::cout<<" *** stting up : min_keycode="<<(int)(setup->min_keycode)<<", max_keycode="<<(int)(setup->max_keycode)<=32 && keysym[m]<256) std::cout<<" ["<add(keycode, m, static_cast(keysym[m])); + if (keysym[m]!=0) _keyboard->add(keycode, m, static_cast(keysym[m])); } } @@ -236,28 +235,25 @@ Xcb_Window::Xcb_Window(const Traits& traits, bool debugLayer, bool apiDumpLayer, std::cout<<"Create window : "<response_type & ~0x80; if (response_type==XCB_PROPERTY_NOTIFY) { auto propety_notify = reinterpret_cast(event); - first_xcb_time = false; - first_xcb_timestamp = propety_notify->time; - first_xcb_time_point = vsg::clock::now(); + _first_xcb_timestamp = propety_notify->time; + _first_xcb_time_point = vsg::clock::now(); } free(event); } } - + vsg::clock::time_point start_point = _first_xcb_time_point; xcb_map_window(_connection, _window); @@ -347,8 +343,8 @@ Xcb_Window::Xcb_Window(const Traits& traits, bool debugLayer, bool apiDumpLayer, while(!close) { - using EventQueue = std::list>; - EventQueue events; + using Events = std::list>; + Events events; xcb_generic_event_t *event; int i=0; @@ -379,9 +375,9 @@ Xcb_Window::Xcb_Window(const Traits& traits, bool debugLayer, bool apiDumpLayer, { auto key_press = reinterpret_cast(event); - vsg::clock::time_point event_time = first_xcb_time_point + std::chrono::milliseconds(key_press->time-first_xcb_timestamp); - vsg::KeySymbol keySymbol = keyboard->getKeySymbol(key_press->detail, 0); - vsg::KeySymbol keySymbolModified = keyboard->getKeySymbol(key_press->detail, key_press->state); + vsg::clock::time_point event_time = _first_xcb_time_point + std::chrono::milliseconds(key_press->time-_first_xcb_timestamp); + vsg::KeySymbol keySymbol = _keyboard->getKeySymbol(key_press->detail, 0); + vsg::KeySymbol keySymbolModified = _keyboard->getKeySymbol(key_press->detail, key_press->state); events.emplace_back(new vsg::KeyPressEvent(0, event_time, keySymbol, keySymbolModified, KeyModifier(key_press->state), 0)); break; @@ -390,9 +386,9 @@ Xcb_Window::Xcb_Window(const Traits& traits, bool debugLayer, bool apiDumpLayer, { auto key_release = reinterpret_cast(event); - vsg::clock::time_point event_time = first_xcb_time_point + std::chrono::milliseconds(key_release->time-first_xcb_timestamp); - vsg::KeySymbol keySymbol = keyboard->getKeySymbol(key_release->detail, 0); - vsg::KeySymbol keySymbolModified = keyboard->getKeySymbol(key_release->detail, key_release->state); + vsg::clock::time_point event_time = _first_xcb_time_point + std::chrono::milliseconds(key_release->time-_first_xcb_timestamp); + vsg::KeySymbol keySymbol = _keyboard->getKeySymbol(key_release->detail, 0); + vsg::KeySymbol keySymbolModified = _keyboard->getKeySymbol(key_release->detail, key_release->state); events.emplace_back(new vsg::KeyReleaseEvent(0, event_time, keySymbol, keySymbolModified, KeyModifier(key_release->state), 0)); break; @@ -501,9 +497,65 @@ bool Xcb_Window::valid() const return _window!=9; } -bool Xcb_Window::pollEvents() +bool Xcb_Window::pollEvents(Events& events) { - return false; + unsigned numEventsBefore = events.size(); + xcb_generic_event_t *event; + int i=0; + while ((event = xcb_poll_for_event(_connection)) ) + { + ++i; + uint8_t response_type = event->response_type & ~0x80; + switch(response_type) + { + case(XCB_EXPOSE): + { + auto expose = reinterpret_cast(event); + std::cout<<"expose "<window<<", "<x<<", "<y<<", "<width<<", "<height<<", count="<count<(event); + if (client_message->data.data32[0]==_wmDeleteWindow) + { + std::cout<<"client message "<data.data32[0]< */ #include -#include +#include #include namespace vsg @@ -264,18 +264,16 @@ namespace vsg MODKEY_Meta = 128 }; - class KeyEvent : public Inherit + class KeyEvent : public Inherit { public: KeyEvent(Window* in_window, time_point in_time, KeySymbol in_keyBase, KeySymbol in_keyModified, KeyModifier in_modifier, uint32_t in_repeatCount=0): - Inherit(in_time), - window(in_window), + Inherit(in_window, in_time), keyBase(in_keyBase), keyModified(in_keyModified), keyModifier(in_modifier), repeatCount(in_repeatCount) {} - observer_ptr window; KeySymbol keyBase; KeySymbol keyModified; KeyModifier keyModifier; diff --git a/include/vsg/ui/PointerEvent.h b/include/vsg/ui/PointerEvent.h index bbd8f9e1a5..5dedfb699e 100644 --- a/include/vsg/ui/PointerEvent.h +++ b/include/vsg/ui/PointerEvent.h @@ -13,7 +13,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ #include -#include +#include #include namespace vsg @@ -30,17 +30,15 @@ namespace vsg // VSG_type_name(vsg::PointerEvent); - class PointerEvent : public Inherit + class PointerEvent : public Inherit { public: PointerEvent(Window* in_window, time_point in_time, uint32_t in_x, uint32_t in_y, ButtonMask in_buttonMask): - Inherit(in_time), - window(in_window), + Inherit(in_window, in_time), x(in_x), y(in_y), buttonMask(in_buttonMask) {} - observer_ptr window; uint32_t x; uint32_t y; ButtonMask buttonMask; diff --git a/include/vsg/ui/WindowEvent.h b/include/vsg/ui/WindowEvent.h new file mode 100644 index 0000000000..cfea5cb32f --- /dev/null +++ b/include/vsg/ui/WindowEvent.h @@ -0,0 +1,56 @@ +#pragma once + +/* + +Copyright(c) 2018 Robert Osfield + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + +#include +#include +#include + +namespace vsg +{ + + class WindowEvent : public Inherit + { + public: + WindowEvent(Window* in_window, time_point in_time): + Inherit(in_time), + window(in_window) {} + + observer_ptr window; + }; + + class ExposeWindowEvent : public Inherit + { + public: + ExposeWindowEvent(Window* in_window, time_point in_time, int32_t in_x, int32_t in_y, uint32_t in_width, uint32_t in_height): + Inherit(in_window, in_time), + x(in_x), + y(in_y), + width(in_width), + height(in_height) {} + + int x = 0; + int y = 0; + int width = 0; + int height = 0; + }; + + class DeleteWindowEvent : public Inherit + { + public: + DeleteWindowEvent(Window* in_window, time_point in_time): + Inherit(in_window, in_time) {} + }; + + +} diff --git a/src/vsg/core/ConstVisitor.cpp b/src/vsg/core/ConstVisitor.cpp index 31bcd3307b..7c40bbbe40 100644 --- a/src/vsg/core/ConstVisitor.cpp +++ b/src/vsg/core/ConstVisitor.cpp @@ -305,10 +305,22 @@ void ConstVisitor::apply(const UIEvent& event) { apply(static_cast(event)); } -void ConstVisitor::apply(const KeyEvent& event) +void ConstVisitor::apply(const WindowEvent& event) { apply(static_cast(event)); } +void ConstVisitor::apply(const ExposeWindowEvent& event) +{ + apply(static_cast(event)); +} +void ConstVisitor::apply(const DeleteWindowEvent& event) +{ + apply(static_cast(event)); +} +void ConstVisitor::apply(const KeyEvent& event) +{ + apply(static_cast(event)); +} void ConstVisitor::apply(const KeyPressEvent& event) { apply(static_cast(event)); @@ -319,7 +331,7 @@ void ConstVisitor::apply(const KeyReleaseEvent& event) } void ConstVisitor::apply(const PointerEvent& event) { - apply(static_cast(event)); + apply(static_cast(event)); } void ConstVisitor::apply(const ButtonPressEvent& event) { diff --git a/src/vsg/core/Visitor.cpp b/src/vsg/core/Visitor.cpp index 302cde840a..b3cbe9cc92 100644 --- a/src/vsg/core/Visitor.cpp +++ b/src/vsg/core/Visitor.cpp @@ -305,10 +305,22 @@ void Visitor::apply(UIEvent& event) { apply(static_cast(event)); } -void Visitor::apply(KeyEvent& event) +void Visitor::apply(WindowEvent& event) { apply(static_cast(event)); } +void Visitor::apply(ExposeWindowEvent& event) +{ + apply(static_cast(event)); +} +void Visitor::apply(DeleteWindowEvent& event) +{ + apply(static_cast(event)); +} +void Visitor::apply(KeyEvent& event) +{ + apply(static_cast(event)); +} void Visitor::apply(KeyPressEvent& event) { apply(static_cast(event)); @@ -319,7 +331,7 @@ void Visitor::apply(KeyReleaseEvent& event) } void Visitor::apply(PointerEvent& event) { - apply(static_cast(event)); + apply(static_cast(event)); } void Visitor::apply(ButtonPressEvent& event) { diff --git a/src/vsg/viewer/Xcb_Window.cpp b/src/vsg/viewer/Xcb_Window.cpp index 39f42a7062..b7c0a6c5dd 100644 --- a/src/vsg/viewer/Xcb_Window.cpp +++ b/src/vsg/viewer/Xcb_Window.cpp @@ -346,92 +346,49 @@ Xcb_Window::Xcb_Window(const Traits& traits, bool debugLayer, bool apiDumpLayer, using Events = std::list>; Events events; - xcb_generic_event_t *event; - int i=0; - while ((event = xcb_poll_for_event(_connection)) ) - { - ++i; - uint8_t response_type = event->response_type & ~0x80; - switch(response_type) + if (pollEvents(events)) + { + struct PrintEvents : public vsg::Visitor { - case(XCB_EXPOSE): + vsg::clock::time_point start_point; + bool& close; + + PrintEvents(vsg::clock::time_point in_start_point, bool& in_close) : start_point(in_start_point), close(in_close) {} + + void apply(vsg::UIEvent& event) { - auto expose = reinterpret_cast(event); - std::cout<<"expose "<window<<", "<x<<", "<y<<", "<width<<", "<height<<", count="<count<(event.time - start_point).count()<(event); - if (client_message->data.data32[0]==_wmDeleteWindow) - { - std::cout<<"client message "<data.data32[0]<(event.time - start_point).count()<<" "<(event); - vsg::clock::time_point event_time = _first_xcb_time_point + std::chrono::milliseconds(key_press->time-_first_xcb_timestamp); - vsg::KeySymbol keySymbol = _keyboard->getKeySymbol(key_press->detail, 0); - vsg::KeySymbol keySymbolModified = _keyboard->getKeySymbol(key_press->detail, key_press->state); - events.emplace_back(new vsg::KeyPressEvent(0, event_time, keySymbol, keySymbolModified, KeyModifier(key_press->state), 0)); - - break; - } - case XCB_KEY_RELEASE: + void apply(vsg::DeleteWindowEvent& event) { - auto key_release = reinterpret_cast(event); - - vsg::clock::time_point event_time = _first_xcb_time_point + std::chrono::milliseconds(key_release->time-_first_xcb_timestamp); - vsg::KeySymbol keySymbol = _keyboard->getKeySymbol(key_release->detail, 0); - vsg::KeySymbol keySymbolModified = _keyboard->getKeySymbol(key_release->detail, key_release->state); - events.emplace_back(new vsg::KeyReleaseEvent(0, event_time, keySymbol, keySymbolModified, KeyModifier(key_release->state), 0)); - - break; + std::cout<<"Delete window : "<(event.time - start_point).count()<(keyRelease.time - start_point).count()<<", "<(keyPress.time - start_point).count()<<", "<(event.time - start_point).count()<(keyRelease.time - start_point).count()<<", "<accept(print); } - - void apply(vsg::KeyPressEvent& keyPress) - { - std::cout<<"KeyPressEvent : "<(keyPress.time - start_point).count()<<", "<accept(print); } - - if (i>0) std::cout<(event); - std::cout<<"expose "<window<<", "<x<<", "<y<<", "<width<<", "<height<<", count="<count<x, expose->y, expose->width, expose->height)); break; } case XCB_CLIENT_MESSAGE: { auto client_message = reinterpret_cast(event); + if (client_message->data.data32[0]==_wmDeleteWindow) { - std::cout<<"client message "<data.data32[0]< +#include #include @@ -380,6 +381,21 @@ Xcb_Window::Xcb_Window(const Traits& traits, bool debugLayer, bool apiDumpLayer, { std::cout<<"KeyPressEvent : "<(keyPress.time - start_point).count()<<", "<(buttonPress.time - start_point).count()<<", "<(buttonRelease.time - start_point).count()<<", "<(move.time - start_point).count()<<", "<(event); + + vsg::clock::time_point event_time = _first_xcb_time_point + std::chrono::milliseconds(button_press->time-_first_xcb_timestamp); + events.emplace_back(new vsg::ButtonPressEvent(this, event_time, button_press->event_x, button_press->event_y, vsg::ButtonMask(button_press->state), button_press->detail)); + + break; + } + case(XCB_BUTTON_RELEASE): + { + auto button_release = reinterpret_cast(event); + + vsg::clock::time_point event_time = _first_xcb_time_point + std::chrono::milliseconds(button_release->time-_first_xcb_timestamp); + events.emplace_back(new vsg::ButtonPressEvent(this, event_time, button_release->event_x, button_release->event_y, vsg::ButtonMask(button_release->state), button_release->detail)); + + break; + } + case(XCB_MOTION_NOTIFY): + { + auto motion_notify = reinterpret_cast(event); + + vsg::clock::time_point event_time = _first_xcb_time_point + std::chrono::milliseconds(motion_notify->time-_first_xcb_timestamp); + events.emplace_back(new vsg::MoveEvent(this, event_time, motion_notify->event_x, motion_notify->event_y, vsg::ButtonMask(motion_notify->state))); + + break; + } default: { std::cout<<"event not handled, response_type = "<<(int)response_type< Date: Fri, 30 Nov 2018 12:11:58 +0000 Subject: [PATCH 14/17] Moved the PrintEvents visitor into Viewer::pollEvents() to facilitate test across Window implementations. Cleaned up the XcbWindow constructor in prep for implementing the Vulkan setup. --- src/vsg/viewer/Viewer.cpp | 65 ++++++++++++ src/vsg/viewer/Xcb_Window.cpp | 195 +--------------------------------- 2 files changed, 67 insertions(+), 193 deletions(-) diff --git a/src/vsg/viewer/Viewer.cpp b/src/vsg/viewer/Viewer.cpp index 85954135e2..775023daa2 100644 --- a/src/vsg/viewer/Viewer.cpp +++ b/src/vsg/viewer/Viewer.cpp @@ -73,6 +73,9 @@ bool Viewer::done() const return false; } +#include +#include + bool Viewer::pollEvents() { bool result = false; @@ -81,6 +84,68 @@ bool Viewer::pollEvents() { if (window->pollEvents(events)) result = true; } + + if (result) + { + struct PrintEvents : public vsg::Visitor + { + vsg::clock::time_point start_point; + bool& close; + + PrintEvents(vsg::clock::time_point in_start_point, bool& in_close) : start_point(in_start_point), close(in_close) {} + + void apply(vsg::UIEvent& event) + { + std::cout<<"event : "<(event.time - start_point).count()<(event.time - start_point).count()<<" "<(event.time - start_point).count()<(keyRelease.time - start_point).count()<<", "<(keyPress.time - start_point).count()<<", "<(buttonPress.time - start_point).count()<<", "<(buttonRelease.time - start_point).count()<<", "<(move.time - start_point).count()<<", "<accept(print); + } + } + return result; } diff --git a/src/vsg/viewer/Xcb_Window.cpp b/src/vsg/viewer/Xcb_Window.cpp index 23e92c891e..ec53199683 100644 --- a/src/vsg/viewer/Xcb_Window.cpp +++ b/src/vsg/viewer/Xcb_Window.cpp @@ -138,7 +138,7 @@ Xcb_Window::Xcb_Window(const Traits& traits, bool debugLayer, bool apiDumpLayer, - + // select the appropriate screen for the window xcb_screen_iterator_t screen_iterator = xcb_setup_roots_iterator(setup); for (;screenNum>0; --screenNum) xcb_screen_next(&screen_iterator); _screen = screen_iterator.data; @@ -221,22 +221,9 @@ Xcb_Window::Xcb_Window(const Traits& traits, bool debugLayer, bool apiDumpLayer, MotifHints hints = fullscreen ? MotifHints::borderless() : MotifHints::window(); xcb_change_property(_connection, XCB_PROP_MODE_REPLACE, _window, motifHintAtom, motifHintAtom, 32, 5, &hints); -#if 0 - // allowed actions - AtomRequest wmAllowedActions(_connection, "_NET_WM_ALLOWED_ACTIONS"); - AtomRequest wmActionFullScreen(_connection, "_NET_WM_ACTION_FULLSCREEN"); - std::vector actionAtoms - { - wmActionFullScreen - }; - - xcb_change_property(_connection, XCB_PROP_MODE_REPLACE, _window, wmAllowedActions, XCB_ATOM_ATOM, 32, actionAtoms.size(), actionAtoms.data()); - -#endif std::cout<<"Create window : "< windows; - windows["main"] = _window; - - xcb_query_tree_cookie_t tree_cookie = xcb_query_tree(_connection, _window); - xcb_query_tree_reply_t* tree_reply = xcb_query_tree_reply(_connection, tree_cookie, nullptr); - - xcb_drawable_t root{}; - - if (tree_reply!=nullptr) - { - root = tree_reply->root; - - windows["parent"] = tree_reply->parent; - - std::cout<<"number children = "<children_len<x; - y = geometry_reply->y; - width = geometry_reply->width; - height = geometry_reply->height; - - std::cout<<" geometry_rely : "<dst_x = "<dst_x<<", trans->dst_y = "<dst_y<>; - Events events; - - if (pollEvents(events)) - { - struct PrintEvents : public vsg::Visitor - { - vsg::clock::time_point start_point; - bool& close; - - PrintEvents(vsg::clock::time_point in_start_point, bool& in_close) : start_point(in_start_point), close(in_close) {} - - void apply(vsg::UIEvent& event) - { - std::cout<<"event : "<(event.time - start_point).count()<(event.time - start_point).count()<<" "<(event.time - start_point).count()<(keyRelease.time - start_point).count()<<", "<(keyPress.time - start_point).count()<<", "<(buttonPress.time - start_point).count()<<", "<(buttonRelease.time - start_point).count()<<", "<(move.time - start_point).count()<<", "<accept(print); - } - } - } - - -#if 0 - for(int i=0; i<1000; ++i) - { - int32_t x, y; - uint32_t width, height; - if (xcb::getWindowGeometry(_connection, _window, x, y, width, height)) - { - std::cout<<"Window geometry : "< Date: Fri, 30 Nov 2018 14:13:08 +0000 Subject: [PATCH 15/17] First cut of VCB Vulkan Window+Surface creation --- src/vsg/viewer/Win32_Window.cpp | 2 +- src/vsg/viewer/Xcb_Window.cpp | 97 ++++++++++++++++++++++++++++++--- src/vsg/viewer/Xcb_Window.h | 8 +++ 3 files changed, 99 insertions(+), 8 deletions(-) diff --git a/src/vsg/viewer/Win32_Window.cpp b/src/vsg/viewer/Win32_Window.cpp index 1b1bf78c0a..a4448aca71 100644 --- a/src/vsg/viewer/Win32_Window.cpp +++ b/src/vsg/viewer/Win32_Window.cpp @@ -34,7 +34,7 @@ namespace vsgWin32 vsg::Names vsgWin32::getInstanceExtensions() { // check the extensions are avaliable first - Names requiredExtensions = {"VK_KHR_surface", "VK_KHR_win32_surface"}; + Names requiredExtensions = {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME}; if (!vsg::isExtensionListSupported(requiredExtensions)) { diff --git a/src/vsg/viewer/Xcb_Window.cpp b/src/vsg/viewer/Xcb_Window.cpp index ec53199683..cc26e13eab 100644 --- a/src/vsg/viewer/Xcb_Window.cpp +++ b/src/vsg/viewer/Xcb_Window.cpp @@ -17,6 +17,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include +#include + #include #include #include @@ -52,16 +54,31 @@ void KeyboardMap::add(uint16_t keycode, std::initializer_list window(new Xcb_Window(traits, debugLayer, apiDumpLayer, allocator)); - - return Result("Failed to created Window, no Xcb implementation yet.", VK_ERROR_INVALID_EXTERNAL_HANDLE); - -// return window; + try + { + ref_ptr window(new Xcb_Window(traits, debugLayer, apiDumpLayer, allocator)); + return Result(window); + } + catch(vsg::Window::Result result) + { + return result; + } } @@ -251,9 +268,73 @@ Xcb_Window::Xcb_Window(const Traits& traits, bool debugLayer, bool apiDumpLayer, #endif + //xcb_flush(_connection); + + if (traits.shareWindow) + { + throw Result("Error: vsg::Xcb_Window::create(...) Sharing of Windows not Not supported yet.", VK_ERROR_INVALID_EXTERNAL_HANDLE); + } + else + { + Names instanceExtensions = {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME}; + + vsg::Names requestedLayers; + if (debugLayer) + { + instanceExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); + requestedLayers.push_back("VK_LAYER_LUNARG_standard_validation"); + if (apiDumpLayer) requestedLayers.push_back("VK_LAYER_LUNARG_api_dump"); + } + + vsg::Names validatedNames = vsg::validateInstancelayerNames(requestedLayers); + + vsg::Names deviceExtensions; + deviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + + vsg::ref_ptr instance = vsg::Instance::create(instanceExtensions, validatedNames, allocator); + if (!instance) throw Result("Error: vsg::Xcb_Window::create(...) failed to create Window, unable to create Vulkan instance.", VK_ERROR_INVALID_EXTERNAL_HANDLE); + + std::cout<<"Instance created"< surface(new Xcb_Surface(instance, _connection, _window, allocator)); + if (!surface) throw Result("Error: vsg::Xcb_Window::create(...) failed to create Window, unable to create GLFWSurface.", VK_ERROR_INVALID_EXTERNAL_HANDLE); + + std::cout<<"Surface created"< physicalDevice = vsg::PhysicalDevice::create(instance, VK_QUEUE_GRAPHICS_BIT, surface); + if (!physicalDevice) throw Result("Error: vsg::Xcb_Window::create(...) failed to create Window, no Vulkan PhysicalDevice supported.", VK_ERROR_INVALID_EXTERNAL_HANDLE); + + std::cout<<"Physical Device created"< device = vsg::Device::create(physicalDevice, validatedNames, deviceExtensions, allocator); + if (!device) throw Result("Error: vsg::Xcb_Window::create(...) failed to create Window, unable to create Vulkan logical Device.", VK_ERROR_INVALID_EXTERNAL_HANDLE); + + std::cout<<"Device created"< renderPass = vsg::RenderPass::create(device, imageFormat.format, depthFormat, allocator); + if (!renderPass) throw Result("Error: vsg::Xcb_Window::create(...) failed to create Window, unable to create Vulkan RenderPass.", VK_ERROR_INVALID_EXTERNAL_HANDLE); + + _instance = instance; + _surface = surface; + _physicalDevice = physicalDevice; + _device = device; + _renderPass = renderPass; + _debugLayersEnabled = debugLayer; + + std::cout<<"Renderpass created"< Date: Fri, 30 Nov 2018 14:39:20 +0000 Subject: [PATCH 16/17] Implemented handling of window resizing --- src/vsg/viewer/Xcb_Window.cpp | 27 ++++++++++++++++++++++++--- src/vsg/viewer/Xcb_Window.h | 1 + 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/vsg/viewer/Xcb_Window.cpp b/src/vsg/viewer/Xcb_Window.cpp index cc26e13eab..f3238382e3 100644 --- a/src/vsg/viewer/Xcb_Window.cpp +++ b/src/vsg/viewer/Xcb_Window.cpp @@ -332,9 +332,11 @@ Xcb_Window::Xcb_Window(const Traits& traits, bool debugLayer, bool apiDumpLayer, xcb_flush(_connection); - uint32_t width = traits.width; - uint32_t height = traits.height; - buildSwapchain(width, height); + // sleep to give the window manage time to do any repositing and resizing + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + + // build the swap chain, reuse the reize() for this + resize(); } @@ -374,6 +376,9 @@ bool Xcb_Window::pollEvents(Events& events) vsg::clock::time_point event_time = vsg::clock::now(); events.emplace_back(new vsg::ExposeWindowEvent(this, event_time, expose->x, expose->y, expose->width, expose->height)); + + _windowResized = (expose->width != _extent2D.width || expose->height != _extent2D.height); + break; } case XCB_CLIENT_MESSAGE: @@ -452,9 +457,25 @@ bool Xcb_Window::pollEvents(Events& events) bool Xcb_Window::resized() const { +#if 0 + return _windowResized; +#else + xcb_get_geometry_reply_t* geometry_reply = xcb_get_geometry_reply(_connection, xcb_get_geometry(_connection, _window), nullptr); + if (geometry_reply) + { + return (geometry_reply->width != _extent2D.width || geometry_reply->height != _extent2D.height); + } + return false; +#endif } void Xcb_Window::resize() { + xcb_get_geometry_reply_t* geometry_reply = xcb_get_geometry_reply(_connection, xcb_get_geometry(_connection, _window), nullptr); + if (geometry_reply) + { + buildSwapchain(geometry_reply->width, geometry_reply->height); + } + _windowResized = false; } diff --git a/src/vsg/viewer/Xcb_Window.h b/src/vsg/viewer/Xcb_Window.h index 7a2de77fc7..ace4f5cafc 100644 --- a/src/vsg/viewer/Xcb_Window.h +++ b/src/vsg/viewer/Xcb_Window.h @@ -234,6 +234,7 @@ namespace xcb xcb_atom_t _wmDeleteWindow{}; bool _closeEventRecieved = false; + bool _windowResized = false; xcb_timestamp_t _first_xcb_timestamp = 0; vsg::clock::time_point _first_xcb_time_point; From fef3aaf9bb7912693300d2b3b82dcddc51ebfcf7 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 30 Nov 2018 14:47:36 +0000 Subject: [PATCH 17/17] Added XCB_CONFIGURE_NOTIFY case to see how values and frequence compare to XCB_EXPOSE --- src/vsg/viewer/Xcb_Window.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/vsg/viewer/Xcb_Window.cpp b/src/vsg/viewer/Xcb_Window.cpp index f3238382e3..3e55cd64a5 100644 --- a/src/vsg/viewer/Xcb_Window.cpp +++ b/src/vsg/viewer/Xcb_Window.cpp @@ -370,6 +370,20 @@ bool Xcb_Window::pollEvents(Events& events) uint8_t response_type = event->response_type & ~0x80; switch(response_type) { +#if 0 + case(XCB_CONFIGURE_NOTIFY): + { + auto configure = reinterpret_cast(event); + + //vsg::clock::time_point event_time = vsg::clock::now(); + //events.emplace_back(new vsg::ExposeWindowEvent(this, event_time, expose->x, expose->y, expose->width, expose->height)); + + std::cout<<"XCB_CONFIGURE_NOTIFY x = "<x<<", y = "<y<<", "<width<<", "<height<width != _extent2D.width || configure->height != _extent2D.height); + break; + } +#endif case(XCB_EXPOSE): { auto expose = reinterpret_cast(event);