diff --git a/Source/WPE/CMakeLists.txt b/Source/WPE/CMakeLists.txt index a6ae2a64eccdc..deb0abf52c52f 100644 --- a/Source/WPE/CMakeLists.txt +++ b/Source/WPE/CMakeLists.txt @@ -39,6 +39,11 @@ if (USE_WPE_BACKEND_INTEL_CE) add_definitions(-DWPE_BACKEND_INTEL_CE=1) endif () +if (USE_WPE_BACKEND_WESTEROS) + find_package(westeros REQUIRED) + add_definitions(-DWPE_BACKEND_WESTEROS=1) +endif () + if (USE_WPE_BUFFER_MANAGEMENT_GBM) find_package(LibGBM REQUIRED) add_definitions(-DWPE_BUFFER_MANAGEMENT_GBM=1) @@ -60,6 +65,7 @@ set(WPE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/Source/WPE/Source/Graphics/BCMRPi" "${CMAKE_SOURCE_DIR}/Source/WPE/Source/Graphics/GBM" "${CMAKE_SOURCE_DIR}/Source/WPE/Source/Graphics/IntelCE" + "${CMAKE_SOURCE_DIR}/Source/WPE/Source/Graphics/Westeros" "${CMAKE_SOURCE_DIR}/Source/WPE/Source/Input" "${CMAKE_SOURCE_DIR}/Source/WPE/Source/Pasteboard" "${CMAKE_SOURCE_DIR}/Source/WPE/Source/Pasteboard" @@ -72,6 +78,7 @@ set(WPE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/Source/WPE/Source/ViewBackend/IntelCE" "${CMAKE_SOURCE_DIR}/Source/WPE/Source/ViewBackend/Wayland" "${CMAKE_SOURCE_DIR}/Source/WPE/Source/ViewBackend/Wayland/Protocols" + "${CMAKE_SOURCE_DIR}/Source/WPE/Source/ViewBackend/Westeros" ${BCM_HOST_INCLUDE_DIRS} ${GDL_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} @@ -79,6 +86,7 @@ set(WPE_INCLUDE_DIRECTORIES ${LIBUDEV_INCLUDE_DIRS} ${LIBXKBCOMMON_INCLUDE_DIRS} ${WAYLAND_INCLUDE_DIRS} + ${WESTEROS_INCLUDE_DIRS} ) set(WPE_LIBRARIES @@ -138,6 +146,23 @@ if (USE_WPE_BACKEND_INTEL_CE) ) endif () +if (USE_WPE_BACKEND_WESTEROS) + list(APPEND WPE_INCLUDE_DIRECTORIES + ${WESTEROS_INCLUDE_DIRS} + ${WESTEROSEGL_INCLUDE_DIRS} + ) + list(APPEND WPE_LIBRARIES + ${WESTEROS_LIBRARIES} + ${WESTEROSEGL_LIBRARIES} + ) + list(APPEND WPE_SOURCES + Source/Graphics/Westeros/RenderingBackendWesteros.cpp + + Source/ViewBackend/Westeros/ViewBackendWesteros.cpp + Source/ViewBackend/Westeros/WesterosViewbackendInput.cpp + ) +endif () + if (USE_WPE_BUFFER_MANAGEMENT_GBM) list(APPEND WPE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/Source/WPE/Source/Graphics/GBM" diff --git a/Source/WPE/Source/Graphics/RenderingBackend.cpp b/Source/WPE/Source/Graphics/RenderingBackend.cpp index b0f6aed8fd3f1..9e0c49bbb819b 100644 --- a/Source/WPE/Source/Graphics/RenderingBackend.cpp +++ b/Source/WPE/Source/Graphics/RenderingBackend.cpp @@ -29,6 +29,7 @@ #include "RenderingBackendBCMNexus.h" #include "RenderingBackendBCMRPi.h" #include "RenderingBackendIntelCE.h" +#include "RenderingBackendWesteros.h" #include #if WPE_BUFFER_MANAGEMENT(GBM) @@ -76,6 +77,10 @@ std::unique_ptr RenderingBackend::create(const uint8_t* data, return std::unique_ptr(new RenderingBackendIntelCE); #endif +#if WPE_BACKEND(WESTEROS) + return std::unique_ptr(new RenderingBackendWesteros); +#endif + fprintf(stderr, "RenderingBackend: no usable backend found, will crash.\n"); return nullptr; } diff --git a/Source/WPE/Source/Graphics/Westeros/RenderingBackendWesteros.cpp b/Source/WPE/Source/Graphics/Westeros/RenderingBackendWesteros.cpp new file mode 100644 index 0000000000000..3e7c95ee2e997 --- /dev/null +++ b/Source/WPE/Source/Graphics/Westeros/RenderingBackendWesteros.cpp @@ -0,0 +1,211 @@ +#include "Config.h" + +#if WPE_BACKEND(WESTEROS) + +#include "RenderingBackendWesteros.h" +#include +#include +#include +#include +#include +#include + +namespace WPE { + +namespace Graphics { + +typedef struct _GSource GSource; + +class EventSource { +public: + static GSourceFuncs sourceFuncs; + + GSource source; + GPollFD pfd; + struct wl_display* display; +}; + +GSourceFuncs EventSource::sourceFuncs = { + // prepare + [](GSource* base, gint* timeout) -> gboolean + { + auto* source = reinterpret_cast(base); + struct wl_display* display = source->display; + + *timeout = -1; + wl_display_flush(display); + wl_display_dispatch_pending(display); + + return FALSE; + }, + // check + [](GSource* base) -> gboolean + { + auto* source = reinterpret_cast(base); + return !!source->pfd.revents; + }, + // dispatch + [](GSource* base, GSourceFunc, gpointer) -> gboolean + { + auto* source = reinterpret_cast(base); + struct wl_display* display = source->display; + + if (source->pfd.revents & G_IO_IN) + wl_display_dispatch(display); + + if (source->pfd.revents & (G_IO_ERR | G_IO_HUP)) + return FALSE; + + source->pfd.revents = 0; + return TRUE; + }, + nullptr, // finalize + nullptr, // closure_callback + nullptr, // closure_marshall +}; + +static wl_display* g_WlDisplay = nullptr; + +static struct wl_registry_listener registryListener = { + + RenderingBackendWesteros::globalCallback, + RenderingBackendWesteros::globalRemoveCallback +}; + +void RenderingBackendWesteros::globalCallback(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t) +{ + auto& backend = *static_cast(data); + + if (!std::strcmp(interface, "wl_compositor")) + backend.m_compositor = static_cast(wl_registry_bind(registry, name, &wl_compositor_interface, 1)); +} + +void RenderingBackendWesteros::globalRemoveCallback(void*, struct wl_registry*, uint32_t) +{ + // FIXME: if this can happen without the UI Process getting shut down + // we should probably destroy our cached display instance. +} + +RenderingBackendWesteros::RenderingBackendWesteros() + : m_display(nullptr) + , m_registry(nullptr) + , m_compositor(nullptr) +{ + if (const char* nestedDisplay = std::getenv("WPE_WESTEROS_NESTED_DISPLAY")) { + m_display = wl_display_connect(nestedDisplay); + } else { + m_display = wl_display_connect(nullptr); + } + g_WlDisplay = m_display; + + if(!m_display) + return; + + m_registry = wl_display_get_registry(m_display); + wl_registry_add_listener(m_registry, ®istryListener, this); + wl_display_roundtrip(m_display); + + m_eventSource = g_source_new(&EventSource::sourceFuncs, sizeof(EventSource)); + auto* source = reinterpret_cast(m_eventSource); + source->display = m_display; + + source->pfd.fd = wl_display_get_fd(m_display); + source->pfd.events = G_IO_IN | G_IO_ERR | G_IO_HUP; + source->pfd.revents = 0; + g_source_add_poll(m_eventSource, &source->pfd); + + g_source_set_name(m_eventSource, "[WPE] WaylandDisplay"); + g_source_set_priority(m_eventSource, G_PRIORITY_HIGH + 30); + g_source_set_can_recurse(m_eventSource, TRUE); + g_source_attach(m_eventSource, g_main_context_get_thread_default()); +} + +RenderingBackendWesteros::~RenderingBackendWesteros() +{ + if (m_eventSource) + g_source_unref(m_eventSource); + m_eventSource = nullptr; + + g_WlDisplay = nullptr; + + if (m_compositor) + wl_compositor_destroy(m_compositor); + if (m_registry) + wl_registry_destroy(m_registry); + if (m_display) + wl_display_disconnect(m_display); +} + +EGLNativeDisplayType RenderingBackendWesteros::nativeDisplay() +{ + return m_display; +} + +std::unique_ptr RenderingBackendWesteros::createSurface(uint32_t width, uint32_t height, uint32_t targetHandle, RenderingBackend::Surface::Client& client) +{ + return std::unique_ptr(new RenderingBackendWesteros::Surface(*this, width, height, targetHandle, client)); +} + +std::unique_ptr RenderingBackendWesteros::createOffscreenSurface() +{ + return std::unique_ptr(new RenderingBackendWesteros::OffscreenSurface(*this)); +} + +RenderingBackendWesteros::Surface::Surface(const RenderingBackendWesteros& backend, uint32_t width, uint32_t height, uint32_t, RenderingBackendWesteros::Surface::Client&) +{ + m_surface = wl_compositor_create_surface(backend.m_compositor); + + if (m_surface) + m_window = wl_egl_window_create(m_surface, width, height); +} + +RenderingBackendWesteros::Surface::~Surface() +{ + if (m_window) + wl_egl_window_destroy(m_window); + if (m_surface) + wl_surface_destroy(m_surface); +} + +EGLNativeWindowType RenderingBackendWesteros::Surface::nativeWindow() +{ + return m_window; +} + +void RenderingBackendWesteros::Surface::resize(uint32_t width, uint32_t height) +{ + if(m_window) { + wl_egl_window_resize(m_window, width, height, 0, 0); + if(g_WlDisplay) + wl_display_flush(g_WlDisplay); + } +} + +RenderingBackend::BufferExport RenderingBackendWesteros::Surface::lockFrontBuffer() +{ + // This needs to be called for every eglSwapBuffers for the events to get flushed. + if(g_WlDisplay) + wl_display_flush(g_WlDisplay); + return std::make_tuple(-1, nullptr, 0); +} + +void RenderingBackendWesteros::Surface::releaseBuffer(uint32_t) +{ +} + +RenderingBackendWesteros::OffscreenSurface::OffscreenSurface(const RenderingBackendWesteros&) +{ +} + +RenderingBackendWesteros::OffscreenSurface::~OffscreenSurface() = default; + +EGLNativeWindowType RenderingBackendWesteros::OffscreenSurface::nativeWindow() +{ + return nullptr; +} + +} // namespace Graphics + +} // namespace WPE + +#endif // WPE_BACKEND(WESTEROS); diff --git a/Source/WPE/Source/Graphics/Westeros/RenderingBackendWesteros.h b/Source/WPE/Source/Graphics/Westeros/RenderingBackendWesteros.h new file mode 100644 index 0000000000000..a7857a19d6b99 --- /dev/null +++ b/Source/WPE/Source/Graphics/Westeros/RenderingBackendWesteros.h @@ -0,0 +1,60 @@ +#ifndef WPE_Graphics_RenderingBackendWesteros_h +#define WPE_Graphics_RenderingBackendWesteros_h + +#include +#include +#include + +typedef struct _GSource GSource; + +namespace WPE { + +namespace Graphics { + +class RenderingBackendWesteros final : public RenderingBackend { +public: + class Surface final : public RenderingBackend::Surface { + public: + Surface(const RenderingBackendWesteros&, uint32_t, uint32_t, uint32_t, Client&); + WPE_EXPORT virtual ~Surface(); + + EGLNativeWindowType nativeWindow() override; + void resize(uint32_t, uint32_t) override; + + BufferExport lockFrontBuffer() override; + void releaseBuffer(uint32_t) override; + + private: + struct wl_surface* m_surface; + struct wl_egl_window* m_window; + }; + + class OffscreenSurface final : public RenderingBackend::OffscreenSurface { + public: + OffscreenSurface(const RenderingBackendWesteros&); + virtual ~OffscreenSurface(); + + EGLNativeWindowType nativeWindow() override; + }; + + RenderingBackendWesteros(); + virtual ~RenderingBackendWesteros(); + + EGLNativeDisplayType nativeDisplay() override; + std::unique_ptr createSurface(uint32_t, uint32_t, uint32_t, RenderingBackend::Surface::Client&) override; + std::unique_ptr createOffscreenSurface() override; + static void globalCallback(void* data, struct wl_registry*, uint32_t name, const char* interface, uint32_t version); + static void globalRemoveCallback(void* data, struct wl_registry*, uint32_t name); + +private: + struct wl_display* m_display; + struct wl_registry* m_registry; + struct wl_compositor* m_compositor; + GSource* m_eventSource; +}; + +} // namespace Graphics + +} // namespace WPE + +#endif // WPE_Graphics_RenderingBackendWesteros_h diff --git a/Source/WPE/Source/ViewBackend/ViewBackend.cpp b/Source/WPE/Source/ViewBackend/ViewBackend.cpp index 49d032abd0b76..df169a9b00a33 100644 --- a/Source/WPE/Source/ViewBackend/ViewBackend.cpp +++ b/Source/WPE/Source/ViewBackend/ViewBackend.cpp @@ -30,6 +30,7 @@ #include "ViewBackendBCMNexus.h" #include "ViewBackendBCMRPi.h" #include "ViewBackendIntelCE.h" +#include "ViewBackendWesteros.h" #include #include #include @@ -74,6 +75,11 @@ std::unique_ptr ViewBackend::create() return std::unique_ptr(new ViewBackendIntelCE); #endif +#if WPE_BACKEND(WESTEROS) + if (!backendEnv || !std::strcmp(backendEnv, "westeros")) + return std::unique_ptr(new ViewBackendWesteros); +#endif + fprintf(stderr, "ViewBackend: no usable backend found, will crash.\n"); return nullptr; } diff --git a/Source/WPE/Source/ViewBackend/Westeros/ViewBackendWesteros.cpp b/Source/WPE/Source/ViewBackend/Westeros/ViewBackendWesteros.cpp new file mode 100644 index 0000000000000..d134342f0c496 --- /dev/null +++ b/Source/WPE/Source/ViewBackend/Westeros/ViewBackendWesteros.cpp @@ -0,0 +1,95 @@ +#include "Config.h" + +#if WPE_BACKEND(WESTEROS) + +#include "ViewBackendWesteros.h" +#include "WesterosViewbackendInput.h" +#include + +namespace WPE { + +namespace ViewBackend { + + +ViewBackendWesteros::ViewBackendWesteros() + : m_client(nullptr) + , m_input_handler(nullptr) +{ + m_compositor = WstCompositorCreate(); + if (!m_compositor) + return; + + m_input_handler = new WesterosViewbackendInput(); + const char* nestedTargetDisplay = std::getenv("WAYLAND_DISPLAY"); + if (nestedTargetDisplay) { + fprintf(stderr, "ViewBackendWesteros: running as the nested compositor\n"); + WstCompositorSetIsNested(m_compositor, true); + WstCompositorSetIsRepeater( m_compositor, true); + WstCompositorSetNestedDisplayName( m_compositor, nestedTargetDisplay); + //Register for all the necessary callback before starting the compositor + m_input_handler->initializeNestedInputHandler(m_compositor, this); + const char * nestedDisplayName = WstCompositorGetDisplayName(m_compositor); + setenv("WPE_WESTEROS_NESTED_DISPLAY", nestedDisplayName, 1); + } + + if (!WstCompositorStart(m_compositor)) + { + fprintf(stderr, "ViewBackendWesteros: failed to start the compositor: %s\n", + WstCompositorGetLastErrorDetail(m_compositor)); + WstCompositorDestroy(m_compositor); + m_compositor = nullptr; + } +} + +ViewBackendWesteros::~ViewBackendWesteros() +{ + if(m_input_handler) + m_input_handler->unregisterInputClient(); + m_client = nullptr; + + if (!m_compositor) + return; + + WstCompositorStop(m_compositor); + WstCompositorDestroy(m_compositor); + m_compositor = nullptr; + if(m_input_handler) + delete m_input_handler; +} + +void ViewBackendWesteros::setClient(Client* client) +{ + m_client = client; + if(m_client && m_compositor) { + uint32_t width, height; + WstCompositorGetNestedSize( m_compositor, &width, &height ); + m_client->setSize(width, height); + } +} + +uint32_t ViewBackendWesteros::constructRenderingTarget(uint32_t, uint32_t) +{ + return 0; +} + +void ViewBackendWesteros::commitBuffer(int, const uint8_t*, size_t) +{ + if (m_client) + m_client->frameComplete(); +} + +void ViewBackendWesteros::destroyBuffer(uint32_t) +{ +} + +void ViewBackendWesteros::setInputClient(Input::Client* client) +{ + if(m_input_handler) + m_input_handler->registerInputClient(client); +} + +} // namespace ViewBackend + +} // namespace WPE + +#endif // WPE_BACKEND(WESTEROS) diff --git a/Source/WPE/Source/ViewBackend/Westeros/ViewBackendWesteros.h b/Source/WPE/Source/ViewBackend/Westeros/ViewBackendWesteros.h new file mode 100644 index 0000000000000..177806635984f --- /dev/null +++ b/Source/WPE/Source/ViewBackend/Westeros/ViewBackendWesteros.h @@ -0,0 +1,41 @@ +#ifndef WPE_ViewBackend_ViewBackendWesteros_h +#define WPE_ViewBackend_ViewBackendWesteros_h + +#if WPE_BACKEND(WESTEROS) + +#include + +#include + +namespace WPE { + +namespace ViewBackend { + +class WesterosViewbackendInput; + +class ViewBackendWesteros final : public ViewBackend { +public: + ViewBackendWesteros(); + virtual ~ViewBackendWesteros(); + + void setClient(Client*) override; + std::pair authenticate() override { return { nullptr, 0 }; }; + uint32_t constructRenderingTarget(uint32_t, uint32_t) override; + void commitBuffer(int, const uint8_t*, size_t) override; + void destroyBuffer(uint32_t) override; + void setInputClient(Input::Client*) override; + +private: + WesterosViewbackendInput* m_input_handler; + WstCompositor* m_compositor; + Client* m_client; + uint32_t m_width; + uint32_t m_height; +}; + +} // namespace ViewBackend + +} // namespace WPE + +#endif // WPE_BACKEND(WESTEROS) +#endif // WPE_ViewBackend_ViewBackendWesteros_h diff --git a/Source/WPE/Source/ViewBackend/Westeros/WesterosViewbackendInput.cpp b/Source/WPE/Source/ViewBackend/Westeros/WesterosViewbackendInput.cpp new file mode 100644 index 0000000000000..e274da3a5a576 --- /dev/null +++ b/Source/WPE/Source/ViewBackend/Westeros/WesterosViewbackendInput.cpp @@ -0,0 +1,289 @@ +#include "Config.h" + +#if WPE_BACKEND(WESTEROS) + +#include "ViewBackendWesteros.h" +#include "WesterosViewbackendInput.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace WPE { + +namespace ViewBackend { + + +static WstKeyboardNestedListener keyboard_listener = { + WesterosViewbackendInput::keyboardHandleKeyMap, + WesterosViewbackendInput::keyboardHandleEnter, + WesterosViewbackendInput::keyboardHandleLeave, + WesterosViewbackendInput::keyboardHandleKey, + WesterosViewbackendInput::keyboardHandleModifiers, + WesterosViewbackendInput::keyboardHandleRepeatInfo +}; + +static WstPointerNestedListener pointer_listener = { + WesterosViewbackendInput::pointerHandleEnter, + WesterosViewbackendInput::pointerHandleLeave, + WesterosViewbackendInput::pointerHandleMotion, + WesterosViewbackendInput::pointerHandleButton, + WesterosViewbackendInput::pointerHandleAxis +}; + +void WesterosViewbackendInput::keyboardHandleKeyMap( void *userData, uint32_t format, int fd, uint32_t size ) +{ + auto& backend_input = *static_cast(userData); + auto& handlerData = backend_input.m_handlerData; + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + return; + } + + void* mapping = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0); + if (mapping == MAP_FAILED) { + close(fd); + return; + } + + auto& xkb = handlerData.xkb; + xkb.keymap = xkb_keymap_new_from_string(xkb.context, static_cast(mapping), + XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + munmap(mapping, size); + close(fd); + + if (!xkb.keymap) + return; + + xkb.state = xkb_state_new(xkb.keymap); + if (!xkb.state) + return; + + xkb.indexes.control = xkb_keymap_mod_get_index(xkb.keymap, XKB_MOD_NAME_CTRL); + xkb.indexes.alt = xkb_keymap_mod_get_index(xkb.keymap, XKB_MOD_NAME_ALT); + xkb.indexes.shift = xkb_keymap_mod_get_index(xkb.keymap, XKB_MOD_NAME_SHIFT); +} + +void WesterosViewbackendInput::keyboardHandleEnter( void *userData, struct wl_array *keys ) +{ +} + +void WesterosViewbackendInput::keyboardHandleLeave( void *userData ) +{ +} + +void WesterosViewbackendInput::keyboardHandleKey( void *userData, uint32_t time, uint32_t key, uint32_t state ) +{ + auto& backend_input = *static_cast(userData); + auto& handlerData = backend_input.m_handlerData; + + // IDK. + key += 8; + + handleKeyEvent(userData, key, state, time); + + if (!handlerData.repeatInfo.rate) + return; + + if (state == WL_KEYBOARD_KEY_STATE_RELEASED + && handlerData.repeatData.key == key) { + if (handlerData.repeatData.eventSource) + g_source_remove(handlerData.repeatData.eventSource); + handlerData.repeatData = { 0, 0, 0, 0 }; + } else if (state == WL_KEYBOARD_KEY_STATE_PRESSED + && xkb_keymap_key_repeats(handlerData.xkb.keymap, key)) { + + if (handlerData.repeatData.eventSource) + g_source_remove(handlerData.repeatData.eventSource); + + handlerData.repeatData = { key, time, state, g_timeout_add(handlerData.repeatInfo.delay, static_cast(repeatDelayTimeout), userData) }; + } +} + +void WesterosViewbackendInput::keyboardHandleModifiers( void *userData, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group ) +{ + auto& backend_input = *static_cast(userData); + auto& handlerData = backend_input.m_handlerData; + + auto& xkb = handlerData.xkb; + xkb_state_update_mask(xkb.state, mods_depressed, mods_latched, mods_locked, 0, 0, group); + + auto& modifiers = xkb.modifiers; + modifiers = 0; + auto component = static_cast(XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED); + if (xkb_state_mod_index_is_active(xkb.state, xkb.indexes.control, component)) + modifiers |= Input::KeyboardEvent::Control; + if (xkb_state_mod_index_is_active(xkb.state, xkb.indexes.alt, component)) + modifiers |= Input::KeyboardEvent::Alt; + if (xkb_state_mod_index_is_active(xkb.state, xkb.indexes.shift, component)) + modifiers |= Input::KeyboardEvent::Shift; +} + +void WesterosViewbackendInput::keyboardHandleRepeatInfo( void *userData, int32_t rate, int32_t delay ) +{ + auto& backend_input = *static_cast(userData); + auto& handlerData = backend_input.m_handlerData; + + auto& repeatInfo = handlerData.repeatInfo; + repeatInfo = { rate, delay }; + + // A rate of zero disables any repeating. + if (!rate) { + auto& repeatData = handlerData.repeatData; + if (repeatData.eventSource) { + g_source_remove(repeatData.eventSource); + repeatData = { 0, 0, 0, 0 }; + } + } +} + +void WesterosViewbackendInput::handleKeyEvent(void* userData, uint32_t key, uint32_t state, uint32_t time) +{ + auto& backend_input = *static_cast(userData); + auto& handlerData = backend_input.m_handlerData; + + auto& xkb = handlerData.xkb; + uint32_t keysym = xkb_state_key_get_one_sym(xkb.state, key); + uint32_t unicode = xkb_state_key_get_utf32(xkb.state, key); + + if (xkb.composeState + && state == WL_KEYBOARD_KEY_STATE_PRESSED + && xkb_compose_state_feed(xkb.composeState, keysym) == XKB_COMPOSE_FEED_ACCEPTED + && xkb_compose_state_get_status(xkb.composeState) == XKB_COMPOSE_COMPOSED) + { + keysym = xkb_compose_state_get_one_sym(xkb.composeState); + unicode = xkb_keysym_to_utf32(keysym); + } + + backend_input.m_client->handleKeyboardEvent({time, keysym, unicode, !!state, xkb.modifiers}); +} + +gboolean WesterosViewbackendInput::repeatRateTimeout(void* userData) +{ + auto& backend_input = *static_cast(userData); + auto& handlerData = backend_input.m_handlerData; + + handleKeyEvent(userData, handlerData.repeatData.key, handlerData.repeatData.state, handlerData.repeatData.time); + return G_SOURCE_CONTINUE; +} + +gboolean WesterosViewbackendInput::repeatDelayTimeout(void* userData) +{ + auto& backend_input = *static_cast(userData); + auto& handlerData = backend_input.m_handlerData; + + handleKeyEvent(userData, handlerData.repeatData.key, handlerData.repeatData.state, handlerData.repeatData.time); + handlerData.repeatData.eventSource = g_timeout_add(handlerData.repeatInfo.rate, static_cast(repeatRateTimeout), userData); + return G_SOURCE_REMOVE; +} + +void WesterosViewbackendInput::pointerHandleEnter( void *userData, wl_fixed_t sx, wl_fixed_t sy ) +{ +} + +void WesterosViewbackendInput::pointerHandleLeave( void *userData ) +{ +} + +void WesterosViewbackendInput::pointerHandleMotion( void *userData, uint32_t time, wl_fixed_t sx, wl_fixed_t sy ) +{ + auto& backend_input = *static_cast(userData); + auto& handlerData = backend_input.m_handlerData; + + auto x = wl_fixed_to_int(sx); + auto y = wl_fixed_to_int(sy); + + auto& pointer = handlerData.pointer; + pointer.coords = { x, y }; + + backend_input.m_client->handlePointerEvent({ Input::PointerEvent::Motion, time, x, y, 0, 0 }); +} + +void WesterosViewbackendInput::pointerHandleButton( void *userData, uint32_t time, uint32_t button, uint32_t state ) +{ + auto& backend_input = *static_cast(userData); + auto& handlerData = backend_input.m_handlerData; + + if (button >= BTN_MOUSE) + button = button - BTN_MOUSE + 1; + else + button = 0; + + auto& pointer = handlerData.pointer; + auto& coords = pointer.coords; + + backend_input.m_client->handlePointerEvent({ Input::PointerEvent::Button, time, coords.first, coords.second, button, state }); +} + +void WesterosViewbackendInput::pointerHandleAxis( void *userData, uint32_t time, uint32_t axis, wl_fixed_t value ) +{ + auto& backend_input = *static_cast(userData); + auto& handlerData = backend_input.m_handlerData; + + auto& pointer = handlerData.pointer; + auto& coords = pointer.coords; + + backend_input.m_client->handleAxisEvent({ Input::AxisEvent::Motion, time, coords.first, coords.second, axis, -wl_fixed_to_int(value) }); +} + +WesterosViewbackendInput::WesterosViewbackendInput() + : m_compositor(nullptr) + , m_viewbackend(nullptr) + , m_client(nullptr) +{ + m_handlerData.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + m_handlerData.xkb.composeTable = xkb_compose_table_new_from_locale(m_handlerData.xkb.context, setlocale(LC_CTYPE, nullptr), XKB_COMPOSE_COMPILE_NO_FLAGS); + if (m_handlerData.xkb.composeTable) + m_handlerData.xkb.composeState = xkb_compose_state_new(m_handlerData.xkb.composeTable, XKB_COMPOSE_STATE_NO_FLAGS); +} + +WesterosViewbackendInput::~WesterosViewbackendInput() +{ + m_compositor = nullptr; + m_viewbackend = nullptr; + m_client = nullptr; + + if (m_handlerData.xkb.context) + xkb_context_unref(m_handlerData.xkb.context); + if (m_handlerData.xkb.keymap) + xkb_keymap_unref(m_handlerData.xkb.keymap); + if (m_handlerData.xkb.state) + xkb_state_unref(m_handlerData.xkb.state); + if (m_handlerData.xkb.composeTable) + xkb_compose_table_unref(m_handlerData.xkb.composeTable); + if (m_handlerData.xkb.composeState) + xkb_compose_state_unref(m_handlerData.xkb.composeState); + if (m_handlerData.repeatData.eventSource) + g_source_remove(m_handlerData.repeatData.eventSource); +} + +void WesterosViewbackendInput::initializeNestedInputHandler(WstCompositor *compositor, ViewBackendWesteros *backend) +{ + m_compositor = compositor; + m_viewbackend = backend; + + if (m_compositor && m_viewbackend) + { + if (!WstCompositorSetKeyboardNestedListener( m_compositor, &keyboard_listener, this )) { + fprintf(stderr, "ViewBackendWesteros: failed to set keyboard nested listener: %s\n", + WstCompositorGetLastErrorDetail(m_compositor)); + } + if (!WstCompositorSetPointerNestedListener( m_compositor, &pointer_listener, this )) { + fprintf(stderr, "WesterosViewbackendInput: failed to set pointer nested listener: %s\n", + WstCompositorGetLastErrorDetail(m_compositor)); + } + } +} + +} // namespace ViewBackend + +} // namespace WPE + +#endif // WPE_BACKEND(WESTEROS) diff --git a/Source/WPE/Source/ViewBackend/Westeros/WesterosViewbackendInput.h b/Source/WPE/Source/ViewBackend/Westeros/WesterosViewbackendInput.h new file mode 100644 index 0000000000000..9e31d1c79bcd8 --- /dev/null +++ b/Source/WPE/Source/ViewBackend/Westeros/WesterosViewbackendInput.h @@ -0,0 +1,84 @@ +#ifndef WPE_ViewBackend_WesterosViewbackendInput_h +#define WPE_ViewBackend_WesterosViewbackendInput_h + +#if WPE_BACKEND(WESTEROS) + +#include "ViewBackendWesteros.h" + +#include +#include +#include +#include + +namespace WPE { + +namespace ViewBackend { + +class WesterosViewbackendInput { +public: + WesterosViewbackendInput(); + virtual ~WesterosViewbackendInput(); + void registerInputClient(Input::Client* client) { m_client = client; } + void unregisterInputClient() { m_client = nullptr; } + void initializeNestedInputHandler(WstCompositor *compositor, ViewBackendWesteros *backend); + + static void keyboardHandleKeyMap( void *userData, uint32_t format, int fd, uint32_t size ); + static void keyboardHandleEnter( void *userData, struct wl_array *keys ); + static void keyboardHandleLeave( void *userData ); + static void keyboardHandleKey( void *userData, uint32_t time, uint32_t key, uint32_t state ); + static void keyboardHandleModifiers( void *userData, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group ); + static void keyboardHandleRepeatInfo( void *userData, int32_t rate, int32_t delay ); + static void pointerHandleEnter( void *userData, wl_fixed_t sx, wl_fixed_t sy ); + static void pointerHandleLeave( void *userData ); + static void pointerHandleMotion( void *userData, uint32_t time, wl_fixed_t sx, wl_fixed_t sy ); + static void pointerHandleButton( void *userData, uint32_t time, uint32_t button, uint32_t state ); + static void pointerHandleAxis( void *userData, uint32_t time, uint32_t axis, wl_fixed_t value ); + static void handleKeyEvent(void* userData, uint32_t key, uint32_t state, uint32_t time); + static gboolean repeatRateTimeout(void* userData); + static gboolean repeatDelayTimeout(void* userData); + + struct HandlerData { + struct { + std::pair coords; + } pointer { { 0, 0 } }; + + struct { + struct xkb_context* context; + struct xkb_keymap* keymap; + struct xkb_state* state; + struct { + xkb_mod_index_t control; + xkb_mod_index_t alt; + xkb_mod_index_t shift; + } indexes; + uint8_t modifiers; + struct xkb_compose_table* composeTable; + struct xkb_compose_state* composeState; + } xkb { nullptr, nullptr, nullptr, { 0, 0, 0 }, 0, nullptr, nullptr }; + + struct { + int32_t rate; + int32_t delay; + } repeatInfo { 0, 0 }; + + struct { + uint32_t key; + uint32_t time; + uint32_t state; + uint32_t eventSource; + } repeatData { 0, 0, 0, 0 }; + }; + +private: + WstCompositor* m_compositor; + ViewBackendWesteros* m_viewbackend; + Input::Client* m_client; + HandlerData m_handlerData; +}; + +} // namespace ViewBackend + +} // namespace WPE + +#endif // WPE_BACKEND(WESTEROS) +#endif // WPE_ViewBackend_WesterosViewbackendInput_h diff --git a/Source/cmake/Findwesteros-egl.cmake b/Source/cmake/Findwesteros-egl.cmake new file mode 100644 index 0000000000000..a79074a3768eb --- /dev/null +++ b/Source/cmake/Findwesteros-egl.cmake @@ -0,0 +1,36 @@ +# - Try to find Athol. +# Once done, this will define +# +# WESTEROSEGL_FOUND - system has westeros-egl. +# WESTEROSEGL_INCLUDE_DIRS - the westeros-egl include directories +# WESTEROSEGL_LIBRARIES - link these to use westeros-egl. +# +# Copyright (C) 2014 Igalia S.L. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS +# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +find_package(PkgConfig) +pkg_check_modules(WESTEROSEGL westeros-egl) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(WESTEROSEGL DEFAULT_MSG WESTEROSEGL_FOUND) + diff --git a/Source/cmake/Findwesteros.cmake b/Source/cmake/Findwesteros.cmake new file mode 100644 index 0000000000000..e550b7399c467 --- /dev/null +++ b/Source/cmake/Findwesteros.cmake @@ -0,0 +1,35 @@ +# - Try to find Athol. +# Once done, this will define +# +# WESTEROS_FOUND - system has westeros. +# WESTEROS_INCLUDE_DIRS - the westeros include directories +# WESTEROS_LIBRARIES - link these to use westeros. +# +# Copyright (C) 2014 Igalia S.L. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS +# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +find_package(PkgConfig) +pkg_check_modules(WESTEROS westeros-compositor) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(WESTEROS DEFAULT_MSG WESTEROS_FOUND) diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake index 1dd032563242d..926d50574cf3f 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -38,6 +38,7 @@ WEBKIT_OPTION_DEFINE(USE_WPE_BACKEND_INTEL_CE "Whether to enable support for the WEBKIT_OPTION_DEFINE(USE_WPE_BACKEND_DRM "Whether to enable support for the DRM WPE backend" PUBLIC OFF) WEBKIT_OPTION_DEFINE(USE_WPE_BACKEND_DRM_TEGRA "Whether to enable support for the Tegra-specific quirks in the DRM WPE backend" PUBLIC OFF) WEBKIT_OPTION_DEFINE(USE_WPE_BACKEND_WAYLAND "Whether to enable support for the Wayland WPE backend" PUBLIC OFF) +WEBKIT_OPTION_DEFINE(USE_WPE_BACKEND_WESTEROS "Whether to enable support for the Westeros WPE backend" PUBLIC OFF) WEBKIT_OPTION_DEFINE(USE_WPE_BUFFER_MANAGEMENT_GBM "Whether to enable support for the GBM WPE rendering backend" PUBLIC OFF) WEBKIT_OPTION_DEFINE(USE_WPE_BUFFER_MANAGEMENT_BCM_RPI "Whether to enable support for the BCM RPi rendering backend" PUBLIC OFF) WEBKIT_OPTION_DEFINE(USE_WPE_BUFFER_MANAGEMENT_BCM_NEXUS "Whether to enable support for the BCM_NEXUS rendering backend" PUBLIC OFF) @@ -91,6 +92,12 @@ if (USE_WPE_BACKEND_BCM_RPI) find_package(BCMHost REQUIRED) endif () +if (USE_WPE_BACKEND_WESTEROS) + find_package(WaylandEGL REQUIRED) + find_package(westeros-egl REQUIRED) + find_package(westeros REQUIRED) +endif(USE_WPE_BACKEND_WESTEROS) + if (ENABLE_SUBTLE_CRYPTO) find_package(GnuTLS 3.0.0) if (NOT GNUTLS_FOUND)