diff --git a/CMakeLists.txt b/CMakeLists.txt index ab44908..3d4d486 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,7 @@ option(USE_BACKEND_BCM_NEXUS_WAYLAND "Whether to enable support for the BCM_NEXU option(USE_BACKEND_BCM_RPI "Whether to enable support for the BCM_RPi WPE backend" OFF) option(USE_BACKEND_INTEL_CE "Whether to enable support for the Intel CE WPE backend" OFF) option(USE_BACKEND_WAYLAND_EGL "Whether to enable support for the wayland-egl WPE backend" OFF) +option(USE_BACKEND_DIRECTFB "Whether to enable support for the directfb WPE backend" OFF) option(USE_BACKEND_WESTEROS "Whether to enable support for the Westeros WPE backend" OFF) option(USE_BACKEND_REALTEK "Whether to enable support for Realtek's Wayland EGL WPE backend" OFF) option(USE_BACKEND_VIV_IMX6_EGL "Whether to enable support for NXP's IMX6 EGL WPE backend" OFF) @@ -126,6 +127,10 @@ if (USE_BACKEND_WAYLAND_EGL) include(src/wayland-egl/CMakeLists.txt) endif () +if (USE_BACKEND_DIRECTFB) + include(src/directfb/CMakeLists.txt) +endif () + if (USE_BACKEND_WESTEROS) include(src/westeros/CMakeLists.txt) endif () diff --git a/cmake/FindDirectFB.cmake b/cmake/FindDirectFB.cmake new file mode 100755 index 0000000..4a46d7c --- /dev/null +++ b/cmake/FindDirectFB.cmake @@ -0,0 +1,54 @@ +# - Try to Find DirectFB +# Once done, this will define +# +# DIRECTFB_FOUND - system has DirectFB. +# DIRECTFB_INCLUDE_DIRS - the DirectFB include directories +# DIRECTFB_LIBRARIES - link these to use DirectFB. +# +# Copyright (C) 2014 Igalia S.L. +# Copyright (C) 1994-2020 OpenTV, Inc. and Nagravision S.A. +# +# 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(PC_DIRECTFB directfb) + +if (PC_DIRECTFB_FOUND) + set(DIRECTFB_DEFINITIONS ${PC_DIRECTFB_CFLAGS_OTHER}) +endif () + +find_path(DIRECTFB_INCLUDE_DIRS NAMES directfb.h + HINTS ${PC_DIRECTFB_INCLUDEDIR} ${PC_DIRECTFB_INCLUDE_DIRS} +) + +find_library(DIRECTFB_LIBRARIES directfb + HINTS ${PC_DIRECTFB_LIBDIR} ${PC_DIRECTFB_LIBRARY_DIRS} +) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(DIRECTFB DEFAULT_MSG DIRECTFB_INCLUDE_DIRS DIRECTFB_LIBRARIES) + +mark_as_advanced(DIRECTFB_INCLUDE_DIRS DIRECTFB_LIBRARIES) + diff --git a/src/directfb/CMakeLists.txt b/src/directfb/CMakeLists.txt new file mode 100644 index 0000000..0b16eef --- /dev/null +++ b/src/directfb/CMakeLists.txt @@ -0,0 +1,27 @@ +LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/src/directfb/cmake") + +find_package(EGL REQUIRED) +find_package(DirectFB REQUIRED) + +add_definitions(-DBACKEND_DIRECTFB=1) + +list(APPEND WPE_PLATFORM_INCLUDE_DIRECTORIES + ${DIRECTFB_INCLUDE_DIRS} + "${CMAKE_SOURCE_DIR}/src/diretfb/" +) + +list(APPEND WPE_PLATFORM_LIBRARIES + ${DIRECTFB_LIBRARIES} + ${EGL_LIBRARIES_dbpl} +) + +list(APPEND WPE_PLATFORM_SOURCES + src/directfb/renderer-backend.cpp + src/directfb/view-backend.cpp + src/directfb/display.cpp +) + +if (USE_INPUT_LIBINPUT OR USE_VIRTUAL_KEYBOARD) + add_definitions(-DKEY_INPUT_HANDLING_LIBINPUT=1) +endif () + diff --git a/src/directfb/dfb_backend_log.h b/src/directfb/dfb_backend_log.h new file mode 100644 index 0000000..a3868a7 --- /dev/null +++ b/src/directfb/dfb_backend_log.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2018-2020 OpenTV, Inc. and Nagravision S.A. + * All rights reserved. + * + * 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 HOLDERS AND 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 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. + */ + +#ifndef __DFB_BACKEND_LOG_H +#define __DFB_BACKEND_LOG_H + +#include + +#define WPEB_DFB_LOG_DEFAULT_TYPE 1 /* Default fprintf with color logging */ + +#define WPEB_DFB_ABORT(cond) abort() +#define WPEB_DFB_ASSERT(cond) assert((cond)) + +#if defined (WPEB_DFB_LOG_DEFAULT_TYPE) && (WPEB_DFB_LOG_DEFAULT_TYPE == 1) + +#define WPEB_DFB_LOG_LEVEL 3 /* 0 Critical, 1 Error, 2 Warning, 3 Info, 4 Debug, 5 Trace */ + +#if (WPEB_DFB_LOG_LEVEL >= 0) + #define WPEB_DFB_LOG_CRITICAL(msg, args...) fprintf(stderr, "\033[22;31m[WPEBACKEND_DFB] [CRITICAL] %-24s +%-4d : \033[22;0m" msg , __FILE__, __LINE__, ## args); +#else + #define WPEB_DFB_LOG_CRITICAL(msg, args...) ((void)0) +#endif + +#if (WPEB_DFB_LOG_LEVEL >= 1) + #define WPEB_DFB_LOG_ERROR(msg, args...) fprintf(stderr, "\033[22;31m[WPEBACKEND_DFB] [ERROR] %-24s +%-4d : \033[22;0m" msg , __FILE__, __LINE__, ## args); +#else + #define WPEB_DFB_LOG_ERROR(msg, args...) ((void)0) +#endif + +#if (WPEB_DFB_LOG_LEVEL >= 2) + #define WPEB_DFB_LOG_WARNING(msg, args...) fprintf(stderr, "\033[22;35m[WPEBACKEND_DFB] [WARN] %-24s +%-4d : \033[22;0m" msg , __FILE__, __LINE__, ## args); +#else + #define WPEB_DFB_LOG_WARNING(msg, args...) ((void)0) +#endif + +#if (WPEB_DFB_LOG_LEVEL >= 3) + #define WPEB_DFB_LOG_INFO(msg, args...) fprintf(stderr, "\033[22;34m[WPEBACKEND_DFB] [INFO] %-24s +%-4d : \033[22;0m" msg , __FILE__, __LINE__, ## args); +#else + #define WPEB_DFB_LOG_INFO(msg, args...) ((void)0) +#endif + +#if (WPEB_DFB_LOG_LEVEL >= 4) + #define WPEB_DFB_LOG_DEBUG(msg, args...) fprintf(stderr, "\033[22;32m[WPEBACKEND_DFB] [DEBUG] %-24s +%-4d : \033[22;0m" msg , __FILE__, __LINE__, ## args); +#else + #define WPEB_DFB_LOG_DEBUG(msg, args...) ((void)0) +#endif + +#if (WPEB_DFB_LOG_LEVEL >= 5) + #define WPEB_DFB_LOG_TRACE(msg, args...) fprintf(stderr, "\033[22;33m[WPEBACKEND_DFB] [TRACE] %-24s +%-4d : \033[22;0m" msg , __FILE__, __LINE__, ## args); +#else + #define WPEB_DFB_LOG_TRACE(msg, args...) ((void)0) +#endif + +#else /* Disable logging */ + +#define WPEB_DFB_LOG_CRITICAL ((void)0) +#define WPEB_DFB_LOG_ERROR ((void)0) +#define WPEB_DFB_LOG_WARNING ((void)0) +#define WPEB_DFB_LOG_INFO ((void)0) +#define WPEB_DFB_LOG_DEBUG ((void)0) +#define WPEB_DFB_LOG_TRACE ((void)0) + +#endif /* WPEB_DFB_LOG_DEFAULT_TYPE*/ + +#endif /*__DFB_BACKEND_LOG_H*/ diff --git a/src/directfb/display.cpp b/src/directfb/display.cpp new file mode 100644 index 0000000..bc5c86f --- /dev/null +++ b/src/directfb/display.cpp @@ -0,0 +1,554 @@ +/* + * Copyright (C) 2015, 2016 Igalia S.L. + * Copyright (C) 1994-2020 OpenTV, Inc. and Nagravision S.A. + * All rights reserved. + * + * 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 HOLDERS AND 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 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. + */ + +#include "display.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Directfb { + + class EventSource { + public: + static GSourceFuncs sourceFuncs; + + GSource source; + GPollFD pfd; + IDirectFBEventBuffer* eventBuffer; + }; + +static uint32_t +get_time_from_timeval( const struct timeval *tv ) +{ + long long monotonic = direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ); + long long realtime = direct_clock_get_time( DIRECT_CLOCK_REALTIME ); + + return tv->tv_sec * 1000 + tv->tv_usec / 1000 + monotonic / 1000 - realtime / 1000; +} + +static xkb_keysym_t +dfb_key_xkb_translate(DFBInputDeviceKeyIdentifier key_id, + DFBInputDeviceKeySymbol key_symbol) +{ + xkb_keysym_t keysym = XKB_KEY_NoSymbol; + + /* special case numpad */ + if (key_id >= DIKI_KP_DIV && key_id <= DIKI_KP_9) { + switch (key_symbol) { + case DIKS_SLASH: keysym = WPE_KEY_KP_Divide; break; + case DIKS_ASTERISK: keysym = WPE_KEY_KP_Multiply; break; + case DIKS_PLUS_SIGN: keysym = WPE_KEY_KP_Add; break; + case DIKS_MINUS_SIGN: keysym = WPE_KEY_KP_Subtract; break; + case DIKS_ENTER: keysym = WPE_KEY_KP_Enter; break; + case DIKS_SPACE: keysym = WPE_KEY_KP_Space; break; + case DIKS_TAB: keysym = WPE_KEY_KP_Tab; break; + case DIKS_EQUALS_SIGN: keysym = WPE_KEY_KP_Equal; break; + case DIKS_COMMA: + case DIKS_PERIOD: keysym = WPE_KEY_KP_Decimal; break; + case DIKS_HOME: keysym = WPE_KEY_KP_Home; break; + case DIKS_END: keysym = WPE_KEY_KP_End; break; + case DIKS_PAGE_UP: keysym = WPE_KEY_KP_Page_Up; break; + case DIKS_PAGE_DOWN: keysym = WPE_KEY_KP_Page_Down; break; + case DIKS_CURSOR_LEFT: keysym = WPE_KEY_KP_Left; break; + case DIKS_CURSOR_RIGHT: keysym = WPE_KEY_KP_Right; break; + case DIKS_CURSOR_UP: keysym = WPE_KEY_KP_Up; break; + case DIKS_CURSOR_DOWN: keysym = WPE_KEY_KP_Down; break; + case DIKS_BEGIN: keysym = WPE_KEY_KP_Begin; break; + case DIKS_INSERT: keysym = WPE_KEY_KP_Insert; break; + case DIKS_DELETE: keysym = WPE_KEY_KP_Delete; break; + case DIKS_0 ... DIKS_9: keysym = WPE_KEY_0 + key_symbol - DIKS_0; break; + case DIKS_F1 ... DIKS_F4:keysym = WPE_KEY_F1 + key_symbol - DIKS_F1; break; + + default: + keysym = WPE_KEY_Escape; + break; + } + } else { + switch (DFB_KEY_TYPE (key_symbol)) { + case DIKT_UNICODE: + switch (key_symbol) { + case DIKS_NULL: keysym = WPE_KEY_VoidSymbol; break; + case DIKS_BACKSPACE: keysym = WPE_KEY_BackSpace; break; + case DIKS_TAB: keysym = WPE_KEY_Tab; break; + case DIKS_RETURN: keysym = WPE_KEY_Return; break; /* same as DIKS_ENTER*/ + case DIKS_CANCEL: keysym = WPE_KEY_Cancel; break; + case DIKS_ESCAPE: keysym = WPE_KEY_Escape; break; + case DIKS_SPACE: keysym = WPE_KEY_space; break; + case DIKS_DELETE: keysym = WPE_KEY_Delete; break; + case DIKS_BACK: keysym = WPE_KEY_Back; break; + + default: + if (keysym & 0x01000000) + keysym = WPE_KEY_VoidSymbol; + else + keysym = key_symbol; + } + break; + + case DIKT_SPECIAL: + switch (key_symbol) { + case DIKS_CURSOR_LEFT: keysym = WPE_KEY_Left; break; + case DIKS_CURSOR_RIGHT: keysym = WPE_KEY_Right; break; + case DIKS_CURSOR_UP: keysym = WPE_KEY_Up; break; + case DIKS_CURSOR_DOWN: keysym = WPE_KEY_Down; break; + case DIKS_INSERT: keysym = WPE_KEY_Insert; break; + case DIKS_HOME: keysym = WPE_KEY_Home; break; + case DIKS_END: keysym = WPE_KEY_End; break; + case DIKS_PAGE_UP: keysym = WPE_KEY_Page_Up; break; + case DIKS_PAGE_DOWN: keysym = WPE_KEY_Page_Down; break; + case DIKS_PRINT: keysym = WPE_KEY_Print; break; + case DIKS_PAUSE: keysym = WPE_KEY_Pause; break; + case DIKS_SELECT: keysym = WPE_KEY_Select; break; + case DIKS_CLEAR: keysym = WPE_KEY_Clear; break; + case DIKS_MENU: keysym = WPE_KEY_Menu; break; + case DIKS_HELP: keysym = WPE_KEY_Help; break; + case DIKS_BEGIN: keysym = WPE_KEY_Begin; break; + case DIKS_BREAK: keysym = WPE_KEY_Break; break; + case DIKS_OK: keysym = WPE_KEY_Return; break; + case DIKS_BACK: keysym = WPE_KEY_Back; break; + default: + /* Pass thru all other DIKT_SPECIAL keys */ + keysym = key_symbol; + break; + } + break; + + case DIKT_FUNCTION: + keysym = WPE_KEY_F1 + key_symbol - DIKS_F1; + if (keysym > WPE_KEY_F35) + keysym = WPE_KEY_VoidSymbol; + break; + + case DIKT_MODIFIER: + switch (key_id) { + case DIKI_SHIFT_L: keysym = WPE_KEY_Shift_L; break; + case DIKI_SHIFT_R: keysym = WPE_KEY_Shift_R; break; + case DIKI_CONTROL_L: keysym = WPE_KEY_Control_L; break; + case DIKI_CONTROL_R: keysym = WPE_KEY_Control_R; break; + case DIKI_ALT_L: keysym = WPE_KEY_Alt_L; break; + case DIKI_ALT_R: keysym = WPE_KEY_Alt_R; break; + case DIKI_META_L: keysym = WPE_KEY_Meta_L; break; + case DIKI_META_R: keysym = WPE_KEY_Meta_R; break; + case DIKI_SUPER_L: keysym = WPE_KEY_Super_L; break; + case DIKI_SUPER_R: keysym = WPE_KEY_Super_R; break; + case DIKI_HYPER_L: keysym = WPE_KEY_Hyper_L; break; + case DIKI_HYPER_R: keysym = WPE_KEY_Hyper_R; break; + default: + break; + } + break; + + case DIKT_LOCK: + switch (key_symbol) { + case DIKS_CAPS_LOCK: keysym = WPE_KEY_Caps_Lock; break; + case DIKS_NUM_LOCK: keysym = WPE_KEY_Num_Lock; break; + case DIKS_SCROLL_LOCK: keysym = WPE_KEY_Scroll_Lock; break; + default: + break; + } + break; + + case DIKT_DEAD: + /* dead keys are handled directly by directfb */ + break; + + case DIKT_CUSTOM: + /* Pass thru all DIKT_CUSTOM keys */ + keysym = key_symbol; + break; + } /*switch*/ + } /* else*/ + + return keysym; +} + +static void +handleKeyEvent(uint32_t time_, + int32_t key_id, + int32_t key_code, + int32_t key_symbol, + uint32_t state, + gpointer data) +{ + auto* seatData = reinterpret_cast(data); + xkb_keysym_t keysym = XKB_KEY_NoSymbol; + uint32_t unicode = key_symbol; + + if( key_code <= 0 || + ((keysym = xkb_state_key_get_one_sym (seatData->xkb.state, key_code)) == XKB_KEY_NoSymbol) || + keysym >= 0x1008FF00) { /* if system doesnt understand XKB symbols of extended (internet/multimedia) keyboard inputs*/ + keysym = dfb_key_xkb_translate((DFBInputDeviceKeyIdentifier)key_id, (DFBInputDeviceKeySymbol)key_symbol); + } + if(key_code > 0) { + unicode = xkb_state_key_get_utf32(seatData->xkb.state, key_code); + xkb_state_update_key(seatData->xkb.state, key_code, state ? XKB_KEY_DOWN : XKB_KEY_UP); + } + struct wpe_input_keyboard_event event = { time_, keysym, unicode, state ? true : false, seatData->xkb.modifiers }; + EventDispatcher::singleton().sendEvent( event ); + WPEB_DFB_LOG_DEBUG("DIET_%s : key_id 0x%X , key_sym 0x%X, key_code 0x%X xkb_keysym_t 0x%X unicode %u modifiers %u\n", + state == DIET_KEYPRESS ? "KEYPRESS":"KEYRELEASE", key_id, key_symbol, key_code, keysym, unicode, seatData->xkb.modifiers); + return; +} + +static void +handleKeyModifier(const DFBWindowEvent *input_event, gpointer data) +{ + auto* seatData = reinterpret_cast(data); + auto& xkb = seatData->xkb; + + uint32_t latched_mods = 0, locked_mods = 0, base_mods = 0; + uint8_t keyModifiers = 0; + + auto& modifiers = xkb.modifiers; + modifiers = 0; + + if(input_event->modifiers || input_event->locks) { + /*XKB modifier Index values shift : 0, caps : 1, ctrl : 2, alt : 3, num : 4*/ + if(input_event->modifiers & DIMM_SHIFT) + latched_mods |= (1U << 0); + if(input_event->locks & DILS_CAPS) + locked_mods |= (1U << 1); + if(input_event->modifiers & DIMM_CONTROL) + base_mods |= (1U << 2); + if(input_event->modifiers & DIMM_ALT) + base_mods |= (1U << 3); + if(input_event->locks & DILS_NUM) + locked_mods |= (1U << 4); + } + xkb_state_update_mask (xkb.state, base_mods, latched_mods, locked_mods, 0, 0, 0); + + if(input_event->modifiers || input_event->locks) { + 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 |= wpe_input_keyboard_modifier_control; + if (xkb_state_mod_index_is_active(xkb.state, xkb.indexes.alt, component)) + modifiers |= wpe_input_keyboard_modifier_alt; + if (xkb_state_mod_index_is_active(xkb.state, xkb.indexes.shift, component)) + modifiers |= wpe_input_keyboard_modifier_shift; + } + return; +} + +static void +handleDfbEvent(DFBEvent &event, gpointer data) +{ + switch(event.clazz) { + case DFEC_WINDOW: { + const DFBWindowEvent &input = event.window; + switch(input.type) { + case DWET_KEYDOWN: + case DWET_KEYUP: { + handleKeyModifier(&input, data); /* Not required in final build, we wont use keyboard*/ + handleKeyEvent(get_time_from_timeval(&input.timestamp), + input.key_id, + (input.key_code > 0) ? (input.key_code + 8) : input.key_code, // Keycode system starts at 8. + input.key_symbol, + (input.type == DWET_KEYDOWN), + data); + break; + } + default: /* Mouse events not handled */ + break; + } + } + default: + WPEB_DFB_LOG_DEBUG("!!!!!!!!!! UnHandled Event Class %d !!!!!!!!!!\n", event.clazz); + break; + } +} + +GSourceFuncs EventSource::sourceFuncs = { + // prepare + [](GSource* base, gint* timeout) -> gboolean + { + auto* source = reinterpret_cast(base); + if(source->pfd.fd == -1) { + source->eventBuffer->Reset( source->eventBuffer ); + return TRUE; + } + *timeout = -1; + + return FALSE; + }, + // check + [](GSource* base) -> gboolean + { + auto* source = reinterpret_cast(base); + + if (source->pfd.revents & G_IO_IN) { + return TRUE; + } else { + return FALSE; + } + }, + // dispatch + [](GSource* base, GSourceFunc callback, gpointer data) -> gboolean + { + auto* source = reinterpret_cast(base); + auto* seatData = reinterpret_cast(data); + DFBEvent event; + unsigned char buffer[sizeof(DFBEvent)]; + + if (source->pfd.revents & G_IO_IN) { + ssize_t bytes; + size_t bufferOffset = 0; + assert(bufferOffset < sizeof(DFBEvent)); + const size_t needed = sizeof(DFBEvent) - bufferOffset; + do { + bytes = ::read(source->pfd.fd, buffer + bufferOffset, needed); + } while(bytes == -1 && errno == EINTR); + assert(bytes != -1 || errno == EWOULDBLOCK || errno == EAGAIN); + if(bytes > 0) { + bufferOffset += bytes; + if(bufferOffset == sizeof(DFBEvent)) { + memcpy(&event, buffer, sizeof(DFBEvent)); + bufferOffset = 0; + } + } + handleDfbEvent(event, data); + } else if(source->pfd.fd == -1) { + if(source->eventBuffer->WaitForEvent(source->eventBuffer) != DFB_OK) { + source->eventBuffer->GetEvent( source->eventBuffer, DFB_EVENT(&event) ); + handleDfbEvent(event, data); + } + } + + if (source->pfd.revents & (G_IO_ERR | G_IO_HUP)) + return G_SOURCE_REMOVE; + + source->pfd.revents = 0; + return G_SOURCE_CONTINUE; + }, + nullptr, // finalize + nullptr, // closure_callback + nullptr, // closure_marshall +}; + +void Display::unregisterDirectFBDisplayPlatform() +{ + if (m_dfb) { + /* Add Platform Specific code */ + } +} + +void Display::deInitDirectFB() +{ + if (m_dfb) { + m_dfb->Release( m_dfb ); + m_dfb = NULL; + } +} + +bool Display::initDirectFB() +{ + if (m_dfb) + return true; + + if (DirectFBInit(NULL, NULL) != DFB_OK) + return false; + + if (DirectFBCreate(&m_dfb) != DFB_OK) + return false; + + IDirectFBDisplayLayer *layer = NULL; + m_dfb->GetDisplayLayer( m_dfb, DLID_PRIMARY, &layer ); + assert(layer); + if(layer){ + layer->SetCooperativeLevel( layer, DLSCL_SHARED ); + layer->GetConfiguration(layer, &m_layerConfig); + layer->Release(layer); + } + return true; +} + +bool Display::registerDirectFBDisplayPlatform() +{ + /* Add Platform Specific code */ + return true; +} + +Display& Display::singleton() +{ + static Display display; + return display; +} + +Display::Display() + :m_dfb(NULL) +{ + memset(&m_layerConfig, sizeof(m_layerConfig), 0); + + struct xkb_context* context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + struct xkb_rule_names names = { "evdev", "pc105", "us", "", "" }; + + initDirectFB(); + + m_seatData.xkb.keymap = xkb_keymap_new_from_names(context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!m_seatData.xkb.keymap){ + WPEB_DFB_LOG_CRITICAL("Dfb::Display Couldnt create xkbKeymap\n"); + WPEB_DFB_ABORT(0); + } + m_seatData.xkb.state = xkb_state_new(m_seatData.xkb.keymap); + if (!m_seatData.xkb.state){ + WPEB_DFB_LOG_CRITICAL("Dfb::Display Couldnt create xkbState\n"); + WPEB_DFB_ABORT(0); + } + + m_seatData.xkb.indexes.control = xkb_keymap_mod_get_index(m_seatData.xkb.keymap, XKB_MOD_NAME_CTRL); + m_seatData.xkb.indexes.alt = xkb_keymap_mod_get_index(m_seatData.xkb.keymap, XKB_MOD_NAME_ALT); + m_seatData.xkb.indexes.shift = xkb_keymap_mod_get_index(m_seatData.xkb.keymap, XKB_MOD_NAME_SHIFT); + m_seatData.xkb.modifiers = 0; + + xkb_context_unref(context); +} + +void Display::initializeEventSource(IDirectFBWindow *dfb_window) +{ + DFBResult ret; + IDirectFBEventBuffer *eventBuffer = NULL; + + if(ret = m_dfb->CreateEventBuffer(m_dfb,&eventBuffer)) { + WPEB_DFB_LOG_CRITICAL("xxxxxxxxxx Create Direct FB Event Buffer failed xxxxxxxxxx %s", DirectFBErrorString(ret)); + } else { + dfb_window->AttachEventBuffer(dfb_window, eventBuffer); + dfb_window->RequestFocus(dfb_window); + } + WPEB_DFB_LOG_DEBUG("Initialize DirectFb Event Input handling\n"); + + m_eventSource = g_source_new(&EventSource::sourceFuncs, sizeof(EventSource)); + auto* source = reinterpret_cast(m_eventSource); + + source->eventBuffer = eventBuffer; + + if(source->eventBuffer) { + if((ret = source->eventBuffer->CreateFileDescriptor(source->eventBuffer, &source->pfd.fd)) != DFB_OK) { + WPEB_DFB_LOG_CRITICAL("xxxxxxxxxx Couldnt Create FD from eventBuffer xxxxxxxxxx %s", DirectFBErrorString(ret)); + source->pfd.fd = -1; + } + } + 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] DirectFb EventBuffer"); + 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()); + g_source_set_callback (m_eventSource, static_cast(NULL), &m_seatData, NULL); + WPEB_DFB_LOG_DEBUG("Initialized with G_SOURCE input handling\n"); + return; +} + +Display::~Display() +{ + if (m_eventSource) { + auto* source = reinterpret_cast(m_eventSource); + source->eventBuffer->WakeUp( source->eventBuffer ); + g_source_unref(m_eventSource); + m_eventSource = nullptr; + } + + unregisterDirectFBDisplayPlatform(); /* XXX do we need this here or to use atexit */ + deInitDirectFB(); + + m_seatData = SeatData{ }; + + if (m_seatData.xkb.keymap) + xkb_keymap_unref(m_seatData.xkb.keymap); + if (m_seatData.xkb.state) + xkb_state_unref(m_seatData.xkb.state); +} + +EventDispatcher& EventDispatcher::singleton() +{ + static EventDispatcher event; + return event; +} + +void EventDispatcher::sendEvent( wpe_input_axis_event& event ) +{ + if ( m_ipc != nullptr ) { + IPC::Message message; + message.messageCode = MsgType::AXIS; + memcpy( message.messageData, &event, sizeof(event) ); + m_ipc->sendMessage(IPC::Message::data(message), IPC::Message::size); + } +} + +void EventDispatcher::sendEvent( wpe_input_pointer_event& event ) +{ + if ( m_ipc != nullptr ) { + IPC::Message message; + message.messageCode = MsgType::POINTER; + memcpy( message.messageData, &event, sizeof(event) ); + m_ipc->sendMessage(IPC::Message::data(message), IPC::Message::size); + } +} + +void EventDispatcher::sendEvent( wpe_input_touch_event& event ) +{ + if ( m_ipc != nullptr ) { + IPC::Message message; + message.messageCode = MsgType::TOUCH; + memcpy( message.messageData, &event, sizeof(event) ); + m_ipc->sendMessage(IPC::Message::data(message), IPC::Message::size); + } +} + +void EventDispatcher::sendEvent( wpe_input_keyboard_event& event ) +{ + if ( m_ipc != nullptr ) { + IPC::Message message; + message.messageCode = MsgType::KEYBOARD; + memcpy( message.messageData, &event, sizeof(event) ); + m_ipc->sendMessage(IPC::Message::data(message), IPC::Message::size); + } +} + +void EventDispatcher::sendEvent( wpe_input_touch_event_raw& event ) +{ + if ( m_ipc != nullptr ) { + IPC::Message message; + message.messageCode = MsgType::TOUCHSIMPLE; + memcpy( message.messageData, &event, sizeof(event) ); + m_ipc->sendMessage(IPC::Message::data(message), IPC::Message::size); + } +} + +void EventDispatcher::setIPC( IPC::Client& ipcClient ) +{ + m_ipc = &ipcClient; +} + +} // namespace Wayland diff --git a/src/directfb/display.h b/src/directfb/display.h new file mode 100644 index 0000000..50652fa --- /dev/null +++ b/src/directfb/display.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2015, 2016 Igalia S.L. + * Copyright (C) 1994-2020 OpenTV, Inc. and Nagravision S.A. + * All rights reserved. + * + * 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 HOLDERS AND 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 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. + */ + +#ifndef wpe_view_backend_directfb_display_h +#define wpe_view_backend_directfb_display_h + +#include + +#define DFB_EVENT_BUFFER_TIMOUT_SEC 0 /* seconds*/ +#define DFB_EVENT_BUFFER_TIMOUT_MS 100 /* MiliSeconds*/ + +#include "dfb_backend_log.h" + +#include +#include +#include +#include +#include +#include +#include "ipc.h" + +struct wpe_view_backend; + +typedef struct _GSource GSource; + +namespace Directfb { + +class EventDispatcher +{ +public: + static EventDispatcher& singleton(); + void sendEvent( wpe_input_axis_event& event ); + void sendEvent( wpe_input_pointer_event& event ); + void sendEvent( wpe_input_touch_event& event ); + void sendEvent( wpe_input_keyboard_event& event ); + void sendEvent( wpe_input_touch_event_raw& event ); + void setIPC( IPC::Client& ipcClient ); + enum MsgType + { + AXIS = 0, + POINTER, + TOUCH, + TOUCHSIMPLE, + KEYBOARD + }; +private: + EventDispatcher() {}; + ~EventDispatcher() {}; + IPC::Client * m_ipc; +}; + +class Display { +public: + static Display& singleton(); + void unregisterDirectFBDisplayPlatform(); + bool registerDirectFBDisplayPlatform(); + bool initDirectFB(); + void deInitDirectFB(); + void initializeEventSource(IDirectFBWindow *dfb_window); + + IDirectFB* iDirectfb() const { return m_dfb; } + unsigned int width() const { return m_layerConfig.width; } + unsigned int height() const { return m_layerConfig.height; } + + struct SeatData { + struct { + 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; + } xkb { nullptr, nullptr, { 0, 0, 0 }, 0}; + }; + +private: + Display(); + ~Display(); + + IDirectFB* m_dfb; + DFBDisplayLayerConfig m_layerConfig; + + SeatData m_seatData; + GSource* m_eventSource; +}; + +} // namespace Directfb + +#endif // wpe_view_backend_directfb_display_h + diff --git a/src/directfb/interfaces.h b/src/directfb/interfaces.h new file mode 100644 index 0000000..976bef6 --- /dev/null +++ b/src/directfb/interfaces.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015, 2016 Igalia S.L. + * Copyright (C) 2015, 2016 Metrological + * Copyright (C) 1994-2020 OpenTV, Inc. and Nagravision S.A. + * All rights reserved. + * + * 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 HOLDERS AND 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 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. + */ + +#ifndef directfb_interfaces_h +#define directfb_interfaces_h + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct wpe_renderer_backend_egl_interface directfb_renderer_backend_egl_interface; +extern struct wpe_renderer_backend_egl_target_interface directfb_renderer_backend_egl_target_interface; +extern struct wpe_renderer_backend_egl_offscreen_target_interface directfb_renderer_backend_egl_offscreen_target_interface; + +extern struct wpe_view_backend_interface directfb_view_backend_interface; + +#ifdef __cplusplus +} +#endif + +#endif // directfb_interfaces_h diff --git a/src/directfb/ipc-directfb.h b/src/directfb/ipc-directfb.h new file mode 100644 index 0000000..877d43e --- /dev/null +++ b/src/directfb/ipc-directfb.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2015, 2016 Igalia S.L. + * Copyright (C) 2015, 2016 Metrological + * Copyright (C) 2016 SoftAtHome + * Copyright (C) 1994-2020 OpenTV, Inc. and Nagravision S.A. + * All rights reserved. + * + * 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 HOLDERS AND 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 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. + */ + +#ifndef wpe_platform_ipc_directfb_h +#define wpe_platform_ipc_directfb_h + +#include +#include + +namespace IPC { + +namespace Directfb { + +struct BufferCommit { + uint32_t width; + uint32_t height; + uint8_t padding[24]; + + static const uint64_t code = 1; + static void construct(Message& message, uint32_t width, uint32_t height) + { + message.messageCode = code; + + auto& messageData = *reinterpret_cast(std::addressof(message.messageData)); + messageData.width = width; + messageData.height = height; + } + static BufferCommit& cast(Message& message) + { + return *reinterpret_cast(std::addressof(message.messageData)); + } +}; +static_assert(sizeof(BufferCommit) == Message::dataSize, "BufferCommit is of correct size"); + +struct FrameComplete { + int8_t padding[Message::dataSize]; + + static const uint64_t code = 2; + static void construct(Message& message) + { + message.messageCode = code; + } + static FrameComplete& cast(Message& message) + { + return *reinterpret_cast(std::addressof(message.messageData)); + } +}; +static_assert(sizeof(FrameComplete) == Message::dataSize, "FrameComplete is of correct size"); + +} // namespace Directfb + +} // namespace IPC + +#endif // wpe_platform_ipc_directfb_h diff --git a/src/directfb/renderer-backend.cpp b/src/directfb/renderer-backend.cpp new file mode 100644 index 0000000..63ec2f0 --- /dev/null +++ b/src/directfb/renderer-backend.cpp @@ -0,0 +1,363 @@ +/* + * Copyright (C) 2015, 2016 Igalia S.L. + * Copyright (C) 2015, 2016 Metrological + * Copyright (C) 2016 SoftAtHome + * Copyright (C) 1994-2020 OpenTV, Inc. and Nagravision S.A. + * All rights reserved. + * + * 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 HOLDERS AND 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 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. + */ + +#include +#include + +#include "display.h" +#include "ipc.h" +#include "ipc-directfb.h" +#include +#include +#include +#include + +#define OPENGL_ES_2 1 + +#include + +namespace Directfb { + +static IDirectFB *s_dfb = 0; + +struct Backend { + Backend(); + ~Backend(); + + Directfb::Display& display; +}; + +Backend::Backend() + : display(Directfb::Display::singleton()) +{ + WPEB_DFB_LOG_DEBUG("Platform DFB Backend Initialization\n"); +} + +Backend::~Backend() +{ + WPEB_DFB_LOG_WARNING("!!!!!!!!!! Not Implemented !!!!!!!!!!\n"); +} + +struct EGLTarget : public IPC::Client::Handler { + EGLTarget(struct wpe_renderer_backend_egl_target*, int); + virtual ~EGLTarget(); + + void initialize(Backend& backend, uint32_t, uint32_t); + void resize(uint32_t, uint32_t); + + // IPC::Client::Handler + void handleMessage(char*, size_t) override; + + struct wpe_renderer_backend_egl_target* target; + IPC::Client ipcClient; + void* nativeWindow; + void* dfbWindow; + bool windowSuspended; + DFBSurfaceCapabilities surfaceCaps; + Backend* m_backend { nullptr }; + uint32_t width { 0 }; + uint32_t height { 0 }; + + // main window created by the web process. This is always the first window after WebProcess starts. All subsequent windows are usually popup windows + static IDirectFBWindow* mainWindow; +}; + +IDirectFBWindow* EGLTarget::mainWindow = NULL; + +EGLTarget::EGLTarget(struct wpe_renderer_backend_egl_target* target, int hostFd) + : target(target) + , nativeWindow(nullptr) + , dfbWindow(nullptr) + , windowSuspended(false) + , surfaceCaps(DSCAPS_NONE) +{ + ipcClient.initialize(*this, hostFd); + Directfb::EventDispatcher::singleton().setIPC( ipcClient ); +} + +EGLTarget::~EGLTarget() +{ + ipcClient.deinitialize(); + if(nativeWindow){ + IDirectFBSurface *dfb_surface = reinterpret_cast(nativeWindow); + dfb_surface->Release(dfb_surface); + } + + if(dfbWindow){ + if(dfbWindow == mainWindow) + mainWindow = NULL; + + IDirectFBWindow *dfb_window = reinterpret_cast(dfbWindow); + dfb_window->Release(dfb_window); + } +} + +static void +update_surface_capabilities(IDirectFBWindow *window ,DFBWindowDescription *Desc) +{ + /* For WPE_DFB_WINDOW_FLAGS setenv is in mainc.pp */ + const char * window_flags_str = getenv("WPE_DFB_WINDOW_FLAGS"); + WPEB_DFB_LOG_INFO("Using window-flags for DFB WINDOW = %s\n", window_flags_str); + + DFBSurfaceCapabilities dscaps_premultiplied = DSCAPS_NONE; + DFBSurfaceCapabilities dscaps_buffer = DSCAPS_NONE; + DFBSurfaceCapabilities dscaps_gl = DSCAPS_NONE; + + if(window_flags_str) { + gchar** window_flags = g_strsplit(window_flags_str, ",", -1); + if(window_flags) { + unsigned int i = 0; + while(window_flags[i]) { + if(strcmp("premultiplied", window_flags[i]) == 0) + dscaps_premultiplied = DSCAPS_PREMULTIPLIED; + else if (strcmp("double-buffer", window_flags[i]) == 0) + dscaps_buffer = DSCAPS_DOUBLE; + else if (strcmp("triple-buffer", window_flags[i]) == 0) + dscaps_buffer = DSCAPS_TRIPLE; + else if (strcmp("opengl", window_flags[i]) == 0) + dscaps_gl = DSCAPS_GL; + i++; + } + Desc->surface_caps = DFBSurfaceCapabilities(dscaps_gl | dscaps_premultiplied | dscaps_buffer); + g_strfreev(window_flags); + } + } +} + +void EGLTarget::resize(uint32_t w, uint32_t h) +{ + assert(dfbWindow); + IDirectFBWindow *dfb_window = reinterpret_cast(dfbWindow); + + if(w <= 1 && h <= 1) { + // if width and height are 1 or less, the app is being made invisible, so we can free graphics memory by resizing the surface to a minimum + WPEB_DFB_LOG_INFO("WPE Backend resize(): suspending DFB Window\n"); + + dfb_window->ResizeSurface(dfb_window, w, h); + windowSuspended = true; + }else if(windowSuspended) { + WPEB_DFB_LOG_INFO("WPE Backend resize(): resuming DFB Window\n"); + + // if window was suspended previously and now we are restoring it by setting width and height to larger than 1, we need to resize the surface back to original size + dfb_window->ResizeSurface(dfb_window, this->width, this->height); + windowSuspended = false; + } + + assert(nativeWindow); + IDirectFBSurface *dfb_surface = reinterpret_cast(nativeWindow); + dfb_surface->Clear(dfb_surface, 0x0, 0x0, 0x0, 0x0); + dfb_surface->Flip(dfb_surface, NULL, DSFLIP_WAITFORSYNC); + + if (surfaceCaps & DSCAPS_DOUBLE){ + // one more time since it's a double surface + dfb_surface->Clear(dfb_surface, 0x0, 0x0, 0x0, 0x0); + dfb_surface->Flip(dfb_surface, NULL, DSFLIP_WAITFORSYNC); + }else if(surfaceCaps & DSCAPS_TRIPLE){ + // two more times since it's a triple surface + dfb_surface->Clear(dfb_surface, 0x0, 0x0, 0x0, 0x0); + dfb_surface->Flip(dfb_surface, NULL, DSFLIP_WAITFORSYNC); + dfb_surface->Clear(dfb_surface, 0x0, 0x0, 0x0, 0x0); + dfb_surface->Flip(dfb_surface, NULL, DSFLIP_WAITFORSYNC); + } +} + +void EGLTarget::initialize(Backend& backend, uint32_t width, uint32_t height) +{ + DFBResult res; + DFBWindowDescription desc; + + IDirectFBSurface *dfb_surface = NULL; + IDirectFBDisplayLayer *layer = NULL; + IDirectFBWindow *dfb_window = NULL; + DFBDisplayLayerConfig layerConfig; + + WPEB_DFB_LOG_DEBUG("!!!!!!!!!! EGLTarget::initialize Creating DFB Window !!!!!!!!!!\n"); + + m_backend = &backend; + + if (nativeWindow) + return; + + s_dfb = m_backend->display.iDirectfb(); + s_dfb->GetDisplayLayer( s_dfb, DLID_PRIMARY, &layer ); + layer->SetCooperativeLevel( layer, DLSCL_SHARED ); + layer->GetConfiguration(layer, &layerConfig); + + WPEB_DFB_LOG_INFO("EGL Target Requested WidthxHeight = %dx%d, Layer Configuration %dx%d\n", width, height, layerConfig.width, layerConfig.height); + + desc.posx = 0; + desc.posy = 0; + desc.width = width; + desc.height = height; + desc.surface_caps = DFBSurfaceCapabilities(DSCAPS_DOUBLE | DSCAPS_PREMULTIPLIED); + desc.flags = DFBWindowDescriptionFlags(DWDESC_POSX | DWDESC_POSY | DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_CAPS | DWDESC_SURFACE_CAPS); + desc.caps = DFBWindowCapabilities(DWCAPS_ALPHACHANNEL | DWCAPS_DOUBLEBUFFER); + + update_surface_capabilities(dfb_window, &desc); + + if (mainWindow){ + // don't give focus to non-main windows (i.e. webkit popups) + desc.caps = DFBWindowCapabilities(desc.caps | DWCAPS_NOFOCUS); + } + + res = layer->CreateWindow( layer, &desc, &dfb_window ); + + // clear window contents + dfb_window->GetSurface( dfb_window, &dfb_surface ); + dfb_surface->Clear( dfb_surface, 0,0,0,0); + dfb_surface->Flip( dfb_surface, NULL, DSFLIP_NONE ); + dfb_surface->Clear( dfb_surface, 0,0,0,0); + + // make it visible + dfb_window->SetOpacity( dfb_window, 0xff); + dfb_window->RaiseToTop( dfb_window ); + + layer->Release( layer ); + nativeWindow = (void*)dfb_surface; + dfbWindow = (void*)dfb_window; + surfaceCaps = desc.surface_caps; + + this->width = width; + this->height = height; + + if(!mainWindow){ + mainWindow = dfb_window; // first window is always the main window + m_backend->display.initializeEventSource(dfb_window); + } +} + +void EGLTarget::handleMessage(char* data, size_t size) +{ + if (size != IPC::Message::size) + return; + + auto& message = IPC::Message::cast(data); + switch (message.messageCode) { + case IPC::Directfb::FrameComplete::code: { + wpe_renderer_backend_egl_target_dispatch_frame_complete(target); + break; + } + default: + WPEB_DFB_LOG_WARNING("EGLTarget: unhandled message\n"); + }; +} + +} // namespace Directfb + +extern "C" { + +struct wpe_renderer_backend_egl_interface directfb_renderer_backend_egl_interface = { + // create + [](int) -> void* + { + return new Directfb::Backend; + }, + // destroy + [](void* data) + { + auto* backend = static_cast(data); + delete backend; + }, + // get_native_display + [](void* data) -> EGLNativeDisplayType + { + auto& backend = *static_cast(data); + backend.display.registerDirectFBDisplayPlatform(); + return EGL_DEFAULT_DISPLAY; + }, +}; + +struct wpe_renderer_backend_egl_target_interface directfb_renderer_backend_egl_target_interface = { + // create + [](struct wpe_renderer_backend_egl_target* target, int host_fd) -> void* + { + return new Directfb::EGLTarget(target, host_fd); + }, + // destroy + [](void* data) + { + auto* target = static_cast(data); + delete target; + }, + // initialize + [](void* data, void* backend_data, uint32_t width, uint32_t height) + { + auto& target = *static_cast(data); + auto& backend = *static_cast(backend_data); + target.initialize(backend, width, height); + }, + // get_native_window + [](void* data) -> EGLNativeWindowType + { + auto& target = *static_cast(data); + return (EGLNativeWindowType)target.nativeWindow; + }, + // resize + [](void* data, uint32_t width, uint32_t height) + { + auto& target = *static_cast(data); + target.resize(width, height); + }, + // frame_will_render + [](void* data) + { + }, + // frame_rendered + [](void* data) + { + auto& target = *static_cast(data); + + IPC::Message message; + IPC::Directfb::BufferCommit::construct(message, target.width, target.height); + target.ipcClient.sendMessage(IPC::Message::data(message), IPC::Message::size); + }, +}; + +struct wpe_renderer_backend_egl_offscreen_target_interface directfb_renderer_backend_egl_offscreen_target_interface = { + // create + []() -> void* + { + return nullptr; + }, + // destroy + [](void* data) + { + }, + // initialize + [](void* data, void* backend_data) + { + }, + // get_native_window + [](void* data) -> EGLNativeWindowType + { + return (EGLNativeWindowType)nullptr; + }, +}; + +} diff --git a/src/directfb/view-backend.cpp b/src/directfb/view-backend.cpp new file mode 100644 index 0000000..c56b9c9 --- /dev/null +++ b/src/directfb/view-backend.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2015, 2016 Igalia S.L. + * Copyright (C) 2015, 2016 Metrological + * Copyright (C) 2016 SoftAtHome + * Copyright (C) 1994-2020 OpenTV, Inc. and Nagravision S.A. + * All rights reserved. + * + * 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 HOLDERS AND 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 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. + */ + +#include + +#ifdef KEY_INPUT_HANDLING_LIBINPUT +#include "Libinput/LibinputServer.h" +#endif + +#include "display.h" + +#include "ipc.h" +#include "ipc-directfb.h" +#include +#include +#include +#include +#include +#include +#include + +namespace Directfb { + +struct ViewBackend : public IPC::Host::Handler +#ifdef KEY_INPUT_HANDLING_LIBINPUT + , public WPE::LibinputServer::Client +#endif +{ + ViewBackend(struct wpe_view_backend*); + virtual ~ViewBackend(); + + void initialize(); + + // IPC::Host::Handler + void handleFd(int) override; + void handleMessage(char*, size_t) override; + + void commitBuffer(uint32_t, uint32_t); + +#ifdef KEY_INPUT_HANDLING_LIBINPUT + // WPE::LibinputServer::Client + void handleKeyboardEvent(struct wpe_input_keyboard_event*) override; + void handlePointerEvent(struct wpe_input_pointer_event*) override; + void handleAxisEvent(struct wpe_input_axis_event*) override; + void handleTouchEvent(struct wpe_input_touch_event*) override; +#endif + + struct wpe_view_backend* backend; + IPC::Host ipcHost; + + Directfb::Display& m_display; + + uint32_t width { 0 }; + uint32_t height { 0 }; +}; + +ViewBackend::ViewBackend(struct wpe_view_backend* backend) + : backend(backend) + , m_display(Directfb::Display::singleton()) +{ + ipcHost.initialize(*this); +} + +ViewBackend::~ViewBackend() +{ + ipcHost.deinitialize(); + +#ifdef KEY_INPUT_HANDLING_LIBINPUT + WPE::LibinputServer::singleton().setClient(nullptr); +#endif + +} + +void ViewBackend::initialize() +{ + WPEB_DFB_LOG_DEBUG("Platform DFB View Backend Initialization\n"); + + assert(m_display.width() != 0); + assert(m_display.height() != 0); + + WPEB_DFB_LOG_INFO("Viewbackend initialize DirectFB Display resolution: %dx%d\n", m_display.width(), m_display.height()); + + width = m_display.width(); + height = m_display.height(); + + wpe_view_backend_dispatch_set_size(backend, width, height); + +#ifdef KEY_INPUT_HANDLING_LIBINPUT + WPE::LibinputServer::singleton().setClient(this); +#endif + +} + +void ViewBackend::handleFd(int) +{ + WPEB_DFB_LOG_WARNING("!!!!!!!!!! Not Implemented !!!!!!!!!!\n"); +} + +void ViewBackend::handleMessage(char* data, size_t size) +{ + if (size != IPC::Message::size) + return; + + auto& message = IPC::Message::cast(data); + switch (message.messageCode) { + case IPC::Directfb::BufferCommit::code: { + auto& bufferCommit = IPC::Directfb::BufferCommit::cast(message); + commitBuffer(bufferCommit.width, bufferCommit.height); + break; + } + case Directfb::EventDispatcher::MsgType::KEYBOARD: { + struct wpe_input_keyboard_event * event = reinterpret_cast(std::addressof(message.messageData)); + wpe_view_backend_dispatch_keyboard_event(backend, event); + break; + } + default: { + WPEB_DFB_LOG_WARNING("ViewBackend: unhandled message\n"); + break; + } + } +} + +void ViewBackend::commitBuffer(uint32_t width, uint32_t height) +{ + if (width != this->width || height != this->height) + return; + + IPC::Message message; + IPC::Directfb::FrameComplete::construct(message); + ipcHost.sendMessage(IPC::Message::data(message), IPC::Message::size); + + wpe_view_backend_dispatch_frame_displayed(backend); +} + +#ifdef KEY_INPUT_HANDLING_LIBINPUT +void ViewBackend::handleKeyboardEvent(struct wpe_input_keyboard_event* event) +{ + wpe_view_backend_dispatch_keyboard_event(backend, event); +} + +void ViewBackend::handlePointerEvent(struct wpe_input_pointer_event* event) +{ + wpe_view_backend_dispatch_pointer_event(backend, event); +} + +void ViewBackend::handleAxisEvent(struct wpe_input_axis_event* event) +{ + wpe_view_backend_dispatch_axis_event(backend, event); +} + +void ViewBackend::handleTouchEvent(struct wpe_input_touch_event* event) +{ + wpe_view_backend_dispatch_touch_event(backend, event); +} +#endif + +} // namespace Directfb + +extern "C" { + +struct wpe_view_backend_interface directfb_view_backend_interface = { + // create + [](void*, struct wpe_view_backend* backend) -> void* + { + return new Directfb::ViewBackend(backend); + }, + // destroy + [](void* data) + { + auto* backend = static_cast(data); + delete backend; + }, + // initialize + [](void* data) + { + auto& backend = *static_cast(data); + backend.initialize(); + }, + // get_renderer_host_fd + [](void* data) -> int + { + auto& backend = *static_cast(data); + return backend.ipcHost.releaseClientFD(); + }, +}; + +} diff --git a/src/loader-impl.cpp b/src/loader-impl.cpp index 5c38a2b..41158f6 100644 --- a/src/loader-impl.cpp +++ b/src/loader-impl.cpp @@ -50,6 +50,10 @@ #include "wayland-egl/interfaces.h" #endif +#ifdef BACKEND_DIRECTFB +#include "directfb/interfaces.h" +#endif + #ifdef BACKEND_WESTEROS #include "westeros/interfaces.h" #endif @@ -148,6 +152,18 @@ struct wpe_loader_interface _wpe_loader_interface = { return &wayland_egl_view_backend_interface; #endif +#ifdef BACKEND_DIRECTFB + if (!std::strcmp(object_name, "_wpe_renderer_backend_egl_interface")) + return &directfb_renderer_backend_egl_interface; + if (!std::strcmp(object_name, "_wpe_renderer_backend_egl_target_interface")) + return &directfb_renderer_backend_egl_target_interface; + if (!std::strcmp(object_name, "_wpe_renderer_backend_egl_offscreen_target_interface")) + return &directfb_renderer_backend_egl_offscreen_target_interface; + + if (!std::strcmp(object_name, "_wpe_view_backend_interface")) + return &directfb_view_backend_interface; +#endif + #ifdef BACKEND_WESTEROS if (!std::strcmp(object_name, "_wpe_renderer_backend_egl_interface")) return &westeros_renderer_backend_egl_interface;