From 019d5dea79b9ac8ec17d5925546aab66473f67f5 Mon Sep 17 00:00:00 2001
From: Roger Zanoni <rzanoni@igalia.com>
Date: Mon, 15 May 2023 20:32:06 +0200
Subject: [PATCH 01/33] [agl][compositor] Add agl_shell_wrapper / AGL wayland
 extension

This is a backport of the chages we did on top of chromium webosose to
be able to communicate with the agl-compositor

Signed-off-by: Roger Zanoni <rzanoni@igalia.com>
---
 ui/base/ui_base_switches.cc                   |   2 +
 ui/base/ui_base_switches.h                    |   3 +
 ui/ozone/platform/wayland/BUILD.gn            |   7 +
 .../platform/wayland/extensions/agl/BUILD.gn  |  40 ++++
 .../agl/common/wayland_object_agl.cc          |  26 +++
 .../agl/common/wayland_object_agl.h           |  34 ++++
 .../extensions/agl/host/agl_shell_wrapper.cc  | 113 +++++++++++
 .../extensions/agl/host/agl_shell_wrapper.h   |  62 ++++++
 .../agl/host/wayland_extensions_agl.h         |  37 ++++
 .../agl/host/wayland_extensions_agl_impl.cc   |  93 +++++++++
 .../agl/host/wayland_extensions_agl_impl.h    |  54 ++++++
 .../extensions/agl/protocol/agl-shell.xml     | 179 ++++++++++++++++++
 .../wayland/host/wayland_connection.cc        |  12 +-
 .../wayland/host/wayland_connection.h         |   4 +
 .../wayland/host/wayland_extensions.h         |  56 ++++++
 15 files changed, 720 insertions(+), 2 deletions(-)
 create mode 100644 ui/ozone/platform/wayland/extensions/agl/BUILD.gn
 create mode 100644 ui/ozone/platform/wayland/extensions/agl/common/wayland_object_agl.cc
 create mode 100644 ui/ozone/platform/wayland/extensions/agl/common/wayland_object_agl.h
 create mode 100644 ui/ozone/platform/wayland/extensions/agl/host/agl_shell_wrapper.cc
 create mode 100644 ui/ozone/platform/wayland/extensions/agl/host/agl_shell_wrapper.h
 create mode 100644 ui/ozone/platform/wayland/extensions/agl/host/wayland_extensions_agl.h
 create mode 100644 ui/ozone/platform/wayland/extensions/agl/host/wayland_extensions_agl_impl.cc
 create mode 100644 ui/ozone/platform/wayland/extensions/agl/host/wayland_extensions_agl_impl.h
 create mode 100644 ui/ozone/platform/wayland/extensions/agl/protocol/agl-shell.xml
 create mode 100644 ui/ozone/platform/wayland/host/wayland_extensions.h

diff --git a/ui/base/ui_base_switches.cc b/ui/base/ui_base_switches.cc
index 514bb3cdb580d..d94e2c5e78306 100644
--- a/ui/base/ui_base_switches.cc
+++ b/ui/base/ui_base_switches.cc
@@ -112,4 +112,6 @@ const char kUIDisablePartialSwap[] = "ui-disable-partial-swap";
 // Enables the ozone x11 clipboard for linux-chromeos.
 const char kUseSystemClipboard[] = "use-system-clipboard";
 
+const char kAglShellAppId[] = "agl-shell-appid";
+
 }  // namespace switches
diff --git a/ui/base/ui_base_switches.h b/ui/base/ui_base_switches.h
index ec664b866c5d2..cf483e0339072 100644
--- a/ui/base/ui_base_switches.h
+++ b/ui/base/ui_base_switches.h
@@ -53,6 +53,9 @@ COMPONENT_EXPORT(UI_BASE) extern const char kTopChromeTouchUiEnabled[];
 COMPONENT_EXPORT(UI_BASE) extern const char kUIDisablePartialSwap[];
 COMPONENT_EXPORT(UI_BASE) extern const char kUseSystemClipboard[];
 
+// Agl related
+COMPONENT_EXPORT(UI_BASE) extern const char kAglShellAppId[];
+
 // Test related.
 COMPONENT_EXPORT(UI_BASE) extern const char kDisallowNonExactResourceReuse[];
 COMPONENT_EXPORT(UI_BASE) extern const char kMangleLocalizedStrings[];
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
index ae763d441d55c..8a436de0fafe3 100644
--- a/ui/ozone/platform/wayland/BUILD.gn
+++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -397,6 +397,13 @@ source_set("wayland") {
   ]
 
   configs += [ "//third_party/khronos:khronos_headers" ]
+
+  sources += [
+   "host/wayland_extensions.h",
+   "host/wayland_extensions_stub.cc",
+  ]
+
+  deps += [ "extensions/agl" ]
 }
 
 source_set("test_support") {
diff --git a/ui/ozone/platform/wayland/extensions/agl/BUILD.gn b/ui/ozone/platform/wayland/extensions/agl/BUILD.gn
new file mode 100644
index 0000000000000..ce289bc5dbbca
--- /dev/null
+++ b/ui/ozone/platform/wayland/extensions/agl/BUILD.gn
@@ -0,0 +1,40 @@
+# Copyright 2021 LG Electronics, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import("//third_party/wayland/wayland_protocol.gni")
+
+visibility = [ "//ui/ozone/*" ]
+
+wayland_protocol("agl_shell_protocol") {
+  sources = [ "protocol/agl-shell.xml" ]
+}
+
+source_set("agl") {
+  sources = [
+    "common/wayland_object_agl.cc",
+    "common/wayland_object_agl.h",
+    "host/agl_shell_wrapper.cc",
+    "host/agl_shell_wrapper.h",
+    "host/wayland_extensions_agl.h",
+    "host/wayland_extensions_agl_impl.cc",
+    "host/wayland_extensions_agl_impl.h",
+  ]
+
+  deps = [
+    ":agl_shell_protocol",
+    "//ui/ozone/platform/wayland/mojom",
+  ]
+}
diff --git a/ui/ozone/platform/wayland/extensions/agl/common/wayland_object_agl.cc b/ui/ozone/platform/wayland/extensions/agl/common/wayland_object_agl.cc
new file mode 100644
index 0000000000000..9f3300766df2c
--- /dev/null
+++ b/ui/ozone/platform/wayland/extensions/agl/common/wayland_object_agl.cc
@@ -0,0 +1,26 @@
+// Copyright 2021 LG Electronics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#include "ui/ozone/platform/wayland/extensions/agl/common/wayland_object_agl.h"
+
+#include <agl-shell-client-protocol.h>
+
+namespace wl {
+
+const wl_interface* ObjectTraits<agl_shell>::interface = &agl_shell_interface;
+void (*ObjectTraits<agl_shell>::deleter)(agl_shell*) = &agl_shell_destroy;
+
+}  // namespace wl
\ No newline at end of file
diff --git a/ui/ozone/platform/wayland/extensions/agl/common/wayland_object_agl.h b/ui/ozone/platform/wayland/extensions/agl/common/wayland_object_agl.h
new file mode 100644
index 0000000000000..e91ac0da8d2fc
--- /dev/null
+++ b/ui/ozone/platform/wayland/extensions/agl/common/wayland_object_agl.h
@@ -0,0 +1,34 @@
+// Copyright 2021 LG Electronics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_EXTENSIONS_AGL_COMMON_WAYLAND_OBJECT_AGL_H_
+#define UI_OZONE_PLATFORM_WAYLAND_EXTENSIONS_AGL_COMMON_WAYLAND_OBJECT_AGL_H_
+
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+
+struct agl_shell;
+
+namespace wl {
+
+template <>
+struct ObjectTraits<agl_shell> {
+  static const wl_interface* interface;
+  static void (*deleter)(agl_shell*);
+};
+
+}  // namespace wl
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_EXTENSIONS_AGL_COMMON_WAYLAND_OBJECT_AGL_H_
\ No newline at end of file
diff --git a/ui/ozone/platform/wayland/extensions/agl/host/agl_shell_wrapper.cc b/ui/ozone/platform/wayland/extensions/agl/host/agl_shell_wrapper.cc
new file mode 100644
index 0000000000000..c74fa5d9cd221
--- /dev/null
+++ b/ui/ozone/platform/wayland/extensions/agl/host/agl_shell_wrapper.cc
@@ -0,0 +1,113 @@
+// Copyright 2021 LG Electronics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#include "ui/ozone/platform/wayland/extensions/agl/host/agl_shell_wrapper.h"
+
+#include "agl_shell_wrapper.h"
+#include "base/logging.h"
+#include "ui/base/ui_base_switches.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+
+namespace ui {
+
+static const struct agl_shell_listener shell_listener = {
+    &AglShellWrapper::AglShellBoundOk,
+    &AglShellWrapper::AglShellBoundFail,
+#ifdef AGL_SHELL_APP_STATE_SINCE_VERSION
+    &AglShellWrapper::AglAppState,
+#endif
+};
+
+AglShellWrapper::AglShellWrapper(agl_shell* agl_shell,
+                                 WaylandConnection* wayland_connection)
+    : agl_shell_(agl_shell), connection_(wayland_connection) {
+  if (wl::get_version_of_object(agl_shell) >= AGL_SHELL_BOUND_OK_SINCE_VERSION)
+    agl_shell_add_listener(agl_shell, &shell_listener, this);
+}
+
+AglShellWrapper::~AglShellWrapper() = default;
+
+void AglShellWrapper::SetAglActivateApp(const std::string& app_id) {
+  wl_output* output =
+      connection_->wayland_output_manager()->GetPrimaryOutput()->get_output();
+  agl_shell_activate_app(agl_shell_.get(), app_id.c_str(), output);
+}
+
+void AglShellWrapper::SetAglPanel(WaylandWindow* window, uint32_t edge) {
+  wl_surface* surface = window->root_surface()->surface();
+  wl_output* output =
+      connection_->wayland_output_manager()->GetPrimaryOutput()->get_output();
+
+  agl_shell_set_panel(agl_shell_.get(), surface, output, edge);
+}
+
+void AglShellWrapper::SetAglBackground(WaylandWindow* window) {
+  wl_surface* surface = window->root_surface()->surface();
+  wl_output* output =
+      connection_->wayland_output_manager()->GetPrimaryOutput()->get_output();
+
+  agl_shell_set_background(agl_shell_.get(), surface, output);
+}
+
+void AglShellWrapper::SetAglReady() {
+  agl_shell_ready(agl_shell_.get());
+}
+
+// static
+void AglShellWrapper::AglShellBoundOk(void* data, struct agl_shell*) {
+  AglShellWrapper* wrapper = static_cast<AglShellWrapper*>(data);
+  wrapper->wait_for_bound_ = false;
+  wrapper->bound_ok_ = true;
+  LOG(INFO) << "Bound to agl_shell (bound_ok)";
+}
+
+// static
+void AglShellWrapper::AglShellBoundFail(void* data, struct agl_shell*) {
+  AglShellWrapper* wrapper = static_cast<AglShellWrapper*>(data);
+  wrapper->wait_for_bound_ = false;
+  wrapper->bound_ok_ = false;
+  LOG(INFO) << "Failed to bind to agl_shell (bound_fail)";
+}
+
+#ifdef AGL_SHELL_APP_STATE_SINCE_VERSION
+// static
+void AglShellWrapper::AglAppState(void* data,
+                                  struct agl_shell*,
+                                  const char* app_id,
+                                  uint32_t state) {
+  AglShellWrapper* wrapper = static_cast<AglShellWrapper*>(data);
+
+  LOG(INFO) << "State for app " << app_id << " changed to " << state;
+
+  if (state == AGL_SHELL_APP_STATE_STARTED) {
+    wrapper->SetAglActivateApp(app_id);
+    LOG(INFO) << "Activating app " << app_id;
+  }
+}
+#endif
+
+bool AglShellWrapper::WaitUntilBoundOk() {
+  int ret = 0;
+  while (ret != -1 && wait_for_bound_) {
+    ret = wl_display_dispatch(connection_->display());
+  }
+
+  return bound_ok_;
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/extensions/agl/host/agl_shell_wrapper.h b/ui/ozone/platform/wayland/extensions/agl/host/agl_shell_wrapper.h
new file mode 100644
index 0000000000000..2ab765883057e
--- /dev/null
+++ b/ui/ozone/platform/wayland/extensions/agl/host/agl_shell_wrapper.h
@@ -0,0 +1,62 @@
+// Copyright 2021 LG Electronics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_EXTENSIONS_AGL_HOST_AGL_SHELL_WRAPPER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_EXTENSIONS_AGL_HOST_AGL_SHELL_WRAPPER_H_
+
+#include <string>
+
+#include <agl-shell-client-protocol.h>
+
+#include "ui/ozone/platform/wayland/extensions/agl/common/wayland_object_agl.h"
+
+namespace ui {
+
+class WaylandConnection;
+class WaylandWindow;
+
+class AglShellWrapper {
+ public:
+  AglShellWrapper(agl_shell* agl_shell, WaylandConnection* wayland_connection);
+  AglShellWrapper(const AglShellWrapper&) = delete;
+  AglShellWrapper& operator=(const AglShellWrapper&) = delete;
+  ~AglShellWrapper();
+
+  void SetAglActivateApp(const std::string& app_id);
+  void SetAglPanel(WaylandWindow* window, uint32_t edge);
+  void SetAglBackground(WaylandWindow* window);
+  void SetAglReady();
+  bool WaitUntilBoundOk();
+
+  static void AglShellBoundOk(void* data, struct agl_shell*);
+  static void AglShellBoundFail(void* data, struct agl_shell*);
+#ifdef AGL_SHELL_APP_STATE_SINCE_VERSION
+  static void AglAppState(void* data,
+                          struct agl_shell*,
+                          const char* app_id,
+                          uint32_t state);
+#endif
+
+ private:
+  wl::Object<agl_shell> agl_shell_;
+  WaylandConnection* connection_;
+  bool wait_for_bound_ = true;
+  bool bound_ok_ = false;
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_EXTENSIONS_AGL_HOST_AGL_SHELL_WRAPPER_H_
diff --git a/ui/ozone/platform/wayland/extensions/agl/host/wayland_extensions_agl.h b/ui/ozone/platform/wayland/extensions/agl/host/wayland_extensions_agl.h
new file mode 100644
index 0000000000000..df42fc00c84da
--- /dev/null
+++ b/ui/ozone/platform/wayland/extensions/agl/host/wayland_extensions_agl.h
@@ -0,0 +1,37 @@
+// Copyright 2021 LG Electronics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_EXTENSIONS_AGL_HOST_WAYLAND_EXTENSIONS_AGL_H_
+#define UI_OZONE_PLATFORM_WAYLAND_EXTENSIONS_AGL_HOST_WAYLAND_EXTENSIONS_AGL_H_
+
+namespace ui {
+
+class AglShellWrapper;
+
+// AGL extensions implementation for webOS/Lite
+class WaylandExtensionsAgl {
+ public:
+  WaylandExtensionsAgl() = default;
+  WaylandExtensionsAgl(const WaylandExtensionsAgl&) = delete;
+  WaylandExtensionsAgl& operator=(const WaylandExtensionsAgl&) = delete;
+  virtual ~WaylandExtensionsAgl() = default;
+
+  virtual AglShellWrapper* GetAglShell() = 0;
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_EXTENSIONS_AGL_HOST_WAYLAND_EXTENSIONS_AGL_H_
\ No newline at end of file
diff --git a/ui/ozone/platform/wayland/extensions/agl/host/wayland_extensions_agl_impl.cc b/ui/ozone/platform/wayland/extensions/agl/host/wayland_extensions_agl_impl.cc
new file mode 100644
index 0000000000000..26a5f0550c302
--- /dev/null
+++ b/ui/ozone/platform/wayland/extensions/agl/host/wayland_extensions_agl_impl.cc
@@ -0,0 +1,93 @@
+// Copyright 2021 LG Electronics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#include "ui/ozone/platform/wayland/extensions/agl/host/wayland_extensions_agl_impl.h"
+
+#include <cstring>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "ui/base/ui_base_switches.h"
+#include "ui/ozone/platform/wayland/extensions/agl/host/agl_shell_wrapper.h"
+#include "ui/ozone/platform/wayland/extensions/agl/common/wayland_object_agl.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+
+namespace ui {
+
+namespace {
+
+constexpr uint32_t kMinAglShellExtensionVersion = 1;
+constexpr uint32_t kMaxAglShellExtensionVersion = 3;
+
+}  // namespace
+
+WaylandExtensionsAglImpl::WaylandExtensionsAglImpl(
+    WaylandConnection* connection)
+    : connection_(connection) {}
+
+WaylandExtensionsAglImpl::~WaylandExtensionsAglImpl() = default;
+
+bool WaylandExtensionsAglImpl::Bind(wl_registry* registry,
+                                    uint32_t name,
+                                    const char* interface,
+                                    uint32_t version) {
+  bool should_use_agl_shell = base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kAglShellAppId);
+  bool can_bind = wl::CanBind(interface, version, kMinAglShellExtensionVersion,
+                              kMaxAglShellExtensionVersion);
+  bool is_agl_shell_interface = (strcmp(interface, "agl_shell") == 0);
+
+  if (!is_agl_shell_interface) {
+      return false;
+  }
+
+  LOG(INFO) << "should_use_agl_shell: " << should_use_agl_shell <<
+               " can_bind: " << can_bind;
+
+  if (should_use_agl_shell && !agl_shell_ &&
+      is_agl_shell_interface && can_bind) {
+    wl::Object<agl_shell> aglshell = wl::Bind<agl_shell>(
+        registry, name, std::min(version, kMaxAglShellExtensionVersion));
+    if (!aglshell) {
+      LOG(ERROR) << "Failed to bind to agl_shell global";
+      return false;
+    }
+    agl_shell_ =
+        std::make_unique<AglShellWrapper>(aglshell.release(), connection_);
+
+    LOG(INFO) << "Waiting until bound...";
+    return agl_shell_->WaitUntilBoundOk();
+  } else {
+    LOG(INFO) << "Cant bind.";
+  }
+
+  return false;
+}
+
+bool WaylandExtensionsAglImpl::HasShellObject() const {
+  return !!agl_shell_;
+}
+
+AglShellWrapper* WaylandExtensionsAglImpl::GetAglShell() {
+  return agl_shell_.get();
+}
+
+std::unique_ptr<WaylandExtensions> CreateWaylandExtensions(
+    WaylandConnection* connection) {
+  return std::make_unique<WaylandExtensionsAglImpl>(connection);
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/extensions/agl/host/wayland_extensions_agl_impl.h b/ui/ozone/platform/wayland/extensions/agl/host/wayland_extensions_agl_impl.h
new file mode 100644
index 0000000000000..f6cbabe99ed0b
--- /dev/null
+++ b/ui/ozone/platform/wayland/extensions/agl/host/wayland_extensions_agl_impl.h
@@ -0,0 +1,54 @@
+// Copyright 2021 LG Electronics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_EXTENSIONS_AGL_HOST_WAYLAND_EXTENSIONS_AGL_IMPL_H_
+#define UI_OZONE_PLATFORM_WAYLAND_EXTENSIONS_AGL_HOST_WAYLAND_EXTENSIONS_AGL_IMPL_H_
+
+#include "ui/ozone/platform/wayland/extensions/agl/host/wayland_extensions_agl.h"
+#include "ui/ozone/platform/wayland/host/wayland_extensions.h"
+
+namespace ui {
+
+class AglShellWrapper;
+
+// AGL extension implementation for webOS/Lite
+class WaylandExtensionsAglImpl : public WaylandExtensions,
+                                 public WaylandExtensionsAgl {
+ public:
+  explicit WaylandExtensionsAglImpl(WaylandConnection* connection);
+  WaylandExtensionsAglImpl(const WaylandExtensionsAglImpl&) = delete;
+  WaylandExtensionsAglImpl& operator=(const WaylandExtensionsAglImpl&) = delete;
+  ~WaylandExtensionsAglImpl() override;
+
+  // WaylandExtensions overrides
+  bool Bind(wl_registry* registry,
+            uint32_t name,
+            const char* interface,
+            uint32_t version) override;
+
+  bool HasShellObject() const override;
+
+  // WaylandExtensionsAgl overrides
+  AglShellWrapper* GetAglShell() override;
+
+ private:
+  std::unique_ptr<AglShellWrapper> agl_shell_;
+  WaylandConnection* connection_;
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_EXTENSIONS_AGL_HOST_WAYLAND_EXTENSIONS_AGL_IMPL_H_
diff --git a/ui/ozone/platform/wayland/extensions/agl/protocol/agl-shell.xml b/ui/ozone/platform/wayland/extensions/agl/protocol/agl-shell.xml
new file mode 100644
index 0000000000000..ad5553d61f189
--- /dev/null
+++ b/ui/ozone/platform/wayland/extensions/agl/protocol/agl-shell.xml
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="agl_shell">
+  <copyright>
+    Copyright © 2019, 2022 Collabora, Ltd.
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+  <interface name="agl_shell" version="3">
+    <description summary="user interface for Automotive Grade Linux platform">
+      Starting with version 2 of the protocol, the client is required to wait
+      for the 'bound_ok' or 'bound_fail' events in order to proceed further.
+
+      In case the client gets a 'bound_fail' event then it should consider that
+      there's another client already bound to the agl_shell protocol.
+      A client that receives a 'bound_ok' event should consider that there's
+      no other client already bound to the interface and can proceed further.
+
+      If the client uses an older version of the protocol it will receive
+      automatically an error and the compositor will terminate the connection,
+      if there's another client already bound the interface.
+
+      If the client receives the 'bound_fail' event and attempts to use the
+      interface further it will receive an error and the compositor will
+      terminate the connection. After the 'bound_fail' event was received the
+      client should call the destructor, which has been added with version 2
+      of the protocol. The client is free to try at a later point in time to
+      see if it will receive the 'bound_ok' event, but there's no explicit way
+      of finding out when that event will be delivered.
+      It is assumed that it can infer that information through other
+      means/other channels.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_argument" value="0"/>
+      <entry name="background_exists" value="1"/>
+      <entry name="panel_exists" value="2"/>
+    </enum>
+
+    <enum name="edge">
+      <entry name="top" value="0"/>
+      <entry name="bottom" value="1"/>
+      <entry name="left" value="2"/>
+      <entry name="right" value="3"/>
+    </enum>
+
+    <enum name="app_state" since="3">
+      <entry name="started" value="0"/>
+      <entry name="terminated" value="1"/>
+      <entry name="activated" value="2"/>
+      <entry name="deactivated" value="3"/>
+    </enum>
+
+    <request name="ready">
+      <description summary="client is ready to be shown">
+        Tell the server that this client is ready to be shown. The server
+        will delay presentation during start-up until all shell clients are
+        ready to be shown, and will display a black screen instead.
+        This gives the client an opportunity to set up and configure several
+        surfaces into a coherent interface.
+
+        The client that binds to this interface must send this request, otherwise
+        they may stall the compositor unnecessarily.
+
+        If this request is called after the compositor has already finished
+        start-up, no operation is performed.
+      </description>
+    </request>
+
+    <request name="set_background">
+      <description summary="set surface as output's background">
+        Set the surface to act as the background of an output. After this
+        request, the server will immediately send a configure event with
+        the dimensions the client should use to cover the entire output.
+
+        The surface must have a "desktop" surface role, as supported by
+        libweston-desktop.
+
+        Only a single surface may be the background for any output. If a
+        background surface already exists, a protocol error is raised.
+      </description>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="output" type="object" interface="wl_output"/>
+    </request>
+
+    <request name="set_panel">
+      <description summary="set surface as panel">
+        Set the surface to act as a panel of an output. The 'edge' argument
+        says what edge of the output the surface will be anchored to.
+        After this request, the server will send a configure event with the
+        corresponding width/height that the client should use, and 0 for the
+        other dimension. E.g. if the edge is 'top', the width will be the
+        output's width, and the height will be 0.
+
+        The surface must have a "desktop" surface role, as supported by
+        libweston-desktop.
+
+        The compositor will take the panel's window geometry into account when
+        positioning other windows, so the panels are not covered.
+
+        XXX: What happens if e.g. both top and left are used at the same time?
+        Who gets to have the corner?
+
+        Only a single surface may be the panel for an output's edge. If a
+        surface already exists on an edge, a protocol error is raised.
+      </description>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="output" type="object" interface="wl_output"/>
+      <arg name="edge" type="uint" enum="edge"/>
+    </request>
+
+    <request name="activate_app">
+      <description summary="make client current window">
+        Ask the compositor to make a toplevel to become the current/focused
+        window for window management purposes.
+
+        See xdg_toplevel.set_app_id from the xdg-shell protocol for a
+        description of app_id.
+
+        If multiple toplevels have the same app_id, the result is unspecified.
+
+        XXX: Do we need feedback to say it didn't work? (e.g. client does
+        not exist)
+      </description>
+      <arg name="app_id" type="string"/>
+      <arg name="output" type="object" interface="wl_output"/>
+    </request>
+
+    <event name="bound_ok" since="2">
+     <description summary="event sent if binding was ok">
+        Informs the client that it was able to bind the agl_shell
+        interface succesfully. Clients are required to wait for this
+        event before continuing further.
+     </description>
+    </event>
+
+    <event name="bound_fail" since="2">
+      <description summary="event sent if binding was nok">
+        Informs the client that binding to the agl_shell interface was
+        unsuccesfull. Clients are required to wait for this event for
+        continuing further.
+      </description>
+    </event>
+
+    <request name="destroy" type="destructor" since="2">
+      <description summary="destroys the factory object">
+      </description>
+    </request>
+
+    <event name="app_state" since="3">
+      <description summary="event sent when an application suffered state modification">
+        Informs the client that an application has changed its state to another,
+        specified by the app_state enum. Client can use this event to track
+        current application state. For instance to know when the application has
+        started, or when terminated/stopped.
+      </description>
+      <arg name="app_id" type="string"/>
+      <arg name="state" type="uint" enum="app_state"/>
+    </event>
+
+
+  </interface>
+</protocol>
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.cc b/ui/ozone/platform/wayland/host/wayland_connection.cc
index ad3bbd6e37157..7a47d4a636998 100644
--- a/ui/ozone/platform/wayland/host/wayland_connection.cc
+++ b/ui/ozone/platform/wayland/host/wayland_connection.cc
@@ -68,6 +68,8 @@
 #include "ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h"
 #include "ui/platform_window/common/platform_window_defaults.h"
 
+#include "ui/ozone/platform/wayland/host/wayland_extensions.h"
+
 namespace ui {
 
 namespace {
@@ -212,6 +214,10 @@ bool WaylandConnection::Initialize(bool use_threaded_polling) {
     use_threaded_polling = false;
   }
 
+  if (!extensions_) {
+    extensions_ = CreateWaylandExtensions(this);
+  }
+
   // Now that the connection with the display server has been properly
   // estabilished, initialize the event source and input objects.
   DCHECK(!event_source_);
@@ -243,7 +249,7 @@ bool WaylandConnection::Initialize(bool use_threaded_polling) {
     LOG(ERROR) << "No wl_shm object";
     return false;
   }
-  if (!shell_) {
+  if (!shell_  && !(extensions_ && extensions_->HasShellObject())) {
     LOG(ERROR) << "No Wayland shell found";
     return false;
   }
@@ -538,7 +544,9 @@ void WaylandConnection::HandleGlobal(wl_registry* registry,
                                      const char* interface,
                                      uint32_t version) {
   auto factory_it = global_object_factories_.find(interface);
-  if (factory_it != global_object_factories_.end()) {
+  if (extensions_->Bind(registry, name, interface, version)) {
+    DVLOG(1) << "Successfully bound to " << interface;
+  } else if (factory_it != global_object_factories_.end()) {
     (*factory_it->second)(this, registry, name, interface, version);
   } else if (!compositor_ && strcmp(interface, "wl_compositor") == 0) {
     compositor_ = wl::Bind<wl_compositor>(
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.h b/ui/ozone/platform/wayland/host/wayland_connection.h
index 6659bc54bd475..ba293e5bcd088 100644
--- a/ui/ozone/platform/wayland/host/wayland_connection.h
+++ b/ui/ozone/platform/wayland/host/wayland_connection.h
@@ -50,6 +50,7 @@ class WaylandBufferManagerHost;
 class WaylandCursor;
 class WaylandCursorBufferListener;
 class WaylandEventSource;
+class WaylandExtensions;
 class WaylandOutputManager;
 class WaylandSeat;
 class WaylandZAuraShell;
@@ -201,6 +202,8 @@ class WaylandConnection {
 
   WaylandZAuraShell* zaura_shell() const { return zaura_shell_.get(); }
 
+  WaylandExtensions* extensions() { return extensions_.get(); }
+
   WaylandZcrColorManager* zcr_color_manager() const {
     return zcr_color_manager_.get();
   }
@@ -486,6 +489,7 @@ class WaylandConnection {
   std::unique_ptr<OverlayPrioritizer> overlay_prioritizer_;
   std::unique_ptr<SurfaceAugmenter> surface_augmenter_;
   std::unique_ptr<SinglePixelBuffer> single_pixel_buffer_;
+  std::unique_ptr<WaylandExtensions> extensions_;
 
   // Clipboard-related objects. |clipboard_| must be declared after all
   // DeviceManager instances it depends on, otherwise tests may crash with
diff --git a/ui/ozone/platform/wayland/host/wayland_extensions.h b/ui/ozone/platform/wayland/host/wayland_extensions.h
new file mode 100644
index 0000000000000..3bd2fd7a211ae
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/wayland_extensions.h
@@ -0,0 +1,56 @@
+// Copyright 2019 LG Electronics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_EXTENSIONS_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_EXTENSIONS_H_
+
+#include <memory>
+
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+
+namespace ui {
+
+class ShellToplevelWrapper;
+class ShellPopupWrapper;
+class WaylandConnection;
+
+// Wayland extensions abstract interface to support extending of the Wayland
+// protocol. Inherit it to provide your own Wayland extensions implementation.
+class WaylandExtensions {
+ public:
+  WaylandExtensions() = default;
+  WaylandExtensions(const WaylandExtensions&) = delete;
+  WaylandExtensions& operator=(const WaylandExtensions&) = delete;
+  virtual ~WaylandExtensions() = default;
+
+  // Binds to the extensions interface(s). Can encapsulate binding of several
+  // interfaces, defined by |interface|.
+  virtual bool Bind(wl_registry* registry,
+                    uint32_t name,
+                    const char* interface,
+                    uint32_t version) = 0;
+
+  // Checks whether the extensions have bound shell object(s).
+  virtual bool HasShellObject() const = 0;
+};
+
+// Creates Wayland extensions.
+std::unique_ptr<WaylandExtensions> CreateWaylandExtensions(
+  WaylandConnection* connection);
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_EXTENSIONS_H_
-- 
2.42.1