WebKit Bugzilla
Attachment 342254 Details for
Bug 186345
: [WPE] Add a MiniBrowser and use it to run WebDriver tests
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Updated patch
wpe-mini-browser.diff (text/plain), 81.26 KB, created by
Carlos Garcia Campos
on 2018-06-08 06:38:29 PDT
(
hide
)
Description:
Updated patch
Filename:
MIME Type:
Creator:
Carlos Garcia Campos
Created:
2018-06-08 06:38:29 PDT
Size:
81.26 KB
patch
obsolete
>diff --git a/ChangeLog b/ChangeLog >index 3557d94ff42..8d128766b42 100644 >--- a/ChangeLog >+++ b/ChangeLog >@@ -1,3 +1,15 @@ >+2018-06-08 Carlos Garcia Campos <cgarcia@igalia.com> >+ >+ [WPE] Add a MiniBrowser and use it to run WebDriver tests >+ https://bugs.webkit.org/show_bug.cgi?id=186345 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add an option to enable building the MiniBrowser. >+ >+ * Source/cmake/FindWaylandProtocols.cmake: Added. >+ * Source/cmake/OptionsWPE.cmake: >+ > 2018-05-28 Carlos Garcia Campos <cgarcia@igalia.com> > > Unreviewed. Update OptionsGTK.cmake and NEWS for 2.21.3 release. >diff --git a/Source/WebDriver/ChangeLog b/Source/WebDriver/ChangeLog >index e0a28bb8fb6..45491997f8f 100644 >--- a/Source/WebDriver/ChangeLog >+++ b/Source/WebDriver/ChangeLog >@@ -1,3 +1,15 @@ >+2018-06-08 Carlos Garcia Campos <cgarcia@igalia.com> >+ >+ [WPE] Add a MiniBrowser and use it to run WebDriver tests >+ https://bugs.webkit.org/show_bug.cgi?id=186345 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Use MiniBrowser instead of dyz as the default WebDriver browser for WPE. >+ >+ * wpe/WebDriverServiceWPE.cpp: >+ (WebDriver::WebDriverService::platformParseCapabilities const): >+ > 2018-06-04 Carlos Garcia Campos <cgarcia@igalia.com> > > [WPE] WebDriver: stop making mandatory to provide a browser path if wpe:browserOptions is present in capabilities >diff --git a/Source/WebDriver/wpe/WebDriverServiceWPE.cpp b/Source/WebDriver/wpe/WebDriverServiceWPE.cpp >index 0aaac3dffa0..d63f5a4ba23 100644 >--- a/Source/WebDriver/wpe/WebDriverServiceWPE.cpp >+++ b/Source/WebDriver/wpe/WebDriverServiceWPE.cpp >@@ -81,7 +81,7 @@ bool WebDriverService::platformMatchCapability(const String&, const RefPtr<JSON: > > void WebDriverService::platformParseCapabilities(const JSON::Object& matchedCapabilities, Capabilities& capabilities) const > { >- capabilities.browserBinary = String("dyz"); >+ capabilities.browserBinary = String("MiniBrowser"); > capabilities.browserArguments = Vector<String> { ASCIILiteral("--automation") }; > > RefPtr<JSON::Object> browserOptions; >diff --git a/Source/cmake/FindWaylandProtocols.cmake b/Source/cmake/FindWaylandProtocols.cmake >new file mode 100644 >index 00000000000..69bdc7a3be9 >--- /dev/null >+++ b/Source/cmake/FindWaylandProtocols.cmake >@@ -0,0 +1,38 @@ >+# - Try to find WaylandProtocols >+# Once done, this will define >+# >+# WAYLAND_PROTOCOLS_FOUND - system has WaylandProtocols. >+# WAYLAND_PROTOCOLS_DATADIR - the WaylandProtocols data directory >+# WAYLAND_SCANNER - the path to the wayland-scanner command. >+# >+# Copyright (C) 2018 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(WAYLAND_PROTOCOLS wayland-protocols) >+ >+if (WAYLAND_PROTOCOLS_FOUND) >+ pkg_get_variable(WAYLAND_PROTOCOLS_DATADIR wayland-protocols pkgdatadir) >+ find_program(WAYLAND_SCANNER NAMES wayland-scanner) >+ mark_as_advanced(WAYLAND_PROTOCOLS_DATADIR WAYLAND_SCANNER) >+endif () >diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake >index 8b0cd1f8195..10e156c967f 100644 >--- a/Source/cmake/OptionsWPE.cmake >+++ b/Source/cmake/OptionsWPE.cmake >@@ -60,6 +60,7 @@ endif () > SET_AND_EXPOSE_TO_BUILD(ENABLE_DEVELOPER_MODE ${DEVELOPER_MODE}) > if (DEVELOPER_MODE) > WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_API_TESTS PRIVATE ON) >+ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MINIBROWSER PUBLIC ON) > endif () > > include(GStreamerDependencies) >diff --git a/Tools/CMakeLists.txt b/Tools/CMakeLists.txt >index 0a481184b2e..5f4f9e0c963 100644 >--- a/Tools/CMakeLists.txt >+++ b/Tools/CMakeLists.txt >@@ -21,14 +21,21 @@ elseif ("${PORT}" STREQUAL "Mac") > add_subdirectory(MiniBrowser/mac) > elseif ("${PORT}" STREQUAL "JSCOnly") > elseif ("${PORT}" STREQUAL "WPE") >+ if (DEVELOPER_MODE OR ENABLE_MINIBROWSER) >+ add_subdirectory(wpe/backends) >+ endif () >+ > if (DEVELOPER_MODE) > add_subdirectory(ImageDiff) > add_subdirectory(WebKitTestRunner) >- add_subdirectory(wpe/HeadlessViewBackend) > if (ENABLE_API_TESTS) > add_subdirectory(TestWebKitAPI/glib) > endif () > endif () >+ >+ if (ENABLE_MINIBROWSER) >+ add_subdirectory(MiniBrowser/wpe) >+ endif () > elseif ("${PORT}" STREQUAL "Win") > add_subdirectory(DumpRenderTree) > add_subdirectory(ImageDiff) >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index afd96e3c0f1..92df3c20d57 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,71 @@ >+2018-06-08 Carlos Garcia Campos <cgarcia@igalia.com> >+ >+ [WPE] Add a MiniBrowser and use it to run WebDriver tests >+ https://bugs.webkit.org/show_bug.cgi?id=186345 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Most of the code is based on dyz and gtk MiniBrowser. This patch adds a new internal library WPEToolingBackends, >+ including the headless view backend and a new window backend to be used by the MiniBrowser. MiniBrowser can also >+ run in headless mode, by using the headless backend instead of the window one, which will allow us to run the >+ WebDriver tests in the bots. >+ >+ * CMakeLists.txt: >+ * MiniBrowser/wpe/CMakeLists.txt: Added. >+ * MiniBrowser/wpe/main.cpp: Added. >+ (automationStartedCallback): >+ (createViewBackend): >+ (main): >+ * Scripts/run-minibrowser: Remove WPE specific code. >+ * Scripts/run-webdriver-tests: Add headless display-server option. >+ * Scripts/webkitdirs.pm: >+ (launcherName): Remove WPE specific code. >+ * Scripts/webkitpy/webdriver_tests/webdriver_driver_wpe.py: >+ (WebDriverWPE.browser_name): Return MiniBrowser. >+ (WebDriverWPE.browser_path): Return the path to the MiniBrowser in build dir. >+ (WebDriverWPE.browser_args): Add --headless when running in headless mode. >+ (WebDriverWPE.capabilities): Use the full browser path. >+ * Scripts/webkitpy/webdriver_tests/webdriver_test_runner_selenium.py: >+ (WebDriverTestRunnerSelenium.collect_tests): Fix early return value. >+ * TestWebKitAPI/PlatformWPE.cmake: Use WPEToolingBackends instead of HeadlessViewBackend. >+ * TestWebKitAPI/PlatformWebView.h: Ditto. >+ * TestWebKitAPI/glib/PlatformWPE.cmake: Ditto >+ * TestWebKitAPI/glib/WebKitGLib/TestMain.h: >+ (Test::createWebViewBackend): Ditto. >+ * TestWebKitAPI/wpe/PlatformWebViewWPE.cpp: >+ (TestWebKitAPI::PlatformWebView::initialize): Ditto. >+ * WebKitTestRunner/PlatformWPE.cmake: Ditto. >+ * WebKitTestRunner/PlatformWebView.h: Ditto. >+ * WebKitTestRunner/wpe/PlatformWebViewWPE.cpp: >+ (WTR::PlatformWebView::PlatformWebView): Ditto. >+ * wpe/HeadlessViewBackend/CMakeLists.txt: Removed. >+ * wpe/backends/CMakeLists.txt: Added. >+ * wpe/backends/HeadlessViewBackend.cpp: Renamed from Tools/wpe/HeadlessViewBackend/HeadlessViewBackend.cpp. >+ (WPEToolingBackends::getEGLDisplay): >+ (WPEToolingBackends::HeadlessViewBackend::HeadlessViewBackend): >+ (WPEToolingBackends::HeadlessViewBackend::~HeadlessViewBackend): >+ (WPEToolingBackends::HeadlessViewBackend::createSnapshot): >+ (WPEToolingBackends::HeadlessViewBackend::performUpdate): >+ (WPEToolingBackends::HeadlessViewBackend::displayBuffer): >+ * wpe/backends/HeadlessViewBackend.h: Renamed from Tools/wpe/HeadlessViewBackend/HeadlessViewBackend.h. >+ * wpe/backends/ViewBackend.cpp: Added. >+ (WPEToolingBackends::ViewBackend::ViewBackend): >+ (WPEToolingBackends::ViewBackend::~ViewBackend): >+ (WPEToolingBackends::ViewBackend::initialize): >+ (WPEToolingBackends::ViewBackend::setInputClient): >+ (WPEToolingBackends::ViewBackend::backend const): >+ (WPEToolingBackends::ViewBackend::dispatchInputPointerEvent): >+ (WPEToolingBackends::ViewBackend::dispatchInputAxisEvent): >+ (WPEToolingBackends::ViewBackend::dispatchInputKeyboardEvent): >+ * wpe/backends/ViewBackend.h: Added. >+ * wpe/backends/WindowViewBackend.cpp: Added. >+ (WPEToolingBackends::WindowViewBackend::WindowViewBackend): >+ (WPEToolingBackends::WindowViewBackend::~WindowViewBackend): >+ (WPEToolingBackends::WindowViewBackend::displayBuffer): >+ (WPEToolingBackends::WindowViewBackend::handleKeyEvent): >+ * wpe/backends/WindowViewBackend.h: Added. >+ * wpe/jhbuild.modules: Remove dyz and add wayland-protocols. >+ > 2018-06-04 Dan Bernstein <mitz@apple.com> > > Fixed building ImageDiff with the default build system in the Xcode 10 developer beta. >diff --git a/Tools/MiniBrowser/wpe/CMakeLists.txt b/Tools/MiniBrowser/wpe/CMakeLists.txt >new file mode 100644 >index 00000000000..f261379683b >--- /dev/null >+++ b/Tools/MiniBrowser/wpe/CMakeLists.txt >@@ -0,0 +1,36 @@ >+set(MINIBROWSER_DIR "${TOOLS_DIR}/MiniBrowser/wpe") >+ >+set(MiniBrowser_SOURCES >+ ${MINIBROWSER_DIR}/main.cpp >+) >+ >+set(MiniBrowser_INCLUDE_DIRECTORIES >+ ${TOOLS_DIR}/wpe/backends/ >+ ${DERIVED_SOURCES_WPE_API_DIR} >+ ${FORWARDING_HEADERS_WPE_DIR} >+ ${CMAKE_BINARY_DIR}/DerivedSources/WPEToolingBackends >+) >+ >+set(MiniBrowser_SYSTEM_INCLUDE_DIRECTORIES >+ ${WPE_INCLUDE_DIRS} >+ ${WPEBACKEND_FDO_INCLUDE_DIRS} >+) >+ >+set(MiniBrowser_LIBRARIES >+ ${JavaScriptCore_LIBRARY_NAME} >+ WPEToolingBackends >+ WebKit >+ ${WPE_LIBRARIES} >+ ${WPEBACKEND_FDO_LIBRARIES} >+) >+ >+if (DEVELOPER_MODE) >+ add_definitions(-DWEBKIT_INJECTED_BUNDLE_PATH="${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") >+endif () >+ >+include_directories(${MiniBrowser_INCLUDE_DIRECTORIES}) >+include_directories(SYSTEM ${MiniBrowser_SYSTEM_INCLUDE_DIRECTORIES}) >+add_executable(MiniBrowser ${MiniBrowser_SOURCES}) >+target_link_libraries(MiniBrowser ${MiniBrowser_LIBRARIES}) >+ >+install(TARGETS MiniBrowser DESTINATION "${LIBEXEC_INSTALL_DIR}") >diff --git a/Tools/MiniBrowser/wpe/main.cpp b/Tools/MiniBrowser/wpe/main.cpp >new file mode 100644 >index 00000000000..4885ff5cb5e >--- /dev/null >+++ b/Tools/MiniBrowser/wpe/main.cpp >@@ -0,0 +1,196 @@ >+/* >+ * Copyright (C) 2018 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 APPLE INC. ``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 APPLE INC. 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 "cmakeconfig.h" >+ >+#include "HeadlessViewBackend.h" >+#include "WindowViewBackend.h" >+#include <gst/gst.h> >+#include <memory> >+#include <wpe/webkit.h> >+ >+static const char** uriArguments; >+static const char** ignoreHosts; >+static gboolean headlessMode; >+static gboolean privateMode; >+static gboolean automationMode; >+static const char* cookiesFile; >+static const char* cookiesPolicy; >+static const char* proxy; >+ >+static const GOptionEntry commandLineOptions[] = >+{ >+ { "headless", 'h', 0, G_OPTION_ARG_NONE, &headlessMode, "Run in headless mode", nullptr }, >+ { "private", 'p', 0, G_OPTION_ARG_NONE, &privateMode, "Run in private browsing mode", nullptr }, >+ { "automation", 0, 0, G_OPTION_ARG_NONE, &automationMode, "Run in automation mode", nullptr }, >+ { "cookies-file", 'c', 0, G_OPTION_ARG_FILENAME, &cookiesFile, "Persistent cookie storage database file", "FILE" }, >+ { "cookies-policy", 0, 0, G_OPTION_ARG_STRING, &cookiesPolicy, "Cookies accept policy (always, never, no-third-party). Default: no-third-party", "POLICY" }, >+ { "proxy", 0, 0, G_OPTION_ARG_STRING, &proxy, "Set proxy", "PROXY" }, >+ { "ignore-host", 0, 0, G_OPTION_ARG_STRING_ARRAY, &ignoreHosts, "Set proxy ignore hosts", "HOSTS" }, >+ { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &uriArguments, nullptr, "[URL]" }, >+ { nullptr, 0, 0, G_OPTION_ARG_NONE, nullptr, nullptr, nullptr } >+}; >+ >+class InputClient final : public WPEToolingBackends::ViewBackend::InputClient { >+public: >+ InputClient(GMainLoop* loop) >+ : m_loop(loop) >+ { >+ } >+ >+ bool dispatchKeyboardEvent(struct wpe_input_keyboard_event* event) override >+ { >+ if (event->pressed && event->modifiers & wpe_input_keyboard_modifier_control && event->keyCode == 'q') { >+ g_main_loop_quit(m_loop); >+ return true; >+ } >+ >+ return false; >+ } >+ >+private: >+ GMainLoop* m_loop { nullptr }; >+}; >+ >+static WebKitWebView* createWebViewForAutomationCallback(WebKitAutomationSession*, WebKitWebView* view) >+{ >+ return view; >+} >+ >+static void automationStartedCallback(WebKitWebContext*, WebKitAutomationSession* session, WebKitWebView* view) >+{ >+ auto* info = webkit_application_info_new(); >+ // FIXME: add version info when wpe has WebKitVersion.h >+ // webkit_application_info_set_version(info, WEBKIT_MAJOR_VERSION, WEBKIT_MINOR_VERSION, WEBKIT_MICRO_VERSION); >+ webkit_automation_session_set_application_info(session, info); >+ webkit_application_info_unref(info); >+ >+ g_signal_connect(session, "create-web-view", G_CALLBACK(createWebViewForAutomationCallback), view); >+} >+ >+static std::unique_ptr<WPEToolingBackends::ViewBackend> createViewBackend(uint32_t width, uint32_t height) >+{ >+ if (headlessMode) >+ return std::make_unique<WPEToolingBackends::HeadlessViewBackend>(width, height); >+ return std::make_unique<WPEToolingBackends::WindowViewBackend>(width, height); >+} >+ >+int main(int argc, char *argv[]) >+{ >+ // MiniBrowser only works with WPEBackend-fdo, so ensure no other backend is used, >+ // either by passing the WPE_BACKEND_LIBRARY env var or loading the default symlink. >+ g_setenv("WPE_BACKEND_LIBRARY", "libWPEBackend-fdo-0.1.so", TRUE); >+#if ENABLE_DEVELOPER_MODE >+ g_setenv("WEBKIT_INJECTED_BUNDLE_PATH", WEBKIT_INJECTED_BUNDLE_PATH, FALSE); >+#endif >+ >+ GOptionContext* context = g_option_context_new(nullptr); >+ g_option_context_add_main_entries(context, commandLineOptions, nullptr); >+ g_option_context_add_group(context, gst_init_get_option_group()); >+ >+ GError* error = nullptr; >+ if (!g_option_context_parse(context, &argc, &argv, &error)) { >+ g_printerr("Cannot parse arguments: %s\n", error->message); >+ g_error_free(error); >+ g_option_context_free(context); >+ >+ return 1; >+ } >+ g_option_context_free(context); >+ >+ auto* loop = g_main_loop_new(nullptr, FALSE); >+ >+ auto backend = createViewBackend(1280, 720); >+ struct wpe_view_backend* wpeBackend = backend->backend(); >+ if (!wpeBackend) { >+ g_warning("Failed to create WPE view backend"); >+ g_main_loop_unref(loop); >+ return 1; >+ } >+ >+ backend->setInputClient(std::make_unique<InputClient>(loop)); >+ >+ auto* viewBackend = webkit_web_view_backend_new(wpeBackend, [](gpointer data) { >+ delete static_cast<WPEToolingBackends::ViewBackend*>(data); >+ }, backend.release()); >+ >+ auto* webContext = (privateMode || automationMode) ? webkit_web_context_new_ephemeral() : webkit_web_context_get_default(); >+ >+ if (cookiesPolicy) { >+ auto* cookieManager = webkit_web_context_get_cookie_manager(webContext); >+ auto* enumClass = static_cast<GEnumClass*>(g_type_class_ref(WEBKIT_TYPE_COOKIE_ACCEPT_POLICY)); >+ GEnumValue* enumValue = g_enum_get_value_by_nick(enumClass, cookiesPolicy); >+ if (enumValue) >+ webkit_cookie_manager_set_accept_policy(cookieManager, static_cast<WebKitCookieAcceptPolicy>(enumValue->value)); >+ g_type_class_unref(enumClass); >+ } >+ >+ if (cookiesFile && !webkit_web_context_is_ephemeral(webContext)) { >+ auto* cookieManager = webkit_web_context_get_cookie_manager(webContext); >+ auto storageType = g_str_has_suffix(cookiesFile, ".txt") ? WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT : WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE; >+ webkit_cookie_manager_set_persistent_storage(cookieManager, cookiesFile, storageType); >+ } >+ >+ if (proxy) { >+ auto* webkitProxySettings = webkit_network_proxy_settings_new(proxy, ignoreHosts); >+ webkit_web_context_set_network_proxy_settings(webContext, WEBKIT_NETWORK_PROXY_MODE_CUSTOM, webkitProxySettings); >+ webkit_network_proxy_settings_free(webkitProxySettings); >+ } >+ >+ const char* singleprocess = g_getenv("MINIBROWSER_SINGLEPROCESS"); >+ webkit_web_context_set_process_model(webContext, (singleprocess && *singleprocess) ? >+ WEBKIT_PROCESS_MODEL_SHARED_SECONDARY_PROCESS : WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES); >+ >+ auto* settings = webkit_settings_new_with_settings( >+ "enable-developer-extras", TRUE, >+ "enable-webgl", TRUE, >+ "enable-media-stream", TRUE, >+ nullptr); >+ >+ auto* webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, >+ "backend", viewBackend, >+ "web-context", webContext, >+ "settings", settings, >+ "is-controlled-by-automation", automationMode, >+ nullptr)); >+ g_object_unref(settings); >+ >+ webkit_web_context_set_automation_allowed(webContext, automationMode); >+ g_signal_connect(webContext, "automation-started", G_CALLBACK(automationStartedCallback), webView); >+ >+ if (uriArguments) >+ webkit_web_view_load_uri(webView, uriArguments[0]); >+ else if (!automationMode) >+ webkit_web_view_load_uri(webView, "https://wpewebkit.org"); >+ >+ g_main_loop_run(loop); >+ >+ g_object_unref(webView); >+ if (privateMode) >+ g_object_unref(webContext); >+ g_main_loop_unref(loop); >+ >+ return 0; >+} >diff --git a/Tools/Scripts/run-minibrowser b/Tools/Scripts/run-minibrowser >index 86ccca0e33f..495440531ae 100755 >--- a/Tools/Scripts/run-minibrowser >+++ b/Tools/Scripts/run-minibrowser >@@ -44,7 +44,7 @@ my @jhbuildWrapper; > prohibitUnknownPort(); > setConfiguration(); > >-if (isGtk()) { >+if (isGtk() || isWPE()) { > # Check to see that all the frameworks are built. > checkFrameworks(); > >@@ -53,17 +53,6 @@ if (isGtk()) { > @jhbuildWrapper = wrapperPrefixIfNeeded(); > print "Starting MiniBrowser.\n"; > exec @jhbuildWrapper, $launcherPath, @ARGV or die; >-} elsif (isWPE()) { >- # Check to see that all the frameworks are built. >- checkFrameworks(); >- >- $launcherName = launcherName(); >- @jhbuildWrapper = wrapperPrefixIfNeeded(); >- $ENV{"WEBKIT_EXEC_PATH"} = catdir(productDir(), "bin"); >- $ENV{"WEBKIT_INJECTED_BUNDLE_PATH"} = catdir(productDir(), "lib"); >- $ENV{"LD_LIBRARY_PATH"} = catdir(productDir(), "lib") . (defined $ENV{"LD_LIBRARY_PATH"} ? ":" . $ENV{"LD_LIBRARY_PATH"} : "" ); >- print "Starting $launcherName \n"; >- exec @jhbuildWrapper, $launcherName, @ARGV or die; > } elsif (isAppleCocoaWebKit()) { > printHelpAndExitForRunAndDebugWebKitAppIfNeeded(); > exit exitStatus(runMiniBrowser()); >diff --git a/Tools/Scripts/run-webdriver-tests b/Tools/Scripts/run-webdriver-tests >index 4051a1a26fb..10f7fede66f 100755 >--- a/Tools/Scripts/run-webdriver-tests >+++ b/Tools/Scripts/run-webdriver-tests >@@ -49,9 +49,10 @@ option_parser.add_option('--timeout', action='store', type='int', dest='timeout' > help='Time in seconds until a test times out (use 0 to disable)') > option_parser.add_option('--json-output', action='store', metavar="FILE", > help='Write results to JSON file at the given path') >-option_parser.add_option('--display-server', choices=['xvfb', 'xorg', 'weston', 'wayland'], default='xvfb', >+option_parser.add_option('--display-server', choices=['xvfb', 'xorg', 'weston', 'wayland', 'headless'], default='xvfb', > help='"xvfb": Use a virtualized X11 server. "xorg": Use the current X11 session. ' >- '"weston": Use a virtualized Weston server. "wayland": Use the current wayland session.') >+ '"weston": Use a virtualized Weston server. "wayland": Use the current wayland session.' >+ '"headless": Headless mode in current session') > > options, args = option_parser.parse_args() > >diff --git a/Tools/Scripts/webkitdirs.pm b/Tools/Scripts/webkitdirs.pm >index 30700b625f3..357ddd4e08b 100755 >--- a/Tools/Scripts/webkitdirs.pm >+++ b/Tools/Scripts/webkitdirs.pm >@@ -1650,14 +1650,12 @@ sub launcherPath() > > sub launcherName() > { >- if (isGtk()) { >+ if (isGtk() || isWPE()) { > return "MiniBrowser"; > } elsif (isAppleMacWebKit()) { > return "Safari"; > } elsif (isAppleWinWebKit()) { > return "MiniBrowser"; >- } elsif (isWPE()) { >- return "dyz"; > } > } > >diff --git a/Tools/Scripts/webkitpy/webdriver_tests/webdriver_driver_wpe.py b/Tools/Scripts/webkitpy/webdriver_tests/webdriver_driver_wpe.py >index f025731b9ab..3ce48b0b7a5 100644 >--- a/Tools/Scripts/webkitpy/webdriver_tests/webdriver_driver_wpe.py >+++ b/Tools/Scripts/webkitpy/webdriver_tests/webdriver_driver_wpe.py >@@ -33,27 +33,21 @@ class WebDriverWPE(WebDriver): > return self._port._build_path('bin', 'WPEWebDriver') > > def browser_name(self): >- return 'dyz' >+ return 'MiniBrowser' >+ >+ def browser_path(self): >+ return self._port._build_path('bin', 'MiniBrowser') > > def browser_args(self): >- return ['--automation'] >+ args = ['--automation'] >+ if self._port._display_server == 'headless': >+ args.append('--headless') >+ return args > > def capabilities(self): > return {'wpe:browserOptions': { >- 'binary': self.browser_name(), >+ 'binary': self.browser_path(), > 'args': self.browser_args()}} > >- def browser_env(self): >- env = {} >- env['WEBKIT_EXEC_PATH'] = self._port._build_path('bin') >- try: >- ld_library_path = os.environ['LD_LIBRARY_PATH'] >- except KeyError: >- ld_library_path = None >- env['LD_LIBRARY_PATH'] = self._port._build_path('lib') >- if ld_library_path: >- env['LD_LIBRARY_PATH'] += ':' + ld_library_path >- return env >- > > register_driver('wpe', WebDriverWPE) >diff --git a/Tools/Scripts/webkitpy/webdriver_tests/webdriver_test_runner_selenium.py b/Tools/Scripts/webkitpy/webdriver_tests/webdriver_test_runner_selenium.py >index 4e58a3d252c..48f11124a14 100644 >--- a/Tools/Scripts/webkitpy/webdriver_tests/webdriver_test_runner_selenium.py >+++ b/Tools/Scripts/webkitpy/webdriver_tests/webdriver_test_runner_selenium.py >@@ -44,7 +44,7 @@ class WebDriverTestRunnerSelenium(object): > > def collect_tests(self, tests): > if self._driver.selenium_name() is None: >- return 0 >+ return [] > > skipped = [os.path.join(self._tests_dir, test) for test in self._expectations.skipped_tests()] > relative_tests_dir = os.path.join('imported', 'selenium', 'py', 'test') >diff --git a/Tools/TestWebKitAPI/PlatformWPE.cmake b/Tools/TestWebKitAPI/PlatformWPE.cmake >index 366255e8cbc..17c9f6f3ee6 100644 >--- a/Tools/TestWebKitAPI/PlatformWPE.cmake >+++ b/Tools/TestWebKitAPI/PlatformWPE.cmake >@@ -17,7 +17,7 @@ include_directories( > ${FORWARDING_HEADERS_DIR}/JavaScriptCore > ${FORWARDING_HEADERS_DIR}/JavaScriptCore/glib > ${DERIVED_SOURCES_JAVASCRIPCOREWPE_DIR} >- ${TOOLS_DIR}/wpe/HeadlessViewBackend >+ ${TOOLS_DIR}/wpe/backends > ) > > include_directories(SYSTEM >@@ -79,7 +79,7 @@ set_target_properties(TestWebCore PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${TESTWEBK > # TestWebKit > > list(APPEND test_webkit_api_LIBRARIES >- WPEHeadlessViewBackend >+ WPEToolingBackends > ) > > add_executable(TestWebKit ${test_webkit_api_SOURCES}) >diff --git a/Tools/TestWebKitAPI/PlatformWebView.h b/Tools/TestWebKitAPI/PlatformWebView.h >index 6b39dc20287..b957c5ad084 100644 >--- a/Tools/TestWebKitAPI/PlatformWebView.h >+++ b/Tools/TestWebKitAPI/PlatformWebView.h >@@ -48,10 +48,12 @@ typedef NSWindow *PlatformWindow; > typedef WKViewRef PlatformWKView; > typedef GtkWidget *PlatformWindow; > #elif PLATFORM(WPE) >+namespace WPEToolingBackends { > class HeadlessViewBackend; >+} > struct wpe_view_backend; > typedef WKViewRef PlatformWKView; >-typedef HeadlessViewBackend *PlatformWindow; >+typedef WPEToolingBackends::HeadlessViewBackend *PlatformWindow; > #elif PLATFORM(WIN) > typedef WKViewRef PlatformWKView; > typedef HWND PlatformWindow; >diff --git a/Tools/TestWebKitAPI/glib/PlatformWPE.cmake b/Tools/TestWebKitAPI/glib/PlatformWPE.cmake >index c102b1a5a37..f511cd2a684 100644 >--- a/Tools/TestWebKitAPI/glib/PlatformWPE.cmake >+++ b/Tools/TestWebKitAPI/glib/PlatformWPE.cmake >@@ -10,7 +10,7 @@ list(APPEND WebKitGLibAPITests_INCLUDE_DIRECTORIES > ${FORWARDING_HEADERS_WPE_DIR} > ${FORWARDING_HEADERS_WPE_EXTENSION_DIR} > ${FORWARDING_HEADERS_WPE_DOM_DIR} >- ${TOOLS_DIR}/wpe/HeadlessViewBackend >+ ${TOOLS_DIR}/wpe/backends > ) > > list(APPEND WebKitGLibAPITests_SYSTEM_INCLUDE_DIRECTORIES >@@ -21,5 +21,5 @@ list(APPEND WebKitGLibAPITests_SYSTEM_INCLUDE_DIRECTORIES > list(APPEND WebKitGLibAPITest_LIBRARIES > ${WPE_LIBRARIES} > ${WPEBACKEND_FDO_LIBRARIES} >- WPEHeadlessViewBackend >+ WPEToolingBackends > ) >diff --git a/Tools/TestWebKitAPI/glib/WebKitGLib/TestMain.h b/Tools/TestWebKitAPI/glib/WebKitGLib/TestMain.h >index 1d3da7f2458..13ba28e244d 100644 >--- a/Tools/TestWebKitAPI/glib/WebKitGLib/TestMain.h >+++ b/Tools/TestWebKitAPI/glib/WebKitGLib/TestMain.h >@@ -142,9 +142,9 @@ public: > #if PLATFORM(WPE) > static WebKitWebViewBackend* createWebViewBackend() > { >- auto* headlessBackend = new HeadlessViewBackend; >+ auto* headlessBackend = new WPEToolingBackends::HeadlessViewBackend(800, 600); > return webkit_web_view_backend_new(headlessBackend->backend(), [](gpointer userData) { >- delete static_cast<HeadlessViewBackend*>(userData); >+ delete static_cast<WPEToolingBackends::HeadlessViewBackend*>(userData); > }, headlessBackend); > } > #endif >diff --git a/Tools/TestWebKitAPI/wpe/PlatformWebViewWPE.cpp b/Tools/TestWebKitAPI/wpe/PlatformWebViewWPE.cpp >index 7d8358e8182..8cc3b71a732 100644 >--- a/Tools/TestWebKitAPI/wpe/PlatformWebViewWPE.cpp >+++ b/Tools/TestWebKitAPI/wpe/PlatformWebViewWPE.cpp >@@ -66,7 +66,7 @@ PlatformWebView::~PlatformWebView() > > void PlatformWebView::initialize(WKPageConfigurationRef configuration) > { >- m_window = new HeadlessViewBackend; >+ m_window = new WPEToolingBackends::HeadlessViewBackend(800, 600); > m_view = WKViewCreate(m_window->backend(), configuration); > } > >diff --git a/Tools/WebKitTestRunner/PlatformWPE.cmake b/Tools/WebKitTestRunner/PlatformWPE.cmake >index 89faeded44d..0453ff6ea72 100644 >--- a/Tools/WebKitTestRunner/PlatformWPE.cmake >+++ b/Tools/WebKitTestRunner/PlatformWPE.cmake >@@ -19,7 +19,7 @@ list(APPEND WebKitTestRunner_SOURCES > list(APPEND WebKitTestRunner_INCLUDE_DIRECTORIES > ${WEBKIT_TESTRUNNER_DIR}/InjectedBundle/wpe > ${FORWARDING_HEADERS_DIR} >- ${TOOLS_DIR}/wpe/HeadlessViewBackend >+ ${TOOLS_DIR}/wpe/backends > ) > > list(APPEND WebKitTestRunner_SYSTEM_INCLUDE_DIRECTORIES >@@ -34,7 +34,7 @@ list(APPEND WebKitTestRunner_LIBRARIES > ${GLIB_LIBRARIES} > ${LIBXKBCOMMON_LIBRARIES} > ${WPEBACKEND_FDO_LIBRARIES} >- WPEHeadlessViewBackend >+ WPEToolingBackends > ) > > set(WebKitTestRunnerInjectedBundle_LIBRARIES >diff --git a/Tools/WebKitTestRunner/PlatformWebView.h b/Tools/WebKitTestRunner/PlatformWebView.h >index 1cc8131a19a..6d0e9b0c748 100644 >--- a/Tools/WebKitTestRunner/PlatformWebView.h >+++ b/Tools/WebKitTestRunner/PlatformWebView.h >@@ -51,9 +51,11 @@ typedef WKViewRef PlatformWKView; > typedef GtkWidget* PlatformWindow; > typedef cairo_surface_t *PlatformImage; > #elif PLATFORM(WPE) >+namespace WPEToolingBackends { > class HeadlessViewBackend; >+} > typedef WKViewRef PlatformWKView; >-typedef HeadlessViewBackend* PlatformWindow; >+typedef WPEToolingBackends::HeadlessViewBackend* PlatformWindow; > typedef cairo_surface_t* PlatformImage; > #endif > >diff --git a/Tools/WebKitTestRunner/wpe/PlatformWebViewWPE.cpp b/Tools/WebKitTestRunner/wpe/PlatformWebViewWPE.cpp >index fe582c73d5f..05c65681273 100644 >--- a/Tools/WebKitTestRunner/wpe/PlatformWebViewWPE.cpp >+++ b/Tools/WebKitTestRunner/wpe/PlatformWebViewWPE.cpp >@@ -39,7 +39,7 @@ PlatformWebView::PlatformWebView(WKPageConfigurationRef configuration, const Tes > : m_windowIsKey(true) > , m_options(options) > { >- m_window = new HeadlessViewBackend; >+ m_window = new WPEToolingBackends::HeadlessViewBackend(800, 600); > m_view = WKViewCreate(m_window->backend(), configuration); > } > >diff --git a/Tools/wpe/HeadlessViewBackend/CMakeLists.txt b/Tools/wpe/HeadlessViewBackend/CMakeLists.txt >deleted file mode 100644 >index 13dbd422999..00000000000 >--- a/Tools/wpe/HeadlessViewBackend/CMakeLists.txt >+++ /dev/null >@@ -1,23 +0,0 @@ >-find_package(WPEBackend-fdo REQUIRED) >- >-set(WPEHeadlessViewBackend_SOURCES >- ${TOOLS_DIR}/wpe/HeadlessViewBackend/HeadlessViewBackend.cpp >-) >- >-set(WPEHeadlessViewBackend_SYSTEM_INCLUDE_DIRECTORIES >- ${CAIRO_INCLUDE_DIRS} >- ${GLIB_INCLUDE_DIRS} >- ${WPE_INCLUDE_DIRS} >- ${WPEBACKEND_FDO_INCLUDE_DIRS} >-) >- >-set(WPEHeadlessViewBackend_LIBRARIES >- ${CAIRO_LIBRARIES} >- ${GLIB_LIBRARIES} >- ${WPE_LIBRARIES} >- ${WPEBACKEND_FDO_LIBRARIES} >-) >- >-add_library(WPEHeadlessViewBackend ${WPEHeadlessViewBackend_SOURCES}) >-include_directories(SYSTEM ${WPEHeadlessViewBackend_SYSTEM_INCLUDE_DIRECTORIES}) >-target_link_libraries(WPEHeadlessViewBackend ${WPEHeadlessViewBackend_LIBRARIES}) >diff --git a/Tools/wpe/backends/CMakeLists.txt b/Tools/wpe/backends/CMakeLists.txt >new file mode 100644 >index 00000000000..f9e8b43b9fb >--- /dev/null >+++ b/Tools/wpe/backends/CMakeLists.txt >@@ -0,0 +1,53 @@ >+find_package(Libxkbcommon 0.4.0 REQUIRED) >+find_package(Wayland REQUIRED) >+find_package(WaylandProtocols 1.12 REQUIRED) >+find_package(WPEBackend-fdo REQUIRED) >+ >+set(DERIVED_SOURCES_WPETOOLINGBACKENDS_DIR "${CMAKE_BINARY_DIR}/DerivedSources/WPEToolingBackends") >+ >+file(MAKE_DIRECTORY ${DERIVED_SOURCES_WPETOOLINGBACKENDS_DIR}) >+ >+set(WPEToolingBackends_SOURCES >+ ${DERIVED_SOURCES_WPETOOLINGBACKENDS_DIR}/xdg-shell-unstable-v6-protocol.c >+ ${TOOLS_DIR}/wpe/backends/HeadlessViewBackend.cpp >+ ${TOOLS_DIR}/wpe/backends/ViewBackend.cpp >+ ${TOOLS_DIR}/wpe/backends/WindowViewBackend.cpp >+) >+ >+set(WPEToolingBackends_INCLUDE_DIRECTORIES >+ ${DERIVED_SOURCES_WPETOOLINGBACKENDS_DIR} >+) >+ >+set(WPEToolingBackends_SYSTEM_INCLUDE_DIRECTORIES >+ ${CAIRO_INCLUDE_DIRS} >+ ${GLIB_INCLUDE_DIRS} >+ ${WPE_INCLUDE_DIRS} >+ ${WPEBACKEND_FDO_INCLUDE_DIRS} >+) >+ >+set(WPEToolingBackends_LIBRARIES >+ ${CAIRO_LIBRARIES} >+ ${GLIB_LIBRARIES} >+ ${LIBXKBCOMMON_LIBRARIES} >+ ${WAYLAND_LIBRARIES} >+ ${WPE_LIBRARIES} >+ ${WPEBACKEND_FDO_LIBRARIES} >+) >+ >+add_custom_command( >+ OUTPUT ${DERIVED_SOURCES_WPETOOLINGBACKENDS_DIR}/xdg-shell-unstable-v6-protocol.c >+ MAIN_DEPENDENCY ${WAYLAND_PROTOCOLS_DATADIR}/unstable/xdg-shell/xdg-shell-unstable-v6.xml >+ DEPENDS ${DERIVED_SOURCES_WPETOOLINGBACKENDS_DIR}/xdg-shell-unstable-v6-client-protocol.h >+ COMMAND ${WAYLAND_SCANNER} code ${WAYLAND_PROTOCOLS_DATADIR}/unstable/xdg-shell/xdg-shell-unstable-v6.xml ${DERIVED_SOURCES_WPETOOLINGBACKENDS_DIR}/xdg-shell-unstable-v6-protocol.c >+ VERBATIM) >+ >+add_custom_command( >+ OUTPUT ${DERIVED_SOURCES_WPETOOLINGBACKENDS_DIR}/xdg-shell-unstable-v6-client-protocol.h >+ MAIN_DEPENDENCY ${WAYLAND_PROTOCOLS_DATADIR}/unstable/xdg-shell/xdg-shell-unstable-v6.xml >+ COMMAND ${WAYLAND_SCANNER} client-header ${WAYLAND_PROTOCOLS_DATADIR}/unstable/xdg-shell/xdg-shell-unstable-v6.xml ${DERIVED_SOURCES_WPETOOLINGBACKENDS_DIR}/xdg-shell-unstable-v6-client-protocol.h >+ VERBATIM) >+ >+add_library(WPEToolingBackends ${WPEToolingBackends_SOURCES}) >+include_directories(${WPEToolingBackends_INCLUDE_DIRECTORIES}) >+include_directories(SYSTEM ${WPEToolingBackends_SYSTEM_INCLUDE_DIRECTORIES}) >+target_link_libraries(WPEToolingBackends ${WPEToolingBackends_LIBRARIES}) >diff --git a/Tools/wpe/HeadlessViewBackend/HeadlessViewBackend.cpp b/Tools/wpe/backends/HeadlessViewBackend.cpp >similarity index 57% >rename from Tools/wpe/HeadlessViewBackend/HeadlessViewBackend.cpp >rename to Tools/wpe/backends/HeadlessViewBackend.cpp >index 1a6b7995722..79953a433eb 100644 >--- a/Tools/wpe/HeadlessViewBackend/HeadlessViewBackend.cpp >+++ b/Tools/wpe/backends/HeadlessViewBackend.cpp >@@ -28,13 +28,27 @@ > #include <cassert> > #include <fcntl.h> > #include <unistd.h> >+ >+// This include order is necessary to enforce the GBM EGL platform. >+#include <gbm.h> >+#include <epoxy/egl.h> > #include <wpe/fdo-egl.h> > >-// Manually provide the EGL_CAST C++ definition in case eglplatform.h doesn't provide it. >-#ifndef EGL_CAST >-#define EGL_CAST(type, value) (static_cast<type>(value)) >+#ifndef EGL_WL_bind_wayland_display >+#define EGL_WL_bind_wayland_display 1 >+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL) (EGLDisplay dpy, struct wl_resource* buffer, EGLint attribute, EGLint* value); >+ >+#define EGL_WAYLAND_BUFFER_WL 0x31D5 // eglCreateImageKHR target >+#define EGL_WAYLAND_PLANE_WL 0x31D6 // eglCreateImageKHR target > #endif > >+namespace WPEToolingBackends { >+ >+static PFNEGLCREATEIMAGEKHRPROC createImage; >+static PFNEGLDESTROYIMAGEKHRPROC destroyImage; >+static PFNEGLQUERYWAYLANDBUFFERWL queryBuffer; >+static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC imageTargetTexture2DOES; >+ > // Keep this in sync with wtf/glib/RunLoopSourcePriority.h. > static int kRunLoopSourcePriorityDispatcher = -70; > >@@ -46,64 +60,32 @@ static EGLDisplay getEGLDisplay() > if (display == EGL_NO_DISPLAY) > return EGL_NO_DISPLAY; > >- if (!eglInitialize(display, nullptr, nullptr)) >- return EGL_NO_DISPLAY; >- >- if (!eglBindAPI(EGL_OPENGL_ES_API)) >- return EGL_NO_DISPLAY; >- >- wpe_fdo_initialize_for_egl_display(display); > s_display = display; > } > > return s_display; > } > >-HeadlessViewBackend::HeadlessViewBackend() >+HeadlessViewBackend::HeadlessViewBackend(uint32_t width, uint32_t height) >+ : ViewBackend(width, height) > { >- m_egl.display = getEGLDisplay(); >- >- static const EGLint configAttributes[13] = { >- EGL_SURFACE_TYPE, EGL_WINDOW_BIT, >- EGL_RED_SIZE, 1, >- EGL_GREEN_SIZE, 1, >- EGL_BLUE_SIZE, 1, >- EGL_ALPHA_SIZE, 1, >- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, >- EGL_NONE >- }; >- >- EGLint numConfigs; >- EGLBoolean ret = eglChooseConfig(m_egl.display, configAttributes, &m_egl.config, 1, &numConfigs); >- if (!ret || !numConfigs) >- return; >- >- static const EGLint contextAttributes[3] = { >- EGL_CONTEXT_CLIENT_VERSION, 2, >- EGL_NONE >- }; >- >- m_egl.context = eglCreateContext(m_egl.display, m_egl.config, EGL_NO_CONTEXT, contextAttributes); >- if (m_egl.context == EGL_NO_CONTEXT) >+ m_eglDisplay = getEGLDisplay(); >+ if (!initialize()) > return; > >- if (!eglMakeCurrent(m_egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, m_egl.context)) >+ if (!eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, m_eglContext)) > return; > >- m_egl.createImage = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR")); >- m_egl.destroyImage = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR")); >- m_egl.queryBuffer = reinterpret_cast<PFNEGLQUERYWAYLANDBUFFERWL>(eglGetProcAddress("eglQueryWaylandBufferWL")); >- m_egl.imageTargetTexture2DOES = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES")); >- >- m_exportable = wpe_view_backend_exportable_fdo_create(&s_exportableClient, this, 800, 600); >+ createImage = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR")); >+ destroyImage = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR")); >+ queryBuffer = reinterpret_cast<PFNEGLQUERYWAYLANDBUFFERWL>(eglGetProcAddress("eglQueryWaylandBufferWL")); >+ imageTargetTexture2DOES = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES")); > > m_updateSource = g_timeout_source_new(m_frameRate / 1000); >- g_source_set_callback(m_updateSource, >- [](gpointer data) -> gboolean { >- auto& backend = *static_cast<HeadlessViewBackend*>(data); >- backend.performUpdate(); >- return TRUE; >- }, this, nullptr); >+ g_source_set_callback(m_updateSource, [](gpointer data) -> gboolean { >+ static_cast<HeadlessViewBackend*>(data)->performUpdate(); >+ return TRUE; >+ }, this, nullptr); > g_source_set_priority(m_updateSource, kRunLoopSourcePriorityDispatcher); > g_source_attach(m_updateSource, g_main_context_default()); > } >@@ -116,23 +98,16 @@ HeadlessViewBackend::~HeadlessViewBackend() > } > > if (auto image = std::get<0>(m_pendingImage.second)) >- m_egl.destroyImage(m_egl.display, image); >+ destroyImage(m_eglDisplay, image); > if (auto image = std::get<0>(m_lockedImage.second)) >- m_egl.destroyImage(m_egl.display, image); >- >- if (m_egl.context) >- eglDestroyContext(m_egl.display, m_egl.context); >- >- wpe_view_backend_exportable_fdo_destroy(m_exportable); >-} >- >-struct wpe_view_backend* HeadlessViewBackend::backend() const >-{ >- return wpe_view_backend_exportable_fdo_get_view_backend(m_exportable); >+ destroyImage(m_eglDisplay, image); > } > > cairo_surface_t* HeadlessViewBackend::createSnapshot() > { >+ if (!m_eglContext) >+ return nullptr; >+ > performUpdate(); > > EGLImageKHR image = std::get<0>(m_lockedImage.second); >@@ -145,7 +120,7 @@ cairo_surface_t* HeadlessViewBackend::createSnapshot() > uint8_t* buffer = new uint8_t[4 * width * height]; > bool successfulSnapshot = false; > >- if (!eglMakeCurrent(m_egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, m_egl.context)) >+ if (!eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, m_eglContext)) > return nullptr; > > GLuint imageTexture; >@@ -157,7 +132,7 @@ cairo_surface_t* HeadlessViewBackend::createSnapshot() > glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); > glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, width, height, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, nullptr); > >- m_egl.imageTargetTexture2DOES(GL_TEXTURE_2D, image); >+ imageTargetTexture2DOES(GL_TEXTURE_2D, image); > glBindTexture(GL_TEXTURE_2D, 0); > > GLuint imageFramebuffer; >@@ -202,39 +177,30 @@ void HeadlessViewBackend::performUpdate() > wpe_view_backend_exportable_fdo_dispatch_frame_complete(m_exportable); > if (m_lockedImage.first) { > wpe_view_backend_exportable_fdo_dispatch_release_buffer(m_exportable, m_lockedImage.first); >- m_egl.destroyImage(m_egl.display, std::get<0>(m_lockedImage.second)); >+ destroyImage(m_eglDisplay, std::get<0>(m_lockedImage.second)); > } > > m_lockedImage = m_pendingImage; > m_pendingImage = std::pair<struct wl_resource*, std::tuple<EGLImageKHR, uint32_t, uint32_t>> { }; > } > >-struct wpe_view_backend_exportable_fdo_client HeadlessViewBackend::s_exportableClient = { >- // export_buffer_resource >- [](void* data, struct wl_resource* bufferResource) >- { >- auto& backend = *static_cast<HeadlessViewBackend*>(data); >- if (backend.m_pendingImage.first) >- std::abort(); >- >- auto& egl = backend.m_egl; >- >- EGLint format = 0; >- if (!egl.queryBuffer(egl.display, bufferResource, EGL_TEXTURE_FORMAT, &format) || format != EGL_TEXTURE_RGBA) >- return; >- >- EGLint width, height; >- if (!egl.queryBuffer(egl.display, bufferResource, EGL_WIDTH, &width) >- || !egl.queryBuffer(egl.display, bufferResource, EGL_HEIGHT, &height)) >- return; >- >- EGLint attributes[] = { EGL_WAYLAND_PLANE_WL, 0, EGL_NONE }; >- EGLImageKHR image = egl.createImage(egl.display, EGL_NO_CONTEXT, EGL_WAYLAND_BUFFER_WL, bufferResource, attributes); >- backend.m_pendingImage = { bufferResource, std::make_tuple(image, width, height) }; >- }, >- // padding >- nullptr, >- nullptr, >- nullptr, >- nullptr >-}; >+void HeadlessViewBackend::displayBuffer(struct wl_resource* bufferResource) >+{ >+ if (m_pendingImage.first) >+ std::abort(); >+ >+ EGLint format = 0; >+ if (!queryBuffer(m_eglDisplay, bufferResource, EGL_TEXTURE_FORMAT, &format) || format != EGL_TEXTURE_RGBA) >+ return; >+ >+ EGLint width, height; >+ if (!queryBuffer(m_eglDisplay, bufferResource, EGL_WIDTH, &width) >+ || !queryBuffer(m_eglDisplay, bufferResource, EGL_HEIGHT, &height)) >+ return; >+ >+ EGLint attributes[] = { EGL_WAYLAND_PLANE_WL, 0, EGL_NONE }; >+ EGLImageKHR image = createImage(m_eglDisplay, EGL_NO_CONTEXT, EGL_WAYLAND_BUFFER_WL, bufferResource, attributes); >+ m_pendingImage = { bufferResource, std::make_tuple(image, width, height) }; >+} >+ >+} // namespace WPEToolingBackends >diff --git a/Tools/wpe/HeadlessViewBackend/HeadlessViewBackend.h b/Tools/wpe/backends/HeadlessViewBackend.h >similarity index 61% >rename from Tools/wpe/HeadlessViewBackend/HeadlessViewBackend.h >rename to Tools/wpe/backends/HeadlessViewBackend.h >index e142e69d834..178424e978e 100644 >--- a/Tools/wpe/HeadlessViewBackend/HeadlessViewBackend.h >+++ b/Tools/wpe/backends/HeadlessViewBackend.h >@@ -25,53 +25,32 @@ > > #pragma once > >-// This include order is necessary to enforce the GBM EGL platform. >-#include <gbm.h> >-#include <epoxy/egl.h> >- >+#include "ViewBackend.h" > #include <cairo.h> > #include <glib.h> > #include <unordered_map> >-#include <wpe/fdo.h> > >-#ifndef EGL_WL_bind_wayland_display >-#define EGL_WL_bind_wayland_display 1 >-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL) (EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value); >+typedef void* EGLImageKHR; > >-#define EGL_WAYLAND_BUFFER_WL 0x31D5 /* eglCreateImageKHR target */ >-#define EGL_WAYLAND_PLANE_WL 0x31D6 /* eglCreateImageKHR target */ >-#endif >+namespace WPEToolingBackends { > >-class HeadlessViewBackend { >+class HeadlessViewBackend final : public ViewBackend { > public: >- HeadlessViewBackend(); >+ HeadlessViewBackend(uint32_t width, uint32_t height); > ~HeadlessViewBackend(); > >- struct wpe_view_backend* backend() const; >- > cairo_surface_t* createSnapshot(); > > private: >- void performUpdate(); >- >- static struct wpe_view_backend_exportable_fdo_client s_exportableClient; >+ void displayBuffer(struct wl_resource*) override; > >- struct { >- EGLDisplay display; >- EGLConfig config; >- EGLContext context { nullptr }; >- >- PFNEGLCREATEIMAGEKHRPROC createImage; >- PFNEGLDESTROYIMAGEKHRPROC destroyImage; >- PFNEGLQUERYWAYLANDBUFFERWL queryBuffer; >- PFNGLEGLIMAGETARGETTEXTURE2DOESPROC imageTargetTexture2DOES; >- } m_egl; >- >- struct wpe_view_backend_exportable_fdo* m_exportable; >+ void performUpdate(); > > std::pair<struct wl_resource*, std::tuple<EGLImageKHR, uint32_t, uint32_t>> m_pendingImage { }; > std::pair<struct wl_resource*, std::tuple<EGLImageKHR, uint32_t, uint32_t>> m_lockedImage { }; > >- GSource* m_updateSource; >+ GSource* m_updateSource { nullptr }; > gint64 m_frameRate { G_USEC_PER_SEC / 60 }; > }; >+ >+} // namespace WPEToolingBackends >diff --git a/Tools/wpe/backends/ViewBackend.cpp b/Tools/wpe/backends/ViewBackend.cpp >new file mode 100644 >index 00000000000..3d0ac69c3a2 >--- /dev/null >+++ b/Tools/wpe/backends/ViewBackend.cpp >@@ -0,0 +1,137 @@ >+/* >+ * Copyright (C) 2018 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 APPLE INC. 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 APPLE INC. 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. >+ */ >+ >+#include "ViewBackend.h" >+ >+#include <epoxy/egl.h> >+#include <glib.h> >+#include <wpe/fdo-egl.h> >+ >+namespace WPEToolingBackends { >+ >+ViewBackend::ViewBackend(uint32_t width, uint32_t height) >+ : m_width(width) >+ , m_height(height) >+{ >+} >+ >+ViewBackend::~ViewBackend() >+{ >+ if (m_exportable) >+ wpe_view_backend_exportable_fdo_destroy(m_exportable); >+ >+ if (m_eglContext) >+ eglDestroyContext(m_eglDisplay, m_eglContext); >+} >+ >+bool ViewBackend::initialize() >+{ >+ if (m_eglDisplay == EGL_NO_DISPLAY) >+ return false; >+ >+ eglInitialize(m_eglDisplay, nullptr, nullptr); >+ >+ if (!eglBindAPI(EGL_OPENGL_ES_API)) >+ return false; >+ >+ wpe_fdo_initialize_for_egl_display(m_eglDisplay); >+ >+ static const EGLint configAttributes[13] = { >+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT, >+ EGL_RED_SIZE, 1, >+ EGL_GREEN_SIZE, 1, >+ EGL_BLUE_SIZE, 1, >+ EGL_ALPHA_SIZE, 1, >+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, >+ EGL_NONE >+ }; >+ >+ { >+ EGLint count = 0; >+ if (!eglGetConfigs(m_eglDisplay, nullptr, 0, &count) || count < 1) >+ return false; >+ >+ EGLConfig* configs = g_new0(EGLConfig, count); >+ EGLint matched = 0; >+ if (eglChooseConfig(m_eglDisplay, configAttributes, configs, count, &matched) && !!matched) >+ m_eglConfig = configs[0]; >+ g_free(configs); >+ } >+ >+ static const EGLint contextAttributes[3] = { >+ EGL_CONTEXT_CLIENT_VERSION, 2, >+ EGL_NONE >+ }; >+ >+ m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, contextAttributes); >+ if (!m_eglContext) >+ return false; >+ >+ static struct wpe_view_backend_exportable_fdo_client exportableClient = { >+ // export_buffer_resource >+ [](void* data, struct wl_resource* bufferResource) >+ { >+ static_cast<ViewBackend*>(data)->displayBuffer(bufferResource); >+ }, >+ // padding >+ nullptr, nullptr, nullptr, nullptr >+ }; >+ m_exportable = wpe_view_backend_exportable_fdo_create(&exportableClient, this, m_width, m_height); >+ >+ return true; >+} >+ >+void ViewBackend::setInputClient(std::unique_ptr<InputClient>&& client) >+{ >+ m_inputClient = std::move(client); >+} >+ >+struct wpe_view_backend* ViewBackend::backend() const >+{ >+ return m_exportable ? wpe_view_backend_exportable_fdo_get_view_backend(m_exportable) : nullptr; >+} >+ >+void ViewBackend::dispatchInputPointerEvent(struct wpe_input_pointer_event* event) >+{ >+ if (m_inputClient && m_inputClient->dispatchPointerEvent(event)) >+ return; >+ wpe_view_backend_dispatch_pointer_event(backend(), event); >+} >+ >+void ViewBackend::dispatchInputAxisEvent(struct wpe_input_axis_event* event) >+{ >+ if (m_inputClient && m_inputClient->dispatchAxisEvent(event)) >+ return; >+ wpe_view_backend_dispatch_axis_event(backend(), event); >+} >+ >+void ViewBackend::dispatchInputKeyboardEvent(struct wpe_input_keyboard_event* event) >+{ >+ if (m_inputClient && m_inputClient->dispatchKeyboardEvent(event)) >+ return; >+ wpe_view_backend_dispatch_keyboard_event(backend(), event); >+} >+ >+} // namespace WPEToolingBackends >diff --git a/Tools/wpe/backends/ViewBackend.h b/Tools/wpe/backends/ViewBackend.h >new file mode 100644 >index 00000000000..e6cb2687ff3 >--- /dev/null >+++ b/Tools/wpe/backends/ViewBackend.h >@@ -0,0 +1,78 @@ >+/* >+ * Copyright (C) 2018 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 APPLE INC. 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 APPLE INC. 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. >+ */ >+ >+#pragma once >+ >+#include <memory> >+#include <wpe/fdo.h> >+ >+typedef void* EGLConfig; >+typedef void* EGLContext; >+typedef void* EGLDisplay; >+ >+// Manually provide the EGL_CAST C++ definition in case eglplatform.h doesn't provide it. >+#ifndef EGL_CAST >+#define EGL_CAST(type, value) (static_cast<type>(value)) >+#endif >+ >+namespace WPEToolingBackends { >+ >+class ViewBackend { >+public: >+ virtual ~ViewBackend(); >+ >+ class InputClient { >+ public: >+ virtual ~InputClient() = default; >+ >+ virtual bool dispatchPointerEvent(struct wpe_input_pointer_event*) { return false; } >+ virtual bool dispatchAxisEvent(struct wpe_input_axis_event*) { return false; } >+ virtual bool dispatchKeyboardEvent(struct wpe_input_keyboard_event*) { return false; } >+ }; >+ void setInputClient(std::unique_ptr<InputClient>&&); >+ >+ struct wpe_view_backend* backend() const; >+ >+protected: >+ ViewBackend(uint32_t width, uint32_t height); >+ >+ bool initialize(); >+ >+ void dispatchInputPointerEvent(struct wpe_input_pointer_event*); >+ void dispatchInputAxisEvent(struct wpe_input_axis_event*); >+ void dispatchInputKeyboardEvent(struct wpe_input_keyboard_event*); >+ >+ virtual void displayBuffer(struct wl_resource*) = 0; >+ >+ uint32_t m_width { 0 }; >+ uint32_t m_height { 0 }; >+ EGLDisplay m_eglDisplay { nullptr }; >+ EGLContext m_eglContext { nullptr }; >+ EGLConfig m_eglConfig; >+ struct wpe_view_backend_exportable_fdo* m_exportable { nullptr }; >+ std::unique_ptr<InputClient> m_inputClient; >+}; >+ >+} // namespace WPEToolingBackends >diff --git a/Tools/wpe/backends/WindowViewBackend.cpp b/Tools/wpe/backends/WindowViewBackend.cpp >new file mode 100644 >index 00000000000..8134a1b306f >--- /dev/null >+++ b/Tools/wpe/backends/WindowViewBackend.cpp >@@ -0,0 +1,611 @@ >+/* >+ * Copyright (C) 2018 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 APPLE INC. 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 APPLE INC. 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. >+ */ >+ >+#include "WindowViewBackend.h" >+ >+#include <cstdio> >+#include <cstring> >+#include <linux/input.h> >+#include <memory> >+#include <sys/mman.h> >+#include <unistd.h> >+ >+// This include order is necessary to enforce the Wayland EGL platform. >+#include <wayland-egl.h> >+#include <epoxy/egl.h> >+ >+#ifndef EGL_WL_bind_wayland_display >+#define EGL_WL_bind_wayland_display 1 >+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL) (EGLDisplay dpy, struct wl_resource* buffer, EGLint attribute, EGLint* value); >+ >+#define EGL_WAYLAND_BUFFER_WL 0x31D5 // eglCreateImageKHR target >+#define EGL_WAYLAND_PLANE_WL 0x31D6 // eglCreateImageKHR target >+#endif >+ >+namespace WPEToolingBackends { >+ >+static PFNEGLCREATEIMAGEKHRPROC createImage; >+static PFNEGLDESTROYIMAGEKHRPROC destroyImage; >+static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC imageTargetTexture2DOES; >+ >+struct EventSource { >+ static GSourceFuncs sourceFuncs; >+ >+ GSource source; >+ GPollFD pfd; >+ struct wl_display* display; >+}; >+ >+GSourceFuncs EventSource::sourceFuncs = { >+ // prepare >+ [](GSource* base, gint* timeout) -> gboolean >+ { >+ auto* source = reinterpret_cast<EventSource*>(base); >+ struct wl_display* display = source->display; >+ >+ *timeout = -1; >+ >+ wl_display_dispatch_pending(display); >+ wl_display_flush(display); >+ >+ return FALSE; >+ }, >+ // check >+ [](GSource* base) -> gboolean >+ { >+ auto* source = reinterpret_cast<EventSource*>(base); >+ return !!source->pfd.revents; >+ }, >+ // dispatch >+ [](GSource* base, GSourceFunc, gpointer) -> gboolean >+ { >+ auto* source = reinterpret_cast<EventSource*>(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 >+}; >+ >+const struct wl_registry_listener WindowViewBackend::s_registryListener = { >+ // global >+ [](void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t) >+ { >+ auto* window = static_cast<WindowViewBackend*>(data); >+ >+ if (!std::strcmp(interface, "wl_compositor")) >+ window->m_compositor = static_cast<struct wl_compositor*>(wl_registry_bind(registry, name, &wl_compositor_interface, 1)); >+ >+ if (!std::strcmp(interface, "zxdg_shell_v6")) >+ window->m_xdg = static_cast<struct zxdg_shell_v6*>(wl_registry_bind(registry, name, &zxdg_shell_v6_interface, 1)); >+ >+ if (!std::strcmp(interface, "wl_seat")) >+ window->m_seat = static_cast<struct wl_seat*>(wl_registry_bind(registry, name, &wl_seat_interface, 4)); >+ }, >+ // global_remove >+ [](void*, struct wl_registry*, uint32_t) { }, >+}; >+ >+const struct zxdg_shell_v6_listener WindowViewBackend::s_xdgWmBaseListener = { >+ // ping >+ [](void*, struct zxdg_shell_v6* shell, uint32_t serial) >+ { >+ zxdg_shell_v6_pong(shell, serial); >+ }, >+}; >+ >+const struct wl_pointer_listener WindowViewBackend::s_pointerListener = { >+ // enter >+ [](void* data, struct wl_pointer*, uint32_t /*serial*/, struct wl_surface* surface, wl_fixed_t, wl_fixed_t) >+ { >+ auto& window = *static_cast<WindowViewBackend*>(data); >+ if (window.m_surface == surface) >+ window.m_seatData.pointer.target = surface; >+ }, >+ // leave >+ [](void* data, struct wl_pointer*, uint32_t /*serial*/, struct wl_surface* surface) >+ { >+ auto& window = *static_cast<WindowViewBackend*>(data); >+ if (window.m_surface == surface && window.m_seatData.pointer.target == surface) >+ window.m_seatData.pointer.target = nullptr; >+ }, >+ // motion >+ [](void* data, struct wl_pointer*, uint32_t time, wl_fixed_t fixedX, wl_fixed_t fixedY) >+ { >+ auto& window = *static_cast<WindowViewBackend*>(data); >+ int x = wl_fixed_to_int(fixedX); >+ int y = wl_fixed_to_int(fixedY); >+ window.m_seatData.pointer.coords = { x, y }; >+ >+ if (window.m_seatData.pointer.target) { >+ struct wpe_input_pointer_event event = { wpe_input_pointer_event_type_motion, >+ time, x, y, window.m_seatData.pointer.button, window.m_seatData.pointer.state }; >+ window.dispatchInputPointerEvent(&event); >+ } >+ }, >+ // button >+ [](void* data, struct wl_pointer*, uint32_t /*serial*/, uint32_t time, uint32_t button, uint32_t state) >+ { >+ auto& window = *static_cast<WindowViewBackend*>(data); >+ if (button >= BTN_MOUSE) >+ button = button - BTN_MOUSE + 1; >+ else >+ button = 0; >+ >+ window.m_seatData.pointer.button = !!state ? button : 0; >+ window.m_seatData.pointer.state = state; >+ >+ if (window.m_seatData.pointer.target) { >+ struct wpe_input_pointer_event event = { wpe_input_pointer_event_type_button, >+ time, window.m_seatData.pointer.coords.first, window.m_seatData.pointer.coords.second, button, state }; >+ window.dispatchInputPointerEvent(&event); >+ } >+ }, >+ // axis >+ [](void* data, struct wl_pointer*, uint32_t time, uint32_t axis, wl_fixed_t value) >+ { >+ auto& window = *static_cast<WindowViewBackend*>(data); >+ if (window.m_seatData.pointer.target) { >+ struct wpe_input_axis_event event = { wpe_input_axis_event_type_motion, >+ time, window.m_seatData.pointer.coords.first, window.m_seatData.pointer.coords.second, axis, -wl_fixed_to_int(value) }; >+ window.dispatchInputAxisEvent(&event); >+ } >+ }, >+}; >+ >+const struct wl_keyboard_listener WindowViewBackend::s_keyboardListener = { >+ // keymap >+ [](void* data, struct wl_keyboard*, uint32_t format, int fd, uint32_t size) >+ { >+ auto& window = *static_cast<WindowViewBackend*>(data); >+ 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 = window.m_seatData.xkb; >+ xkb.keymap = xkb_keymap_new_from_string(xkb.context, static_cast<char*>(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); >+ }, >+ // enter >+ [](void* data, struct wl_keyboard*, uint32_t /*serial*/, struct wl_surface* surface, struct wl_array*) >+ { >+ auto& window = *static_cast<WindowViewBackend*>(data); >+ if (window.m_surface == surface) >+ window.m_seatData.keyboard.target = surface; >+ }, >+ // leave >+ [](void* data, struct wl_keyboard*, uint32_t /*serial*/, struct wl_surface* surface) >+ { >+ auto& window = *static_cast<WindowViewBackend*>(data); >+ if (window.m_surface == surface && window.m_seatData.keyboard.target == surface) >+ window.m_seatData.keyboard.target = nullptr; >+ }, >+ // key >+ [](void* data, struct wl_keyboard*, uint32_t /*serial*/, uint32_t time, uint32_t key, uint32_t state) >+ { >+ auto& window = *static_cast<WindowViewBackend*>(data); >+ >+ // IDK. >+ key += 8; >+ >+ window.handleKeyEvent(key, state, time); >+ >+ auto& seatData = window.m_seatData; >+ if (!seatData.repeatInfo.rate) >+ return; >+ >+ if (state == WL_KEYBOARD_KEY_STATE_RELEASED >+ && seatData.repeatData.key == key) { >+ if (seatData.repeatData.eventSource) >+ g_source_remove(seatData.repeatData.eventSource); >+ seatData.repeatData = { 0, 0, 0, 0 }; >+ } else if (state == WL_KEYBOARD_KEY_STATE_PRESSED >+ && xkb_keymap_key_repeats(seatData.xkb.keymap, key)) { >+ >+ if (seatData.repeatData.eventSource) >+ g_source_remove(seatData.repeatData.eventSource); >+ >+ auto sourceID = g_timeout_add(seatData.repeatInfo.delay, [](void* data) -> gboolean { >+ auto& window = *static_cast<WindowViewBackend*>(data); >+ auto& seatData = window.m_seatData; >+ window.handleKeyEvent(seatData.repeatData.key, seatData.repeatData.state, seatData.repeatData.time); >+ seatData.repeatData.eventSource = g_timeout_add(seatData.repeatInfo.rate, [](void* data) -> gboolean { >+ auto& window = *static_cast<WindowViewBackend*>(data); >+ auto& seatData = window.m_seatData; >+ window.handleKeyEvent(seatData.repeatData.key, seatData.repeatData.state, seatData.repeatData.time); >+ return G_SOURCE_CONTINUE; >+ }, data); >+ return G_SOURCE_REMOVE; >+ }, data); >+ seatData.repeatData = { key, time, state, sourceID }; >+ } >+ }, >+ // modifiers >+ [](void* data, struct wl_keyboard*, uint32_t /*serial*/, uint32_t depressedMods, uint32_t latchedMods, uint32_t lockedMods, uint32_t group) >+ { >+ auto& xkb = static_cast<WindowViewBackend*>(data)->m_seatData.xkb; >+ >+ xkb_state_update_mask(xkb.state, depressedMods, latchedMods, lockedMods, 0, 0, group); >+ >+ auto& modifiers = xkb.modifiers; >+ modifiers = 0; >+ auto component = static_cast<xkb_state_component>(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; >+ }, >+ // repeat_info >+ [](void* data, struct wl_keyboard*, int32_t rate, int32_t delay) >+ { >+ auto& seatData = static_cast<WindowViewBackend*>(data)->m_seatData; >+ >+ auto& repeatInfo = seatData.repeatInfo; >+ repeatInfo = { rate, delay }; >+ >+ // A rate of zero disables any repeating. >+ if (!rate) { >+ auto& repeatData = seatData.repeatData; >+ if (repeatData.eventSource) { >+ g_source_remove(repeatData.eventSource); >+ repeatData = { 0, 0, 0, 0 }; >+ } >+ } >+ }, >+}; >+ >+const struct wl_seat_listener WindowViewBackend::s_seatListener = { >+ // capabilities >+ [](void* data, struct wl_seat* seat, uint32_t capabilities) >+ { >+ auto* window = static_cast<WindowViewBackend*>(data); >+ auto& seatData = window->m_seatData; >+ >+ // WL_SEAT_CAPABILITY_POINTER >+ const bool hasPointerCap = capabilities & WL_SEAT_CAPABILITY_POINTER; >+ if (hasPointerCap && !seatData.pointer.object) { >+ seatData.pointer.object = wl_seat_get_pointer(seat); >+ wl_pointer_add_listener(seatData.pointer.object, &s_pointerListener, window); >+ } >+ if (!hasPointerCap && seatData.pointer.object) { >+ wl_pointer_destroy(seatData.pointer.object); >+ seatData.pointer.object = nullptr; >+ } >+ >+ // WL_SEAT_CAPABILITY_KEYBOARD >+ const bool hasKeyboardCap = capabilities & WL_SEAT_CAPABILITY_KEYBOARD; >+ if (hasKeyboardCap && !seatData.keyboard.object) { >+ seatData.keyboard.object = wl_seat_get_keyboard(seat); >+ wl_keyboard_add_listener(seatData.keyboard.object, &s_keyboardListener, window); >+ } >+ if (!hasKeyboardCap && seatData.keyboard.object) { >+ wl_keyboard_destroy(seatData.keyboard.object); >+ seatData.keyboard.object = nullptr; >+ } >+ }, >+ // name >+ [](void*, struct wl_seat*, const char*) { } >+}; >+ >+const struct zxdg_surface_v6_listener WindowViewBackend::s_xdgSurfaceListener = { >+ // configure >+ [](void*, struct zxdg_surface_v6* surface, uint32_t serial) >+ { >+ zxdg_surface_v6_ack_configure(surface, serial); >+ }, >+}; >+ >+const struct zxdg_toplevel_v6_listener WindowViewBackend::s_xdgToplevelListener = { >+ // configure >+ [](void*, struct zxdg_toplevel_v6*, int32_t /*width*/, int32_t /*height*/, struct wl_array*) >+ { >+ // FIXME: dispatch the size against wpe_view_backend. >+ }, >+ // close >+ [](void*, struct zxdg_toplevel_v6*) { }, >+}; >+ >+WindowViewBackend::WindowViewBackend(uint32_t width, uint32_t height) >+ : ViewBackend(width, height) >+{ >+ m_display = wl_display_connect(nullptr); >+ if (!m_display) >+ return; >+ >+ m_eglDisplay = eglGetDisplay(m_display); >+ if (!initialize()) >+ return; >+ >+ { >+ auto* registry = wl_display_get_registry(m_display); >+ wl_registry_add_listener(registry, &s_registryListener, this); >+ wl_display_roundtrip(m_display); >+ >+ if (m_xdg) >+ zxdg_shell_v6_add_listener(m_xdg, &s_xdgWmBaseListener, nullptr); >+ >+ if (m_seat) >+ wl_seat_add_listener(m_seat, &s_seatListener, this); >+ >+ m_seatData.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); >+ m_seatData.xkb.composeTable = xkb_compose_table_new_from_locale(m_seatData.xkb.context, setlocale(LC_CTYPE, nullptr), XKB_COMPOSE_COMPILE_NO_FLAGS); >+ if (m_seatData.xkb.composeTable) >+ m_seatData.xkb.composeState = xkb_compose_state_new(m_seatData.xkb.composeTable, XKB_COMPOSE_STATE_NO_FLAGS); >+ } >+ >+ m_eventSource = g_source_new(&EventSource::sourceFuncs, sizeof(EventSource)); >+ { >+ auto& source = *reinterpret_cast<EventSource*>(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(&source.source, &source.pfd); >+ >+ g_source_set_priority(&source.source, G_PRIORITY_HIGH + 30); >+ g_source_set_can_recurse(&source.source, TRUE); >+ g_source_attach(&source.source, g_main_context_get_thread_default()); >+ } >+ >+ m_surface = wl_compositor_create_surface(m_compositor); >+ if (m_xdg) { >+ m_xdgSurface = zxdg_shell_v6_get_xdg_surface(m_xdg, m_surface); >+ zxdg_surface_v6_add_listener(m_xdgSurface, &s_xdgSurfaceListener, nullptr); >+ m_xdgToplevel = zxdg_surface_v6_get_toplevel(m_xdgSurface); >+ if (m_xdgToplevel) { >+ zxdg_toplevel_v6_add_listener(m_xdgToplevel, &s_xdgToplevelListener, nullptr); >+ zxdg_toplevel_v6_set_title(m_xdgToplevel, "WPE"); >+ wl_surface_commit(m_surface); >+ } >+ } >+ >+ m_eglWindow = wl_egl_window_create(m_surface, m_width, m_height); >+ >+ auto createPlatformWindowSurface = >+ reinterpret_cast<PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC>(eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT")); >+ m_eglSurface = createPlatformWindowSurface(m_eglDisplay, m_eglConfig, m_eglWindow, nullptr); >+ if (!m_eglSurface) >+ return; >+ >+ if (!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext)) >+ return; >+ >+ createImage = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR")); >+ destroyImage = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR")); >+ imageTargetTexture2DOES = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES")); >+ >+ { >+ static const char* vertexShaderSource = >+ "attribute vec2 pos;\n" >+ "attribute vec2 texture;\n" >+ "varying vec2 v_texture;\n" >+ "void main() {\n" >+ " v_texture = texture;\n" >+ " gl_Position = vec4(pos, 0, 1);\n" >+ "}\n"; >+ static const char* fragmentShaderSource = >+ "precision mediump float;\n" >+ "uniform sampler2D u_texture;\n" >+ "varying vec2 v_texture;\n" >+ "void main() {\n" >+ " gl_FragColor = texture2D(u_texture, v_texture);\n" >+ "}\n"; >+ >+ GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); >+ glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr); >+ glCompileShader(vertexShader); >+ >+ GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); >+ glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr); >+ glCompileShader(fragmentShader); >+ >+ m_program = glCreateProgram(); >+ glAttachShader(m_program, vertexShader); >+ glAttachShader(m_program, fragmentShader); >+ glLinkProgram(m_program); >+ >+ glBindAttribLocation(m_program, 0, "pos"); >+ glBindAttribLocation(m_program, 1, "texture"); >+ m_textureUniform = glGetUniformLocation(m_program, "u_texture"); >+ } >+ { >+ glGenTextures(1, &m_viewTexture); >+ glBindTexture(GL_TEXTURE_2D, m_viewTexture); >+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); >+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); >+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); >+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); >+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); >+ glBindTexture(GL_TEXTURE_2D, 0); >+ } >+} >+ >+WindowViewBackend::~WindowViewBackend() >+{ >+ if (m_eventSource) { >+ g_source_destroy(m_eventSource); >+ g_source_unref(m_eventSource); >+ } >+ >+ if (m_xdgToplevel) >+ zxdg_toplevel_v6_destroy(m_xdgToplevel); >+ >+ if (m_xdgSurface) >+ zxdg_surface_v6_destroy(m_xdgSurface); >+ >+ if (m_surface) >+ wl_surface_destroy(m_surface); >+ >+ if (m_eglWindow) >+ wl_egl_window_destroy(m_eglWindow); >+ >+ if (m_xdg) >+ zxdg_shell_v6_destroy(m_xdg); >+ >+ if (m_seat) >+ wl_seat_destroy(m_seat); >+ >+ if (m_compositor) >+ wl_compositor_destroy(m_compositor); >+ >+ if (m_committed.image) >+ destroyImage(m_eglDisplay, m_committed.image); >+ >+ if (m_eglSurface) >+ eglDestroySurface(m_eglDisplay, m_eglSurface); >+ >+ if (m_display) >+ wl_display_disconnect(m_display); >+} >+ >+const struct wl_callback_listener WindowViewBackend::s_frameListener = { >+ // frame >+ [](void* data, struct wl_callback* callback, uint32_t) >+ { >+ if (callback) >+ wl_callback_destroy(callback); >+ >+ auto& window = *static_cast<WindowViewBackend*>(data); >+ wpe_view_backend_exportable_fdo_dispatch_frame_complete(window.m_exportable); >+ >+ if (window.m_committed.image) >+ destroyImage(window.m_eglDisplay, window.m_committed.image); >+ if (window.m_committed.bufferResource) >+ wpe_view_backend_exportable_fdo_dispatch_release_buffer(window.m_exportable, window.m_committed.bufferResource); >+ window.m_committed = { nullptr, nullptr }; >+ } >+}; >+ >+void WindowViewBackend::displayBuffer(struct wl_resource* bufferResource) >+{ >+ if (!m_eglContext) >+ return; >+ >+ eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext); >+ >+ glClearColor(1, 0, 0, 1); >+ glClear(GL_COLOR_BUFFER_BIT); >+ >+ glUseProgram(m_program); >+ >+ { >+ static EGLint imageAttributes[] = { >+ EGL_WAYLAND_PLANE_WL, 0, >+ EGL_NONE >+ }; >+ EGLImageKHR image = createImage(m_eglDisplay, EGL_NO_CONTEXT, EGL_WAYLAND_BUFFER_WL, bufferResource, imageAttributes); >+ >+ glActiveTexture(GL_TEXTURE0); >+ glBindTexture(GL_TEXTURE_2D, m_viewTexture); >+ imageTargetTexture2DOES(GL_TEXTURE_2D, image); >+ glUniform1i(m_textureUniform, 0); >+ >+ m_committed = { bufferResource, image }; >+ } >+ >+ static const GLfloat vertices[4][2] = { >+ { -1.0, 1.0 }, >+ { 1.0, 1.0 }, >+ { -1.0, -1.0 }, >+ { 1.0, -1.0 }, >+ }; >+ >+ static const GLfloat texturePos[4][2] = { >+ { 0, 0 }, >+ { 1, 0 }, >+ { 0, 1 }, >+ { 1, 1 }, >+ }; >+ >+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices); >+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texturePos); >+ >+ glEnableVertexAttribArray(0); >+ glEnableVertexAttribArray(1); >+ >+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); >+ >+ glDisableVertexAttribArray(0); >+ glDisableVertexAttribArray(1); >+ >+ struct wl_callback* callback = wl_surface_frame(m_surface); >+ wl_callback_add_listener(callback, &s_frameListener, this); >+ >+ eglSwapBuffers(m_eglDisplay, m_eglSurface); >+} >+ >+void WindowViewBackend::handleKeyEvent(uint32_t key, uint32_t state, uint32_t time) >+{ >+ auto& xkb = m_seatData.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); >+ } >+ >+ if (m_seatData.keyboard.target) { >+ struct wpe_input_keyboard_event event = { time, keysym, unicode, !!state, xkb.modifiers }; >+ dispatchInputKeyboardEvent(&event); >+ } >+} >+ >+} // namespace WPEToolingBackends >diff --git a/Tools/wpe/backends/WindowViewBackend.h b/Tools/wpe/backends/WindowViewBackend.h >new file mode 100644 >index 00000000000..044b5b7ddd6 >--- /dev/null >+++ b/Tools/wpe/backends/WindowViewBackend.h >@@ -0,0 +1,121 @@ >+/* >+ * Copyright (C) 2018 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 APPLE INC. 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 APPLE INC. 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. >+ */ >+ >+#pragma once >+ >+#include "ViewBackend.h" >+#include "xdg-shell-unstable-v6-client-protocol.h" >+#include <glib.h> >+#include <unordered_map> >+#include <xkbcommon/xkbcommon.h> >+#include <xkbcommon/xkbcommon-compose.h> >+ >+typedef void* EGLImageKHR; >+typedef void* EGLSurface; >+typedef struct wl_egl_window *EGLNativeWindowType; >+ >+namespace WPEToolingBackends { >+ >+class WindowViewBackend final : public ViewBackend { >+public: >+ WindowViewBackend(uint32_t width, uint32_t height); >+ ~WindowViewBackend(); >+ >+private: >+ void displayBuffer(struct wl_resource*) override; >+ >+ static const struct wl_registry_listener s_registryListener; >+ static const struct zxdg_shell_v6_listener s_xdgWmBaseListener; >+ static const struct wl_pointer_listener s_pointerListener; >+ static const struct wl_keyboard_listener s_keyboardListener; >+ static const struct wl_seat_listener s_seatListener; >+ static const struct wl_callback_listener s_frameListener; >+ static const struct zxdg_surface_v6_listener s_xdgSurfaceListener; >+ static const struct zxdg_toplevel_v6_listener s_xdgToplevelListener; >+ >+ void handleKeyEvent(uint32_t key, uint32_t state, uint32_t time); >+ >+ struct SeatData { >+ struct { >+ struct wl_pointer* object { nullptr }; >+ struct wl_surface* target { nullptr }; >+ std::pair<int, int> coords { 0, 0 }; >+ uint32_t button { 0 }; >+ uint32_t state { 0 }; >+ } pointer; >+ >+ struct { >+ struct wl_keyboard* object { nullptr }; >+ struct wl_surface* target { nullptr }; >+ } keyboard; >+ >+ struct { >+ struct xkb_context* context { nullptr }; >+ struct xkb_keymap* keymap { nullptr }; >+ struct xkb_state* state { nullptr }; >+ struct { >+ xkb_mod_index_t control { 0 }; >+ xkb_mod_index_t alt { 0 }; >+ xkb_mod_index_t shift { 0 }; >+ } indexes; >+ uint8_t modifiers { 0 }; >+ struct xkb_compose_table* composeTable { nullptr }; >+ struct xkb_compose_state* composeState { nullptr }; >+ } xkb; >+ >+ struct { >+ int32_t rate { 0 }; >+ int32_t delay { 0 }; >+ } repeatInfo; >+ >+ struct { >+ uint32_t key { 0 }; >+ uint32_t time { 0 }; >+ uint32_t state { 0 }; >+ uint32_t eventSource { 0 }; >+ } repeatData; >+ >+ } m_seatData; >+ >+ struct wl_display* m_display { nullptr }; >+ struct wl_compositor* m_compositor { nullptr }; >+ struct zxdg_shell_v6* m_xdg { nullptr }; >+ struct wl_seat* m_seat { nullptr }; >+ GSource* m_eventSource { nullptr }; >+ struct wl_surface* m_surface { nullptr }; >+ struct zxdg_surface_v6* m_xdgSurface { nullptr }; >+ struct zxdg_toplevel_v6* m_xdgToplevel { nullptr }; >+ struct wl_egl_window* m_eglWindow { nullptr }; >+ EGLSurface m_eglSurface { nullptr }; >+ unsigned m_program { 0 }; >+ unsigned m_textureUniform { 0 }; >+ unsigned m_viewTexture { 0 }; >+ struct { >+ struct wl_resource* bufferResource { nullptr }; >+ EGLImageKHR image; >+ } m_committed; >+}; >+ >+} // WPEToolingBackends >diff --git a/Tools/wpe/jhbuild.modules b/Tools/wpe/jhbuild.modules >index 85d91455d47..f08621cac02 100644 >--- a/Tools/wpe/jhbuild.modules >+++ b/Tools/wpe/jhbuild.modules >@@ -23,7 +23,7 @@ > <dep package="libgpg-error"/> > <dep package="libgcrypt"/> > <dep package="libepoxy"/> >- <dep package="dyz"/> >+ <dep package="wayland-protocols"/> > </dependencies> > </metamodule> > >@@ -36,6 +36,8 @@ > href="http://cairographics.org"/> > <repository type="tarball" name="freedesktop.org" > href="http://www.freedesktop.org"/> >+ <repository type="tarball" name="wayland.freedesktop.org" >+ href="http://wayland.freedesktop.org"/> > <repository type="git" name="github.com" > href="https://github.com"/> > <repository type="tarball" name="github-tarball" >@@ -202,8 +204,11 @@ > version="1.4.3" repo="github-tarball"/> > </autotools> > >- <autotools id="dyz" supports-non-srcdir-builds="no"> >- <branch repo="github.com" module="Igalia/dyz" tag="4f196778c82ed72095e72c9d401cd2ff8ba36c60"/> >+ <autotools id="wayland-protocols" autogen-sh="configure"> >+ <branch module="releases/wayland-protocols-${version}.tar.xz" >+ version="1.12" >+ repo="wayland.freedesktop.org" >+ hash="sha256:3b19e8a9e1e19474756a7069db23b90ca9b8ebb438448c6063b4a7fc89b7c8b2"/> > </autotools> > > <meson id="graphene">
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
zan
:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 186345
:
342043
|
342246
|
342249
|
342250
| 342254