summaryrefslogtreecommitdiff
path: root/chromium/ui/ozone
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui/ozone')
-rw-r--r--chromium/ui/ozone/BUILD.gn9
-rw-r--r--chromium/ui/ozone/demo/gl_renderer.cc14
-rw-r--r--chromium/ui/ozone/demo/gl_renderer.h4
-rw-r--r--chromium/ui/ozone/demo/skia/skia_gl_renderer.cc17
-rw-r--r--chromium/ui/ozone/demo/skia/skia_gl_renderer.h4
-rw-r--r--chromium/ui/ozone/demo/skia/skia_renderer_factory.h1
-rw-r--r--chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc9
-rw-r--r--chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.h3
-rw-r--r--chromium/ui/ozone/demo/surfaceless_gl_renderer.cc11
-rw-r--r--chromium/ui/ozone/demo/surfaceless_gl_renderer.h3
-rw-r--r--chromium/ui/ozone/demo/vulkan_renderer.cc1
-rw-r--r--chromium/ui/ozone/ozone.gni7
-rw-r--r--chromium/ui/ozone/platform/cast/BUILD.gn1
-rw-r--r--chromium/ui/ozone/platform/cast/ozone_platform_cast.cc10
-rw-r--r--chromium/ui/ozone/platform/drm/BUILD.gn3
-rw-r--r--chromium/ui/ozone/platform/drm/common/drm_util.cc3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_device.h1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_device_manager.cc1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_display.cc70
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_display.h11
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_display_unittest.cc192
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc12
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h6
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_gpu_util.cc1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_thread.cc46
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_thread.h17
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.cc7
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.h6
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc33
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.h9
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane.cc9
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h2
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/screen_manager.cc1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc1
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_device_handle.cc1
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_display_host.cc12
-rw-r--r--chromium/ui/ozone/platform/drm/host/gpu_thread_adapter.h11
-rw-r--r--chromium/ui/ozone/platform/drm/host/host_drm_device.cc27
-rw-r--r--chromium/ui/ozone/platform/drm/host/host_drm_device.h7
-rw-r--r--chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc10
-rw-r--r--chromium/ui/ozone/platform/headless/BUILD.gn2
-rw-r--r--chromium/ui/ozone/platform/headless/ozone_platform_headless.cc10
-rw-r--r--chromium/ui/ozone/platform/scenic/BUILD.gn2
-rw-r--r--chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc10
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_surface.cc17
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_surface.h6
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc7
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_window.cc26
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_window.h4
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_window_manager.cc4
-rw-r--r--chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc58
-rw-r--r--chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h15
-rw-r--r--chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.cc8
-rw-r--r--chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.h5
-rw-r--r--chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc14
-rw-r--r--chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h4
-rw-r--r--chromium/ui/ozone/platform/wayland/BUILD.gn21
-rw-r--r--chromium/ui/ozone/platform/wayland/DEPS2
-rw-r--r--chromium/ui/ozone/platform/wayland/OWNERS1
-rw-r--r--chromium/ui/ozone/platform/wayland/common/data_util.cc218
-rw-r--r--chromium/ui/ozone/platform/wayland/common/data_util.h40
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland_object.cc11
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland_object.h14
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/drm_render_node_handle.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc68
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h17
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc3
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc4
-rw-r--r--chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc9
-rw-r--r--chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.h3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.cc31
-rw-r--r--chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h26
-rw-r--r--chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_source.cc76
-rw-r--r--chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_source.h46
-rw-r--r--chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.cc3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc192
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h1
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc221
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h54
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_connection.cc112
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_connection.h83
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc1
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc478
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device.h139
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h1
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc22
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.h20
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc293
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc355
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h136
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc406
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_source.cc226
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_source.h126
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_source_base.cc21
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_source_base.h38
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_drm.cc1
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc54
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_event_source.h22
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc26
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h21
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc11
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_pointer.h1
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_popup.cc4
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.cc1
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc10
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_surface.cc347
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_surface.h129
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc368
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h131
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window.cc63
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window.h23
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc325
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h126
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc519
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc6
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc5
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_manager.h4
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_observer.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_observer.h3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc204
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc157
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h6
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc7
-rw-r--r--chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.cc16
-rw-r--r--chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.h5
-rw-r--r--chromium/ui/ozone/platform/wayland/test/scoped_wl_array.cc41
-rw-r--r--chromium/ui/ozone/platform/wayland/test/scoped_wl_array.h31
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_data_device.cc21
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_data_device.h15
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_data_source.cc18
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_data_source.h10
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_subsurface.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/test/wayland_test.cc35
-rw-r--r--chromium/ui/ozone/platform/wayland/test/wayland_test.h13
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc322
-rw-r--r--chromium/ui/ozone/platform/windows/BUILD.gn2
-rw-r--r--chromium/ui/ozone/platform/windows/ozone_platform_windows.cc10
-rw-r--r--chromium/ui/ozone/platform/x11/BUILD.gn14
-rw-r--r--chromium/ui/ozone/platform/x11/ozone_platform_x11.cc47
-rw-r--r--chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc229
-rw-r--r--chromium/ui/ozone/platform/x11/x11_clipboard_ozone.h39
-rw-r--r--chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.cc118
-rw-r--r--chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.h55
-rw-r--r--chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone_unittest.cc31
-rw-r--r--chromium/ui/ozone/platform/x11/x11_cursor_ozone.cc56
-rw-r--r--chromium/ui/ozone/platform/x11/x11_cursor_ozone.h55
-rw-r--r--chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.cc14
-rw-r--r--chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h5
-rw-r--r--chromium/ui/ozone/platform/x11/x11_screen_ozone.cc10
-rw-r--r--chromium/ui/ozone/platform/x11/x11_screen_ozone.h3
-rw-r--r--chromium/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc6
-rw-r--r--chromium/ui/ozone/platform/x11/x11_surface_factory.cc3
-rw-r--r--chromium/ui/ozone/platform/x11/x11_window_ozone.cc158
-rw-r--r--chromium/ui/ozone/platform/x11/x11_window_ozone.h66
-rw-r--r--chromium/ui/ozone/platform/x11/x11_window_ozone_chromeos.cc28
-rw-r--r--chromium/ui/ozone/platform/x11/x11_window_ozone_chromeos.h33
-rw-r--r--chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc27
-rw-r--r--chromium/ui/ozone/public/cursor_factory_ozone.cc63
-rw-r--r--chromium/ui/ozone/public/cursor_factory_ozone.h61
-rw-r--r--chromium/ui/ozone/public/input_controller.cc2
-rw-r--r--chromium/ui/ozone/public/input_controller.h2
-rw-r--r--chromium/ui/ozone/public/mojom/drm_device.mojom11
-rw-r--r--chromium/ui/ozone/public/ozone_platform.cc17
-rw-r--r--chromium/ui/ozone/public/ozone_platform.h34
-rw-r--r--chromium/ui/ozone/public/platform_clipboard.h1
-rw-r--r--chromium/ui/ozone/public/platform_screen.cc2
-rw-r--r--chromium/ui/ozone/public/platform_window_surface.h16
175 files changed, 5202 insertions, 3440 deletions
diff --git a/chromium/ui/ozone/BUILD.gn b/chromium/ui/ozone/BUILD.gn
index a3e07b47d27..e3eb1e17596 100644
--- a/chromium/ui/ozone/BUILD.gn
+++ b/chromium/ui/ozone/BUILD.gn
@@ -66,8 +66,6 @@ constructor_list_cc_file = "$target_gen_dir/constructor_list.cc"
jumbo_component("ozone_base") {
sources = [
- "public/cursor_factory_ozone.cc",
- "public/cursor_factory_ozone.h",
"public/gl_ozone.h",
"public/gpu_platform_support_host.cc",
"public/gpu_platform_support_host.h",
@@ -105,7 +103,6 @@ jumbo_component("ozone_base") {
"//ipc",
"//skia",
"//ui/base/clipboard:clipboard_types",
- "//ui/base/cursor/mojom:cursor_type",
"//ui/display",
"//ui/display/types",
"//ui/display/util",
@@ -125,11 +122,13 @@ jumbo_component("ozone_base") {
public_deps += [ "//gpu/vulkan" ]
}
+ if (is_fuchsia) {
+ public_deps += [ "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.images" ]
+ }
+
visibility += [
# Everyone should depend on //ui/ozone instead except a handful of
# things that would otherwise create a cycle.
- "//ui/base",
- "//ui/base/cursor",
"//ui/events/ozone/*",
"//ui/ozone/common/*",
"//ui/ozone/public/mojom",
diff --git a/chromium/ui/ozone/demo/gl_renderer.cc b/chromium/ui/ozone/demo/gl_renderer.cc
index c5812189846..c25b8f9c15d 100644
--- a/chromium/ui/ozone/demo/gl_renderer.cc
+++ b/chromium/ui/ozone/demo/gl_renderer.cc
@@ -46,7 +46,7 @@ bool GlRenderer::Initialize() {
gl_surface_->Resize(size_, 1.f, gfx::ColorSpace(), true);
// Schedule the initial render.
- PostRenderFrameTask(gfx::SwapResult::SWAP_ACK, nullptr);
+ PostRenderFrameTask(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_ACK));
return true;
}
@@ -69,16 +69,14 @@ void GlRenderer::RenderFrame() {
weak_ptr_factory_.GetWeakPtr()));
} else {
PostRenderFrameTask(
- gl_surface_->SwapBuffers(base::BindOnce(
- &GlRenderer::OnPresentation, weak_ptr_factory_.GetWeakPtr())),
- nullptr);
+ gfx::SwapCompletionResult(gl_surface_->SwapBuffers(base::BindOnce(
+ &GlRenderer::OnPresentation, weak_ptr_factory_.GetWeakPtr()))));
}
}
-void GlRenderer::PostRenderFrameTask(gfx::SwapResult result,
- std::unique_ptr<gfx::GpuFence> gpu_fence) {
- if (gpu_fence)
- gpu_fence->Wait();
+void GlRenderer::PostRenderFrameTask(gfx::SwapCompletionResult result) {
+ if (result.gpu_fence)
+ result.gpu_fence->Wait();
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
diff --git a/chromium/ui/ozone/demo/gl_renderer.h b/chromium/ui/ozone/demo/gl_renderer.h
index c5a6a3b2ada..62d391b0f1d 100644
--- a/chromium/ui/ozone/demo/gl_renderer.h
+++ b/chromium/ui/ozone/demo/gl_renderer.h
@@ -14,7 +14,6 @@
#include "ui/ozone/demo/renderer_base.h"
namespace gfx {
-class GpuFence;
struct PresentationFeedback;
} // namespace gfx
@@ -39,8 +38,7 @@ class GlRenderer : public RendererBase {
private:
void RenderFrame();
- void PostRenderFrameTask(gfx::SwapResult result,
- std::unique_ptr<gfx::GpuFence> gpu_fence);
+ void PostRenderFrameTask(gfx::SwapCompletionResult result);
void OnPresentation(const gfx::PresentationFeedback& feedback);
std::unique_ptr<PlatformWindowSurface> window_surface_;
diff --git a/chromium/ui/ozone/demo/skia/skia_gl_renderer.cc b/chromium/ui/ozone/demo/skia/skia_gl_renderer.cc
index ceb5cc4f5f2..c5be0bb4632 100644
--- a/chromium/ui/ozone/demo/skia/skia_gl_renderer.cc
+++ b/chromium/ui/ozone/demo/skia/skia_gl_renderer.cc
@@ -76,7 +76,7 @@ bool SkiaGlRenderer::Initialize() {
gr_context_ = GrContext::MakeGL(std::move(native_interface), options);
DCHECK(gr_context_);
- PostRenderFrameTask(gfx::SwapResult::SWAP_ACK, nullptr);
+ PostRenderFrameTask(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_ACK));
return true;
}
@@ -106,7 +106,7 @@ void SkiaGlRenderer::RenderFrame() {
} else {
Draw(sk_surface_->getCanvas(), NextFraction());
}
- gr_context_->flush();
+ gr_context_->flushAndSubmit();
glFinish();
if (gl_surface_->SupportsAsyncSwap()) {
@@ -117,17 +117,14 @@ void SkiaGlRenderer::RenderFrame() {
weak_ptr_factory_.GetWeakPtr()));
} else {
PostRenderFrameTask(
- gl_surface_->SwapBuffers(base::BindOnce(
- &SkiaGlRenderer::OnPresentation, weak_ptr_factory_.GetWeakPtr())),
- nullptr);
+ gfx::SwapCompletionResult(gl_surface_->SwapBuffers(base::BindOnce(
+ &SkiaGlRenderer::OnPresentation, weak_ptr_factory_.GetWeakPtr()))));
}
}
-void SkiaGlRenderer::PostRenderFrameTask(
- gfx::SwapResult result,
- std::unique_ptr<gfx::GpuFence> gpu_fence) {
- if (gpu_fence)
- gpu_fence->Wait();
+void SkiaGlRenderer::PostRenderFrameTask(gfx::SwapCompletionResult result) {
+ if (result.gpu_fence)
+ result.gpu_fence->Wait();
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&SkiaGlRenderer::RenderFrame,
diff --git a/chromium/ui/ozone/demo/skia/skia_gl_renderer.h b/chromium/ui/ozone/demo/skia/skia_gl_renderer.h
index 8abcc67d6cf..08195eebf87 100644
--- a/chromium/ui/ozone/demo/skia/skia_gl_renderer.h
+++ b/chromium/ui/ozone/demo/skia/skia_gl_renderer.h
@@ -21,7 +21,6 @@
#include "ui/ozone/demo/renderer_base.h"
namespace gfx {
-class GpuFence;
struct PresentationFeedback;
} // namespace gfx
@@ -47,8 +46,7 @@ class SkiaGlRenderer : public RendererBase,
protected:
virtual void RenderFrame();
- virtual void PostRenderFrameTask(gfx::SwapResult result,
- std::unique_ptr<gfx::GpuFence>);
+ virtual void PostRenderFrameTask(gfx::SwapCompletionResult result);
void Draw(SkCanvas* canvas, float fraction);
void StartDDLRenderThreadIfNecessary(SkSurface* sk_surface);
diff --git a/chromium/ui/ozone/demo/skia/skia_renderer_factory.h b/chromium/ui/ozone/demo/skia/skia_renderer_factory.h
index 192c12d67af..029211cad06 100644
--- a/chromium/ui/ozone/demo/skia/skia_renderer_factory.h
+++ b/chromium/ui/ozone/demo/skia/skia_renderer_factory.h
@@ -7,6 +7,7 @@
#include <memory>
+#include "base/macros.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/demo/renderer_factory.h"
diff --git a/chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc b/chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc
index e2ee9432d98..ec083066e53 100644
--- a/chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc
+++ b/chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc
@@ -244,7 +244,7 @@ void SurfacelessSkiaGlRenderer::RenderFrame() {
} else {
Draw(sk_surface->getCanvas(), NextFraction());
}
- gr_context_->flush();
+ gr_context_->flushAndSubmit();
glFinish();
if (!disable_primary_plane_) {
@@ -270,9 +270,8 @@ void SurfacelessSkiaGlRenderer::RenderFrame() {
}
void SurfacelessSkiaGlRenderer::PostRenderFrameTask(
- gfx::SwapResult result,
- std::unique_ptr<gfx::GpuFence> gpu_fence) {
- switch (result) {
+ gfx::SwapCompletionResult result) {
+ switch (result.swap_result) {
case gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS:
for (size_t i = 0; i < base::size(buffers_); ++i) {
buffers_[i] = std::make_unique<BufferWrapper>();
@@ -282,7 +281,7 @@ void SurfacelessSkiaGlRenderer::PostRenderFrameTask(
}
FALLTHROUGH; // We want to render a new frame anyways.
case gfx::SwapResult::SWAP_ACK:
- SkiaGlRenderer::PostRenderFrameTask(result, std::move(gpu_fence));
+ SkiaGlRenderer::PostRenderFrameTask(std::move(result));
break;
case gfx::SwapResult::SWAP_FAILED:
LOG(FATAL) << "Failed to swap buffers";
diff --git a/chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.h b/chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.h
index e24652c26a5..469083f14dd 100644
--- a/chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.h
+++ b/chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.h
@@ -30,8 +30,7 @@ class SurfacelessSkiaGlRenderer : public SkiaGlRenderer {
private:
// SkiaGlRenderer:
void RenderFrame() override;
- void PostRenderFrameTask(gfx::SwapResult result,
- std::unique_ptr<gfx::GpuFence>) override;
+ void PostRenderFrameTask(gfx::SwapCompletionResult result) override;
class BufferWrapper;
diff --git a/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc b/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc
index 6117ac4f0f3..bc45833e24b 100644
--- a/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc
+++ b/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc
@@ -202,7 +202,7 @@ bool SurfacelessGlRenderer::Initialize() {
use_gpu_fences_ = gl_surface_->SupportsPlaneGpuFences();
// Schedule the initial render.
- PostRenderFrameTask(gfx::SwapResult::SWAP_ACK, nullptr);
+ PostRenderFrameTask(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_ACK));
return true;
}
@@ -288,12 +288,11 @@ void SurfacelessGlRenderer::RenderFrame() {
}
void SurfacelessGlRenderer::PostRenderFrameTask(
- gfx::SwapResult result,
- std::unique_ptr<gfx::GpuFence> gpu_fence) {
- if (gpu_fence)
- gpu_fence->Wait();
+ gfx::SwapCompletionResult result) {
+ if (result.gpu_fence)
+ result.gpu_fence->Wait();
- switch (result) {
+ switch (result.swap_result) {
case gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS:
for (size_t i = 0; i < base::size(buffers_); ++i) {
buffers_[i] = std::make_unique<BufferWrapper>();
diff --git a/chromium/ui/ozone/demo/surfaceless_gl_renderer.h b/chromium/ui/ozone/demo/surfaceless_gl_renderer.h
index ba6d12a24e5..af3a3b2c690 100644
--- a/chromium/ui/ozone/demo/surfaceless_gl_renderer.h
+++ b/chromium/ui/ozone/demo/surfaceless_gl_renderer.h
@@ -34,8 +34,7 @@ class SurfacelessGlRenderer : public RendererBase {
private:
void RenderFrame();
- void PostRenderFrameTask(gfx::SwapResult result,
- std::unique_ptr<gfx::GpuFence> gpu_fence);
+ void PostRenderFrameTask(gfx::SwapCompletionResult result);
void OnPresentation(const gfx::PresentationFeedback& feedback);
class BufferWrapper {
diff --git a/chromium/ui/ozone/demo/vulkan_renderer.cc b/chromium/ui/ozone/demo/vulkan_renderer.cc
index 6d778ce8e98..04235e74ee3 100644
--- a/chromium/ui/ozone/demo/vulkan_renderer.cc
+++ b/chromium/ui/ozone/demo/vulkan_renderer.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/location.h"
+#include "base/logging.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "gpu/vulkan/init/vulkan_factory.h"
diff --git a/chromium/ui/ozone/ozone.gni b/chromium/ui/ozone/ozone.gni
index 13fecf9038a..05d59e73fad 100644
--- a/chromium/ui/ozone/ozone.gni
+++ b/chromium/ui/ozone/ozone.gni
@@ -4,6 +4,7 @@
import("//build/config/chromecast_build.gni")
import("//build/config/ui.gni")
+import("//build/toolchain/kythe.gni")
import("//build/toolchain/toolchain.gni")
declare_args() {
@@ -65,6 +66,12 @@ declare_args() {
ozone_platform = "x11"
ozone_platform_gbm = true
ozone_platform_x11 = true
+
+ # Enable the Ozone Wayland platform for ChromiumOS codesearch-gen bots
+ # so we get cross-references in codesearch. We can remove this once
+ # we can compile both x11 and Ozone on desktop Linux Chrome.
+ # TODO(crbug.com/1085700): Remove enable_kythe_annotations here.
+ ozone_platform_wayland = enable_kythe_annotations
} else if (is_desktop_linux) {
ozone_platform = "x11"
ozone_platform_wayland = true
diff --git a/chromium/ui/ozone/platform/cast/BUILD.gn b/chromium/ui/ozone/platform/cast/BUILD.gn
index 54d03308b82..22ef134ffb2 100644
--- a/chromium/ui/ozone/platform/cast/BUILD.gn
+++ b/chromium/ui/ozone/platform/cast/BUILD.gn
@@ -43,6 +43,7 @@ source_set("cast") {
"//chromecast:chromecast_buildflags",
"//chromecast/base:base",
"//chromecast/graphics:libcast_graphics_1.0",
+ "//ui/base/cursor:cursor_base",
"//ui/base/ime",
"//ui/events/ozone",
"//ui/events/ozone/evdev",
diff --git a/chromium/ui/ozone/platform/cast/ozone_platform_cast.cc b/chromium/ui/ozone/platform/cast/ozone_platform_cast.cc
index a2ce0266582..b5702ad228d 100644
--- a/chromium/ui/ozone/platform/cast/ozone_platform_cast.cc
+++ b/chromium/ui/ozone/platform/cast/ozone_platform_cast.cc
@@ -14,6 +14,7 @@
#include "chromecast/chromecast_buildflags.h"
#include "chromecast/public/cast_egl_platform.h"
#include "chromecast/public/cast_egl_platform_shlib.h"
+#include "ui/base/cursor/cursor_factory.h"
#include "ui/base/ime/input_method_minimal.h"
#include "ui/display/types/native_display_delegate.h"
#include "ui/events/ozone/device/device_manager.h"
@@ -24,7 +25,6 @@
#include "ui/ozone/platform/cast/overlay_manager_cast.h"
#include "ui/ozone/platform/cast/platform_window_cast.h"
#include "ui/ozone/platform/cast/surface_factory_cast.h"
-#include "ui/ozone/public/cursor_factory_ozone.h"
#include "ui/ozone/public/gpu_platform_support_host.h"
#include "ui/ozone/public/input_controller.h"
#include "ui/ozone/public/ozone_platform.h"
@@ -83,9 +83,7 @@ class OzonePlatformCast : public OzonePlatform {
OverlayManagerOzone* GetOverlayManager() override {
return overlay_manager_.get();
}
- CursorFactoryOzone* GetCursorFactoryOzone() override {
- return cursor_factory_.get();
- }
+ CursorFactory* GetCursorFactory() override { return cursor_factory_.get(); }
InputController* GetInputController() override {
return event_factory_ozone_->input_controller();
}
@@ -123,7 +121,7 @@ class OzonePlatformCast : public OzonePlatform {
void InitializeUI(const InitParams& params) override {
device_manager_ = CreateDeviceManager();
- cursor_factory_ = std::make_unique<CursorFactoryOzone>();
+ cursor_factory_ = std::make_unique<CursorFactory>();
gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
// Enable dummy software rendering support if GPU process disabled
@@ -157,7 +155,7 @@ class OzonePlatformCast : public OzonePlatform {
std::unique_ptr<DeviceManager> device_manager_;
std::unique_ptr<CastEglPlatform> egl_platform_;
std::unique_ptr<SurfaceFactoryCast> surface_factory_;
- std::unique_ptr<CursorFactoryOzone> cursor_factory_;
+ std::unique_ptr<CursorFactory> cursor_factory_;
std::unique_ptr<GpuPlatformSupportHost> gpu_platform_support_host_;
std::unique_ptr<OverlayManagerOzone> overlay_manager_;
std::unique_ptr<EventFactoryEvdev> event_factory_ozone_;
diff --git a/chromium/ui/ozone/platform/drm/BUILD.gn b/chromium/ui/ozone/platform/drm/BUILD.gn
index 0ef7cd7e786..01ed60608fd 100644
--- a/chromium/ui/ozone/platform/drm/BUILD.gn
+++ b/chromium/ui/ozone/platform/drm/BUILD.gn
@@ -127,6 +127,8 @@ source_set("gbm") {
"//third_party/libsync",
"//third_party/minigbm",
"//ui/base",
+ "//ui/base/cursor",
+ "//ui/base/cursor:cursor_base",
"//ui/base/ime",
"//ui/display",
"//ui/display/types",
@@ -178,6 +180,7 @@ source_set("gbm_unittests") {
testonly = true
sources = [
"common/drm_util_unittest.cc",
+ "gpu/drm_display_unittest.cc",
"gpu/drm_overlay_manager_unittest.cc",
"gpu/drm_overlay_validator_unittest.cc",
"gpu/drm_thread_unittest.cc",
diff --git a/chromium/ui/ozone/platform/drm/common/drm_util.cc b/chromium/ui/ozone/platform/drm/common/drm_util.cc
index 7ac144c6bdf..656330d42bf 100644
--- a/chromium/ui/ozone/platform/drm/common/drm_util.cc
+++ b/chromium/ui/ozone/platform/drm/common/drm_util.cc
@@ -18,6 +18,7 @@
#include "base/containers/flat_map.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
+#include "base/notreached.h"
#include "ui/display/types/display_constants.h"
#include "ui/display/types/display_mode.h"
#include "ui/display/util/display_util.h"
@@ -210,7 +211,7 @@ display::PanelOrientation GetPanelOrientation(int fd,
int index = GetDrmProperty(fd, connector, "panel orientation", &property);
if (index < 0)
return display::PanelOrientation::kNormal;
- DCHECK_LT(connector->prop_values[index], display::PanelOrientation::kLast);
+ DCHECK_LE(connector->prop_values[index], display::PanelOrientation::kLast);
return static_cast<display::PanelOrientation>(connector->prop_values[index]);
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_device.h b/chromium/ui/ozone/platform/drm/gpu/drm_device.h
index 0cbcca2fe96..fdc7f2d0a38 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_device.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_device.h
@@ -240,6 +240,7 @@ class DrmDevice : public base::RefCountedThreadSafe<DrmDevice> {
protected:
friend class base::RefCountedThreadSafe<DrmDevice>;
+ friend class DrmDisplayTest;
virtual ~DrmDevice();
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_device_manager.cc b/chromium/ui/ozone/platform/drm/gpu/drm_device_manager.cc
index 5d879fa9853..9b1a8b2a4a6 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_device_manager.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_device_manager.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/file_descriptor_posix.h"
+#include "base/logging.h"
#include "base/single_thread_task_runner.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_display.cc b/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
index 89b9ea98bb4..0866e1989ed 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
@@ -7,10 +7,13 @@
#include <xf86drmMode.h>
#include <memory>
+#include "base/logging.h"
#include "base/stl_util.h"
#include "base/trace_event/trace_event.h"
+#include "ui/display/display_features.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/display/types/gamma_ramp_rgb_entry.h"
+#include "ui/gfx/color_space.h"
#include "ui/ozone/platform/drm/common/drm_util.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/screen_manager.h"
@@ -82,12 +85,24 @@ std::vector<drmModeModeInfo> GetDrmModeVector(drmModeConnector* connector) {
return modes;
}
+void FillLinearValues(std::vector<display::GammaRampRGBEntry>* table,
+ size_t table_size,
+ float max_value) {
+ for (size_t i = 0; i < table_size; i++) {
+ const uint16_t v =
+ max_value * std::numeric_limits<uint16_t>::max() * i / (table_size - 1);
+ struct display::GammaRampRGBEntry gamma_entry = {v, v, v};
+ table->push_back(gamma_entry);
+ }
+}
+
} // namespace
DrmDisplay::DrmDisplay(ScreenManager* screen_manager,
const scoped_refptr<DrmDevice>& drm)
- : screen_manager_(screen_manager), drm_(drm) {
-}
+ : screen_manager_(screen_manager),
+ drm_(drm),
+ current_color_space_(gfx::ColorSpace::CreateSRGB()) {}
DrmDisplay::~DrmDisplay() {
}
@@ -112,6 +127,14 @@ std::unique_ptr<display::DisplaySnapshot> DrmDisplay::Update(
display_id_ = params->display_id();
modes_ = GetDrmModeVector(info->connector());
+ is_hdr_capable_ =
+ params->bits_per_channel() > 8 && params->color_space().IsHDR();
+#if defined(OS_CHROMEOS)
+ is_hdr_capable_ =
+ is_hdr_capable_ &&
+ base::FeatureList::IsEnabled(display::features::kUseHDRTransferFunction);
+#endif
+
return params;
}
@@ -202,10 +225,14 @@ void DrmDisplay::SetBackgroundColor(const uint64_t background_color) {
void DrmDisplay::SetGammaCorrection(
const std::vector<display::GammaRampRGBEntry>& degamma_lut,
const std::vector<display::GammaRampRGBEntry>& gamma_lut) {
- if (!drm_->plane_manager()->SetGammaCorrection(crtc_, degamma_lut,
- gamma_lut)) {
- LOG(ERROR) << "Failed to set gamma tables for display: crtc_id = " << crtc_;
- }
+ // When both |degamma_lut| and |gamma_lut| are empty they are interpreted as
+ // "linear/pass-thru" [1]. If the display |is_hdr_capable_| we have to make
+ // sure the |current_color_space_| is considered properly.
+ // [1] https://www.kernel.org/doc/html/v4.19/gpu/drm-kms.html#color-management-properties
+ if (degamma_lut.empty() && gamma_lut.empty() && is_hdr_capable_)
+ SetColorSpace(current_color_space_);
+ else
+ CommitGammaCorrection(degamma_lut, gamma_lut);
}
// TODO(gildekel): consider reformatting this to use the new DRM API or cache
@@ -229,4 +256,35 @@ void DrmDisplay::SetPrivacyScreen(bool enabled) {
}
}
+void DrmDisplay::SetColorSpace(const gfx::ColorSpace& color_space) {
+ // There's only something to do if the display supports HDR.
+ if (!is_hdr_capable_)
+ return;
+ current_color_space_ = color_space;
+
+ // When |color_space| is HDR we can simply leave the gamma tables empty, which
+ // is interpreted as "linear/pass-thru", see [1]. However when we have an SDR
+ // |color_space|, we need to write a scaled down |gamma| function to prevent
+ // the mode change brightness to be visible.
+ std::vector<display::GammaRampRGBEntry> degamma;
+ std::vector<display::GammaRampRGBEntry> gamma;
+ if (current_color_space_.IsHDR())
+ return CommitGammaCorrection(degamma, gamma);
+
+ // TODO(mcasas) This should be the same value as in DisplayChangeObservers's
+ // FillDisplayColorSpaces, move to a common place.
+ constexpr float kHDRLevel = 2.0;
+ // TODO(mcasas): Retrieve this from the |drm_| HardwareDisplayPlaneManager.
+ constexpr size_t kNumGammaSamples = 16ul;
+ FillLinearValues(&gamma, kNumGammaSamples, 1.0 / kHDRLevel);
+ CommitGammaCorrection(degamma, gamma);
+}
+
+void DrmDisplay::CommitGammaCorrection(
+ const std::vector<display::GammaRampRGBEntry>& degamma_lut,
+ const std::vector<display::GammaRampRGBEntry>& gamma_lut) {
+ if (!drm_->plane_manager()->SetGammaCorrection(crtc_, degamma_lut, gamma_lut))
+ LOG(ERROR) << "Failed to set gamma tables for display: crtc_id = " << crtc_;
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_display.h b/chromium/ui/ozone/platform/drm/gpu/drm_display.h
index de721282b28..a658477fc2d 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_display.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_display.h
@@ -13,6 +13,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "ui/display/types/display_constants.h"
+#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/point.h"
#include "ui/ozone/platform/drm/common/scoped_drm_types.h"
@@ -24,7 +25,6 @@ struct GammaRampRGBEntry;
}
namespace ui {
-
class DrmDevice;
class HardwareDisplayControllerInfo;
class ScreenManager;
@@ -54,8 +54,15 @@ class DrmDisplay {
const std::vector<display::GammaRampRGBEntry>& degamma_lut,
const std::vector<display::GammaRampRGBEntry>& gamma_lut);
void SetPrivacyScreen(bool enabled);
+ void SetColorSpace(const gfx::ColorSpace& color_space);
+
+ void set_is_hdr_capable_for_testing(bool value) { is_hdr_capable_ = value; }
private:
+ void CommitGammaCorrection(
+ const std::vector<display::GammaRampRGBEntry>& degamma_lut,
+ const std::vector<display::GammaRampRGBEntry>& gamma_lut);
+
ScreenManager* screen_manager_; // Not owned.
int64_t display_id_ = -1;
@@ -64,6 +71,8 @@ class DrmDisplay {
ScopedDrmConnectorPtr connector_;
std::vector<drmModeModeInfo> modes_;
gfx::Point origin_;
+ bool is_hdr_capable_ = false;
+ gfx::ColorSpace current_color_space_;
DISALLOW_COPY_AND_ASSIGN(DrmDisplay);
};
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_display_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/drm_display_unittest.cc
new file mode 100644
index 00000000000..30e8c7ef8bc
--- /dev/null
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_display_unittest.cc
@@ -0,0 +1,192 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/drm/gpu/drm_display.h"
+
+#include <utility>
+
+#include "base/test/task_environment.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/color_space.h"
+#include "ui/gfx/linux/test/mock_gbm_device.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
+#include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
+#include "ui/ozone/platform/drm/gpu/screen_manager.h"
+
+using ::testing::_;
+using ::testing::SizeIs;
+
+// Verifies that the argument goes from 0 to the maximum uint16_t times |scale|.
+MATCHER_P(MatchesLinearRamp, scale, "") {
+ EXPECT_FALSE(arg.empty());
+
+ EXPECT_EQ(arg.front().r, 0);
+ EXPECT_EQ(arg.front().g, 0);
+ EXPECT_EQ(arg.front().b, 0);
+
+ const uint16_t max_value = std::numeric_limits<uint16_t>::max() * scale;
+
+ const auto middle_element = arg[arg.size() / 2];
+ const uint16_t middle_value = max_value * (arg.size() / 2) / (arg.size() - 1);
+ EXPECT_NEAR(middle_element.r, middle_value, 1);
+ EXPECT_NEAR(middle_element.g, middle_value, 1);
+ EXPECT_NEAR(middle_element.b, middle_value, 1);
+
+ const uint16_t last_value = max_value;
+ EXPECT_EQ(arg.back().r, last_value);
+ EXPECT_EQ(arg.back().g, last_value);
+ EXPECT_EQ(arg.back().b, last_value);
+
+ return true;
+}
+
+namespace ui {
+
+namespace {
+
+class MockHardwareDisplayPlaneManager : public HardwareDisplayPlaneManager {
+ public:
+ explicit MockHardwareDisplayPlaneManager(DrmDevice* drm)
+ : HardwareDisplayPlaneManager(drm) {}
+ ~MockHardwareDisplayPlaneManager() override = default;
+
+ MOCK_METHOD3(SetGammaCorrection,
+ bool(uint32_t crtc_id,
+ const std::vector<display::GammaRampRGBEntry>& degamma_lut,
+ const std::vector<display::GammaRampRGBEntry>& gamma_lut));
+
+ bool Modeset(uint32_t crtc_id,
+ uint32_t framebuffer_id,
+ uint32_t connector_id,
+ const drmModeModeInfo& mode,
+ const HardwareDisplayPlaneList& plane_list) override {
+ return false;
+ }
+ bool DisableModeset(uint32_t crtc_id, uint32_t connector) override {
+ return false;
+ }
+ bool Commit(HardwareDisplayPlaneList* plane_list,
+ scoped_refptr<PageFlipRequest> page_flip_request,
+ std::unique_ptr<gfx::GpuFence>* out_fence) override {
+ return false;
+ }
+ bool DisableOverlayPlanes(HardwareDisplayPlaneList* plane_list) override {
+ return false;
+ }
+ bool SetColorCorrectionOnAllCrtcPlanes(
+ uint32_t crtc_id,
+ ScopedDrmColorCtmPtr ctm_blob_data) override {
+ return false;
+ }
+ bool ValidatePrimarySize(const DrmOverlayPlane& primary,
+ const drmModeModeInfo& mode) override {
+ return false;
+ }
+ void RequestPlanesReadyCallback(
+ DrmOverlayPlaneList planes,
+ base::OnceCallback<void(DrmOverlayPlaneList planes)> callback) override {
+ return;
+ }
+ bool InitializePlanes() override { return false; }
+ bool SetPlaneData(HardwareDisplayPlaneList* plane_list,
+ HardwareDisplayPlane* hw_plane,
+ const DrmOverlayPlane& overlay,
+ uint32_t crtc_id,
+ const gfx::Rect& src_rect) override {
+ return false;
+ }
+ std::unique_ptr<HardwareDisplayPlane> CreatePlane(
+ uint32_t plane_id) override {
+ return nullptr;
+ }
+ bool IsCompatible(HardwareDisplayPlane* plane,
+ const DrmOverlayPlane& overlay,
+ uint32_t crtc_index) const override {
+ return false;
+ }
+ bool CommitColorMatrix(const CrtcProperties& crtc_props) override {
+ return false;
+ }
+ bool CommitGammaCorrection(const CrtcProperties& crtc_props) override {
+ return false;
+ }
+};
+
+} // namespace
+
+class DrmDisplayTest : public testing::Test {
+ protected:
+ DrmDisplayTest()
+ : mock_drm_device_(base::MakeRefCounted<MockDrmDevice>(
+ std::make_unique<MockGbmDevice>())),
+ drm_display_(&screen_manager_, mock_drm_device_) {}
+
+ MockHardwareDisplayPlaneManager* AddMockHardwareDisplayPlaneManager() {
+ auto mock_hardware_display_plane_manager =
+ std::make_unique<MockHardwareDisplayPlaneManager>(
+ mock_drm_device_.get());
+ MockHardwareDisplayPlaneManager* pointer =
+ mock_hardware_display_plane_manager.get();
+ mock_drm_device_->plane_manager_ =
+ std::move(mock_hardware_display_plane_manager);
+ return pointer;
+ }
+
+ base::test::TaskEnvironment env_;
+ scoped_refptr<DrmDevice> mock_drm_device_;
+ ScreenManager screen_manager_;
+ DrmDisplay drm_display_;
+};
+
+TEST_F(DrmDisplayTest, SetColorSpace) {
+ drm_display_.set_is_hdr_capable_for_testing(true);
+ MockHardwareDisplayPlaneManager* plane_manager =
+ AddMockHardwareDisplayPlaneManager();
+
+ ON_CALL(*plane_manager, SetGammaCorrection(_, SizeIs(0), _))
+ .WillByDefault(::testing::Return(true));
+
+ const auto kHDRColorSpace = gfx::ColorSpace::CreateHDR10();
+ EXPECT_CALL(*plane_manager, SetGammaCorrection(_, SizeIs(0), SizeIs(0)));
+ drm_display_.SetColorSpace(kHDRColorSpace);
+
+ const auto kSDRColorSpace = gfx::ColorSpace::CreateREC709();
+ constexpr float kHDRLevel = 2.0;
+ EXPECT_CALL(
+ *plane_manager,
+ SetGammaCorrection(_, SizeIs(0), MatchesLinearRamp(1.0 / kHDRLevel)));
+ drm_display_.SetColorSpace(kSDRColorSpace);
+}
+
+TEST_F(DrmDisplayTest, SetEmptyGammaCorrectionNonHDRDisplay) {
+ MockHardwareDisplayPlaneManager* plane_manager =
+ AddMockHardwareDisplayPlaneManager();
+
+ ON_CALL(*plane_manager, SetGammaCorrection(_, _, _))
+ .WillByDefault(::testing::Return(true));
+
+ EXPECT_CALL(*plane_manager, SetGammaCorrection(_, SizeIs(0), SizeIs(0)));
+ drm_display_.SetGammaCorrection(std::vector<display::GammaRampRGBEntry>(),
+ std::vector<display::GammaRampRGBEntry>());
+}
+
+TEST_F(DrmDisplayTest, SetEmptyGammaCorrectionHDRDisplay) {
+ drm_display_.set_is_hdr_capable_for_testing(true);
+ MockHardwareDisplayPlaneManager* plane_manager =
+ AddMockHardwareDisplayPlaneManager();
+
+ ON_CALL(*plane_manager, SetGammaCorrection(_, _, _))
+ .WillByDefault(::testing::Return(true));
+
+ constexpr float kHDRLevel = 2.0;
+ EXPECT_CALL(
+ *plane_manager,
+ SetGammaCorrection(_, SizeIs(0), MatchesLinearRamp(1.0 / kHDRLevel)));
+ drm_display_.SetGammaCorrection(std::vector<display::GammaRampRGBEntry>(),
+ std::vector<display::GammaRampRGBEntry>());
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc
index 772786b42ed..bdf7db0ec19 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "base/logging.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/linux/drm_util_linux.h"
#include "ui/gfx/linux/gbm_buffer.h"
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
index 74a5f19d91c..e7642e41351 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
@@ -8,6 +8,7 @@
#include <memory>
#include <utility>
+#include "base/logging.h"
#include "ui/display/types/display_mode.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/display/types/gamma_ramp_rgb_entry.h"
@@ -250,6 +251,17 @@ void DrmGpuDisplayManager::SetPrivacyScreen(int64_t display_id, bool enabled) {
display->SetPrivacyScreen(enabled);
}
+void DrmGpuDisplayManager::SetColorSpace(int64_t crtc_id,
+ const gfx::ColorSpace& color_space) {
+ for (const auto& display : displays_) {
+ if (display->crtc() == crtc_id) {
+ display->SetColorSpace(color_space);
+ return;
+ }
+ }
+ LOG(ERROR) << __func__ << " there is no display with CRTC ID " << crtc_id;
+}
+
DrmDisplay* DrmGpuDisplayManager::FindDisplay(int64_t display_id) {
for (const auto& display : displays_) {
if (display->display_id() == display_id)
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
index 5efd37fde04..6bc0d2472ea 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
@@ -21,6 +21,10 @@ class DisplayMode;
struct GammaRampRGBEntry;
}
+namespace gfx {
+class ColorSpace;
+}
+
namespace ui {
class DrmDeviceManager;
@@ -61,6 +65,8 @@ class DrmGpuDisplayManager {
const std::vector<display::GammaRampRGBEntry>& gamma_lut);
void SetPrivacyScreen(int64_t display_id, bool enabled);
+ void SetColorSpace(int64_t crtc_id, const gfx::ColorSpace& color_space);
+
private:
DrmDisplay* FindDisplay(int64_t display_id);
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_util.cc b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_util.cc
index bc1ab154808..4e70e45f0c1 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_util.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_util.cc
@@ -9,6 +9,7 @@
#include <xf86drmMode.h>
#include "base/files/scoped_file.h"
+#include "base/logging.h"
#include "base/trace_event/trace_event.h"
#include "ui/display/types/gamma_ramp_rgb_entry.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
index 181fcd86a18..13b3dd7a141 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
@@ -5,6 +5,7 @@
#include "ui/ozone/platform/drm/gpu/drm_thread.h"
#include <gbm.h>
+
#include <memory>
#include <utility>
@@ -22,6 +23,7 @@
#include "ui/gfx/linux/gbm_util.h"
#include "ui/gfx/presentation_feedback.h"
#include "ui/ozone/platform/drm/common/drm_util.h"
+#include "ui/ozone/platform/drm/gpu/crtc_controller.h"
#include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
#include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
#include "ui/ozone/platform/drm/gpu/drm_dumb_buffer.h"
@@ -108,8 +110,8 @@ void DrmThread::Init() {
device_manager_ =
std::make_unique<DrmDeviceManager>(std::move(device_generator_));
screen_manager_ = std::make_unique<ScreenManager>();
- display_manager_.reset(
- new DrmGpuDisplayManager(screen_manager_.get(), device_manager_.get()));
+ display_manager_ = std::make_unique<DrmGpuDisplayManager>(
+ screen_manager_.get(), device_manager_.get());
DCHECK(task_runner())
<< "DrmThread::Init -- thread doesn't have a task_runner";
@@ -276,8 +278,8 @@ void DrmThread::SetCursor(gfx::AcceleratedWidget widget,
const gfx::Point& location,
int32_t frame_delay_ms) {
TRACE_EVENT0("drm", "DrmThread::SetCursor");
- screen_manager_->GetWindow(widget)
- ->SetCursor(bitmaps, location, frame_delay_ms);
+ screen_manager_->GetWindow(widget)->SetCursor(bitmaps, location,
+ frame_delay_ms);
}
void DrmThread::MoveCursor(gfx::AcceleratedWidget widget,
@@ -324,20 +326,21 @@ void DrmThread::RefreshNativeDisplays(
}
void DrmThread::ConfigureNativeDisplay(
- int64_t id,
- std::unique_ptr<display::DisplayMode> mode,
- const gfx::Point& origin,
+ const display::DisplayConfigurationParams& display_config_params,
base::OnceCallback<void(int64_t, bool)> callback) {
TRACE_EVENT0("drm", "DrmThread::ConfigureNativeDisplay");
- std::move(callback).Run(
- id, display_manager_->ConfigureDisplay(id, *mode, origin));
-}
-void DrmThread::DisableNativeDisplay(
- int64_t id,
- base::OnceCallback<void(int64_t, bool)> callback) {
- TRACE_EVENT0("drm", "DrmThread::DisableNativeDisplay");
- std::move(callback).Run(id, display_manager_->DisableDisplay(id));
+ if (display_config_params.mode) {
+ std::move(callback).Run(
+ display_config_params.id,
+ display_manager_->ConfigureDisplay(display_config_params.id,
+ *display_config_params.mode.value(),
+ display_config_params.origin));
+ } else {
+ std::move(callback).Run(
+ display_config_params.id,
+ display_manager_->DisableDisplay(display_config_params.id));
+ }
}
void DrmThread::TakeDisplayControl(base::OnceCallback<void(bool)> callback) {
@@ -418,4 +421,17 @@ void DrmThread::ProcessPendingTasks() {
pending_tasks_.clear();
}
+void DrmThread::SetColorSpace(gfx::AcceleratedWidget widget,
+ const gfx::ColorSpace& color_space) {
+ DCHECK(screen_manager_->GetWindow(widget));
+ HardwareDisplayController* controller =
+ screen_manager_->GetWindow(widget)->GetController();
+ if (!controller)
+ return;
+
+ const auto& crtc_controllers = controller->crtc_controllers();
+ for (const auto& crtc_controller : crtc_controllers)
+ display_manager_->SetColorSpace(crtc_controller->crtc(), color_space);
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread.h b/chromium/ui/ozone/platform/drm/gpu/drm_thread.h
index b4ec4298339..71457f24c99 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_thread.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread.h
@@ -6,6 +6,7 @@
#define UI_OZONE_PLATFORM_DRM_GPU_DRM_THREAD_H_
#include <stdint.h>
+
#include <memory>
#include "base/files/file.h"
@@ -17,6 +18,7 @@
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "ui/display/types/display_configuration_params.h"
#include "ui/gfx/native_pixmap_handle.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/vsync_provider.h"
@@ -32,14 +34,13 @@ class FilePath;
}
namespace display {
-class DisplayMode;
struct GammaRampRGBEntry;
-}
+} // namespace display
namespace gfx {
class Point;
class Rect;
-}
+} // namespace gfx
namespace ui {
@@ -107,6 +108,9 @@ class DrmThread : public base::Thread,
void AddDrmDeviceReceiver(
mojo::PendingReceiver<ozone::mojom::DrmDevice> receiver);
+ void SetColorSpace(gfx::AcceleratedWidget widget,
+ const gfx::ColorSpace& color_space);
+
// Verifies if the display controller can successfully scanout the given set
// of OverlaySurfaceCandidates and return the status associated with each
// candidate.
@@ -143,13 +147,8 @@ class DrmThread : public base::Thread,
base::OnceCallback<void(MovableDisplaySnapshots)> callback) override;
void AddGraphicsDevice(const base::FilePath& path, base::File file) override;
void RemoveGraphicsDevice(const base::FilePath& path) override;
- void DisableNativeDisplay(
- int64_t id,
- base::OnceCallback<void(int64_t, bool)> callback) override;
void ConfigureNativeDisplay(
- int64_t id,
- std::unique_ptr<display::DisplayMode> mode,
- const gfx::Point& origin,
+ const display::DisplayConfigurationParams& display_config_params,
base::OnceCallback<void(int64_t, bool)> callback) override;
void GetHDCPState(int64_t display_id,
base::OnceCallback<void(int64_t, bool, display::HDCPState)>
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.cc b/chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.cc
index f94428bf86f..64751f39426 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.cc
@@ -52,4 +52,11 @@ bool DrmWindowProxy::SupportsGpuFences() const {
switches::kDisableExplicitDmaFences);
}
+void DrmWindowProxy::SetColorSpace(const gfx::ColorSpace& color_space) const {
+ drm_thread_->task_runner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&DrmThread::SetColorSpace, base::Unretained(drm_thread_),
+ widget_, color_space));
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.h b/chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.h
index 303051c1c25..8bb036e0ef9 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.h
@@ -12,6 +12,10 @@
#include "ui/gfx/vsync_provider.h"
#include "ui/ozone/public/swap_completion_callback.h"
+namespace gfx {
+class ColorSpace;
+}
+
namespace ui {
class DrmThread;
@@ -30,6 +34,8 @@ class DrmWindowProxy {
bool SupportsGpuFences() const;
+ void SetColorSpace(const gfx::ColorSpace& color_space) const;
+
private:
const gfx::AcceleratedWidget widget_;
diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
index 8c32abbafef..29b76be970e 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -79,6 +79,16 @@ bool GbmSurfaceless::ScheduleOverlayPlane(
return true;
}
+bool GbmSurfaceless::Resize(const gfx::Size& size,
+ float scale_factor,
+ const gfx::ColorSpace& color_space,
+ bool has_alpha) {
+ if (window_)
+ window_->SetColorSpace(color_space);
+
+ return SurfacelessEGL::Resize(size, scale_factor, color_space, has_alpha);
+}
+
bool GbmSurfaceless::IsOffscreen() {
return false;
}
@@ -111,7 +121,8 @@ void GbmSurfaceless::SwapBuffersAsync(
TRACE_EVENT0("drm", "GbmSurfaceless::SwapBuffersAsync");
// If last swap failed, don't try to schedule new ones.
if (!last_swap_buffers_result_) {
- std::move(completion_callback).Run(gfx::SwapResult::SWAP_FAILED, nullptr);
+ std::move(completion_callback)
+ .Run(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_FAILED));
// Notify the caller, the buffer is never presented on a screen.
std::move(presentation_callback).Run(gfx::PresentationFeedback::Failure());
return;
@@ -230,6 +241,13 @@ void GbmSurfaceless::SubmitFrame() {
DCHECK(!unsubmitted_frames_.empty());
if (unsubmitted_frames_.front()->ready && !submitted_frame_) {
+ for (auto& overlay : unsubmitted_frames_.front()->overlays) {
+ if (overlay.z_order() == 0 && overlay.gpu_fence()) {
+ submitted_frame_gpu_fence_ = std::make_unique<gfx::GpuFence>(
+ gfx::CloneHandleForIPC(overlay.gpu_fence()->GetGpuFenceHandle()));
+ break;
+ }
+ }
submitted_frame_ = std::move(unsubmitted_frames_.front());
unsubmitted_frames_.erase(unsubmitted_frames_.begin());
@@ -270,12 +288,19 @@ void GbmSurfaceless::OnSubmission(gfx::SwapResult result,
}
void GbmSurfaceless::OnPresentation(const gfx::PresentationFeedback& feedback) {
- // Explicitly destroy overlays to free resources (e.g., fences) early.
+ gfx::PresentationFeedback feedback_copy = feedback;
+
+ if (submitted_frame_gpu_fence_) {
+ feedback_copy.ready_timestamp =
+ submitted_frame_gpu_fence_->GetMaxTimestamp();
+ }
+ submitted_frame_gpu_fence_.reset();
submitted_frame_->overlays.clear();
gfx::SwapResult result = submitted_frame_->swap_result;
- std::move(submitted_frame_->completion_callback).Run(result, nullptr);
- std::move(submitted_frame_->presentation_callback).Run(feedback);
+ std::move(submitted_frame_->completion_callback)
+ .Run(gfx::SwapCompletionResult(result));
+ std::move(submitted_frame_->presentation_callback).Run(feedback_copy);
submitted_frame_.reset();
if (result == gfx::SwapResult::SWAP_FAILED) {
diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.h b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
index 2bfbf347f2e..9b638ef08ff 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
@@ -17,6 +17,10 @@
#include "ui/gl/scoped_binders.h"
#include "ui/ozone/platform/drm/gpu/drm_overlay_plane.h"
+namespace gfx {
+class GpuFence;
+} // namespace gfx
+
namespace ui {
class DrmWindowProxy;
@@ -44,6 +48,10 @@ class GbmSurfaceless : public gl::SurfacelessEGL {
const gfx::RectF& crop_rect,
bool enable_blend,
std::unique_ptr<gfx::GpuFence> gpu_fence) override;
+ bool Resize(const gfx::Size& size,
+ float scale_factor,
+ const gfx::ColorSpace& color_space,
+ bool has_alpha) override;
bool IsOffscreen() override;
bool SupportsAsyncSwap() override;
bool SupportsPostSubBuffer() override;
@@ -104,6 +112,7 @@ class GbmSurfaceless : public gl::SurfacelessEGL {
std::unique_ptr<gfx::VSyncProvider> vsync_provider_;
std::vector<std::unique_ptr<PendingFrame>> unsubmitted_frames_;
std::unique_ptr<PendingFrame> submitted_frame_;
+ std::unique_ptr<gfx::GpuFence> submitted_frame_gpu_fence_;
const bool has_implicit_external_sync_;
const bool has_image_flush_external_;
bool last_swap_buffers_result_ = true;
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane.cc
index 2d19a1a8b26..6505127b024 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane.cc
@@ -126,11 +126,12 @@ std::vector<uint64_t> HardwareDisplayPlane::ModifiersForFormat(
uint32_t format) const {
std::vector<uint64_t> modifiers;
- uint32_t format_index =
- std::find(supported_formats_.begin(), supported_formats_.end(), format) -
- supported_formats_.begin();
- DCHECK_LT(format_index, supported_formats_.size());
+ auto it =
+ std::find(supported_formats_.begin(), supported_formats_.end(), format);
+ if (it == supported_formats_.end())
+ return modifiers;
+ uint32_t format_index = it - supported_formats_.begin();
for (const auto& modifier : supported_format_modifiers_) {
// modifier.formats is a bitmask of the formats the modifier
// applies to, starting at format modifier.offset. That is, if bit
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc
index 28d692268d7..1899daf4e7c 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc
@@ -4,6 +4,7 @@
#include "ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h"
+#include "base/logging.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/drm_gpu_util.h"
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
index b1070a0d89e..b2443c90b07 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
@@ -84,7 +84,7 @@ class HardwareDisplayPlaneManager {
void SetBackgroundColor(uint32_t crtc_id, const uint64_t background_color);
// Sets the degamma/gamma luts on the CRTC object with ID |crtc_id|.
- bool SetGammaCorrection(
+ virtual bool SetGammaCorrection(
uint32_t crtc_id,
const std::vector<display::GammaRampRGBEntry>& degamma_lut,
const std::vector<display::GammaRampRGBEntry>& gamma_lut);
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
index 4ec9db772db..2bdf60aba9d 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
@@ -12,6 +12,7 @@
#include "base/bind.h"
#include "base/files/platform_file.h"
+#include "base/logging.h"
#include "base/stl_util.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "ui/gfx/gpu_fence.h"
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc
index 4bbd89541aa..91926a0d2b2 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc
@@ -10,6 +10,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
diff --git a/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc b/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc
index 42473035751..342bad7004f 100644
--- a/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc
@@ -9,6 +9,7 @@
#include <utility>
#include "base/files/platform_file.h"
+#include "base/logging.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/display/types/display_snapshot.h"
diff --git a/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc b/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc
index 601cdb36873..e3792ee932d 100644
--- a/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc
@@ -7,6 +7,7 @@
#include <memory>
#include "base/files/file_path.h"
+#include "base/logging.h"
#include "base/native_library.h"
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "gpu/vulkan/vulkan_image.h"
diff --git a/chromium/ui/ozone/platform/drm/host/drm_device_handle.cc b/chromium/ui/ozone/platform/drm/host/drm_device_handle.cc
index 7e2a58d4a32..c052a5d1bcb 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_device_handle.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_device_handle.cc
@@ -10,6 +10,7 @@
#include <utility>
#include "base/files/file_path.h"
+#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/time/time.h"
diff --git a/chromium/ui/ozone/platform/drm/host/drm_display_host.cc b/chromium/ui/ozone/platform/drm/host/drm_display_host.cc
index 3c84a92181f..3da0ad8e912 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_display_host.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_display_host.cc
@@ -9,7 +9,9 @@
#include "base/bind.h"
#include "base/location.h"
+#include "base/logging.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "ui/display/types/display_configuration_params.h"
#include "ui/display/types/display_mode.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/ozone/platform/drm/common/drm_util.h"
@@ -44,12 +46,10 @@ void DrmDisplayHost::Configure(const display::DisplayMode* mode,
configure_callback_ = std::move(callback);
bool status = false;
- if (mode) {
- status = sender_->GpuConfigureNativeDisplay(snapshot_->display_id(), *mode,
- origin);
- } else {
- status = sender_->GpuDisableNativeDisplay(snapshot_->display_id());
- }
+
+ display::DisplayConfigurationParams display_config_params(
+ snapshot_->display_id(), origin, mode);
+ status = sender_->GpuConfigureNativeDisplay(display_config_params);
if (!status)
OnDisplayConfigured(false);
diff --git a/chromium/ui/ozone/platform/drm/host/gpu_thread_adapter.h b/chromium/ui/ozone/platform/drm/host/gpu_thread_adapter.h
index d6c6804a586..8b9b8a39eea 100644
--- a/chromium/ui/ozone/platform/drm/host/gpu_thread_adapter.h
+++ b/chromium/ui/ozone/platform/drm/host/gpu_thread_adapter.h
@@ -6,15 +6,12 @@
#define UI_OZONE_PLATFORM_DRM_HOST_GPU_THREAD_ADAPTER_H_
#include "base/file_descriptor_posix.h"
+#include "ui/display/types/display_configuration_params.h"
#include "ui/display/types/display_constants.h"
#include "ui/display/types/gamma_ramp_rgb_entry.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
-namespace display {
-class DisplayMode;
-} // namespace display
-
namespace ui {
class DrmDisplayHostManager;
@@ -46,10 +43,8 @@ class GpuThreadAdapter {
virtual bool GpuRemoveGraphicsDevice(const base::FilePath& path) = 0;
// Services needed by DrmDisplayHost
- virtual bool GpuConfigureNativeDisplay(int64_t display_id,
- const display::DisplayMode& pmode,
- const gfx::Point& point) = 0;
- virtual bool GpuDisableNativeDisplay(int64_t display_id) = 0;
+ virtual bool GpuConfigureNativeDisplay(
+ const display::DisplayConfigurationParams& display_config_params) = 0;
virtual bool GpuGetHDCPState(int64_t display_id) = 0;
virtual bool GpuSetHDCPState(int64_t display_id,
display::HDCPState state) = 0;
diff --git a/chromium/ui/ozone/platform/drm/host/host_drm_device.cc b/chromium/ui/ozone/platform/drm/host/host_drm_device.cc
index a2ca1364f51..58bd76117d4 100644
--- a/chromium/ui/ozone/platform/drm/host/host_drm_device.cc
+++ b/chromium/ui/ozone/platform/drm/host/host_drm_device.cc
@@ -128,36 +128,21 @@ bool HostDrmDevice::GpuRefreshNativeDisplays() {
return true;
}
-bool HostDrmDevice::GpuConfigureNativeDisplay(int64_t id,
- const display::DisplayMode& pmode,
- const gfx::Point& origin) {
+bool HostDrmDevice::GpuConfigureNativeDisplay(
+ const display::DisplayConfigurationParams& display_config_params) {
DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_);
if (!IsConnected())
return false;
- auto mode = std::make_unique<display::DisplayMode>(
- pmode.size(), pmode.is_interlaced(), pmode.refresh_rate());
auto callback =
base::BindOnce(&HostDrmDevice::GpuConfigureNativeDisplayCallback, this);
- drm_device_->ConfigureNativeDisplay(id, std::move(mode), origin,
+ drm_device_->ConfigureNativeDisplay(display_config_params,
std::move(callback));
return true;
}
-bool HostDrmDevice::GpuDisableNativeDisplay(int64_t id) {
- DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_);
- if (!IsConnected())
- return false;
- auto callback =
- base::BindOnce(&HostDrmDevice::GpuDisableNativeDisplayCallback, this);
-
- drm_device_->DisableNativeDisplay(id, std::move(callback));
-
- return true;
-}
-
bool HostDrmDevice::GpuTakeDisplayControl() {
DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_);
if (!IsConnected())
@@ -278,12 +263,6 @@ void HostDrmDevice::GpuRefreshNativeDisplaysCallback(
display_manager_->GpuHasUpdatedNativeDisplays(std::move(displays));
}
-void HostDrmDevice::GpuDisableNativeDisplayCallback(int64_t display_id,
- bool success) const {
- DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_);
- display_manager_->GpuConfiguredDisplay(display_id, success);
-}
-
void HostDrmDevice::GpuTakeDisplayControlCallback(bool success) const {
DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_);
display_manager_->GpuTookDisplayControl(success);
diff --git a/chromium/ui/ozone/platform/drm/host/host_drm_device.h b/chromium/ui/ozone/platform/drm/host/host_drm_device.h
index fbe3723e419..a21505193c6 100644
--- a/chromium/ui/ozone/platform/drm/host/host_drm_device.h
+++ b/chromium/ui/ozone/platform/drm/host/host_drm_device.h
@@ -65,10 +65,8 @@ class HostDrmDevice : public base::RefCountedThreadSafe<HostDrmDevice>,
bool GpuRemoveGraphicsDevice(const base::FilePath& path) override;
// Services needed by DrmDisplayHost
- bool GpuConfigureNativeDisplay(int64_t display_id,
- const display::DisplayMode& pmode,
- const gfx::Point& point) override;
- bool GpuDisableNativeDisplay(int64_t display_id) override;
+ bool GpuConfigureNativeDisplay(const display::DisplayConfigurationParams&
+ display_config_params) override;
bool GpuGetHDCPState(int64_t display_id) override;
bool GpuSetHDCPState(int64_t display_id, display::HDCPState state) override;
bool GpuSetColorMatrix(int64_t display_id,
@@ -98,7 +96,6 @@ class HostDrmDevice : public base::RefCountedThreadSafe<HostDrmDevice>,
bool success) const;
void GpuRefreshNativeDisplaysCallback(MovableDisplaySnapshots displays) const;
- void GpuDisableNativeDisplayCallback(int64_t display_id, bool success) const;
void GpuTakeDisplayControlCallback(bool success) const;
void GpuRelinquishDisplayControlCallback(bool success) const;
void GpuGetHDCPStateCallback(int64_t display_id,
diff --git a/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc b/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc
index 23786834484..9e0cc71662e 100644
--- a/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc
+++ b/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc
@@ -21,6 +21,7 @@
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "ui/base/buildflags.h"
+#include "ui/base/cursor/cursor_factory.h"
#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
#include "ui/events/ozone/device/device_manager.h"
#include "ui/events/ozone/evdev/event_factory_evdev.h"
@@ -43,7 +44,6 @@
#include "ui/ozone/platform/drm/host/drm_window_host.h"
#include "ui/ozone/platform/drm/host/drm_window_host_manager.h"
#include "ui/ozone/platform/drm/host/host_drm_device.h"
-#include "ui/ozone/public/cursor_factory_ozone.h"
#include "ui/ozone/public/gpu_platform_support_host.h"
#include "ui/ozone/public/mojom/drm_device.mojom.h"
#include "ui/ozone/public/ozone_platform.h"
@@ -80,9 +80,7 @@ class OzonePlatformGbm : public OzonePlatform {
OverlayManagerOzone* GetOverlayManager() override {
return overlay_manager_.get();
}
- CursorFactoryOzone* GetCursorFactoryOzone() override {
- return cursor_factory_ozone_.get();
- }
+ CursorFactory* GetCursorFactory() override { return cursor_factory_.get(); }
InputController* GetInputController() override {
return event_factory_ozone_->input_controller();
}
@@ -202,7 +200,7 @@ class OzonePlatformGbm : public OzonePlatform {
display_manager_ = std::make_unique<DrmDisplayHostManager>(
adapter, device_manager_.get(), &host_properties_,
event_factory_ozone_->input_controller());
- cursor_factory_ozone_ = std::make_unique<BitmapCursorFactoryOzone>();
+ cursor_factory_ = std::make_unique<BitmapCursorFactoryOzone>();
host_drm_device_->SetDisplayManager(display_manager_.get());
}
@@ -307,7 +305,7 @@ class OzonePlatformGbm : public OzonePlatform {
scoped_refptr<HostDrmDevice> host_drm_device_;
base::PlatformThreadRef host_thread_;
std::unique_ptr<DeviceManager> device_manager_;
- std::unique_ptr<BitmapCursorFactoryOzone> cursor_factory_ozone_;
+ std::unique_ptr<CursorFactory> cursor_factory_;
std::unique_ptr<DrmWindowHostManager> window_manager_;
std::unique_ptr<DrmCursor> cursor_;
std::unique_ptr<EventFactoryEvdev> event_factory_ozone_;
diff --git a/chromium/ui/ozone/platform/headless/BUILD.gn b/chromium/ui/ozone/platform/headless/BUILD.gn
index 9465b52ff12..ca02e70c2cd 100644
--- a/chromium/ui/ozone/platform/headless/BUILD.gn
+++ b/chromium/ui/ozone/platform/headless/BUILD.gn
@@ -26,6 +26,8 @@ source_set("headless") {
"//base",
"//skia",
"//ui/base",
+ "//ui/base/cursor",
+ "//ui/base/cursor:cursor_base",
"//ui/base/ime",
"//ui/events",
"//ui/events/ozone/layout",
diff --git a/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc b/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc
index 9d356f701e3..707948351e0 100644
--- a/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc
+++ b/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc
@@ -10,6 +10,7 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "build/build_config.h"
+#include "ui/base/cursor/cursor_factory.h"
#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
#include "ui/base/ime/input_method_minimal.h"
#include "ui/display/types/native_display_delegate.h"
@@ -21,7 +22,6 @@
#include "ui/ozone/platform/headless/headless_surface_factory.h"
#include "ui/ozone/platform/headless/headless_window.h"
#include "ui/ozone/platform/headless/headless_window_manager.h"
-#include "ui/ozone/public/cursor_factory_ozone.h"
#include "ui/ozone/public/gpu_platform_support_host.h"
#include "ui/ozone/public/input_controller.h"
#include "ui/ozone/public/ozone_platform.h"
@@ -63,9 +63,7 @@ class OzonePlatformHeadless : public OzonePlatform {
OverlayManagerOzone* GetOverlayManager() override {
return overlay_manager_.get();
}
- CursorFactoryOzone* GetCursorFactoryOzone() override {
- return cursor_factory_ozone_.get();
- }
+ CursorFactory* GetCursorFactory() override { return cursor_factory_.get(); }
InputController* GetInputController() override {
return input_controller_.get();
}
@@ -110,7 +108,7 @@ class OzonePlatformHeadless : public OzonePlatform {
overlay_manager_ = std::make_unique<StubOverlayManager>();
input_controller_ = CreateStubInputController();
- cursor_factory_ozone_ = std::make_unique<BitmapCursorFactoryOzone>();
+ cursor_factory_ = std::make_unique<BitmapCursorFactoryOzone>();
gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
}
@@ -124,7 +122,7 @@ class OzonePlatformHeadless : public OzonePlatform {
std::unique_ptr<HeadlessWindowManager> window_manager_;
std::unique_ptr<HeadlessSurfaceFactory> surface_factory_;
std::unique_ptr<PlatformEventSource> platform_event_source_;
- std::unique_ptr<CursorFactoryOzone> cursor_factory_ozone_;
+ std::unique_ptr<CursorFactory> cursor_factory_;
std::unique_ptr<InputController> input_controller_;
std::unique_ptr<GpuPlatformSupportHost> gpu_platform_support_host_;
std::unique_ptr<OverlayManagerOzone> overlay_manager_;
diff --git a/chromium/ui/ozone/platform/scenic/BUILD.gn b/chromium/ui/ozone/platform/scenic/BUILD.gn
index ed6dd8a0f29..32792aaf31a 100644
--- a/chromium/ui/ozone/platform/scenic/BUILD.gn
+++ b/chromium/ui/ozone/platform/scenic/BUILD.gn
@@ -55,6 +55,8 @@ source_set("scenic") {
"//third_party/fuchsia-sdk/sdk/pkg/scenic_cpp",
"//third_party/fuchsia-sdk/sdk/pkg/sys_cpp",
"//ui/base",
+ "//ui/base/cursor",
+ "//ui/base/cursor:cursor_base",
"//ui/base/ime/fuchsia",
"//ui/display/fake",
"//ui/events:dom_keycode_converter",
diff --git a/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc b/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
index c9f0f74031d..fcd5d1ccf32 100644
--- a/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
+++ b/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
@@ -15,6 +15,7 @@
#include "base/message_loop/message_pump_type.h"
#include "base/notreached.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "ui/base/cursor/cursor_factory.h"
#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
#include "ui/base/ime/fuchsia/input_method_fuchsia.h"
#include "ui/display/fake/fake_display_delegate.h"
@@ -30,7 +31,6 @@
#include "ui/ozone/platform/scenic/scenic_window_manager.h"
#include "ui/ozone/platform/scenic/sysmem_buffer_collection.h"
#include "ui/ozone/platform_selection.h"
-#include "ui/ozone/public/cursor_factory_ozone.h"
#include "ui/ozone/public/gpu_platform_support_host.h"
#include "ui/ozone/public/input_controller.h"
#include "ui/ozone/public/mojom/scenic_gpu_service.mojom.h"
@@ -77,9 +77,7 @@ class OzonePlatformScenic
return overlay_manager_.get();
}
- CursorFactoryOzone* GetCursorFactoryOzone() override {
- return cursor_factory_ozone_.get();
- }
+ CursorFactory* GetCursorFactory() override { return cursor_factory_.get(); }
InputController* GetInputController() override {
return input_controller_.get();
@@ -137,7 +135,7 @@ class OzonePlatformScenic
window_manager_ = std::make_unique<ScenicWindowManager>();
overlay_manager_ = std::make_unique<StubOverlayManager>();
input_controller_ = CreateStubInputController();
- cursor_factory_ozone_ = std::make_unique<BitmapCursorFactoryOzone>();
+ cursor_factory_ = std::make_unique<BitmapCursorFactoryOzone>();
scenic_gpu_host_ = std::make_unique<ScenicGpuHost>(window_manager_.get());
@@ -208,7 +206,7 @@ class OzonePlatformScenic
std::unique_ptr<KeyboardLayoutEngine> keyboard_layout_engine_;
std::unique_ptr<PlatformEventSource> platform_event_source_;
- std::unique_ptr<CursorFactoryOzone> cursor_factory_ozone_;
+ std::unique_ptr<CursorFactory> cursor_factory_;
std::unique_ptr<InputController> input_controller_;
std::unique_ptr<OverlayManagerOzone> overlay_manager_;
std::unique_ptr<ScenicGpuHost> scenic_gpu_host_;
diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface.cc b/chromium/ui/ozone/platform/scenic/scenic_surface.cc
index 2d75a091190..dc7fd2ec10f 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_surface.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_surface.cc
@@ -19,11 +19,13 @@ ScenicSurface::ScenicSurface(
scenic::SessionPtrAndListenerRequest sesion_and_listener_request)
: scenic_session_(std::move(sesion_and_listener_request)),
shape_(&scenic_session_),
- material_(&scenic_session_),
scenic_surface_factory_(scenic_surface_factory),
window_(window) {
+ // Setting alpha to 0 makes this transparent.
+ scenic::Material transparent_material(&scenic_session_);
+ transparent_material.SetColor(0, 0, 0, 0);
shape_.SetShape(scenic::Rectangle(&scenic_session_, 1.f, 1.f));
- shape_.SetMaterial(material_);
+ shape_.SetMaterial(transparent_material);
scenic_surface_factory->AddSurface(window, this);
scenic_session_.SetDebugName("Chromium ScenicSurface");
}
@@ -33,23 +35,28 @@ ScenicSurface::~ScenicSurface() {
scenic_surface_factory_->RemoveSurface(window_);
}
-void ScenicSurface::SetTextureToNewImagePipe(
+bool ScenicSurface::SetTextureToNewImagePipe(
fidl::InterfaceRequest<fuchsia::images::ImagePipe2> image_pipe_request) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
uint32_t image_pipe_id = scenic_session_.AllocResourceId();
scenic_session_.Enqueue(scenic::NewCreateImagePipe2Cmd(
image_pipe_id, std::move(image_pipe_request)));
- material_.SetTexture(image_pipe_id);
+ scenic::Material image_material(&scenic_session_);
+ image_material.SetTexture(image_pipe_id);
+ shape_.SetMaterial(image_material);
scenic_session_.ReleaseResource(image_pipe_id);
scenic_session_.Present2(
/*requested_presentation_time=*/0,
/*requested_prediction_span=*/0,
[](fuchsia::scenic::scheduling::FuturePresentationTimes info) {});
+ return true;
}
void ScenicSurface::SetTextureToImage(const scenic::Image& image) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- material_.SetTexture(image);
+ scenic::Material image_material(&scenic_session_);
+ image_material.SetTexture(image);
+ shape_.SetMaterial(image_material);
}
mojo::PlatformHandle ScenicSurface::CreateView() {
diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface.h b/chromium/ui/ozone/platform/scenic/scenic_surface.h
index d9b730ae611..3264a594fc0 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_surface.h
+++ b/chromium/ui/ozone/platform/scenic/scenic_surface.h
@@ -35,8 +35,9 @@ class ScenicSurface : public ui::PlatformWindowSurface {
~ScenicSurface() override;
// Sets the texture of the surface to a new image pipe.
- void SetTextureToNewImagePipe(
- fidl::InterfaceRequest<fuchsia::images::ImagePipe2> image_pipe_request);
+ bool SetTextureToNewImagePipe(
+ fidl::InterfaceRequest<fuchsia::images::ImagePipe2> image_pipe_request)
+ override;
// Sets the texture of the surface to an image resource.
void SetTextureToImage(const scenic::Image& image);
@@ -58,7 +59,6 @@ class ScenicSurface : public ui::PlatformWindowSurface {
scenic::Session scenic_session_;
std::unique_ptr<scenic::View> parent_;
scenic::ShapeNode shape_;
- scenic::Material material_;
ScenicSurfaceFactory* const scenic_surface_factory_;
const gfx::AcceleratedWidget window_;
diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
index 7280c5e154f..7719bac9d88 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
@@ -9,8 +9,8 @@
#include <memory>
#include "base/bind.h"
-#include "base/fuchsia/default_context.h"
#include "base/fuchsia/fuchsia_logging.h"
+#include "base/fuchsia/process_context.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "third_party/angle/src/common/fuchsia_egl/fuchsia_egl.h"
@@ -43,7 +43,7 @@ struct FuchsiaEGLWindowDeleter {
fuchsia::ui::scenic::ScenicPtr ConnectToScenic() {
fuchsia::ui::scenic::ScenicPtr scenic =
- base::fuchsia::ComponentContextForCurrentProcess()
+ base::ComponentContextForProcess()
->svc()
->Connect<fuchsia::ui::scenic::Scenic>();
scenic.set_error_handler([](zx_status_t status) {
@@ -130,8 +130,7 @@ class GLOzoneEGLScenic : public GLOzoneEGL {
fuchsia::sysmem::AllocatorHandle ConnectSysmemAllocator() {
fuchsia::sysmem::AllocatorHandle allocator;
- base::fuchsia::ComponentContextForCurrentProcess()->svc()->Connect(
- allocator.NewRequest());
+ base::ComponentContextForProcess()->svc()->Connect(allocator.NewRequest());
return allocator;
}
diff --git a/chromium/ui/ozone/platform/scenic/scenic_window.cc b/chromium/ui/ozone/platform/scenic/scenic_window.cc
index 0de00de69aa..81cafe89676 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_window.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_window.cc
@@ -37,8 +37,7 @@ ScenicWindow::ScenicWindow(ScenicWindowManager* window_manager,
"chromium window"),
node_(&scenic_session_),
input_node_(&scenic_session_),
- render_node_(&scenic_session_),
- background_node_(&scenic_session_) {
+ render_node_(&scenic_session_) {
scenic_session_.set_error_handler(
fit::bind_member(this, &ScenicWindow::OnScenicError));
scenic_session_.set_event_handler(
@@ -52,28 +51,8 @@ ScenicWindow::ScenicWindow(ScenicWindowManager* window_manager,
// Add input shape.
node_.AddChild(input_node_);
- // Add rendering subtree, rooted at Z=-2 to make room for background layers in
- // the Z-order (lesser values are higher in the visual ordering).
- constexpr float kRenderNodeZPosition = -2.;
- constexpr float kBackgroundNodeZPosition = kRenderNodeZPosition + 1.;
- render_node_.SetTranslation(0., 0., kRenderNodeZPosition);
node_.AddChild(render_node_);
- // Initialize a black background to be just behind |render_node_|.
- scenic::Material background_color(&scenic_session_);
- background_color.SetColor(0, 0, 0, 255); // RGBA (0,0,0,255) = opaque black.
- background_node_.SetMaterial(background_color);
- scenic::Rectangle background_shape(&scenic_session_, 1., 1.);
- background_node_.SetShape(background_shape);
- background_node_.SetTranslation(0., 0., kBackgroundNodeZPosition);
- node_.AddChild(background_node_);
-
- // Render the background immediately.
- scenic_session_.Present2(
- /*requested_presentation_time=*/0,
- /*requested_prediction_span=*/0,
- [](fuchsia::scenic::scheduling::FuturePresentationTimes info) {});
-
delegate_->OnAcceleratedWidgetAvailable(window_id_);
}
@@ -247,9 +226,6 @@ void ScenicWindow::UpdateSize() {
size_dips_.height());
input_node_.SetShape(window_rect);
- // Resize the input and background nodes to cover the whole surface.
- background_node_.SetShape(window_rect);
-
// This is necessary when using vulkan because ImagePipes are presented
// separately and we need to make sure our sizes change is committed.
scenic_session_.Present2(
diff --git a/chromium/ui/ozone/platform/scenic/scenic_window.h b/chromium/ui/ozone/platform/scenic/scenic_window.h
index d70d88b218f..2edac2d4e7e 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_window.h
+++ b/chromium/ui/ozone/platform/scenic/scenic_window.h
@@ -119,10 +119,6 @@ class COMPONENT_EXPORT(OZONE) ScenicWindow
// Node in |scenic_session_| for rendering (hit testing disabled).
scenic::EntityNode render_node_;
- // Node in |scenic_session_| for rendering a solid color, placed just behind
- // |render_node_| in the Z order.
- scenic::ShapeNode background_node_;
-
std::unique_ptr<scenic::ViewHolder> surface_view_holder_;
// The ratio used for translating device-independent coordinates to absolute
diff --git a/chromium/ui/ozone/platform/scenic/scenic_window_manager.cc b/chromium/ui/ozone/platform/scenic/scenic_window_manager.cc
index b8a8c539251..6a0a177b10d 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_window_manager.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_window_manager.cc
@@ -7,8 +7,8 @@
#include <lib/sys/cpp/component_context.h>
#include <memory>
-#include "base/fuchsia/default_context.h"
#include "base/fuchsia/fuchsia_logging.h"
+#include "base/fuchsia/process_context.h"
#include "ui/ozone/platform/scenic/ozone_platform_scenic.h"
namespace ui {
@@ -33,7 +33,7 @@ std::unique_ptr<PlatformScreen> ScenicWindowManager::CreateScreen() {
fuchsia::ui::scenic::Scenic* ScenicWindowManager::GetScenic() {
if (!scenic_) {
- scenic_ = base::fuchsia::ComponentContextForCurrentProcess()
+ scenic_ = base::ComponentContextForProcess()
->svc()
->Connect<fuchsia::ui::scenic::Scenic>();
scenic_.set_error_handler(
diff --git a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc
index a1a51db49d0..d320987b58e 100644
--- a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc
+++ b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc
@@ -116,7 +116,8 @@ bool SysmemBufferCollection::IsNativePixmapConfigSupported(
format == gfx::BufferFormat::BGRX_8888;
bool usage_supported = usage == gfx::BufferUsage::SCANOUT ||
usage == gfx::BufferUsage::SCANOUT_CPU_READ_WRITE ||
- usage == gfx::BufferUsage::GPU_READ_CPU_READ_WRITE;
+ usage == gfx::BufferUsage::GPU_READ_CPU_READ_WRITE ||
+ usage == gfx::BufferUsage::GPU_READ;
return format_supported && usage_supported;
}
@@ -142,7 +143,7 @@ bool SysmemBufferCollection::Initialize(
if (vk_device == VK_NULL_HANDLE)
return false;
- size_ = size;
+ min_size_ = size;
format_ = format;
usage_ = usage;
vk_device_ = vk_device;
@@ -163,15 +164,24 @@ bool SysmemBufferCollection::Initialize(
bool SysmemBufferCollection::Initialize(
fuchsia::sysmem::Allocator_Sync* allocator,
VkDevice vk_device,
- zx::channel token_handle) {
+ zx::channel token_handle,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ bool force_protected) {
DCHECK(!collection_);
DCHECK(!vk_buffer_collection_);
- usage_ = gfx::BufferUsage::GPU_READ;
- vk_device_ = vk_device;
+ // Set nominal size of 1x1, which will be used only for
+ // vkSetBufferCollectionConstraintsFUCHSIA(). The actual size of the allocated
+ // buffers is determined by constraints set by other sysmem clients for the
+ // same collection. Size of the Vulkan image is determined by the valus passed
+ // to CreateVkImage().
+ min_size_ = gfx::Size(1, 1);
- // Assume that all imported collections are in NV12 format.
- format_ = gfx::BufferFormat::YUV_420_BIPLANAR;
+ vk_device_ = vk_device;
+ format_ = format;
+ usage_ = usage;
+ is_protected_ = force_protected;
fuchsia::sysmem::BufferCollectionTokenSyncPtr token;
token.Bind(std::move(token_handle));
@@ -206,18 +216,12 @@ scoped_refptr<gfx::NativePixmap> SysmemBufferCollection::CreateNativePixmap(
buffers_info_.settings.image_format_constraints;
// The logic should match LogicalBufferCollection::Allocate().
- size_t width =
- RoundUp(std::max(format.min_coded_width, format.required_max_coded_width),
- format.coded_width_divisor);
- size_t stride =
- RoundUp(std::max(static_cast<size_t>(format.min_bytes_per_row),
- gfx::RowSizeForBufferFormat(width, format_, 0)),
- format.bytes_per_row_divisor);
- size_t height = RoundUp(
- std::max(format.min_coded_height, format.required_max_coded_height),
- format.coded_height_divisor);
+ size_t stride = RoundUp(
+ std::max(static_cast<size_t>(format.min_bytes_per_row),
+ gfx::RowSizeForBufferFormat(image_size_.width(), format_, 0)),
+ format.bytes_per_row_divisor);
size_t plane_offset = buffers_info_.buffers[buffer_index].vmo_usable_start;
- size_t plane_size = stride * height;
+ size_t plane_size = stride * image_size_.height();
handle.planes.emplace_back(stride, plane_offset, plane_size,
std::move(main_plane_vmo));
@@ -421,7 +425,7 @@ bool SysmemBufferCollection::InitializeInternal(
ignore_result(token_channel.release());
VkImageCreateInfo image_create_info;
- InitializeImageCreateInfo(&image_create_info, size_);
+ InitializeImageCreateInfo(&image_create_info, min_size_);
if (vkSetBufferCollectionConstraintsFUCHSIA(vk_device_, vk_buffer_collection_,
&image_create_info) !=
@@ -446,6 +450,16 @@ bool SysmemBufferCollection::InitializeInternal(
DCHECK_GE(buffers_info_.buffer_count, buffers_for_camping);
DCHECK(buffers_info_.settings.has_image_format_constraints);
+ // The logic should match LogicalBufferCollection::Allocate().
+ const fuchsia::sysmem::ImageFormatConstraints& format =
+ buffers_info_.settings.image_format_constraints;
+ size_t width =
+ RoundUp(std::max(format.min_coded_width, format.required_max_coded_width),
+ format.coded_width_divisor);
+ size_t height = RoundUp(
+ std::max(format.min_coded_height, format.required_max_coded_height),
+ format.coded_height_divisor);
+ image_size_ = gfx::Size(width, height);
buffer_size_ = buffers_info_.settings.buffer_settings.size_bytes;
is_protected_ = buffers_info_.settings.buffer_settings.is_secure;
@@ -469,7 +483,13 @@ void SysmemBufferCollection::InitializeImageCreateInfo(
vk_image_info->samples = VK_SAMPLE_COUNT_1_BIT;
vk_image_info->tiling =
is_mappable() ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
+
vk_image_info->usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+ if (usage_ == gfx::BufferUsage::SCANOUT ||
+ usage_ == gfx::BufferUsage::SCANOUT_CPU_READ_WRITE) {
+ vk_image_info->usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ }
+
vk_image_info->sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vk_image_info->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
}
diff --git a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h
index 1bfed23b840..34628685327 100644
--- a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h
+++ b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h
@@ -48,7 +48,10 @@ class SysmemBufferCollection
bool Initialize(fuchsia::sysmem::Allocator_Sync* allocator,
VkDevice vk_device,
- zx::channel token);
+ zx::channel token,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ bool force_protected);
// Must not be called more than once.
void SetOnDeletedCallback(base::OnceClosure on_deleted);
@@ -70,7 +73,7 @@ class SysmemBufferCollection
gfx::SysmemBufferCollectionId id() const { return id_; }
size_t num_buffers() const { return buffers_info_.buffer_count; }
- gfx::Size size() const { return size_; }
+ gfx::Size size() const { return image_size_; }
gfx::BufferFormat format() const { return format_; }
size_t buffer_size() const {
return buffers_info_.settings.buffer_settings.size_bytes;
@@ -96,10 +99,11 @@ class SysmemBufferCollection
const gfx::SysmemBufferCollectionId id_;
- gfx::Size size_;
+ // Image size passed to vkSetBufferCollectionConstraintsFUCHSIA(). The actual
+ // buffers size may be larger depending on constraints set by other
+ // sysmem clients. Size of the image is passed to CreateVkImage().
+ gfx::Size min_size_;
- // Valid only for owned buffer collections, i.e. those that that were
- // initialized using the first Initialize() methods.
gfx::BufferFormat format_ = gfx::BufferFormat::RGBA_8888;
gfx::BufferUsage usage_ = gfx::BufferUsage::GPU_READ_CPU_READ_WRITE;
@@ -118,6 +122,7 @@ class SysmemBufferCollection
// threads.
THREAD_CHECKER(vulkan_thread_checker_);
+ gfx::Size image_size_;
size_t buffer_size_ = 0;
bool is_protected_ = false;
diff --git a/chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.cc b/chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.cc
index 2d0a2d5869a..b1bdfb23b55 100644
--- a/chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.cc
+++ b/chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.cc
@@ -51,9 +51,13 @@ scoped_refptr<SysmemBufferCollection>
SysmemBufferManager::ImportSysmemBufferCollection(
VkDevice vk_device,
gfx::SysmemBufferCollectionId id,
- zx::channel token) {
+ zx::channel token,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ bool force_protected) {
auto result = base::MakeRefCounted<SysmemBufferCollection>(id);
- if (!result->Initialize(allocator_.get(), vk_device, std::move(token))) {
+ if (!result->Initialize(allocator_.get(), vk_device, std::move(token), format,
+ usage, force_protected)) {
return nullptr;
}
RegisterCollection(result.get());
diff --git a/chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.h b/chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.h
index b726855beb2..9bc6fe9bd35 100644
--- a/chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.h
+++ b/chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.h
@@ -46,7 +46,10 @@ class SysmemBufferManager {
scoped_refptr<SysmemBufferCollection> ImportSysmemBufferCollection(
VkDevice vk_device,
gfx::SysmemBufferCollectionId id,
- zx::channel token);
+ zx::channel token,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ bool force_protected);
scoped_refptr<SysmemBufferCollection> GetCollectionById(
gfx::SysmemBufferCollectionId id);
diff --git a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
index ce74e4b9cf8..9152a959c73 100644
--- a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
+++ b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
@@ -269,7 +269,7 @@ VulkanImplementationScenic::CreateImageFromGpuMemoryHandle(
auto image = gpu::VulkanImage::Create(
device_queue, vk_image, vk_device_memory, size, vk_image_info.format,
vk_image_info.tiling, vk_device_size, 0 /* memory_type_index */,
- ycbcr_info);
+ ycbcr_info, vk_image_info.flags);
if (image->format() != vk_format) {
DLOG(ERROR) << "Unexpected format " << vk_format << " vs "
@@ -298,10 +298,16 @@ std::unique_ptr<gpu::SysmemBufferCollection>
VulkanImplementationScenic::RegisterSysmemBufferCollection(
VkDevice device,
gfx::SysmemBufferCollectionId id,
- zx::channel token) {
+ zx::channel token,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage) {
+ // SCANOUT images must be protected in protected mode.
+ bool force_protected =
+ usage == gfx::BufferUsage::SCANOUT && enforce_protected_memory();
+
return std::make_unique<SysmemBufferCollectionImpl>(
- sysmem_buffer_manager_->ImportSysmemBufferCollection(device, id,
- std::move(token)));
+ sysmem_buffer_manager_->ImportSysmemBufferCollection(
+ device, id, std::move(token), format, usage, force_protected));
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h
index 6b1a1afa1f1..cbc7e0d111b 100644
--- a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h
+++ b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h
@@ -56,7 +56,9 @@ class VulkanImplementationScenic : public gpu::VulkanImplementation {
std::unique_ptr<gpu::SysmemBufferCollection> RegisterSysmemBufferCollection(
VkDevice device,
gfx::SysmemBufferCollectionId id,
- zx::channel token) override;
+ zx::channel token,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage) override;
private:
ScenicSurfaceFactory* const scenic_surface_factory_;
diff --git a/chromium/ui/ozone/platform/wayland/BUILD.gn b/chromium/ui/ozone/platform/wayland/BUILD.gn
index b0ec8a82a5e..e0d30f2575c 100644
--- a/chromium/ui/ozone/platform/wayland/BUILD.gn
+++ b/chromium/ui/ozone/platform/wayland/BUILD.gn
@@ -18,6 +18,8 @@ source_set("wayland") {
sources = [
"client_native_pixmap_factory_wayland.cc",
"client_native_pixmap_factory_wayland.h",
+ "common/data_util.cc",
+ "common/data_util.h",
"common/wayland_object.cc",
"common/wayland_object.h",
"common/wayland_util.cc",
@@ -41,8 +43,6 @@ source_set("wayland") {
"host/gtk_primary_selection_device_manager.h",
"host/gtk_primary_selection_offer.cc",
"host/gtk_primary_selection_offer.h",
- "host/gtk_primary_selection_source.cc",
- "host/gtk_primary_selection_source.h",
"host/shell_object_factory.cc",
"host/shell_object_factory.h",
"host/shell_popup_wrapper.cc",
@@ -67,14 +67,14 @@ source_set("wayland") {
"host/wayland_data_device_base.h",
"host/wayland_data_device_manager.cc",
"host/wayland_data_device_manager.h",
+ "host/wayland_data_drag_controller.cc",
+ "host/wayland_data_drag_controller.h",
"host/wayland_data_offer.cc",
"host/wayland_data_offer.h",
"host/wayland_data_offer_base.cc",
"host/wayland_data_offer_base.h",
"host/wayland_data_source.cc",
"host/wayland_data_source.h",
- "host/wayland_data_source_base.cc",
- "host/wayland_data_source_base.h",
"host/wayland_drm.cc",
"host/wayland_drm.h",
"host/wayland_event_source.cc",
@@ -105,10 +105,14 @@ source_set("wayland") {
"host/wayland_subsurface.h",
"host/wayland_surface.cc",
"host/wayland_surface.h",
+ "host/wayland_toplevel_window.cc",
+ "host/wayland_toplevel_window.h",
"host/wayland_touch.cc",
"host/wayland_touch.h",
"host/wayland_window.cc",
"host/wayland_window.h",
+ "host/wayland_window_drag_controller.cc",
+ "host/wayland_window_drag_controller.h",
"host/wayland_window_factory.cc",
"host/wayland_window_manager.cc",
"host/wayland_window_manager.h",
@@ -140,6 +144,7 @@ source_set("wayland") {
"//skia",
"//third_party/wayland:wayland_client",
"//third_party/wayland-protocols:gtk_primary_selection_protocol",
+ "//third_party/wayland-protocols:keyboard_extension_protocol",
"//third_party/wayland-protocols:linux_dmabuf_protocol",
"//third_party/wayland-protocols:presentation_time_protocol",
"//third_party/wayland-protocols:text_input_protocol",
@@ -147,6 +152,8 @@ source_set("wayland") {
"//third_party/wayland-protocols:xdg_shell_protocol",
"//ui/base",
"//ui/base:buildflags",
+ "//ui/base/cursor",
+ "//ui/base/cursor:cursor_base",
"//ui/base/ime/linux",
"//ui/events",
"//ui/events:dom_keycode_converter",
@@ -242,6 +249,8 @@ source_set("test_support") {
"test/mock_zwp_linux_dmabuf.h",
"test/mock_zwp_text_input.cc",
"test/mock_zwp_text_input.h",
+ "test/scoped_wl_array.cc",
+ "test/scoped_wl_array.h",
"test/server_object.cc",
"test/server_object.h",
"test/test_compositor.cc",
@@ -306,12 +315,14 @@ source_set("wayland_unittests") {
"gpu/wayland_surface_factory_unittest.cc",
"host/wayland_connection_unittest.cc",
"host/wayland_data_device_unittest.cc",
+ "host/wayland_data_drag_controller_unittest.cc",
"host/wayland_event_source_unittest.cc",
"host/wayland_input_method_context_unittest.cc",
"host/wayland_keyboard_unittest.cc",
"host/wayland_pointer_unittest.cc",
"host/wayland_screen_unittest.cc",
"host/wayland_touch_unittest.cc",
+ "host/wayland_window_drag_controller_unittest.cc",
"host/wayland_window_manager_unittests.cc",
"host/wayland_window_unittest.cc",
"test/wayland_test.cc",
@@ -326,11 +337,13 @@ source_set("wayland_unittests") {
"//testing/gmock",
"//testing/gtest",
"//third_party/wayland:wayland_server",
+ "//third_party/wayland-protocols:keyboard_extension_protocol",
"//third_party/wayland-protocols:linux_dmabuf_protocol",
"//third_party/wayland-protocols:text_input_protocol",
"//third_party/wayland-protocols:xdg_shell_protocol",
"//ui/base",
"//ui/base:buildflags",
+ "//ui/base/cursor",
"//ui/base/ime/linux",
"//ui/events/ozone/layout",
"//ui/gfx/linux:drm",
diff --git a/chromium/ui/ozone/platform/wayland/DEPS b/chromium/ui/ozone/platform/wayland/DEPS
index d61519af80c..44ef7beabfd 100644
--- a/chromium/ui/ozone/platform/wayland/DEPS
+++ b/chromium/ui/ozone/platform/wayland/DEPS
@@ -8,5 +8,5 @@ include_rules = [
"+ui/base/dragdrop/drag_drop_types.h",
"+ui/base/dragdrop/file_info/file_info.h",
"+ui/base/dragdrop/os_exchange_data.h",
- "+ui/base/dragdrop/os_exchange_data_provider_aura.h",
+ "+ui/base/dragdrop/os_exchange_data_provider_non_backed.h",
]
diff --git a/chromium/ui/ozone/platform/wayland/OWNERS b/chromium/ui/ozone/platform/wayland/OWNERS
index ac018fd66db..1aa8e7e3f6f 100644
--- a/chromium/ui/ozone/platform/wayland/OWNERS
+++ b/chromium/ui/ozone/platform/wayland/OWNERS
@@ -1,2 +1,3 @@
msisov@igalia.com
+nickdiego@igalia.com
tonikitoo@igalia.com
diff --git a/chromium/ui/ozone/platform/wayland/common/data_util.cc b/chromium/ui/ozone/platform/wayland/common/data_util.cc
new file mode 100644
index 00000000000..55e594a07e3
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/common/data_util.cc
@@ -0,0 +1,218 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/common/data_util.h"
+
+#include <vector>
+
+#include "base/check.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_split.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/base/clipboard/clipboard_constants.h"
+#include "ui/base/dragdrop/file_info/file_info.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/base/dragdrop/os_exchange_data_provider_non_backed.h"
+#include "ui/ozone/public/platform_clipboard.h"
+#include "url/gurl.h"
+#include "url/url_canon.h"
+#include "url/url_util.h"
+
+namespace wl {
+
+namespace {
+
+using ui::OSExchangeData;
+using ui::PlatformClipboard;
+
+constexpr ui::FilenameToURLPolicy kFilenameToURLPolicy =
+ ui::FilenameToURLPolicy::CONVERT_FILENAMES;
+
+// Converts mime type string to OSExchangeData::Format, if supported, otherwise
+// 0 is returned.
+int MimeTypeToFormat(const std::string& mime_type) {
+ if (mime_type == ui::kMimeTypeText || mime_type == ui::kMimeTypeTextUtf8)
+ return OSExchangeData::STRING;
+ if (mime_type == ui::kMimeTypeURIList)
+ return OSExchangeData::FILE_NAME;
+ if (mime_type == ui::kMimeTypeMozillaURL)
+ return OSExchangeData::URL;
+ if (mime_type == ui::kMimeTypeHTML)
+ return OSExchangeData::HTML;
+ return 0;
+}
+
+// Converts raw data to either narrow or wide string.
+template <typename StringType>
+StringType BytesTo(const PlatformClipboard::Data& bytes) {
+ if (bytes.size() % sizeof(typename StringType::value_type) != 0U) {
+ // This is suspicious.
+ LOG(WARNING)
+ << "Data is possibly truncated, or a wrong conversion is requested.";
+ }
+
+ StringType result;
+ result.assign(reinterpret_cast<typename StringType::const_pointer>(&bytes[0]),
+ bytes.size() / sizeof(typename StringType::value_type));
+ return result;
+}
+
+void AddString(const PlatformClipboard::Data& data,
+ OSExchangeData* os_exchange_data) {
+ DCHECK(os_exchange_data);
+
+ if (data.empty())
+ return;
+
+ os_exchange_data->SetString(base::UTF8ToUTF16(BytesTo<std::string>(data)));
+}
+
+void AddHtml(const PlatformClipboard::Data& data,
+ OSExchangeData* os_exchange_data) {
+ DCHECK(os_exchange_data);
+
+ if (data.empty())
+ return;
+
+ os_exchange_data->SetHtml(base::UTF8ToUTF16(BytesTo<std::string>(data)),
+ GURL());
+}
+
+// Parses |data| as if it had text/uri-list format. Its brief spec is:
+// 1. Any lines beginning with the '#' character are comment lines.
+// 2. Non-comment lines shall be URIs (URNs or URLs).
+// 3. Lines are terminated with a CRLF pair.
+// 4. URL encoding is used.
+void AddFiles(const PlatformClipboard::Data& data,
+ OSExchangeData* os_exchange_data) {
+ DCHECK(os_exchange_data);
+
+ std::string data_as_string = BytesTo<std::string>(data);
+
+ const auto lines = base::SplitString(
+ data_as_string, "\r\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ std::vector<ui::FileInfo> filenames;
+ for (const auto& line : lines) {
+ if (line.empty() || line[0] == '#')
+ continue;
+ GURL url(line);
+ if (!url.is_valid() || !url.SchemeIsFile()) {
+ LOG(WARNING) << "Invalid URI found: " << line;
+ continue;
+ }
+
+ std::string url_path = url.path();
+ url::RawCanonOutputT<base::char16> unescaped;
+ url::DecodeURLEscapeSequences(url_path.data(), url_path.size(),
+ url::DecodeURLMode::kUTF8OrIsomorphic,
+ &unescaped);
+
+ std::string path8;
+ base::UTF16ToUTF8(unescaped.data(), unescaped.length(), &path8);
+ const base::FilePath path(path8);
+ filenames.push_back({path, path.BaseName()});
+ }
+ if (filenames.empty())
+ return;
+
+ os_exchange_data->SetFilenames(filenames);
+}
+
+// Parses |data| as if it had text/x-moz-url format, which is basically
+// two lines separated with newline, where the first line is the URL and
+// the second one is page title. The unpleasant feature of text/x-moz-url is
+// that the URL has UTF-16 encoding.
+void AddUrl(const PlatformClipboard::Data& data,
+ OSExchangeData* os_exchange_data) {
+ DCHECK(os_exchange_data);
+
+ if (data.empty())
+ return;
+
+ base::string16 data_as_string16 = BytesTo<base::string16>(data);
+
+ const auto lines =
+ base::SplitString(data_as_string16, base::ASCIIToUTF16("\r\n"),
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ if (lines.size() != 2U) {
+ LOG(WARNING) << "Invalid data passed as text/x-moz-url; it must contain "
+ << "exactly 2 lines but has " << lines.size() << " instead.";
+ return;
+ }
+ GURL url(lines[0]);
+ if (!url.is_valid()) {
+ LOG(WARNING) << "Invalid data passed as text/x-moz-url; the first line "
+ << "must contain a valid URL but it doesn't.";
+ return;
+ }
+
+ os_exchange_data->SetURL(url, lines[1]);
+}
+
+} // namespace
+
+bool IsMimeTypeSupported(const std::string& mime_type) {
+ return MimeTypeToFormat(mime_type) != 0;
+}
+
+bool ContainsMimeType(const OSExchangeData& exchange_data,
+ const std::string& mime_type) {
+ DCHECK(IsMimeTypeSupported(mime_type));
+ return exchange_data.HasAnyFormat(MimeTypeToFormat(mime_type), {});
+}
+
+void AddToOSExchangeData(const PlatformClipboard::Data& data,
+ const std::string& mime_type,
+ OSExchangeData* exchange_data) {
+ DCHECK(IsMimeTypeSupported(mime_type));
+ DCHECK(exchange_data);
+ int format = MimeTypeToFormat(mime_type);
+ switch (format) {
+ case OSExchangeData::STRING:
+ AddString(data, exchange_data);
+ break;
+ case OSExchangeData::HTML:
+ AddHtml(data, exchange_data);
+ break;
+ case OSExchangeData::URL:
+ AddUrl(data, exchange_data);
+ break;
+ case OSExchangeData::FILE_NAME:
+ AddFiles(data, exchange_data);
+ break;
+ }
+}
+
+bool ExtractOSExchangeData(const OSExchangeData& exchange_data,
+ const std::string& mime_type,
+ std::string* out_content) {
+ DCHECK(out_content);
+ DCHECK(IsMimeTypeSupported(mime_type));
+
+ if (mime_type == ui::kMimeTypeMozillaURL &&
+ exchange_data.HasURL(kFilenameToURLPolicy)) {
+ GURL url;
+ base::string16 title;
+ exchange_data.GetURLAndTitle(kFilenameToURLPolicy, &url, &title);
+ out_content->append(url.spec());
+ return true;
+ }
+ if (mime_type == ui::kMimeTypeHTML && exchange_data.HasHtml()) {
+ base::string16 data;
+ GURL base_url;
+ exchange_data.GetHtml(&data, &base_url);
+ out_content->append(base::UTF16ToUTF8(data));
+ return true;
+ }
+ if (exchange_data.HasString()) {
+ base::string16 data;
+ exchange_data.GetString(&data);
+ out_content->append(base::UTF16ToUTF8(data));
+ return true;
+ }
+ return false;
+}
+
+} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/common/data_util.h b/chromium/ui/ozone/platform/wayland/common/data_util.h
new file mode 100644
index 00000000000..d6c2d10e7f5
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/common/data_util.h
@@ -0,0 +1,40 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_COMMON_DATA_UTIL_H_
+#define UI_OZONE_PLATFORM_WAYLAND_COMMON_DATA_UTIL_H_
+
+#include <string>
+
+#include "ui/ozone/public/platform_clipboard.h"
+
+namespace ui {
+class OSExchangeData;
+} // namespace ui
+
+namespace wl {
+
+// Tells if |mime_type| is supported for Drag and Drop operations.
+bool IsMimeTypeSupported(const std::string& mime_type);
+
+// Tells if |exchange_data| contains |mime_type| content.
+bool ContainsMimeType(const ui::OSExchangeData& exchange_data,
+ const std::string& mime_type);
+
+// Add clipboard |data| content with |mime_type| format to the |exchange_data|.
+// |mime_type| is assumed to be supported (See IsMimeTypeSupported for more).
+void AddToOSExchangeData(const ui::PlatformClipboard::Data& data,
+ const std::string& mime_type,
+ ui::OSExchangeData* exchange_data);
+
+// Extract |exchange_data| of type |mime_type| and put it into |buffer|. If such
+// mime type is not present, false is returned and |buffer| keeps untouched.
+// |mime_type| is assumed to be supported (See IsMimeTypeSupported for more).
+bool ExtractOSExchangeData(const ui::OSExchangeData& exchange_data,
+ const std::string& mime_type,
+ std::string* buffer);
+
+} // namespace wl
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_COMMON_DATA_UTIL_H_
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_object.cc b/chromium/ui/ozone/platform/wayland/common/wayland_object.cc
index d0db0924463..9f9efeae72e 100644
--- a/chromium/ui/ozone/platform/wayland/common/wayland_object.cc
+++ b/chromium/ui/ozone/platform/wayland/common/wayland_object.cc
@@ -5,6 +5,7 @@
#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include <gtk-primary-selection-client-protocol.h>
+#include <keyboard-extension-unstable-v1-client-protocol.h>
#include <linux-dmabuf-unstable-v1-client-protocol.h>
#include <presentation-time-client-protocol.h>
#include <text-input-unstable-v1-client-protocol.h>
@@ -189,6 +190,16 @@ const wl_interface* ObjectTraits<xdg_positioner>::interface =
void (*ObjectTraits<xdg_positioner>::deleter)(xdg_positioner*) =
&xdg_positioner_destroy;
+const wl_interface* ObjectTraits<zcr_keyboard_extension_v1>::interface =
+ &zcr_keyboard_extension_v1_interface;
+void (*ObjectTraits<zcr_keyboard_extension_v1>::deleter)(
+ zcr_keyboard_extension_v1*) = &zcr_keyboard_extension_v1_destroy;
+
+const wl_interface* ObjectTraits<zcr_extended_keyboard_v1>::interface =
+ &zcr_extended_keyboard_v1_interface;
+void (*ObjectTraits<zcr_extended_keyboard_v1>::deleter)(
+ zcr_extended_keyboard_v1*) = &zcr_extended_keyboard_v1_destroy;
+
const wl_interface* ObjectTraits<zwp_linux_dmabuf_v1>::interface =
&zwp_linux_dmabuf_v1_interface;
void (*ObjectTraits<zwp_linux_dmabuf_v1>::deleter)(zwp_linux_dmabuf_v1*) =
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_object.h b/chromium/ui/ozone/platform/wayland/common/wayland_object.h
index 2d048ee3c5b..5c639f2db81 100644
--- a/chromium/ui/ozone/platform/wayland/common/wayland_object.h
+++ b/chromium/ui/ozone/platform/wayland/common/wayland_object.h
@@ -39,6 +39,8 @@ struct xdg_surface;
struct xdg_toplevel;
struct xdg_popup;
struct xdg_positioner;
+struct zcr_keyboard_extension_v1;
+struct zcr_extended_keyboard_v1;
struct zwp_linux_dmabuf_v1;
struct zxdg_shell_v6;
struct zxdg_surface_v6;
@@ -246,6 +248,18 @@ struct ObjectTraits<xdg_positioner> {
};
template <>
+struct ObjectTraits<zcr_keyboard_extension_v1> {
+ static const wl_interface* interface;
+ static void (*deleter)(zcr_keyboard_extension_v1*);
+};
+
+template <>
+struct ObjectTraits<zcr_extended_keyboard_v1> {
+ static const wl_interface* interface;
+ static void (*deleter)(zcr_extended_keyboard_v1*);
+};
+
+template <>
struct ObjectTraits<zwp_linux_dmabuf_v1> {
static const wl_interface* interface;
static void (*deleter)(zwp_linux_dmabuf_v1*);
diff --git a/chromium/ui/ozone/platform/wayland/gpu/drm_render_node_handle.cc b/chromium/ui/ozone/platform/wayland/gpu/drm_render_node_handle.cc
index a049ee5be98..87ec9b08f00 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/drm_render_node_handle.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/drm_render_node_handle.cc
@@ -7,6 +7,8 @@
#include <fcntl.h>
#include <xf86drm.h>
+#include "base/logging.h"
+
namespace ui {
DrmRenderNodeHandle::DrmRenderNodeHandle() = default;
diff --git a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
index 95c840cbf77..734e8b2b699 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
@@ -18,12 +18,17 @@ namespace ui {
namespace {
-void WaitForFence(EGLDisplay display, EGLSyncKHR fence) {
+void WaitForEGLFence(EGLDisplay display, EGLSyncKHR fence) {
eglClientWaitSyncKHR(display, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
EGL_FOREVER_KHR);
eglDestroySyncKHR(display, fence);
}
+void WaitForGpuFences(std::vector<std::unique_ptr<gfx::GpuFence>> fences) {
+ for (auto& fence : fences)
+ fence->Wait();
+}
+
} // namespace
GbmSurfacelessWayland::GbmSurfacelessWayland(
@@ -41,7 +46,7 @@ GbmSurfacelessWayland::GbmSurfacelessWayland(
void GbmSurfacelessWayland::QueueOverlayPlane(OverlayPlane plane,
uint32_t buffer_id) {
- planes_.push_back({std::move(plane), buffer_id});
+ unsubmitted_frames_.back()->planes.push_back({std::move(plane), buffer_id});
}
bool GbmSurfacelessWayland::ScheduleOverlayPlane(
@@ -87,7 +92,8 @@ void GbmSurfacelessWayland::SwapBuffersAsync(
TRACE_EVENT0("wayland", "GbmSurfacelessWayland::SwapBuffersAsync");
// If last swap failed, don't try to schedule new ones.
if (!last_swap_buffers_result_) {
- std::move(completion_callback).Run(gfx::SwapResult::SWAP_FAILED, nullptr);
+ std::move(completion_callback)
+ .Run(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_FAILED));
// Notify the caller, the buffer is never presented on a screen.
std::move(presentation_callback).Run(gfx::PresentationFeedback::Failure());
return;
@@ -102,21 +108,35 @@ void GbmSurfacelessWayland::SwapBuffersAsync(
PendingFrame* frame = unsubmitted_frames_.back().get();
frame->completion_callback = std::move(completion_callback);
frame->presentation_callback = std::move(presentation_callback);
+ frame->ScheduleOverlayPlanes(widget_);
+
unsubmitted_frames_.push_back(std::make_unique<PendingFrame>());
- if (!use_egl_fence_sync_) {
+ if (!use_egl_fence_sync_ || !frame->schedule_planes_succeeded) {
frame->ready = true;
SubmitFrame();
return;
}
- // TODO: the following should be replaced by a per surface flush as it gets
- // implemented in GL drivers.
- EGLSyncKHR fence = InsertFence(has_implicit_external_sync_);
- CHECK_NE(fence, EGL_NO_SYNC_KHR) << "eglCreateSyncKHR failed";
+ std::vector<std::unique_ptr<gfx::GpuFence>> fences;
+ // Uset in-fences provided in the overlays. If there are none, we insert our
+ // own fence and wait.
+ for (auto& plane : frame->planes) {
+ if (plane.plane.gpu_fence)
+ fences.push_back(std::move(plane.plane.gpu_fence));
+ }
+
+ base::OnceClosure fence_wait_task;
+ if (!fences.empty()) {
+ fence_wait_task = base::BindOnce(&WaitForGpuFences, std::move(fences));
+ } else {
+ // TODO: the following should be replaced by a per surface flush as it gets
+ // implemented in GL drivers.
+ EGLSyncKHR fence = InsertFence(has_implicit_external_sync_);
+ CHECK_NE(fence, EGL_NO_SYNC_KHR) << "eglCreateSyncKHR failed";
- base::OnceClosure fence_wait_task =
- base::BindOnce(&WaitForFence, GetDisplay(), fence);
+ fence_wait_task = base::BindOnce(&WaitForEGLFence, GetDisplay(), fence);
+ }
base::OnceClosure fence_retired_callback = base::BindOnce(
&GbmSurfacelessWayland::FenceRetired, weak_factory_.GetWeakPtr(), frame);
@@ -181,12 +201,14 @@ GbmSurfacelessWayland::PendingFrame::PendingFrame() {}
GbmSurfacelessWayland::PendingFrame::~PendingFrame() {}
-bool GbmSurfacelessWayland::PendingFrame::ScheduleOverlayPlanes(
+void GbmSurfacelessWayland::PendingFrame::ScheduleOverlayPlanes(
gfx::AcceleratedWidget widget) {
- for (auto& overlay : overlays)
+ for (auto& overlay : overlays) {
if (!overlay.ScheduleOverlayPlane(widget))
- return false;
- return true;
+ return;
+ }
+ schedule_planes_succeeded = true;
+ return;
}
void GbmSurfacelessWayland::PendingFrame::Flush() {
@@ -201,14 +223,11 @@ void GbmSurfacelessWayland::SubmitFrame() {
submitted_frame_ = std::move(unsubmitted_frames_.front());
unsubmitted_frames_.erase(unsubmitted_frames_.begin());
- bool schedule_planes_succeeded =
- submitted_frame_->ScheduleOverlayPlanes(widget_);
-
- if (!schedule_planes_succeeded) {
+ if (!submitted_frame_->schedule_planes_succeeded) {
last_swap_buffers_result_ = false;
std::move(submitted_frame_->completion_callback)
- .Run(gfx::SwapResult::SWAP_FAILED, nullptr);
+ .Run(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_FAILED));
// Notify the caller, the buffer is never presented on a screen.
std::move(submitted_frame_->presentation_callback)
.Run(gfx::PresentationFeedback::Failure());
@@ -217,11 +236,13 @@ void GbmSurfacelessWayland::SubmitFrame() {
return;
}
- submitted_frame_->buffer_id = planes_.back().buffer_id;
- buffer_manager_->CommitBuffer(widget_, submitted_frame_->buffer_id,
+ DCHECK_EQ(submitted_frame_->planes.size(), 1u);
+ submitted_frame_->buffer_id = submitted_frame_->planes.back().buffer_id;
+ buffer_manager_->CommitBuffer(widget_,
+ submitted_frame_->planes.back().buffer_id,
submitted_frame_->damage_region_);
- planes_.clear();
+ submitted_frame_->planes.clear();
}
}
@@ -247,7 +268,8 @@ void GbmSurfacelessWayland::OnSubmission(uint32_t buffer_id,
submitted_frame_->overlays.clear();
DCHECK_EQ(submitted_frame_->buffer_id, buffer_id);
- std::move(submitted_frame_->completion_callback).Run(swap_result, nullptr);
+ std::move(submitted_frame_->completion_callback)
+ .Run(gfx::SwapCompletionResult(swap_result));
pending_presentation_frames_.push_back(std::move(submitted_frame_));
diff --git a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
index 991d1718fad..137bea20432 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
+++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
@@ -71,11 +71,19 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL,
void OnPresentation(uint32_t buffer_id,
const gfx::PresentationFeedback& feedback) override;
+ struct PlaneData {
+ OverlayPlane plane;
+ // The id of the buffer, which represents buffer that backs this overlay
+ // plane.
+ const uint32_t buffer_id;
+ };
+
struct PendingFrame {
PendingFrame();
~PendingFrame();
- bool ScheduleOverlayPlanes(gfx::AcceleratedWidget widget);
+ // Queues overlay configs to |planes|.
+ void ScheduleOverlayPlanes(gfx::AcceleratedWidget widget);
void Flush();
bool ready = false;
@@ -90,11 +98,9 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL,
std::vector<gl::GLSurfaceOverlay> overlays;
SwapCompletionCallback completion_callback;
PresentationCallback presentation_callback;
- };
- struct PlaneData {
- OverlayPlane plane;
- const uint32_t buffer_id;
+ bool schedule_planes_succeeded = false;
+ std::vector<PlaneData> planes;
};
void SubmitFrame();
@@ -106,7 +112,6 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL,
void SetNoGLFlushForTests();
WaylandBufferManagerGpu* const buffer_manager_;
- std::vector<PlaneData> planes_;
// The native surface. Deleting this is allowed to free the EGLNativeWindow.
gfx::AcceleratedWidget widget_;
diff --git a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc
index 60c70c7e82e..195d061926c 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc
@@ -145,7 +145,8 @@ void GLSurfaceEglReadbackWayland::OnSubmission(
in_flight_pixel_buffers_.pop_front();
DCHECK(!completion_callbacks_.empty());
- std::move(completion_callbacks_.front()).Run(swap_result, nullptr);
+ std::move(completion_callbacks_.front())
+ .Run(gfx::SwapCompletionResult(swap_result));
completion_callbacks_.erase(completion_callbacks_.begin());
}
diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
index 585e5666283..aa649253a68 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
@@ -21,6 +21,7 @@
#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/scoped_wl_array.h"
#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
#include "ui/ozone/platform/wayland/test/test_zwp_linux_buffer_params.h"
#include "ui/ozone/platform/wayland/test/wayland_test.h"
@@ -126,8 +127,7 @@ class CallbacksHelper {
// way.
void FinishSwapBuffersAsync(uint32_t local_swap_id,
scoped_refptr<FakeGLImageNativePixmap> gl_image,
- gfx::SwapResult result,
- std::unique_ptr<gfx::GpuFence> gpu_fence) {
+ gfx::SwapCompletionResult result) {
last_finish_swap_id_ = pending_local_swap_ids_.front();
pending_local_swap_ids_.pop();
diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc
index 23e2eaf306f..1a68f9da34e 100644
--- a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc
+++ b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc
@@ -8,6 +8,7 @@
#include "ui/ozone/platform/wayland/host/gtk_primary_selection_offer.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
namespace ui {
@@ -25,6 +26,14 @@ GtkPrimarySelectionDevice::GtkPrimarySelectionDevice(
GtkPrimarySelectionDevice::~GtkPrimarySelectionDevice() = default;
+void GtkPrimarySelectionDevice::SetSelectionSource(
+ GtkPrimarySelectionSource* source) {
+ DCHECK(source);
+ gtk_primary_selection_device_set_selection(
+ data_device_.get(), source->data_source(), connection()->serial());
+ connection()->ScheduleFlush();
+}
+
// static
void GtkPrimarySelectionDevice::OnDataOffer(
void* data,
diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.h b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.h
index fc567936fe3..4bb586bffc3 100644
--- a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.h
+++ b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.h
@@ -13,6 +13,7 @@
#include "base/macros.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device_base.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
struct gtk_primary_selection_device;
@@ -31,6 +32,8 @@ class GtkPrimarySelectionDevice : public WaylandDataDeviceBase {
return data_device_.get();
}
+ void SetSelectionSource(GtkPrimarySelectionSource* source);
+
private:
// gtk_primary_selection_device_listener callbacks
static void OnDataOffer(void* data,
diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.cc b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.cc
index 90a8225bd73..3d49d7a4576 100644
--- a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.cc
+++ b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.cc
@@ -6,33 +6,42 @@
#include <gtk-primary-selection-client-protocol.h>
-#include "ui/ozone/platform/wayland/host/gtk_primary_selection_source.h"
+#include <memory>
+
+#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
namespace ui {
GtkPrimarySelectionDeviceManager::GtkPrimarySelectionDeviceManager(
gtk_primary_selection_device_manager* manager,
WaylandConnection* connection)
- : gtk_primary_selection_device_manager_(manager), connection_(connection) {
+ : device_manager_(manager), connection_(connection) {
DCHECK(connection_);
- DCHECK(gtk_primary_selection_device_manager_);
+ DCHECK(device_manager_);
}
GtkPrimarySelectionDeviceManager::~GtkPrimarySelectionDeviceManager() = default;
-gtk_primary_selection_device* GtkPrimarySelectionDeviceManager::GetDevice() {
+GtkPrimarySelectionDevice* GtkPrimarySelectionDeviceManager::GetDevice() {
DCHECK(connection_->seat());
- return gtk_primary_selection_device_manager_get_device(
- gtk_primary_selection_device_manager_.get(), connection_->seat());
+ if (!device_) {
+ device_ = std::make_unique<GtkPrimarySelectionDevice>(
+ connection_, gtk_primary_selection_device_manager_get_device(
+ device_manager_.get(), connection_->seat()));
+ }
+ DCHECK(device_);
+ return device_.get();
}
std::unique_ptr<GtkPrimarySelectionSource>
-GtkPrimarySelectionDeviceManager::CreateSource() {
- gtk_primary_selection_source* data_source =
- gtk_primary_selection_device_manager_create_source(
- gtk_primary_selection_device_manager_.get());
- return std::make_unique<GtkPrimarySelectionSource>(data_source, connection_);
+GtkPrimarySelectionDeviceManager::CreateSource(
+ GtkPrimarySelectionSource::Delegate* delegate) {
+ auto* data_source =
+ gtk_primary_selection_device_manager_create_source(device_manager_.get());
+ return std::make_unique<GtkPrimarySelectionSource>(data_source, connection_,
+ delegate);
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h
index ea05aa38882..b059c2c8621 100644
--- a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h
+++ b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h
@@ -7,34 +7,38 @@
#include <memory>
-#include "base/macros.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
-
-struct gtk_primary_selection_device_manager;
-struct gtk_primary_selection_device;
+#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
namespace ui {
-class GtkPrimarySelectionSource;
+class GtkPrimarySelectionDevice;
class WaylandConnection;
class GtkPrimarySelectionDeviceManager {
public:
+ using DataSource = GtkPrimarySelectionSource;
+ using DataDevice = GtkPrimarySelectionDevice;
+
GtkPrimarySelectionDeviceManager(
gtk_primary_selection_device_manager* manager,
WaylandConnection* connection);
+ GtkPrimarySelectionDeviceManager(const GtkPrimarySelectionDeviceManager&) =
+ delete;
+ GtkPrimarySelectionDeviceManager& operator=(
+ const GtkPrimarySelectionDeviceManager&) = delete;
~GtkPrimarySelectionDeviceManager();
- gtk_primary_selection_device* GetDevice();
- std::unique_ptr<GtkPrimarySelectionSource> CreateSource();
+ GtkPrimarySelectionDevice* GetDevice();
+ std::unique_ptr<GtkPrimarySelectionSource> CreateSource(
+ GtkPrimarySelectionSource::Delegate* delegate);
private:
- wl::Object<gtk_primary_selection_device_manager>
- gtk_primary_selection_device_manager_;
+ wl::Object<gtk_primary_selection_device_manager> device_manager_;
- WaylandConnection* connection_;
+ WaylandConnection* const connection_;
- DISALLOW_COPY_AND_ASSIGN(GtkPrimarySelectionDeviceManager);
+ std::unique_ptr<GtkPrimarySelectionDevice> device_;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_source.cc b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_source.cc
deleted file mode 100644
index 7160cdd83fa..00000000000
--- a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_source.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/ozone/platform/wayland/host/gtk_primary_selection_source.h"
-
-#include <gtk-primary-selection-client-protocol.h>
-
-#include "base/check.h"
-#include "base/files/file_util.h"
-#include "ui/base/clipboard/clipboard_constants.h"
-#include "ui/ozone/platform/wayland/host/wayland_connection.h"
-
-namespace ui {
-
-GtkPrimarySelectionSource::GtkPrimarySelectionSource(
- gtk_primary_selection_source* data_source,
- WaylandConnection* connection)
- : data_source_(data_source), connection_(connection) {
- DCHECK(connection_);
- DCHECK(data_source_);
-
- static const struct gtk_primary_selection_source_listener
- kDataSourceListener = {GtkPrimarySelectionSource::OnSend,
- GtkPrimarySelectionSource::OnCancelled};
- gtk_primary_selection_source_add_listener(data_source_.get(),
- &kDataSourceListener, this);
-}
-
-GtkPrimarySelectionSource::~GtkPrimarySelectionSource() = default;
-
-// static
-void GtkPrimarySelectionSource::OnSend(void* data,
- gtk_primary_selection_source* source,
- const char* mime_type,
- int32_t fd) {
- GtkPrimarySelectionSource* self =
- static_cast<GtkPrimarySelectionSource*>(data);
- std::string contents;
- base::Optional<std::vector<uint8_t>> mime_data;
- self->GetClipboardData(mime_type, &mime_data);
- if (!mime_data.has_value() && strcmp(mime_type, kMimeTypeTextUtf8) == 0)
- self->GetClipboardData(kMimeTypeText, &mime_data);
- contents.assign(mime_data->begin(), mime_data->end());
- bool result =
- base::WriteFileDescriptor(fd, contents.data(), contents.length());
- DCHECK(result);
- close(fd);
-}
-
-// static
-void GtkPrimarySelectionSource::OnCancelled(
- void* data,
- gtk_primary_selection_source* source) {
- GtkPrimarySelectionSource* self =
- static_cast<GtkPrimarySelectionSource*>(data);
- self->connection_->clipboard()->DataSourceCancelled(
- ClipboardBuffer::kSelection);
-}
-
-void GtkPrimarySelectionSource::WriteToClipboard(
- const PlatformClipboard::DataMap& data_map) {
- for (const auto& data : data_map) {
- gtk_primary_selection_source_offer(data_source_.get(), data.first.c_str());
- if (strcmp(data.first.c_str(), kMimeTypeText) == 0)
- gtk_primary_selection_source_offer(data_source_.get(), kMimeTypeTextUtf8);
- }
-
- gtk_primary_selection_device_set_selection(
- connection_->primary_selection_device(), data_source_.get(),
- connection_->serial());
-
- connection_->ScheduleFlush();
-}
-
-} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_source.h b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_source.h
deleted file mode 100644
index 994fffa25d3..00000000000
--- a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_source.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_SOURCE_H_
-#define UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_SOURCE_H_
-
-#include "base/macros.h"
-#include "ui/ozone/platform/wayland/common/wayland_object.h"
-#include "ui/ozone/platform/wayland/host/wayland_data_source_base.h"
-#include "ui/ozone/public/platform_clipboard.h"
-
-struct gtk_primary_selection_source;
-
-namespace ui {
-
-class WaylandConnection;
-
-class GtkPrimarySelectionSource : public WaylandDataSourceBase {
- public:
- // Takes ownership of data_source.
- GtkPrimarySelectionSource(gtk_primary_selection_source* data_source,
- WaylandConnection* connection);
- ~GtkPrimarySelectionSource() override;
-
- void WriteToClipboard(const PlatformClipboard::DataMap& data_map) override;
-
- private:
- // gtk_primary_selection_source_listener callbacks
- static void OnSend(void* data,
- gtk_primary_selection_source* source,
- const char* mime_type,
- int32_t fd);
- static void OnCancelled(void* data, gtk_primary_selection_source* source);
-
- // The gtk_primary_selection_source wrapped by this instance.
- wl::Object<gtk_primary_selection_source> data_source_;
-
- WaylandConnection* connection_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(GtkPrimarySelectionSource);
-};
-
-} // namespace ui
-
-#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_SOURCE_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc b/chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc
index 57383be20da..dea71480eb6 100644
--- a/chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc
+++ b/chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc
@@ -4,6 +4,7 @@
#include "ui/ozone/platform/wayland/host/shell_object_factory.h"
+#include "base/logging.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h"
#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h"
@@ -44,4 +45,4 @@ std::unique_ptr<ShellPopupWrapper> ShellObjectFactory::CreateShellPopupWrapper(
return nullptr;
}
-} // namespace ui \ No newline at end of file
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.cc b/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.cc
index 1dc1f4d4f76..f9f5aaa0825 100644
--- a/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.cc
+++ b/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.cc
@@ -4,6 +4,9 @@
#include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h"
+#include "base/check_op.h"
+#include "base/notreached.h"
+
namespace ui {
constexpr uint32_t kAnchorDefaultWidth = 1;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
index 96c4099fdb8..8320574a540 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
@@ -16,6 +16,7 @@
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_drm.h"
#include "ui/ozone/platform/wayland/host/wayland_shm.h"
+#include "ui/ozone/platform/wayland/host/wayland_surface.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h"
@@ -55,10 +56,10 @@ std::string NumberToString(uint32_t number) {
class WaylandBufferManagerHost::Surface {
public:
- Surface(WaylandWindow* window,
+ Surface(WaylandSurface* wayland_surface,
WaylandConnection* connection,
WaylandBufferManagerHost* buffer_manager)
- : window_(window),
+ : wayland_surface_(wayland_surface),
connection_(connection),
buffer_manager_(buffer_manager) {}
~Surface() = default;
@@ -67,7 +68,7 @@ class WaylandBufferManagerHost::Surface {
DCHECK(!pending_buffer_);
// The window has already been destroyed.
- if (!window_)
+ if (!wayland_surface_)
return true;
WaylandBuffer* buffer = GetBuffer(buffer_id);
@@ -95,23 +96,9 @@ class WaylandBufferManagerHost::Surface {
if (buffer->attached && !buffer->wl_buffer)
return false;
- // This request may come earlier than the Wayland compositor has imported a
- // wl_buffer. Wait until the buffer is created. The wait takes place only
- // once. Though, the case when a request to attach a buffer comes earlier
- // than the wl_buffer is created does not happen often. 1) Depending on the
- // zwp linux dmabuf protocol version, the wl_buffer can be created
- // immediately without asynchronous wait 2) the wl_buffer can have been
- // created by this time.
- //
- // Another case, which always happen is waiting until the frame callback is
- // completed. Thus, wait here when the Wayland compositor fires the frame
- // callback.
- if (!buffer->wl_buffer || wl_frame_callback_) {
- pending_buffer_ = buffer;
- return true;
- }
-
- return CommitBufferInternal(buffer);
+ pending_buffer_ = buffer;
+ MaybeProcessPendingBuffer();
+ return true;
}
bool CreateBuffer(const gfx::Size& size, uint32_t buffer_id) {
@@ -140,7 +127,7 @@ class WaylandBufferManagerHost::Surface {
// the client about successful swap.
// If the window has already been destroyed, no need to complete the
// submission.
- if (buffer && !buffer->released && submitted_buffer_ && window_)
+ if (buffer && !buffer->released && submitted_buffer_ && wayland_surface_)
CompleteSubmission();
if (prev_submitted_buffer_ == buffer)
@@ -167,8 +154,8 @@ class WaylandBufferManagerHost::Surface {
if (buffer->wl_buffer)
SetupBufferReleaseListener(buffer);
- if (pending_buffer_ == buffer && !wl_frame_callback_)
- ProcessPendingBuffer();
+ if (pending_buffer_ == buffer)
+ MaybeProcessPendingBuffer();
}
void ClearState() {
@@ -186,17 +173,23 @@ class WaylandBufferManagerHost::Surface {
}
void ResetSurfaceContents() {
- if (!window_)
+ if (!wayland_surface_)
return;
- wl_surface_attach(window_->surface(), nullptr, 0, 0);
- wl_surface_commit(window_->surface());
+ wl_surface_attach(wayland_surface_->surface(), nullptr, 0, 0);
+ wl_surface_commit(wayland_surface_->surface());
// We cannot reset |prev_submitted_buffer_| here as long as the surface
// might have attached a new buffer and is about to receive a release
// callback. Check more comments below where the variable is declared.
contents_reset_ = true;
+ // ResetSurfaceContents happens upon WaylandWindow::Hide call, which
+ // destroyes xdg_surface, xdg_popup, etc. They are going to be reinitialized
+ // once WaylandWindow::Show is called. Thus, they will have to be configured
+ // once again before buffers can be attached.
+ configured_ = false;
+
connection_->ScheduleFlush();
}
@@ -207,8 +200,16 @@ class WaylandBufferManagerHost::Surface {
bool HasBuffers() const { return !buffers_.empty(); }
- void OnWindowRemoved() { window_ = nullptr; }
- bool HasWindow() const { return !!window_; }
+ void OnWindowRemoved() { wayland_surface_ = nullptr; }
+ bool HasWindow() const { return !!wayland_surface_; }
+
+ void OnWindowConfigured() {
+ if (configured_)
+ return;
+
+ configured_ = true;
+ MaybeProcessPendingBuffer();
+ }
private:
struct FeedbackInfo {
@@ -226,7 +227,7 @@ class WaylandBufferManagerHost::Surface {
using PresentationFeedbackQueue = std::vector<FeedbackInfo>;
bool CommitBufferInternal(WaylandBuffer* buffer) {
- DCHECK(buffer && window_);
+ DCHECK(buffer && wayland_surface_);
DCHECK(!pending_buffer_);
DCHECK(!submitted_buffer_);
@@ -274,7 +275,7 @@ class WaylandBufferManagerHost::Surface {
}
void DamageBuffer(WaylandBuffer* buffer) {
- DCHECK(window_);
+ DCHECK(wayland_surface_);
gfx::Rect pending_damage_region = std::move(buffer->damage_region);
// If the size of the damage region is empty, wl_surface_damage must be
@@ -290,10 +291,10 @@ class WaylandBufferManagerHost::Surface {
// https://bit.ly/2u00lv6 for details.
// We don't need to apply any scaling because pending_damage_region is
// already in buffer coordinates.
- wl_surface_damage_buffer(window_->surface(), pending_damage_region.x(),
- pending_damage_region.y(),
- pending_damage_region.width(),
- pending_damage_region.height());
+ wl_surface_damage_buffer(
+ wayland_surface_->surface(), pending_damage_region.x(),
+ pending_damage_region.y(), pending_damage_region.width(),
+ pending_damage_region.height());
} else {
// The calculation for damage region relies on two assumptions:
// 1) The buffer is always attached at surface location (0, 0)
@@ -304,8 +305,9 @@ class WaylandBufferManagerHost::Surface {
// Note: The damage region may not be an integer multiple of scale. To
// keep the implementation simple, the x() and y() coordinates round down,
// and the width() and height() calculations always add an extra pixel.
- int scale = window_->buffer_scale();
- wl_surface_damage(window_->surface(), pending_damage_region.x() / scale,
+ int scale = wayland_surface_->buffer_scale();
+ wl_surface_damage(wayland_surface_->surface(),
+ pending_damage_region.x() / scale,
pending_damage_region.y() / scale,
pending_damage_region.width() / scale + 1,
pending_damage_region.height() / scale + 1);
@@ -313,31 +315,32 @@ class WaylandBufferManagerHost::Surface {
}
void AttachBuffer(WaylandBuffer* buffer) {
- DCHECK(window_);
+ DCHECK(wayland_surface_ && configured_);
// The logic in DamageBuffer currently relies on attachment coordinates of
// (0, 0). If this changes, then the calculation in DamageBuffer will also
// need to be updated.
- wl_surface_attach(window_->surface(), buffer->wl_buffer.get(), 0, 0);
+ wl_surface_attach(wayland_surface_->surface(), buffer->wl_buffer.get(), 0,
+ 0);
}
void CommitSurface() {
- DCHECK(window_);
- wl_surface_commit(window_->surface());
+ DCHECK(wayland_surface_);
+ wl_surface_commit(wayland_surface_->surface());
}
void SetupFrameCallback() {
- DCHECK(window_);
+ DCHECK(wayland_surface_);
static const wl_callback_listener frame_listener = {
&Surface::FrameCallbackDone};
DCHECK(!wl_frame_callback_);
- wl_frame_callback_.reset(wl_surface_frame(window_->surface()));
+ wl_frame_callback_.reset(wl_surface_frame(wayland_surface_->surface()));
wl_callback_add_listener(wl_frame_callback_.get(), &frame_listener, this);
}
void SetupPresentationFeedback(uint32_t buffer_id) {
- DCHECK(window_);
+ DCHECK(wayland_surface_);
// Set up presentation feedback.
if (!connection_->presentation())
return;
@@ -348,7 +351,7 @@ class WaylandBufferManagerHost::Surface {
feedback_queue_.push_back(
{wl::Object<struct wp_presentation_feedback>(wp_presentation_feedback(
- connection_->presentation(), window_->surface())),
+ connection_->presentation(), wayland_surface_->surface())),
buffer_id, /*feedback=*/base::nullopt,
/*submission_completed=*/false});
wp_presentation_feedback_add_listener(
@@ -372,7 +375,7 @@ class WaylandBufferManagerHost::Surface {
DCHECK(wl_frame_callback_.get() == callback);
wl_frame_callback_.reset();
- ProcessPendingBuffer();
+ MaybeProcessPendingBuffer();
}
// wl_callback_listener
@@ -438,13 +441,13 @@ class WaylandBufferManagerHost::Surface {
prev_submitted_buffer_ = submitted_buffer_;
submitted_buffer_ = nullptr;
- if (!window_)
+ if (!wayland_surface_)
return;
// We can now complete the latest submission. We had to wait for this
// release because SwapCompletionCallback indicates to the client that the
// previous buffer is available for reuse.
- buffer_manager_->OnSubmission(window_->GetWidget(), id,
+ buffer_manager_->OnSubmission(wayland_surface_->GetRootWidget(), id,
gfx::SwapResult::SWAP_ACK);
// If presentation feedback is not supported, use a fake feedback. This
@@ -452,7 +455,7 @@ class WaylandBufferManagerHost::Surface {
if (!connection_->presentation()) {
DCHECK(feedback_queue_.empty());
buffer_manager_->OnPresentation(
- window_->GetWidget(), id,
+ wayland_surface_->GetWidget(), id,
gfx::PresentationFeedback(base::TimeTicks::Now(), base::TimeDelta(),
GetPresentationKindFlags(0)));
} else {
@@ -468,13 +471,20 @@ class WaylandBufferManagerHost::Surface {
}
void OnPresentation(struct wp_presentation_feedback* wp_presentation_feedback,
- const gfx::PresentationFeedback& feedback) {
+ const gfx::PresentationFeedback& feedback,
+ bool discarded = false) {
FeedbackInfo* feedback_info = nullptr;
for (auto& info : feedback_queue_) {
if (info.wp_presentation_feedback.get() == wp_presentation_feedback) {
feedback_info = &info;
break;
- } else if (!info.feedback.has_value()) { // Feedback must come in order.
+ } else if (!info.feedback.has_value() && !discarded) {
+ // Feedback must come in order. However, if one of the feedbacks was
+ // discarded and the previous feedbacks haven't been received yet, don't
+ // mark previous feedbacks as failed as they will come later. For
+ // example, imagine you are waiting for f[0], f[1] and f[2]. f[2] gets
+ // discarded, previous ones mustn't be marked as failed as they will
+ // come later.
info.feedback = gfx::PresentationFeedback::Failure();
}
}
@@ -499,15 +509,15 @@ class WaylandBufferManagerHost::Surface {
// This function ensures that we send OnPresentation for each buffer that
// already has had OnSubmission called for it (condition #2).
void ProcessPresentationFeedbacks() {
- if (!window_)
+ if (!wayland_surface_)
return;
while (!feedback_queue_.empty()) {
const auto& info = feedback_queue_.front();
if (!info.submission_completed || !info.feedback.has_value())
break;
- buffer_manager_->OnPresentation(window_->GetWidget(), info.buffer_id,
- *info.feedback);
+ buffer_manager_->OnPresentation(wayland_surface_->GetWidget(),
+ info.buffer_id, *info.feedback);
feedback_queue_.erase(feedback_queue_.begin());
}
// This queue should be small - if not it's likely a bug.
@@ -546,11 +556,31 @@ class WaylandBufferManagerHost::Surface {
Surface* self = static_cast<Surface*>(data);
DCHECK(self);
self->OnPresentation(wp_presentation_feedback,
- gfx::PresentationFeedback::Failure());
+ gfx::PresentationFeedback::Failure(),
+ true /* discarded */);
}
- void ProcessPendingBuffer() {
- if (!pending_buffer_ || !window_)
+ void MaybeProcessPendingBuffer() {
+ // There is nothing to process if there is no pending buffer or the window
+ // has been destroyed.
+ if (!pending_buffer_ || !wayland_surface_)
+ return;
+
+ // This request may come earlier than the Wayland compositor has imported a
+ // wl_buffer. Wait until the buffer is created. The wait takes place only
+ // once. Though, the case when a request to attach a buffer comes earlier
+ // than the wl_buffer is created does not happen often. 1) Depending on the
+ // zwp linux dmabuf protocol version, the wl_buffer can be created
+ // immediately without asynchronous wait 2) the wl_buffer can have been
+ // created by this time.
+ //
+ // Another case, which always happen is waiting until the frame callback is
+ // completed. Thus, wait here when the Wayland compositor fires the frame
+ // callback.
+ //
+ // The third case happens if the window hasn't been configured until a
+ // request to attach a buffer to its surface is sent.
+ if (!pending_buffer_->wl_buffer || wl_frame_callback_ || !configured_)
return;
auto* buffer = pending_buffer_;
@@ -562,7 +592,7 @@ class WaylandBufferManagerHost::Surface {
// WaylandWindow.
// Non-owned. The window this helper surface stores and submits buffers for.
- const WaylandWindow* window_;
+ const WaylandSurface* wayland_surface_;
// Non-owned pointer to the connection.
WaylandConnection* const connection_;
@@ -598,6 +628,11 @@ class WaylandBufferManagerHost::Surface {
// a need to call submission callback manually.
bool contents_reset_ = false;
+ // If WaylandWindow has never been configured, do not try to attach
+ // buffers to its surface. Otherwise, Wayland server will drop the connection
+ // and send an error - "The surface has never been configured.".
+ bool configured_ = false;
+
DISALLOW_COPY_AND_ASSIGN(Surface);
};
@@ -619,7 +654,7 @@ WaylandBufferManagerHost::~WaylandBufferManagerHost() {
void WaylandBufferManagerHost::OnWindowAdded(WaylandWindow* window) {
DCHECK(window);
surfaces_[window->GetWidget()] =
- std::make_unique<Surface>(window, connection_, this);
+ std::make_unique<Surface>(window->wayland_surface(), connection_, this);
}
void WaylandBufferManagerHost::OnWindowRemoved(WaylandWindow* window) {
@@ -632,6 +667,13 @@ void WaylandBufferManagerHost::OnWindowRemoved(WaylandWindow* window) {
surfaces_.erase(it);
}
+void WaylandBufferManagerHost::OnWindowConfigured(WaylandWindow* window) {
+ DCHECK(window);
+ auto it = surfaces_.find(window->GetWidget());
+ DCHECK(it != surfaces_.end());
+ it->second->OnWindowConfigured();
+}
+
void WaylandBufferManagerHost::SetTerminateGpuCallback(
base::OnceCallback<void(std::string)> terminate_callback) {
terminate_gpu_cb_ = std::move(terminate_callback);
@@ -923,11 +965,10 @@ bool WaylandBufferManagerHost::ValidateBufferIdFromGpu(uint32_t buffer_id) {
return true;
}
-bool WaylandBufferManagerHost::ValidateDataFromGpu(
- const base::ScopedFD& fd,
- size_t length,
- const gfx::Size& size,
- uint32_t buffer_id) {
+bool WaylandBufferManagerHost::ValidateDataFromGpu(const base::ScopedFD& fd,
+ size_t length,
+ const gfx::Size& size,
+ uint32_t buffer_id) {
if (!ValidateBufferIdFromGpu(buffer_id))
return false;
@@ -952,21 +993,20 @@ bool WaylandBufferManagerHost::ValidateDataFromGpu(
void WaylandBufferManagerHost::OnCreateBufferComplete(
uint32_t buffer_id,
wl::Object<struct wl_buffer> new_buffer) {
- auto it = anonymous_buffers_.find(buffer_id);
- // It might have already been destroyed or stored by any of the surfaces.
- if (it != anonymous_buffers_.end()) {
- it->second->wl_buffer = std::move(new_buffer);
- } else {
- for (auto& surface : surfaces_) {
- if (surface.second->BufferExists(buffer_id)) {
- surface.second.get()->AttachWlBuffer(buffer_id,
- std::move(new_buffer));
- break;
- }
+ auto it = anonymous_buffers_.find(buffer_id);
+ // It might have already been destroyed or stored by any of the surfaces.
+ if (it != anonymous_buffers_.end()) {
+ it->second->wl_buffer = std::move(new_buffer);
+ } else {
+ for (auto& surface : surfaces_) {
+ if (surface.second->BufferExists(buffer_id)) {
+ surface.second.get()->AttachWlBuffer(buffer_id, std::move(new_buffer));
+ break;
}
}
- // There is no need for the buffer anymore. Let it go out of the scope and
- // be destroyed.
+ }
+ // There is no need for the buffer anymore. Let it go out of the scope and
+ // be destroyed.
}
void WaylandBufferManagerHost::OnSubmission(
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
index c0c6809cad2..b467835f726 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
@@ -81,6 +81,7 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
// WaylandWindowObserver implements:
void OnWindowAdded(WaylandWindow* window) override;
void OnWindowRemoved(WaylandWindow* window) override;
+ void OnWindowConfigured(WaylandWindow* window) override;
void SetTerminateGpuCallback(
base::OnceCallback<void(std::string)> terminate_gpu_cb);
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc
index 11add83d1b0..a0e848a216d 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc
@@ -4,28 +4,137 @@
#include "ui/ozone/platform/wayland/host/wayland_clipboard.h"
+#include <memory>
#include <string>
+#include "base/check.h"
+#include "base/notreached.h"
+#include "ui/base/clipboard/clipboard_buffer.h"
+#include "ui/base/clipboard/clipboard_constants.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device.h"
#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h"
-#include "ui/ozone/platform/wayland/host/gtk_primary_selection_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
-#include "ui/ozone/platform/wayland/host/wayland_data_source_base.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
+#include "ui/ozone/public/platform_clipboard.h"
+
+namespace wl {
+
+// Internal Wayland Clipboard interface. A wl::Clipboard implementation handles
+// a single ui::ClipboardBuffer. With this common interface it is possible to
+// seamlessly support different clipboard buffers backed by different underlying
+// Wayland protocol objects.
+class Clipboard {
+ public:
+ virtual ~Clipboard() = default;
+
+ // Synchronously retrieves the mime types list currently available to be read.
+ virtual std::vector<std::string> ReadMimeTypes() = 0;
+
+ // Asynchronously reads clipboard content with |mime_type| format. The result
+ // data is expected to arrive through WaylandClipboard::SetData().
+ // TODO(nickdiego): Decouple DataDevice impls from WaylandClipboard.
+ virtual bool Read(const std::string& mime_type) = 0;
+
+ // Synchronously stores and announces |data| as available from this clipboard.
+ virtual void Write(const ui::PlatformClipboard::DataMap* data) = 0;
+
+ // Tells if this clipboard instance is the current selection owner.
+ virtual bool IsSelectionOwner() const = 0;
+};
+
+// Templated wl::Clipboard implementation. Whereas DataSource is the data source
+// class capable of creating data offers upon clipboard writes and communicates
+// events through DataSource::Delegate, and DataDevice is its device counterpart
+// providing read and write access to the underlying data selection-related
+// protocol objects. See *_data_{source,device}.h for more details.
+template <typename Manager,
+ typename DataSource = typename Manager::DataSource,
+ typename DataDevice = typename Manager::DataDevice>
+class ClipboardImpl final : public Clipboard, public DataSource::Delegate {
+ public:
+ explicit ClipboardImpl(Manager* manager) : manager_(manager) {}
+ ClipboardImpl(const ClipboardImpl&) = delete;
+ ClipboardImpl& operator=(const ClipboardImpl&) = delete;
+ virtual ~ClipboardImpl() = default;
+
+ virtual bool Read(const std::string& mime_type) override {
+ return GetDevice()->RequestSelectionData(mime_type);
+ }
+
+ std::vector<std::string> ReadMimeTypes() override {
+ return GetDevice()->GetAvailableMimeTypes();
+ }
+
+ virtual void Write(const ui::PlatformClipboard::DataMap* data) override {
+ if (!data || data->empty()) {
+ data_.clear();
+ source_.reset();
+ } else {
+ data_ = *data;
+ if (!source_)
+ source_ = manager_->CreateSource(this);
+ source_->Offer(GetMimeTypes());
+ GetDevice()->SetSelectionSource(source_.get());
+ }
+ }
+
+ bool IsSelectionOwner() const override { return !!source_; }
+
+ private:
+ DataDevice* GetDevice() { return manager_->GetDevice(); }
+
+ std::vector<std::string> GetMimeTypes() {
+ std::vector<std::string> mime_types;
+ for (const auto& data : data_) {
+ mime_types.push_back(data.first);
+ if (data.first == ui::kMimeTypeText)
+ mime_types.push_back(ui::kMimeTypeTextUtf8);
+ }
+ return mime_types;
+ }
+
+ // WaylandDataSource::Delegate:
+ void OnDataSourceFinish(bool completed) override {
+ if (!completed)
+ Write(nullptr);
+ }
+
+ void OnDataSourceSend(const std::string& mime_type,
+ std::string* contents) override {
+ DCHECK(contents);
+ auto it = data_.find(mime_type);
+ if (it == data_.end() && mime_type == ui::kMimeTypeTextUtf8)
+ it = data_.find(ui::kMimeTypeText);
+ if (it != data_.end())
+ contents->assign(it->second.begin(), it->second.end());
+ }
+
+ // The device manager used to access data device and create data sources.
+ Manager* const manager_;
+
+ // The current data source used to offer clipboard data.
+ std::unique_ptr<DataSource> source_;
+
+ // The data currently stored in a given clipboard buffer.
+ ui::PlatformClipboard::DataMap data_;
+};
+
+} // namespace wl
namespace ui {
-WaylandClipboard::WaylandClipboard(
- WaylandDataDeviceManager* data_device_manager,
- WaylandDataDevice* data_device,
- GtkPrimarySelectionDeviceManager* primary_selection_device_manager,
- GtkPrimarySelectionDevice* primary_selection_device)
- : data_device_manager_(data_device_manager),
- data_device_(data_device),
- primary_selection_device_manager_(primary_selection_device_manager),
- primary_selection_device_(primary_selection_device) {
- DCHECK(data_device_manager_);
- DCHECK(data_device_);
+WaylandClipboard::WaylandClipboard(WaylandConnection* connection,
+ WaylandDataDeviceManager* manager)
+ : connection_(connection),
+ copypaste_clipboard_(
+ std::make_unique<wl::ClipboardImpl<WaylandDataDeviceManager>>(
+ manager)) {
+ DCHECK(manager);
+ DCHECK(connection_);
+ DCHECK(copypaste_clipboard_);
}
WaylandClipboard::~WaylandClipboard() = default;
@@ -34,25 +143,8 @@ void WaylandClipboard::OfferClipboardData(
ClipboardBuffer buffer,
const PlatformClipboard::DataMap& data_map,
PlatformClipboard::OfferDataClosure callback) {
- WaylandDataSourceBase* data_source = nullptr;
- if (buffer == ClipboardBuffer::kCopyPaste) {
- if (!clipboard_data_source_)
- clipboard_data_source_ = data_device_manager_->CreateSource();
- data_source = clipboard_data_source_.get();
- } else {
- if (!IsPrimarySelectionSupported()) {
- std::move(callback).Run();
- return;
- }
- if (!primary_data_source_)
- primary_data_source_ = primary_selection_device_manager_->CreateSource();
- data_source = primary_data_source_.get();
- }
-
- DCHECK(data_source);
- data_source->WriteToClipboard(data_map);
- data_source->set_data_map(data_map);
-
+ if (auto* clipboard = GetClipboard(buffer))
+ clipboard->Write(&data_map);
std::move(callback).Run();
}
@@ -61,25 +153,18 @@ void WaylandClipboard::RequestClipboardData(
const std::string& mime_type,
PlatformClipboard::DataMap* data_map,
PlatformClipboard::RequestDataClosure callback) {
- read_clipboard_closure_ = std::move(callback);
DCHECK(data_map);
data_map_ = data_map;
- if (buffer == ClipboardBuffer::kCopyPaste) {
- if (!data_device_->RequestSelectionData(mime_type))
- SetData({}, mime_type);
- } else {
- if (!IsPrimarySelectionSupported() ||
- !primary_selection_device_->RequestSelectionData(mime_type)) {
- SetData({}, mime_type);
- }
- }
+ read_clipboard_closure_ = std::move(callback);
+ auto* clipboard = GetClipboard(buffer);
+ if (!clipboard || !clipboard->Read(mime_type))
+ SetData({}, mime_type);
}
bool WaylandClipboard::IsSelectionOwner(ClipboardBuffer buffer) {
- if (buffer == ClipboardBuffer::kCopyPaste)
- return !!clipboard_data_source_;
- else
- return !!primary_data_source_;
+ if (auto* clipboard = GetClipboard(buffer))
+ return clipboard->IsSelectionOwner();
+ return false;
}
void WaylandClipboard::SetSequenceNumberUpdateCb(
@@ -92,26 +177,10 @@ void WaylandClipboard::SetSequenceNumberUpdateCb(
void WaylandClipboard::GetAvailableMimeTypes(
ClipboardBuffer buffer,
PlatformClipboard::GetMimeTypesClosure callback) {
- if (buffer == ClipboardBuffer::kCopyPaste) {
- std::move(callback).Run(data_device_->GetAvailableMimeTypes());
- } else {
- std::move(callback).Run(
- IsPrimarySelectionSupported()
- ? primary_selection_device_->GetAvailableMimeTypes()
- : std::vector<std::string>{});
- }
-}
-
-void WaylandClipboard::DataSourceCancelled(ClipboardBuffer buffer) {
- if (buffer == ClipboardBuffer::kCopyPaste) {
- DCHECK(clipboard_data_source_);
- SetData({}, {});
- clipboard_data_source_.reset();
- } else {
- DCHECK(primary_data_source_);
- SetData({}, {});
- primary_data_source_.reset();
- }
+ std::vector<std::string> mime_types;
+ if (auto* clipboard = GetClipboard(buffer))
+ mime_types = clipboard->ReadMimeTypes();
+ std::move(callback).Run(mime_types);
}
void WaylandClipboard::SetData(const std::vector<uint8_t>& contents,
@@ -134,8 +203,24 @@ void WaylandClipboard::UpdateSequenceNumber(ClipboardBuffer buffer) {
update_sequence_cb_.Run(buffer);
}
-bool WaylandClipboard::IsPrimarySelectionSupported() const {
- return primary_selection_device_manager_ && primary_selection_device_;
+wl::Clipboard* WaylandClipboard::GetClipboard(ClipboardBuffer buffer) {
+ if (buffer == ClipboardBuffer::kCopyPaste)
+ return copypaste_clipboard_.get();
+
+ if (buffer == ClipboardBuffer::kSelection) {
+ if (auto* manager = connection_->primary_selection_device_manager()) {
+ if (!primary_selection_clipboard_) {
+ primary_selection_clipboard_ = std::make_unique<
+ wl::ClipboardImpl<GtkPrimarySelectionDeviceManager>>(manager);
+ }
+ return primary_selection_clipboard_.get();
+ }
+ // Primary selection extension not available.
+ return nullptr;
+ }
+
+ NOTREACHED() << "Unsupported clipboard buffer: " << static_cast<int>(buffer);
+ return nullptr;
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h
index a4482490071..d4641406e0c 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h
@@ -5,33 +5,36 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CLIPBOARD_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CLIPBOARD_H_
+#include <memory>
#include <string>
#include <vector>
#include "base/callback.h"
+#include "base/containers/flat_map.h"
#include "base/macros.h"
-#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
+#include "base/optional.h"
+#include "ui/base/clipboard/clipboard_buffer.h"
#include "ui/ozone/public/platform_clipboard.h"
+namespace wl {
+class Clipboard;
+} // namespace wl
+
namespace ui {
-class GtkPrimarySelectionDevice;
-class GtkPrimarySelectionDeviceManager;
-class GtkPrimarySelectionSource;
-class WaylandDataDevice;
+class WaylandConnection;
class WaylandDataDeviceManager;
// Handles clipboard operations.
//
-// Owned by WaylandConnection, which provides a data device and a data device
-// manager.
+// WaylandDataDeviceManager singleton is required to be up and running for
+// WaylandClipboard to be minimally functional.
class WaylandClipboard : public PlatformClipboard {
public:
- WaylandClipboard(
- WaylandDataDeviceManager* data_device_manager,
- WaylandDataDevice* data_device,
- GtkPrimarySelectionDeviceManager* primary_selection_device_manager,
- GtkPrimarySelectionDevice* primary_selection_device);
+ WaylandClipboard(WaylandConnection* connection,
+ WaylandDataDeviceManager* device_manager);
+ WaylandClipboard(const WaylandClipboard&) = delete;
+ WaylandClipboard& operator=(const WaylandClipboard&) = delete;
~WaylandClipboard() override;
// PlatformClipboard.
@@ -51,35 +54,34 @@ class WaylandClipboard : public PlatformClipboard {
void SetSequenceNumberUpdateCb(
PlatformClipboard::SequenceNumberUpdateCb cb) override;
- void DataSourceCancelled(ClipboardBuffer buffer);
+ // TODO(nickdiego): Get rid of these methods once DataDevice implementations
+ // are decoupled from WaylandClipboard.
void SetData(const std::vector<uint8_t>& contents,
const std::string& mime_type);
void UpdateSequenceNumber(ClipboardBuffer buffer);
private:
- bool IsPrimarySelectionSupported() const;
+ // Get the wl::Clipboard instance owning a given |buffer|. Can return null in
+ // case |buffer| is unsupported. E.g: primary selection is not available.
+ wl::Clipboard* GetClipboard(ClipboardBuffer buffer);
+
+ // WaylandConnection providing optional data device managers, e.g: gtk
+ // primary selection.
+ WaylandConnection* const connection_;
// Holds a temporary instance of the client's clipboard content
// so that we can asynchronously write to it.
PlatformClipboard::DataMap* data_map_ = nullptr;
- // Notifies whenever clipboard sequence number is changed. Can be empty if not
- // set.
+ // Notifies whenever clipboard sequence number is changed. Can be empty if
+ // not set.
PlatformClipboard::SequenceNumberUpdateCb update_sequence_cb_;
// Stores the callback to be invoked upon data reading from clipboard.
PlatformClipboard::RequestDataClosure read_clipboard_closure_;
- std::unique_ptr<WaylandDataSource> clipboard_data_source_;
- std::unique_ptr<GtkPrimarySelectionSource> primary_data_source_;
-
- // These four instances are owned by the connection.
- WaylandDataDeviceManager* const data_device_manager_;
- WaylandDataDevice* const data_device_;
- GtkPrimarySelectionDeviceManager* const primary_selection_device_manager_;
- GtkPrimarySelectionDevice* const primary_selection_device_;
-
- DISALLOW_COPY_AND_ASSIGN(WaylandClipboard);
+ const std::unique_ptr<wl::Clipboard> copypaste_clipboard_;
+ std::unique_ptr<wl::Clipboard> primary_selection_clipboard_;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc b/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc
index d6c27854df9..0246bc58695 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc
@@ -9,7 +9,7 @@
#include <algorithm>
#include <memory>
-#include <utility>
+#include <vector>
#include "base/bind.h"
#include "base/logging.h"
@@ -17,12 +17,16 @@
#include "base/message_loop/message_loop_current.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "mojo/public/cpp/system/platform_handle.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
-#include "ui/gfx/swap_result.h"
+#include "ui/gfx/geometry/point.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
+#include "ui/ozone/platform/wayland/host/wayland_clipboard.h"
#include "ui/ozone/platform/wayland/host/wayland_cursor.h"
+#include "ui/ozone/platform/wayland/host/wayland_cursor_position.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h"
#include "ui/ozone/platform/wayland/host/wayland_drm.h"
#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
#include "ui/ozone/platform/wayland/host/wayland_input_method_context.h"
@@ -32,6 +36,7 @@
#include "ui/ozone/platform/wayland/host/wayland_shm.h"
#include "ui/ozone/platform/wayland/host/wayland_touch.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_window_drag_controller.h"
#include "ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h"
namespace ui {
@@ -39,6 +44,7 @@ namespace ui {
namespace {
constexpr uint32_t kMaxCompositorVersion = 4;
constexpr uint32_t kMaxGtkPrimarySelectionDeviceManagerVersion = 1;
+constexpr uint32_t kMaxKeyboardExtensionVersion = 1;
constexpr uint32_t kMaxLinuxDmabufVersion = 3;
constexpr uint32_t kMaxSeatVersion = 4;
constexpr uint32_t kMaxShmVersion = 1;
@@ -128,39 +134,10 @@ void WaylandConnection::SetCursorBitmap(const std::vector<SkBitmap>& bitmaps,
cursor_->UpdateBitmap(bitmaps, location, serial_);
}
-void WaylandConnection::StartDrag(const ui::OSExchangeData& data,
- int operation) {
- if (!dragdrop_data_source_)
- dragdrop_data_source_ = data_device_manager_->CreateSource();
- dragdrop_data_source_->Offer(data);
- dragdrop_data_source_->SetAction(operation);
- data_device_->StartDrag(dragdrop_data_source_->data_source(), data);
-}
-
-void WaylandConnection::FinishDragSession(uint32_t dnd_action,
- WaylandWindow* source_window) {
- if (source_window)
- source_window->OnDragSessionClose(dnd_action);
- data_device_->ResetSourceData();
- dragdrop_data_source_.reset();
-}
-
-void WaylandConnection::DeliverDragData(const std::string& mime_type,
- std::string* buffer) {
- data_device_->DeliverDragData(mime_type, buffer);
-}
-
-void WaylandConnection::RequestDragData(
- const std::string& mime_type,
- base::OnceCallback<void(const std::vector<uint8_t>&)> callback) {
- data_device_->RequestDragData(mime_type, std::move(callback));
-}
-
-bool WaylandConnection::IsDragInProgress() {
- // |data_device_| can be null when running on headless weston.
- if (!data_device_)
- return false;
- return data_device_->IsDragEntered() || drag_data_source();
+bool WaylandConnection::IsDragInProgress() const {
+ // |data_drag_controller_| can be null when running on headless weston.
+ return data_drag_controller_ && data_drag_controller_->state() !=
+ WaylandDataDragController::State::kIdle;
}
void WaylandConnection::Flush() {
@@ -190,13 +167,8 @@ void WaylandConnection::UpdateInputDevices(wl_seat* seat,
if (!has_keyboard) {
keyboard_.reset();
- } else if (wl_keyboard* keyboard = wl_seat_get_keyboard(seat)) {
- auto* layout_engine =
- KeyboardLayoutEngineManager::GetKeyboardLayoutEngine();
- keyboard_ = std::make_unique<WaylandKeyboard>(keyboard, this, layout_engine,
- event_source());
- } else {
- LOG(ERROR) << "Failed to get wl_keyboard from seat";
+ } else if (!CreateKeyboard()) {
+ LOG(ERROR) << "Failed to create WaylandKeyboard";
}
if (!has_touch) {
@@ -208,21 +180,34 @@ void WaylandConnection::UpdateInputDevices(wl_seat* seat,
}
}
-void WaylandConnection::EnsureDataDevice() {
- if (!data_device_manager_ || !seat_)
- return;
- DCHECK(!data_device_);
- wl_data_device* data_device = data_device_manager_->GetDevice();
- data_device_ = std::make_unique<WaylandDataDevice>(this, data_device);
+bool WaylandConnection::CreateKeyboard() {
+ wl_keyboard* keyboard = wl_seat_get_keyboard(seat_.get());
+ if (!keyboard)
+ return false;
- if (primary_selection_device_manager_) {
- primary_selection_device_ = std::make_unique<GtkPrimarySelectionDevice>(
- this, primary_selection_device_manager_->GetDevice());
- }
+ auto* layout_engine = KeyboardLayoutEngineManager::GetKeyboardLayoutEngine();
+ // Make sure to destroy the old WaylandKeyboard (if it exists) before creating
+ // the new one.
+ keyboard_.reset();
+ keyboard_.reset(new WaylandKeyboard(keyboard, keyboard_extension_v1_.get(),
+ this, layout_engine, event_source()));
+ return true;
+}
- clipboard_ = std::make_unique<WaylandClipboard>(
- data_device_manager_.get(), data_device_.get(),
- primary_selection_device_manager_.get(), primary_selection_device_.get());
+void WaylandConnection::CreateDataObjectsIfReady() {
+ if (data_device_manager_ && seat_) {
+ DCHECK(!data_drag_controller_);
+ data_drag_controller_ = std::make_unique<WaylandDataDragController>(
+ this, data_device_manager_.get());
+
+ DCHECK(!window_drag_controller_);
+ window_drag_controller_ = std::make_unique<WaylandWindowDragController>(
+ this, data_device_manager_.get(), event_source());
+
+ DCHECK(!clipboard_);
+ clipboard_ =
+ std::make_unique<WaylandClipboard>(this, data_device_manager_.get());
+ }
}
// static
@@ -268,7 +253,7 @@ void WaylandConnection::Global(void* data,
return;
}
wl_seat_add_listener(connection->seat_.get(), &seat_listener, connection);
- connection->EnsureDataDevice();
+ connection->CreateDataObjectsIfReady();
} else if (!connection->shell_v6_ &&
strcmp(interface, "zxdg_shell_v6") == 0) {
// Check for zxdg_shell_v6 first.
@@ -323,7 +308,7 @@ void WaylandConnection::Global(void* data,
connection->data_device_manager_ =
std::make_unique<WaylandDataDeviceManager>(
data_device_manager.release(), connection);
- connection->EnsureDataDevice();
+ connection->CreateDataObjectsIfReady();
} else if (!connection->primary_selection_device_manager_ &&
strcmp(interface, "gtk_primary_selection_device_manager") == 0) {
wl::Object<gtk_primary_selection_device_manager> manager =
@@ -343,6 +328,17 @@ void WaylandConnection::Global(void* data,
(strcmp(interface, "wp_presentation") == 0)) {
connection->presentation_ =
wl::Bind<wp_presentation>(registry, name, kMaxWpPresentationVersion);
+ } else if (!connection->keyboard_extension_v1_ &&
+ strcmp(interface, "zcr_keyboard_extension_v1") == 0) {
+ connection->keyboard_extension_v1_ = wl::Bind<zcr_keyboard_extension_v1>(
+ registry, name, kMaxKeyboardExtensionVersion);
+ if (!connection->keyboard_extension_v1_) {
+ LOG(ERROR) << "Failed to bind zcr_keyboard_extension_v1";
+ return;
+ }
+ // CreateKeyboard may fail if we do not have keyboard seat capabilities yet.
+ // We will create the keyboard when get them in that case.
+ connection->CreateKeyboard();
} else if (!connection->text_input_manager_v1_ &&
strcmp(interface, "zwp_text_input_manager_v1") == 0) {
connection->text_input_manager_v1_ = wl::Bind<zwp_text_input_manager_v1>(
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection.h b/chromium/ui/ozone/platform/wayland/host/wayland_connection.h
index b3e0a8a6c3d..5c5754dd2fa 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_connection.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection.h
@@ -6,21 +6,19 @@
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CONNECTION_H_
#include <memory>
-#include <string>
#include <vector>
-#include "ui/gfx/buffer_types.h"
-#include "ui/gfx/native_widget_types.h"
+#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
-#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device.h"
-#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_clipboard.h"
-#include "ui/ozone/platform/wayland/host/wayland_cursor_position.h"
-#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
-#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
#include "ui/ozone/platform/wayland/host/wayland_window_manager.h"
+namespace gfx {
+class Point;
+}
+
namespace ui {
class WaylandBufferManagerHost;
@@ -32,8 +30,11 @@ class WaylandOutputManager;
class WaylandPointer;
class WaylandShm;
class WaylandTouch;
-class WaylandWindow;
class WaylandZwpLinuxDmabuf;
+class WaylandDataDeviceManager;
+class WaylandCursorPosition;
+class WaylandWindowDragController;
+class GtkPrimarySelectionDeviceManager;
class WaylandConnection {
public:
@@ -54,10 +55,6 @@ class WaylandConnection {
xdg_wm_base* shell() const { return shell_.get(); }
zxdg_shell_v6* shell_v6() const { return shell_v6_.get(); }
wl_seat* seat() const { return seat_.get(); }
- wl_data_device* data_device() const { return data_device_->data_device(); }
- gtk_primary_selection_device* primary_selection_device() const {
- return primary_selection_device_->data_device();
- }
wp_presentation* presentation() const { return presentation_.get(); }
zwp_text_input_manager_v1* text_input_manager_v1() const {
return text_input_manager_v1_.get();
@@ -82,10 +79,6 @@ class WaylandConnection {
WaylandClipboard* clipboard() const { return clipboard_.get(); }
- WaylandDataSource* drag_data_source() const {
- return dragdrop_data_source_.get();
- }
-
WaylandOutputManager* wayland_output_manager() const {
return wayland_output_manager_.get();
}
@@ -109,35 +102,36 @@ class WaylandConnection {
return &wayland_window_manager_;
}
- WaylandDataDevice* wayland_data_device() const { return data_device_.get(); }
-
- // Starts drag with |data| to be delivered, |operation| supported by the
- // source side initiated the dragging.
- void StartDrag(const ui::OSExchangeData& data, int operation);
- // Finishes drag and drop session. It happens when WaylandDataSource gets
- // 'OnDnDFinished' or 'OnCancel', which means the drop is performed or
- // canceled on others.
- void FinishDragSession(uint32_t dnd_action, WaylandWindow* source_window);
- // Delivers the data owned by Chromium which initiates drag-and-drop. |buffer|
- // is an output parameter and it should be filled with the data corresponding
- // to mime_type.
- void DeliverDragData(const std::string& mime_type, std::string* buffer);
- // Requests the data to the platform when Chromium gets drag-and-drop started
- // by others. Once reading the data from platform is done, |callback| should
- // be called with the data.
- void RequestDragData(
- const std::string& mime_type,
- base::OnceCallback<void(const std::vector<uint8_t>&)> callback);
+ WaylandDataDeviceManager* data_device_manager() const {
+ return data_device_manager_.get();
+ }
+
+ GtkPrimarySelectionDeviceManager* primary_selection_device_manager() const {
+ return primary_selection_device_manager_.get();
+ }
+
+ WaylandDataDragController* data_drag_controller() const {
+ return data_drag_controller_.get();
+ }
+
+ WaylandWindowDragController* window_drag_controller() const {
+ return window_drag_controller_.get();
+ }
// Returns true when dragging is entered or started.
- bool IsDragInProgress();
+ bool IsDragInProgress() const;
private:
void Flush();
void UpdateInputDevices(wl_seat* seat, uint32_t capabilities);
- // Make sure data device is properly initialized
- void EnsureDataDevice();
+ // Initialize data-related objects if required protocol objects are already
+ // in place, i.e: wl_seat and wl_data_device_manager.
+ void CreateDataObjectsIfReady();
+
+ // Creates WaylandKeyboard with the currently acquired protocol objects, if
+ // possible. Returns true iff WaylandKeyboard was created.
+ bool CreateKeyboard();
// wl_registry_listener
static void Global(void* data,
@@ -166,10 +160,11 @@ class WaylandConnection {
wl::Object<xdg_wm_base> shell_;
wl::Object<zxdg_shell_v6> shell_v6_;
wl::Object<wp_presentation> presentation_;
+ wl::Object<zcr_keyboard_extension_v1> keyboard_extension_v1_;
wl::Object<zwp_text_input_manager_v1> text_input_manager_v1_;
- // Event source instance. Must be declared before input objects so it outlives
- // them so thus being able to properly handle their destruction.
+ // Event source instance. Must be declared before input objects so it
+ // outlives them so thus being able to properly handle their destruction.
std::unique_ptr<WaylandEventSource> event_source_;
// Input device objects.
@@ -179,9 +174,7 @@ class WaylandConnection {
std::unique_ptr<WaylandCursor> cursor_;
std::unique_ptr<WaylandDataDeviceManager> data_device_manager_;
- std::unique_ptr<WaylandDataDevice> data_device_;
std::unique_ptr<WaylandClipboard> clipboard_;
- std::unique_ptr<WaylandDataSource> dragdrop_data_source_;
std::unique_ptr<WaylandOutputManager> wayland_output_manager_;
std::unique_ptr<WaylandCursorPosition> wayland_cursor_position_;
std::unique_ptr<WaylandZwpLinuxDmabuf> zwp_dmabuf_;
@@ -191,7 +184,9 @@ class WaylandConnection {
std::unique_ptr<GtkPrimarySelectionDeviceManager>
primary_selection_device_manager_;
- std::unique_ptr<GtkPrimarySelectionDevice> primary_selection_device_;
+
+ std::unique_ptr<WaylandDataDragController> data_drag_controller_;
+ std::unique_ptr<WaylandWindowDragController> window_drag_controller_;
// Manages Wayland windows.
WaylandWindowManager wayland_window_manager_;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc
index 0d495501f06..7ffd900fcae 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc
@@ -7,6 +7,7 @@
#include <memory>
#include <vector>
+#include "base/logging.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/skia_util.h"
#include "ui/ozone/platform/wayland/common/wayland_util.h"
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc
index 361ffa519f1..1edd356006b 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc
@@ -5,209 +5,62 @@
#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
#include <memory>
+#include <string>
#include <utility>
-#include <vector>
#include "base/bind.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_split.h"
-#include "base/strings/utf_string_conversions.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "ui/base/clipboard/clipboard_constants.h"
-#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/dragdrop/file_info/file_info.h"
-#include "ui/base/dragdrop/os_exchange_data.h"
-#include "ui/base/dragdrop/os_exchange_data_provider_aura.h"
+#include "base/files/scoped_file.h"
+#include "ui/base/clipboard/clipboard_buffer.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/ozone/platform/wayland/common/data_util.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_data_offer.h"
-#include "ui/ozone/platform/wayland/host/wayland_shm_buffer.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
-#include "url/gurl.h"
-#include "url/url_canon.h"
-#include "url/url_util.h"
namespace ui {
-namespace {
-
-constexpr FilenameToURLPolicy kFilenameToURLPolicy = CONVERT_FILENAMES;
-
-// Converts raw data to either narrow or wide string.
-template <typename StringType>
-StringType BytesTo(const PlatformClipboard::Data& bytes) {
- if (bytes.size() % sizeof(typename StringType::value_type) != 0U) {
- // This is suspicious.
- LOG(WARNING)
- << "Data is possibly truncated, or a wrong conversion is requested.";
- }
-
- StringType result;
- result.assign(reinterpret_cast<typename StringType::const_pointer>(&bytes[0]),
- bytes.size() / sizeof(typename StringType::value_type));
- return result;
-}
-
-// Returns actions possible with the given source and drag'n'drop actions.
-// Also converts enums: input params are wl_data_device_manager_dnd_action but
-// the result is ui::DragDropTypes.
-int GetPossibleActions(uint32_t source_actions, uint32_t dnd_action) {
- // If drag'n'drop action is set, use it but check for ASK action (see below).
- uint32_t action = dnd_action != WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE
- ? dnd_action
- : source_actions;
-
- // We accept any action except ASK (see below).
- int operation = DragDropTypes::DRAG_NONE;
- if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
- operation |= DragDropTypes::DRAG_COPY;
- if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
- operation |= DragDropTypes::DRAG_MOVE;
- if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) {
- // This is very rare and non-standard. Chromium doesn't set this when
- // anything is dragged from it, neither it provides any UI for asking
- // the user about the desired drag'n'drop action when data is dragged
- // from an external source.
- // We are safe with not adding anything here. However, keep NOTIMPLEMENTED
- // for an (unlikely) event of this being hit in distant future.
- NOTIMPLEMENTED_LOG_ONCE();
- }
- return operation;
-}
-
-void AddString(const PlatformClipboard::Data& data,
- OSExchangeData* os_exchange_data) {
- DCHECK(os_exchange_data);
-
- if (data.empty())
- return;
-
- os_exchange_data->SetString(base::UTF8ToUTF16(BytesTo<std::string>(data)));
-}
-
-void AddHtml(const PlatformClipboard::Data& data,
- OSExchangeData* os_exchange_data) {
- DCHECK(os_exchange_data);
-
- if (data.empty())
- return;
-
- os_exchange_data->SetHtml(base::UTF8ToUTF16(BytesTo<std::string>(data)),
- GURL());
-}
-
-// Parses |data| as if it had text/uri-list format. Its brief spec is:
-// 1. Any lines beginning with the '#' character are comment lines.
-// 2. Non-comment lines shall be URIs (URNs or URLs).
-// 3. Lines are terminated with a CRLF pair.
-// 4. URL encoding is used.
-void AddFiles(const PlatformClipboard::Data& data,
- OSExchangeData* os_exchange_data) {
- DCHECK(os_exchange_data);
-
- std::string data_as_string = BytesTo<std::string>(data);
-
- const auto lines = base::SplitString(
- data_as_string, "\r\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- std::vector<FileInfo> filenames;
- for (const auto& line : lines) {
- if (line.empty() || line[0] == '#')
- continue;
- GURL url(line);
- if (!url.is_valid() || !url.SchemeIsFile()) {
- LOG(WARNING) << "Invalid URI found: " << line;
- continue;
- }
-
- std::string url_path = url.path();
- url::RawCanonOutputT<base::char16> unescaped;
- url::DecodeURLEscapeSequences(url_path.data(), url_path.size(),
- url::DecodeURLMode::kUTF8OrIsomorphic,
- &unescaped);
-
- std::string path8;
- base::UTF16ToUTF8(unescaped.data(), unescaped.length(), &path8);
- const base::FilePath path(path8);
- filenames.push_back({path, path.BaseName()});
- }
- if (filenames.empty())
- return;
-
- os_exchange_data->SetFilenames(filenames);
-}
-
-// Parses |data| as if it had text/x-moz-url format, which is basically
-// two lines separated with newline, where the first line is the URL and
-// the second one is page title. The unpleasant feature of text/x-moz-url is
-// that the URL has UTF-16 encoding.
-void AddUrl(const PlatformClipboard::Data& data,
- OSExchangeData* os_exchange_data) {
- DCHECK(os_exchange_data);
-
- if (data.empty())
- return;
-
- base::string16 data_as_string16 = BytesTo<base::string16>(data);
-
- const auto lines =
- base::SplitString(data_as_string16, base::ASCIIToUTF16("\r\n"),
- base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- if (lines.size() != 2U) {
- LOG(WARNING) << "Invalid data passed as text/x-moz-url; it must contain "
- << "exactly 2 lines but has " << lines.size() << " instead.";
- return;
- }
- GURL url(lines[0]);
- if (!url.is_valid()) {
- LOG(WARNING) << "Invalid data passed as text/x-moz-url; the first line "
- << "must contain a valid URL but it doesn't.";
- return;
- }
-
- os_exchange_data->SetURL(url, lines[1]);
-}
-
-void AddToOSExchangeData(const PlatformClipboard::Data& data,
- const std::string& mime_type,
- OSExchangeData* os_exchange_data) {
- DCHECK(os_exchange_data);
- if ((mime_type == kMimeTypeText || mime_type == kMimeTypeTextUtf8)) {
- DCHECK(!os_exchange_data->HasString());
- AddString(data, os_exchange_data);
- } else if (mime_type == kMimeTypeHTML) {
- DCHECK(!os_exchange_data->HasHtml());
- AddHtml(data, os_exchange_data);
- } else if (mime_type == kMimeTypeMozillaURL) {
- DCHECK(!os_exchange_data->HasURL(kFilenameToURLPolicy));
- AddUrl(data, os_exchange_data);
- } else if (mime_type == kMimeTypeURIList) {
- DCHECK(!os_exchange_data->HasFile());
- AddFiles(data, os_exchange_data);
- } else {
- LOG(WARNING) << "Unhandled MIME type: " << mime_type;
- }
-}
-
-} // namespace
-
-// static
WaylandDataDevice::WaylandDataDevice(WaylandConnection* connection,
wl_data_device* data_device)
: WaylandDataDeviceBase(connection), data_device_(data_device) {
static const struct wl_data_device_listener kDataDeviceListener = {
- WaylandDataDevice::OnDataOffer, WaylandDataDevice::OnEnter,
- WaylandDataDevice::OnLeave, WaylandDataDevice::OnMotion,
- WaylandDataDevice::OnDrop, WaylandDataDevice::OnSelection};
+ WaylandDataDevice::OnOffer, WaylandDataDevice::OnEnter,
+ WaylandDataDevice::OnLeave, WaylandDataDevice::OnMotion,
+ WaylandDataDevice::OnDrop, WaylandDataDevice::OnSelection};
wl_data_device_add_listener(data_device_.get(), &kDataDeviceListener, this);
}
WaylandDataDevice::~WaylandDataDevice() = default;
-void WaylandDataDevice::RequestDragData(
- const std::string& mime_type,
- base::OnceCallback<void(const PlatformClipboard::Data&)> callback) {
- base::ScopedFD fd = drag_offer_->Receive(mime_type);
+void WaylandDataDevice::StartDrag(const WaylandDataSource& data_source,
+ const WaylandWindow& origin_window,
+ wl_surface* icon_surface,
+ DragDelegate* delegate) {
+ DCHECK(delegate);
+ DCHECK(!drag_delegate_);
+ drag_delegate_ = delegate;
+
+ wl_data_device_start_drag(data_device_.get(), data_source.data_source(),
+ origin_window.surface(), icon_surface,
+ connection()->serial());
+ drag_delegate_->DrawIcon();
+ connection()->ScheduleFlush();
+}
+
+void WaylandDataDevice::ResetDragDelegate() {
+ DCHECK(drag_delegate_);
+ drag_delegate_ = nullptr;
+}
+
+void WaylandDataDevice::RequestData(WaylandDataOffer* offer,
+ const std::string& mime_type,
+ RequestDataCallback callback) {
+ DCHECK(offer);
+ DCHECK(wl::IsMimeTypeSupported(mime_type));
+
+ base::ScopedFD fd = offer->Receive(mime_type);
if (!fd.is_valid()) {
LOG(ERROR) << "Failed to open file descriptor.";
return;
@@ -221,55 +74,13 @@ void WaylandDataDevice::RequestDragData(
RegisterDeferredReadCallback();
}
-void WaylandDataDevice::DeliverDragData(const std::string& mime_type,
- std::string* buffer) {
- DCHECK(buffer);
- DCHECK(source_data_);
-
- if (mime_type == kMimeTypeMozillaURL &&
- source_data_->HasURL(kFilenameToURLPolicy)) {
- GURL url;
- base::string16 title;
- source_data_->GetURLAndTitle(kFilenameToURLPolicy, &url, &title);
- buffer->append(url.spec());
- } else if (mime_type == kMimeTypeHTML && source_data_->HasHtml()) {
- base::string16 data;
- GURL base_url;
- source_data_->GetHtml(&data, &base_url);
- buffer->append(base::UTF16ToUTF8(data));
- } else if (source_data_->HasString()) {
- base::string16 data;
- source_data_->GetString(&data);
- buffer->append(base::UTF16ToUTF8(data));
- } else {
- LOG(WARNING) << "Cannot deliver data of type " << mime_type
- << " and no text representation is available.";
- }
-}
-
-void WaylandDataDevice::StartDrag(wl_data_source* data_source,
- const ui::OSExchangeData& data) {
- DCHECK(data_source);
-
- WaylandWindow* window =
- connection()->wayland_window_manager()->GetCurrentFocusedWindow();
- if (!window) {
- LOG(ERROR) << "Failed to get focused window.";
- return;
- }
- const SkBitmap* icon = PrepareDragIcon(data);
- source_data_ = std::make_unique<ui::OSExchangeData>(data.provider().Clone());
- wl_data_device_start_drag(data_device_.get(), data_source, window->surface(),
- icon_surface_.get(), connection()->serial());
- if (icon)
- DrawDragIcon(icon);
+void WaylandDataDevice::SetSelectionSource(WaylandDataSource* source) {
+ DCHECK(source);
+ wl_data_device_set_selection(data_device_.get(), source->data_source(),
+ connection()->serial());
connection()->ScheduleFlush();
}
-void WaylandDataDevice::ResetSourceData() {
- source_data_.reset();
-}
-
void WaylandDataDevice::ReadDragDataFromFD(
base::ScopedFD fd,
base::OnceCallback<void(const PlatformClipboard::Data&)> callback) {
@@ -278,17 +89,10 @@ void WaylandDataDevice::ReadDragDataFromFD(
std::move(callback).Run(contents);
}
-void WaylandDataDevice::HandleDeferredLeaveIfNeeded() {
- if (!is_leaving_)
- return;
-
- OnLeave(this, data_device_.get());
-}
-
// static
-void WaylandDataDevice::OnDataOffer(void* data,
- wl_data_device* data_device,
- wl_data_offer* offer) {
+void WaylandDataDevice::OnOffer(void* data,
+ wl_data_device* data_device,
+ wl_data_offer* offer) {
auto* self = static_cast<WaylandDataDevice*>(data);
self->connection()->clipboard()->UpdateSequenceNumber(
@@ -305,40 +109,24 @@ void WaylandDataDevice::OnEnter(void* data,
wl_fixed_t x,
wl_fixed_t y,
wl_data_offer* offer) {
- WaylandWindow* window =
- static_cast<WaylandWindow*>(wl_surface_get_user_data(surface));
+ WaylandWindow* window = WaylandWindow::FromSurface(surface);
if (!window) {
LOG(ERROR) << "Failed to get window.";
return;
}
auto* self = static_cast<WaylandDataDevice*>(data);
+
+ // Null |drag_delegate_| here means that the DND session has been initiated by
+ // an external application. In this case, use the default data drag delegate.
+ if (!self->drag_delegate_)
+ self->drag_delegate_ = self->connection()->data_drag_controller();
+
DCHECK(self->new_offer_);
- DCHECK(!self->drag_offer_);
- self->drag_offer_ = std::move(self->new_offer_);
- self->window_ = window;
-
- // TODO(crbug.com/1004715): Set mime type the client can accept. Now it sets
- // all mime types offered because current implementation doesn't decide
- // action based on mime type.
- self->unprocessed_mime_types_.clear();
- for (auto mime : self->drag_offer_->mime_types()) {
- self->unprocessed_mime_types_.push_back(mime);
- self->drag_offer_->Accept(serial, mime);
- }
+ self->drag_delegate_->OnDragOffer(std::move(self->new_offer_));
gfx::PointF point(wl_fixed_to_double(x), wl_fixed_to_double(y));
-
- // If |source_data_| is set, it means that dragging is started from the
- // same window and it's not needed to read data through Wayland.
- std::unique_ptr<OSExchangeData> dragged_data;
- if (!self->IsDraggingExternalData())
- dragged_data = std::make_unique<OSExchangeData>(
- self->source_data_->provider().Clone());
- self->window_->OnDragEnter(
- point, std::move(dragged_data),
- GetPossibleActions(self->drag_offer_->source_actions(),
- self->drag_offer_->dnd_action()));
+ self->drag_delegate_->OnDragEnter(window, point, serial);
}
void WaylandDataDevice::OnMotion(void* data,
@@ -347,65 +135,31 @@ void WaylandDataDevice::OnMotion(void* data,
wl_fixed_t x,
wl_fixed_t y) {
auto* self = static_cast<WaylandDataDevice*>(data);
- if (!self->window_) {
- LOG(ERROR) << "Failed to get window.";
- return;
+ if (self->drag_delegate_) {
+ gfx::PointF point(wl_fixed_to_double(x), wl_fixed_to_double(y));
+ self->drag_delegate_->OnDragMotion(point);
}
-
- gfx::PointF point(wl_fixed_to_double(x), wl_fixed_to_double(y));
- int client_operation = self->window_->OnDragMotion(
- point, time,
- GetPossibleActions(self->drag_offer_->source_actions(),
- self->drag_offer_->dnd_action()));
- self->SetOperation(client_operation);
}
void WaylandDataDevice::OnDrop(void* data, wl_data_device* data_device) {
auto* self = static_cast<WaylandDataDevice*>(data);
- if (!self->window_) {
- LOG(ERROR) << "Failed to get window.";
- return;
- }
- if (self->IsDraggingExternalData()) {
- // We are about to accept data dragged from another application.
- // Reading all the data may take some time so we set
- // |is_handling_dropped_data_| that will postpone handling of OnLeave
- // until reading is completed.
- self->is_handling_dropped_data_ = true;
- self->received_data_ = std::make_unique<OSExchangeData>(
- std::make_unique<OSExchangeDataProviderAura>());
- self->HandleUnprocessedMimeTypes();
- } else {
- // If the drag session had been started internally by chromium,
- // |source_data_| already holds the data, and it is already forwarded to the
- // delegate through OnDragEnter, so here we short-cut the data transfer by
- // sending nullptr.
- self->HandleReceivedData(nullptr);
- }
+ if (self->drag_delegate_)
+ self->drag_delegate_->OnDragDrop();
}
void WaylandDataDevice::OnLeave(void* data, wl_data_device* data_device) {
- // While reading data, it could get OnLeave event. We don't handle OnLeave
- // event directly if |is_handling_dropped_data_| is set.
auto* self = static_cast<WaylandDataDevice*>(data);
- if (!self->window_) {
- LOG(ERROR) << "Failed to get window.";
- return;
- }
+ if (self->drag_delegate_) {
+ self->drag_delegate_->OnDragLeave();
- if (self->is_handling_dropped_data_) {
- self->is_leaving_ = true;
- return;
+ // When in a DND session initiated by an external application,
+ // |drag_delegate_| is set at OnEnter, and must be reset here to avoid
+ // potential use-after-free.
+ if (!self->drag_delegate_->IsDragSource())
+ self->drag_delegate_ = nullptr;
}
-
- self->window_->OnDragLeave();
- self->window_ = nullptr;
- self->drag_offer_.reset();
- self->is_handling_dropped_data_ = false;
- self->is_leaving_ = false;
}
-// static
void WaylandDataDevice::OnSelection(void* data,
wl_data_device* data_device,
wl_data_offer* offer) {
@@ -428,106 +182,4 @@ void WaylandDataDevice::OnSelection(void* data,
self->data_offer()->EnsureTextMimeTypeIfNeeded();
}
-const SkBitmap* WaylandDataDevice::PrepareDragIcon(const OSExchangeData& data) {
- const SkBitmap* icon_bitmap = data.provider().GetDragImage().bitmap();
- if (!icon_bitmap || icon_bitmap->empty())
- return nullptr;
- icon_surface_.reset(wl_compositor_create_surface(connection()->compositor()));
- DCHECK(icon_surface_);
- return icon_bitmap;
-}
-
-void WaylandDataDevice::DrawDragIcon(const SkBitmap* icon_bitmap) {
- DCHECK(icon_bitmap);
- DCHECK(!icon_bitmap->empty());
- gfx::Size size(icon_bitmap->width(), icon_bitmap->height());
-
- if (!shm_buffer_ || shm_buffer_->size() != size) {
- shm_buffer_ = std::make_unique<WaylandShmBuffer>(connection()->shm(), size);
- if (!shm_buffer_->IsValid()) {
- LOG(ERROR) << "Failed to create drag icon buffer.";
- return;
- }
- }
- wl::DrawBitmap(*icon_bitmap, shm_buffer_.get());
-
- wl_surface* surface = icon_surface_.get();
- wl_surface_attach(surface, shm_buffer_->get(), 0, 0);
- wl_surface_damage(surface, 0, 0, size.width(), size.height());
- wl_surface_commit(surface);
-}
-
-void WaylandDataDevice::HandleUnprocessedMimeTypes() {
- std::string mime_type = SelectNextMimeType();
- if (mime_type.empty()) {
- HandleReceivedData(std::move(received_data_));
- } else {
- RequestDragData(mime_type,
- base::BindOnce(&WaylandDataDevice::OnDragDataReceived,
- base::Unretained(this)));
- }
-}
-
-void WaylandDataDevice::OnDragDataReceived(
- const PlatformClipboard::Data& contents) {
- if (!contents.empty()) {
- AddToOSExchangeData(contents, unprocessed_mime_types_.front(),
- received_data_.get());
- }
-
- unprocessed_mime_types_.pop_front();
-
- // Continue reading data for other negotiated mime types.
- HandleUnprocessedMimeTypes();
-}
-
-void WaylandDataDevice::HandleReceivedData(
- std::unique_ptr<ui::OSExchangeData> received_data) {
- unprocessed_mime_types_.clear();
-
- window_->OnDragDrop(std::move(received_data));
- drag_offer_->FinishOffer();
- is_handling_dropped_data_ = false;
- HandleDeferredLeaveIfNeeded();
-}
-
-std::string WaylandDataDevice::SelectNextMimeType() {
- while (!unprocessed_mime_types_.empty()) {
- const std::string& mime_type = unprocessed_mime_types_.front();
- if ((mime_type == kMimeTypeText || mime_type == kMimeTypeTextUtf8) &&
- !received_data_->HasString()) {
- return mime_type;
- }
- if (mime_type == kMimeTypeURIList && !received_data_->HasFile()) {
- return mime_type;
- }
- if (mime_type == kMimeTypeMozillaURL &&
- !received_data_->HasURL(kFilenameToURLPolicy)) {
- return mime_type;
- }
- if (mime_type == kMimeTypeHTML && !received_data_->HasHtml()) {
- return mime_type;
- }
- unprocessed_mime_types_.pop_front();
- }
- return {};
-}
-
-void WaylandDataDevice::SetOperation(const int operation) {
- uint32_t dnd_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
- uint32_t preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
-
- if (operation & DragDropTypes::DRAG_COPY) {
- dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
- preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
- }
-
- if (operation & DragDropTypes::DRAG_MOVE) {
- dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
- if (preferred_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE)
- preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
- }
- drag_offer_->SetAction(dnd_actions, preferred_action);
-}
-
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h
index cf2e8cc7a65..5512f4c4480 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h
@@ -7,73 +7,84 @@
#include <wayland-client.h>
-#include <list>
+#include <cstdint>
#include <memory>
#include <string>
#include "base/callback.h"
#include "base/files/scoped_file.h"
-#include "base/macros.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device_base.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
#include "ui/ozone/public/platform_clipboard.h"
-class SkBitmap;
+namespace gfx {
+class PointF;
+} // namespace gfx
namespace ui {
-class OSExchangeData;
class WaylandDataOffer;
class WaylandConnection;
-class WaylandShmBuffer;
class WaylandWindow;
// This class provides access to inter-client data transfer mechanisms
// such as copy-and-paste and drag-and-drop mechanisms.
class WaylandDataDevice : public WaylandDataDeviceBase {
public:
+ using RequestDataCallback =
+ base::OnceCallback<void(const PlatformClipboard::Data&)>;
+
+ // DragDelegate is responsible for handling drag and drop sessions.
+ class DragDelegate {
+ public:
+ virtual bool IsDragSource() const = 0;
+ virtual void DrawIcon() = 0;
+ virtual void OnDragOffer(std::unique_ptr<WaylandDataOffer> offer) = 0;
+ virtual void OnDragEnter(WaylandWindow* window,
+ const gfx::PointF& location,
+ uint32_t serial) = 0;
+ virtual void OnDragMotion(const gfx::PointF& location) = 0;
+ virtual void OnDragLeave() = 0;
+ virtual void OnDragDrop() = 0;
+
+ protected:
+ virtual ~DragDelegate() = default;
+ };
+
WaylandDataDevice(WaylandConnection* connection, wl_data_device* data_device);
+ WaylandDataDevice(const WaylandDataDevice&) = delete;
+ WaylandDataDevice& operator=(const WaylandDataDevice&) = delete;
~WaylandDataDevice() override;
- // Requests the data to the platform when Chromium gets drag-and-drop started
- // by others. Once reading the data from platform is done, |callback| should
- // be called with the data.
- void RequestDragData(
- const std::string& mime_type,
- base::OnceCallback<void(const PlatformClipboard::Data&)> callback);
- // Delivers the data owned by Chromium which initiates drag-and-drop. |buffer|
- // is an output parameter and it should be filled with the data corresponding
- // to mime_type.
- void DeliverDragData(const std::string& mime_type, std::string* buffer);
- // Starts drag with |data| to be delivered, |operation| supported by the
- // source side initiated the dragging.
- void StartDrag(wl_data_source* data_source, const ui::OSExchangeData& data);
- // Resets |source_data_| when the dragging is finished.
- void ResetSourceData();
-
- wl_data_device* data_device() const { return data_device_.get(); }
+ // Starts a wayland drag and drop session, controlled by |delegate|.
+ void StartDrag(const WaylandDataSource& data_source,
+ const WaylandWindow& origin_window,
+ wl_surface* icon_surface,
+ DragDelegate* delegate);
- bool IsDragEntered() { return drag_offer_ != nullptr; }
+ // Reset the drag delegate, assuming there is one set. Any wl_data_device
+ // event received after this will be ignored until a new delegate is set.
+ void ResetDragDelegate();
- WaylandWindow* entered_window() const { return window_; }
+ // Requests data for an |offer| in a format specified by |mime_type|. The
+ // transfer happens asynchronously and |callback| is called when it is done.
+ void RequestData(WaylandDataOffer* offer,
+ const std::string& mime_type,
+ RequestDataCallback callback);
- private:
- void ReadDragDataFromFD(
- base::ScopedFD fd,
- base::OnceCallback<void(const PlatformClipboard::Data&)> callback);
+ // Returns the underlying wl_data_device singleton object.
+ wl_data_device* data_device() const { return data_device_.get(); }
- // If source_data_ is not set, data is being dragged from an external
- // application (non-chromium).
- bool IsDraggingExternalData() const { return !source_data_; }
+ void SetSelectionSource(WaylandDataSource* source);
- // If OnLeave event occurs while it's reading drag data, it defers handling
- // it. Once reading data is completed, it's handled.
- void HandleDeferredLeaveIfNeeded();
+ private:
+ void ReadDragDataFromFD(base::ScopedFD fd, RequestDataCallback callback);
// wl_data_device_listener callbacks
- static void OnDataOffer(void* data,
- wl_data_device* data_device,
- wl_data_offer* id);
+ static void OnOffer(void* data,
+ wl_data_device* data_device,
+ wl_data_offer* id);
static void OnEnter(void* data,
wl_data_device* data_device,
@@ -101,60 +112,18 @@ class WaylandDataDevice : public WaylandDataDeviceBase {
wl_data_device* data_device,
wl_data_offer* id);
- // Returns the drag icon bitmap and creates and wayland surface to draw it
- // on, if a valid drag image is present in |data|; otherwise returns null.
- const SkBitmap* PrepareDragIcon(const OSExchangeData& data);
- void DrawDragIcon(const SkBitmap* bitmap);
-
- void OnDragDataReceived(const PlatformClipboard::Data& contents);
-
- // HandleUnprocessedMimeTypes asynchronously request and read data for every
- // negotiated mime type, one after another (OnDragDataReceived calls back
- // HandleUnprocessedMimeTypes so it finish only when there's no more items in
- // unprocessed_mime_types_ vector). HandleReceivedData is called once the
- // process is finished.
- void HandleUnprocessedMimeTypes();
- void HandleReceivedData(std::unique_ptr<ui::OSExchangeData> received_data);
- // Returns the next MIME type to be received from the source process, or an
- // empty string if there are no more interesting MIME types left to process.
- std::string SelectNextMimeType();
-
- // Set drag operation decided by client.
- void SetOperation(const int operation);
-
// The wl_data_device wrapped by this WaylandDataDevice.
wl::Object<wl_data_device> data_device_;
+ DragDelegate* drag_delegate_ = nullptr;
+
// There are two separate data offers at a time, the drag offer and the
// selection offer, each with independent lifetimes. When we receive a new
- // offer, it is not immediately possible to know whether the new offer is the
- // drag offer or the selection offer. This variable is used to store ownership
- // of new data offers temporarily until its identity becomes known.
+ // offer, it is not immediately possible to know whether the new offer is
+ // the drag offer or the selection offer. This variable is used to store
+ // new data offers temporarily until it is possible to determine which kind
+ // session it belongs to.
std::unique_ptr<WaylandDataOffer> new_offer_;
-
- // Offer to receive data from another process via drag-and-drop, or null if no
- // drag-and-drop from another process is in progress.
- std::unique_ptr<WaylandDataOffer> drag_offer_;
-
- WaylandWindow* window_ = nullptr;
-
- bool is_handling_dropped_data_ = false;
- bool is_leaving_ = false;
-
- std::unique_ptr<WaylandShmBuffer> shm_buffer_;
- wl::Object<wl_surface> icon_surface_;
-
- // Mime types to be handled.
- std::list<std::string> unprocessed_mime_types_;
-
- // The data delivered from Wayland
- std::unique_ptr<ui::OSExchangeData> received_data_;
-
- // When dragging is started from Chromium, |source_data_| is forwarded to
- // Wayland when they are ready to get the data.
- std::unique_ptr<ui::OSExchangeData> source_data_;
-
- DISALLOW_COPY_AND_ASSIGN(WaylandDataDevice);
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc
index e61c9b53816..3e020a31134 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/logging.h"
#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
@@ -64,7 +65,7 @@ void WaylandDataDeviceBase::RegisterDeferredReadCallback() {
deferred_read_callback_.reset(wl_display_sync(connection_->display()));
static const wl_callback_listener kListener = {
- GtkPrimarySelectionDevice::DeferredReadCallback};
+ WaylandDataDeviceBase::DeferredReadCallback};
wl_callback_add_listener(deferred_read_callback_.get(), &kListener, this);
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h
index 78abf99aec9..e331243fc5e 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h
@@ -25,6 +25,7 @@ class WaylandDataDeviceBase {
// Returns MIME types given by the current data offer.
const std::vector<std::string>& GetAvailableMimeTypes() const;
+
// Extracts data of the specified MIME type from the data offer.
bool RequestSelectionData(const std::string& mime_type);
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc
index 5b4a79d7979..6c283794473 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc
@@ -4,7 +4,12 @@
#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
+#include <wayland-client-protocol.h>
+
+#include <memory>
+
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
namespace ui {
@@ -19,16 +24,23 @@ WaylandDataDeviceManager::WaylandDataDeviceManager(
WaylandDataDeviceManager::~WaylandDataDeviceManager() = default;
-wl_data_device* WaylandDataDeviceManager::GetDevice() {
+WaylandDataDevice* WaylandDataDeviceManager::GetDevice() {
DCHECK(connection_->seat());
- return wl_data_device_manager_get_data_device(device_manager_.get(),
- connection_->seat());
+ if (!device_) {
+ device_ = std::make_unique<WaylandDataDevice>(
+ connection_, wl_data_device_manager_get_data_device(
+ device_manager_.get(), connection_->seat()));
+ }
+ DCHECK(device_);
+ return device_.get();
}
-std::unique_ptr<WaylandDataSource> WaylandDataDeviceManager::CreateSource() {
+std::unique_ptr<WaylandDataSource> WaylandDataDeviceManager::CreateSource(
+ WaylandDataSource::Delegate* delegate) {
wl_data_source* data_source =
wl_data_device_manager_create_data_source(device_manager_.get());
- return std::make_unique<WaylandDataSource>(data_source, connection_);
+ return std::make_unique<WaylandDataSource>(data_source, connection_,
+ delegate);
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.h
index ea37eee0ba3..7ed3a330ea3 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.h
@@ -5,33 +5,37 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_DEVICE_MANAGER_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_DEVICE_MANAGER_H_
-#include <wayland-client.h>
-
#include <memory>
-#include "base/macros.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
namespace ui {
class WaylandConnection;
-class WaylandDataSource;
+class WaylandDataDevice;
class WaylandDataDeviceManager {
public:
+ using DataSource = WaylandDataSource;
+ using DataDevice = WaylandDataDevice;
+
WaylandDataDeviceManager(wl_data_device_manager* device_manager,
WaylandConnection* connection);
+ WaylandDataDeviceManager(const WaylandDataDeviceManager&) = delete;
+ WaylandDataDeviceManager& operator=(const WaylandDataDeviceManager&) = delete;
~WaylandDataDeviceManager();
- wl_data_device* GetDevice();
- std::unique_ptr<WaylandDataSource> CreateSource();
+ WaylandDataDevice* GetDevice();
+ std::unique_ptr<WaylandDataSource> CreateSource(
+ WaylandDataSource::Delegate* delegate);
private:
wl::Object<wl_data_device_manager> device_manager_;
- WaylandConnection* connection_;
+ WaylandConnection* const connection_;
- DISALLOW_COPY_AND_ASSIGN(WaylandDataDeviceManager);
+ std::unique_ptr<WaylandDataDevice> device_;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc
index 9195d876030..b4bedb59ac9 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc
@@ -14,9 +14,6 @@
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/clipboard/clipboard_constants.h"
-#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/dragdrop/file_info/file_info.h"
-#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/events/base_event_utils.h"
#include "ui/ozone/platform/wayland/test/constants.h"
#include "ui/ozone/platform/wayland/test/mock_surface.h"
@@ -27,8 +24,6 @@
#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
#include "ui/ozone/platform/wayland/test/wayland_test.h"
#include "ui/ozone/public/platform_clipboard.h"
-#include "ui/platform_window/platform_window_handler/wm_drop_handler.h"
-#include "url/gurl.h"
using testing::_;
using testing::Mock;
@@ -37,8 +32,6 @@ namespace ui {
namespace {
-constexpr FilenameToURLPolicy kFilenameToURLPolicy = CONVERT_FILENAMES;
-
template <typename StringType>
ui::PlatformClipboard::Data ToClipboardData(const StringType& data_string) {
ui::PlatformClipboard::Data result;
@@ -52,39 +45,6 @@ ui::PlatformClipboard::Data ToClipboardData(const StringType& data_string) {
} // namespace
-class MockDropHandler : public WmDropHandler {
- public:
- MockDropHandler() = default;
- ~MockDropHandler() override {}
-
- MOCK_METHOD3(OnDragEnter,
- void(const gfx::PointF& point,
- std::unique_ptr<OSExchangeData> data,
- int operation));
- MOCK_METHOD2(OnDragMotion, int(const gfx::PointF& point, int operation));
- MOCK_METHOD0(MockOnDragDrop, void());
- MOCK_METHOD0(OnDragLeave, void());
-
- void SetOnDropClosure(base::RepeatingClosure closure) {
- on_drop_closure_ = closure;
- }
-
- ui::OSExchangeData* dropped_data() { return dropped_data_.get(); }
-
- protected:
- void OnDragDrop(std::unique_ptr<ui::OSExchangeData> data) override {
- dropped_data_ = std::move(data);
- MockOnDragDrop();
- on_drop_closure_.Run();
- on_drop_closure_.Reset();
- }
-
- private:
- base::RepeatingClosure on_drop_closure_;
-
- std::unique_ptr<ui::OSExchangeData> dropped_data_;
-};
-
// This class mocks how a real clipboard/ozone client would
// hook to PlatformClipboard, with one difference: real clients
// have no access to the WaylandConnection instance like this
@@ -143,15 +103,11 @@ class WaylandDataDeviceManagerTest : public WaylandTest {
clipboard_client_ =
std::make_unique<MockClipboardClient>(connection_.get());
-
- drop_handler_ = std::make_unique<MockDropHandler>();
- SetWmDropHandler(window_.get(), drop_handler_.get());
}
protected:
wl::TestDataDeviceManager* data_device_manager_;
std::unique_ptr<MockClipboardClient> clipboard_client_;
- std::unique_ptr<MockDropHandler> drop_handler_;
private:
DISALLOW_COPY_AND_ASSIGN(WaylandDataDeviceManagerTest);
@@ -231,255 +187,6 @@ TEST_P(WaylandDataDeviceManagerTest, IsSelectionOwner) {
ASSERT_FALSE(clipboard_client_->IsSelectionOwner());
}
-TEST_P(WaylandDataDeviceManagerTest, StartDrag) {
- bool restored_focus = window_->has_pointer_focus();
- window_->SetPointerFocus(true);
-
- // The client starts dragging.
- OSExchangeData os_exchange_data;
- int operation = DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE;
- connection_->StartDrag(os_exchange_data, operation);
-
- WaylandDataSource::DragDataMap data;
- data[wl::kTextMimeTypeUtf8] = wl::kSampleTextForDragAndDrop;
- connection_->drag_data_source()->SetDragData(data);
- Sync();
-
- // The server reads the data and the callback gets it.
- base::RunLoop run_loop;
- auto callback = base::BindOnce(
- [](base::RunLoop* loop, PlatformClipboard::Data&& data) {
- std::string result(data.begin(), data.end());
- EXPECT_EQ(wl::kSampleTextForDragAndDrop, result);
- loop->Quit();
- },
- &run_loop);
- data_device_manager_->data_source()->ReadData(wl::kTextMimeTypeUtf8,
- std::move(callback));
- run_loop.Run();
- window_->SetPointerFocus(restored_focus);
-}
-
-TEST_P(WaylandDataDeviceManagerTest, StartDragWithWrongMimeType) {
- bool restored_focus = window_->has_pointer_focus();
- window_->SetPointerFocus(true);
-
- // The client starts dragging offering data with wl::kTextMimeTypeUtf8
- // mime type.
- OSExchangeData os_exchange_data;
- int operation = DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE;
- connection_->StartDrag(os_exchange_data, operation);
-
- WaylandDataSource::DragDataMap data;
- data[wl::kTextMimeTypeUtf8] = wl::kSampleTextForDragAndDrop;
- connection_->drag_data_source()->SetDragData(data);
- Sync();
-
- // The server should get an empty data buffer in ReadData callback
- // when trying to read it.
- base::RunLoop run_loop;
- auto callback = base::BindOnce(
- [](base::RunLoop* loop, PlatformClipboard::Data&& data) {
- std::string result(data.begin(), data.end());
- EXPECT_EQ("", result);
- loop->Quit();
- },
- &run_loop);
- data_device_manager_->data_source()->ReadData(ui::kMimeTypeText,
- std::move(callback));
- run_loop.Run();
- window_->SetPointerFocus(restored_focus);
-}
-
-TEST_P(WaylandDataDeviceManagerTest, ReceiveDrag) {
- auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
- data_offer->OnOffer(
- ui::kMimeTypeText,
- ToClipboardData(std::string(wl::kSampleTextForDragAndDrop)));
-
- gfx::Point entered_point(10, 10);
- // The server sends an enter event.
- data_device_manager_->data_device()->OnEnter(
- 1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
- wl_fixed_from_int(entered_point.y()), data_offer);
-
- int64_t time =
- (ui::EventTimeForNow() - base::TimeTicks()).InMilliseconds() & UINT32_MAX;
- gfx::Point motion_point(11, 11);
-
- // The server sends an motion event.
- data_device_manager_->data_device()->OnMotion(
- time, wl_fixed_from_int(motion_point.x()),
- wl_fixed_from_int(motion_point.y()));
-
- Sync();
-
- auto callback = base::BindOnce([](const PlatformClipboard::Data& contents) {
- std::string result;
- result.assign(reinterpret_cast<std::string::const_pointer>(&contents[0]),
- contents.size());
- EXPECT_EQ(wl::kSampleTextForDragAndDrop, result);
- });
-
- // The client requests the data and gets callback with it.
- connection_->RequestDragData(ui::kMimeTypeText, std::move(callback));
- Sync();
-
- data_device_manager_->data_device()->OnLeave();
-}
-
-TEST_P(WaylandDataDeviceManagerTest, DropSeveralMimeTypes) {
- auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
- data_offer->OnOffer(
- ui::kMimeTypeText,
- ToClipboardData(std::string(wl::kSampleTextForDragAndDrop)));
- data_offer->OnOffer(
- ui::kMimeTypeMozillaURL,
- ToClipboardData(base::UTF8ToUTF16("https://sample.com/\r\n"
- "Sample")));
- data_offer->OnOffer(
- ui::kMimeTypeURIList,
- ToClipboardData(std::string("file:///home/user/file\r\n")));
-
- EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _)).Times(1);
- gfx::Point entered_point(10, 10);
- data_device_manager_->data_device()->OnEnter(
- 1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
- wl_fixed_from_int(entered_point.y()), data_offer);
- Sync();
- Mock::VerifyAndClearExpectations(drop_handler_.get());
-
- EXPECT_CALL(*drop_handler_, MockOnDragDrop()).Times(1);
- base::RunLoop loop;
- drop_handler_->SetOnDropClosure(loop.QuitClosure());
- data_device_manager_->data_device()->OnDrop();
-
- // Here we are expecting three data items, so there will be three roundtrips
- // to the Wayland and back. Hence Sync() three times.
- Sync();
- Sync();
- Sync();
- loop.Run();
- Mock::VerifyAndClearExpectations(drop_handler_.get());
-
- EXPECT_TRUE(drop_handler_->dropped_data()->HasString());
- EXPECT_TRUE(drop_handler_->dropped_data()->HasFile());
- EXPECT_TRUE(drop_handler_->dropped_data()->HasURL(kFilenameToURLPolicy));
-
- data_device_manager_->data_device()->OnLeave();
-}
-
-// Tests URI validation for text/uri-list MIME type. Log warnings rendered in
-// the console when this test is running are the expected and valid side effect.
-TEST_P(WaylandDataDeviceManagerTest, ValidateDroppedUriList) {
- const struct {
- std::string content;
- base::flat_set<std::string> expected_uris;
- } kCases[] = {{{}, {}},
- {"file:///home/user/file\r\n", {"/home/user/file"}},
- {"# Comment\r\n"
- "file:///home/user/file\r\n"
- "file:///home/guest/file\r\n"
- "not a filename at all\r\n"
- "https://valid.url/but/scheme/is/not/file/so/invalid\r\n",
- {"/home/user/file", "/home/guest/file"}}};
-
- for (const auto& kCase : kCases) {
- auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
- data_offer->OnOffer(ui::kMimeTypeURIList, ToClipboardData(kCase.content));
-
- EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _)).Times(1);
- gfx::Point entered_point(10, 10);
- data_device_manager_->data_device()->OnEnter(
- 1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
- wl_fixed_from_int(entered_point.y()), data_offer);
- Sync();
- Mock::VerifyAndClearExpectations(drop_handler_.get());
-
- EXPECT_CALL(*drop_handler_, MockOnDragDrop()).Times(1);
- base::RunLoop loop;
- drop_handler_->SetOnDropClosure(loop.QuitClosure());
- data_device_manager_->data_device()->OnDrop();
-
- Sync();
- loop.Run();
- Mock::VerifyAndClearExpectations(drop_handler_.get());
-
- if (kCase.expected_uris.empty()) {
- EXPECT_FALSE(drop_handler_->dropped_data()->HasFile());
- } else {
- EXPECT_TRUE(drop_handler_->dropped_data()->HasFile());
- std::vector<FileInfo> filenames;
- EXPECT_TRUE(drop_handler_->dropped_data()->GetFilenames(&filenames));
- EXPECT_EQ(filenames.size(), kCase.expected_uris.size());
- for (const auto& filename : filenames)
- EXPECT_EQ(kCase.expected_uris.count(filename.path.AsUTF8Unsafe()), 1U);
- }
-
- EXPECT_CALL(*drop_handler_, OnDragLeave()).Times(1);
- data_device_manager_->data_device()->OnLeave();
- Sync();
- Mock::VerifyAndClearExpectations(drop_handler_.get());
- }
-}
-
-// Tests URI validation for text/x-moz-url MIME type. Log warnings rendered in
-// the console when this test is running are the expected and valid side effect.
-TEST_P(WaylandDataDeviceManagerTest, ValidateDroppedXMozUrl) {
- const struct {
- std::string content;
- std::string expected_url;
- std::string expected_title;
- } kCases[] = {
- {{}, {}, {}},
- {"http://sample.com/\r\nSample", "http://sample.com/", "Sample"},
- {"http://title.must.be.set/", {}, {}},
- {"url.must.be.valid/and/have.scheme\r\nInvalid URL", {}, {}},
- {"file:///files/are/ok\r\nThe policy allows that", "file:///files/are/ok",
- "The policy allows that"}};
-
- for (const auto& kCase : kCases) {
- auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
- data_offer->OnOffer(ui::kMimeTypeMozillaURL,
- ToClipboardData(base::UTF8ToUTF16(kCase.content)));
-
- EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _)).Times(1);
- gfx::Point entered_point(10, 10);
- data_device_manager_->data_device()->OnEnter(
- 1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
- wl_fixed_from_int(entered_point.y()), data_offer);
- Sync();
- Mock::VerifyAndClearExpectations(drop_handler_.get());
-
- EXPECT_CALL(*drop_handler_, MockOnDragDrop()).Times(1);
- base::RunLoop loop;
- drop_handler_->SetOnDropClosure(loop.QuitClosure());
- data_device_manager_->data_device()->OnDrop();
-
- Sync();
- loop.Run();
- Mock::VerifyAndClearExpectations(drop_handler_.get());
-
- const auto* const dropped_data = drop_handler_->dropped_data();
- if (kCase.expected_url.empty()) {
- EXPECT_FALSE(dropped_data->HasURL(kFilenameToURLPolicy));
- } else {
- EXPECT_TRUE(dropped_data->HasURL(kFilenameToURLPolicy));
- GURL url;
- base::string16 title;
- EXPECT_TRUE(
- dropped_data->GetURLAndTitle(kFilenameToURLPolicy, &url, &title));
- EXPECT_EQ(url.spec(), kCase.expected_url);
- EXPECT_EQ(title, base::UTF8ToUTF16(kCase.expected_title));
- }
-
- EXPECT_CALL(*drop_handler_, OnDragLeave()).Times(1);
- data_device_manager_->data_device()->OnLeave();
- Sync();
- Mock::VerifyAndClearExpectations(drop_handler_.get());
- }
-}
-
INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
WaylandDataDeviceManagerTest,
::testing::Values(kXdgShellStable));
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
new file mode 100644
index 00000000000..ec14c3e3b7f
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
@@ -0,0 +1,355 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h"
+
+#include <wayland-client-protocol.h>
+
+#include <cstdint>
+
+#include "base/check.h"
+#include "base/notreached.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/clipboard/clipboard_constants.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/base/dragdrop/os_exchange_data_provider_non_backed.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/ozone/platform/wayland/common/data_util.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_offer.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_shm_buffer.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_window_manager.h"
+
+namespace ui {
+
+namespace {
+
+// Returns actions possible with the given source and drag'n'drop actions.
+// Also converts enums: input params are wl_data_device_manager_dnd_action but
+// the result is ui::DragDropTypes.
+int GetPossibleActions(uint32_t source_actions, uint32_t dnd_action) {
+ // If drag'n'drop action is set, use it but check for ASK action (see below).
+ uint32_t action = dnd_action != WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE
+ ? dnd_action
+ : source_actions;
+
+ // We accept any action except ASK (see below).
+ int operation = DragDropTypes::DRAG_NONE;
+ if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
+ operation |= DragDropTypes::DRAG_COPY;
+ if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
+ operation |= DragDropTypes::DRAG_MOVE;
+ if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) {
+ // This is very rare and non-standard. Chromium doesn't set this when
+ // anything is dragged from it, neither it provides any UI for asking
+ // the user about the desired drag'n'drop action when data is dragged
+ // from an external source.
+ // We are safe with not adding anything here. However, keep NOTIMPLEMENTED
+ // for an (unlikely) event of this being hit in distant future.
+ NOTIMPLEMENTED_LOG_ONCE();
+ }
+ return operation;
+}
+
+const SkBitmap* GetDragImage(const OSExchangeData& data) {
+ const SkBitmap* icon_bitmap = data.provider().GetDragImage().bitmap();
+ return icon_bitmap && !icon_bitmap->empty() ? icon_bitmap : nullptr;
+}
+
+} // namespace
+
+WaylandDataDragController::WaylandDataDragController(
+ WaylandConnection* connection,
+ WaylandDataDeviceManager* data_device_manager)
+ : connection_(connection),
+ data_device_manager_(data_device_manager),
+ data_device_(data_device_manager->GetDevice()),
+ window_manager_(connection->wayland_window_manager()) {
+ DCHECK(connection_);
+ DCHECK(window_manager_);
+ DCHECK(data_device_manager_);
+ DCHECK(data_device_);
+}
+
+WaylandDataDragController::~WaylandDataDragController() = default;
+
+void WaylandDataDragController::StartSession(const OSExchangeData& data,
+ int operation) {
+ DCHECK_EQ(state_, State::kIdle);
+ DCHECK(!origin_window_);
+
+ origin_window_ = window_manager_->GetCurrentFocusedWindow();
+ if (!origin_window_) {
+ LOG(ERROR) << "Failed to get focused window.";
+ return;
+ }
+
+ // Create new new data source and offers |data|.
+ if (!data_source_)
+ data_source_ = data_device_manager_->CreateSource(this);
+ Offer(data, operation);
+
+ // Create drag icon surface (if any) and store the data to be exchanged.
+ icon_surface_.reset(CreateIconSurfaceIfNeeded(data));
+ data_ = std::make_unique<OSExchangeData>(data.provider().Clone());
+
+ // Starts the wayland drag session setting |this| object as delegate.
+ state_ = State::kStarted;
+ data_device_->StartDrag(*data_source_, *origin_window_, icon_surface_.get(),
+ this);
+}
+
+// Sessions initiated from Chromium, will have |origin_window_| pointing to the
+// window where the drag started in. In such cases, |data_| is expected to be
+// non-null, which can be used to save some IO cycles.
+bool WaylandDataDragController::IsDragSource() const {
+ DCHECK(!origin_window_ || data_);
+ return !!origin_window_;
+}
+
+void WaylandDataDragController::DrawIcon() {
+ if (!icon_bitmap_)
+ return;
+
+ DCHECK(!icon_bitmap_->empty());
+ gfx::Size size(icon_bitmap_->width(), icon_bitmap_->height());
+
+ if (!shm_buffer_ || shm_buffer_->size() != size) {
+ shm_buffer_ = std::make_unique<WaylandShmBuffer>(connection_->shm(), size);
+ if (!shm_buffer_->IsValid()) {
+ LOG(ERROR) << "Failed to create drag icon buffer.";
+ return;
+ }
+ }
+ // TODO(crbug.com/1085418): Fix drag icon scaling
+ wl::DrawBitmap(*icon_bitmap_, shm_buffer_.get());
+ wl_surface_attach(icon_surface_.get(), shm_buffer_->get(), 0, 0);
+ wl_surface_damage(icon_surface_.get(), 0, 0, size.width(), size.height());
+ wl_surface_commit(icon_surface_.get());
+}
+
+void WaylandDataDragController::OnDragOffer(
+ std::unique_ptr<WaylandDataOffer> offer) {
+ DCHECK(!data_offer_);
+ data_offer_ = std::move(offer);
+}
+
+void WaylandDataDragController::OnDragEnter(WaylandWindow* window,
+ const gfx::PointF& location,
+ uint32_t serial) {
+ DCHECK(window);
+ window_ = window;
+
+ // TODO(crbug.com/1004715): Set mime type the client can accept. Now it sets
+ // all mime types offered because current implementation doesn't decide
+ // action based on mime type.
+ unprocessed_mime_types_.clear();
+ for (auto mime : data_offer_->mime_types()) {
+ unprocessed_mime_types_.push_back(mime);
+ data_offer_->Accept(serial, mime);
+ }
+
+ std::unique_ptr<OSExchangeData> dragged_data;
+ // If the DND session was initiated from a Chromium window, |data_| already
+ // holds the data to be exchanged, so no needed to read it through Wayland,
+ // thus just copy it here.
+ if (IsDragSource())
+ dragged_data = std::make_unique<OSExchangeData>(data_->provider().Clone());
+ window_->OnDragEnter(location, std::move(dragged_data),
+ GetPossibleActions(data_offer_->source_actions(),
+ data_offer_->dnd_action()));
+}
+
+void WaylandDataDragController::OnDragMotion(const gfx::PointF& location) {
+ if (!window_)
+ return;
+
+ int client_operation = window_->OnDragMotion(
+ location, GetPossibleActions(data_offer_->source_actions(),
+ data_offer_->dnd_action()));
+ SetOperation(client_operation);
+}
+
+void WaylandDataDragController::OnDragLeave() {
+ if (!window_)
+ return;
+
+ // Leave event can arrive while data is being transferred. As it cannot be
+ // handled right away, just mark it to be processed when the data is ready.
+ if (state_ == State::kTransferring) {
+ is_leave_pending_ = true;
+ return;
+ }
+
+ window_->OnDragLeave();
+ window_ = nullptr;
+ data_offer_.reset();
+ is_leave_pending_ = false;
+}
+
+void WaylandDataDragController::OnDragDrop() {
+ if (!window_)
+ return;
+
+ if (IsDragSource()) {
+ // This means the data is being exchanged between Chromium windows. In this
+ // case, data is supposed to have already been sent to the drop handler
+ // before (see OnDragEnter()), expecting to receive null at this stage.
+ OnDataTransferFinished(nullptr);
+ return;
+ }
+
+ // Otherwise, we are about to accept data dragged from another application.
+ // Reading the data may take some time so set |state_| to |kTrasfering|, which
+ // will make final "leave" event handling to be postponed until data is ready.
+ state_ = State::kTransferring;
+ received_data_ = std::make_unique<OSExchangeData>(
+ std::make_unique<OSExchangeDataProviderNonBacked>());
+ HandleUnprocessedMimeTypes();
+}
+
+void WaylandDataDragController::OnDataSourceFinish(bool completed) {
+ DCHECK(data_source_);
+ if (origin_window_)
+ origin_window_->OnDragSessionClose(data_source_->dnd_action());
+
+ origin_window_ = nullptr;
+ data_source_.reset();
+ data_offer_.reset();
+ data_.reset();
+ state_ = State::kIdle;
+}
+
+void WaylandDataDragController::OnDataSourceSend(const std::string& mime_type,
+ std::string* buffer) {
+ DCHECK(data_source_);
+ DCHECK(buffer);
+ DCHECK(data_);
+ if (!wl::ExtractOSExchangeData(*data_, mime_type, buffer)) {
+ LOG(WARNING) << "Cannot deliver data of type " << mime_type
+ << " and no text representation is available.";
+ }
+}
+
+void WaylandDataDragController::Offer(const OSExchangeData& data,
+ int operation) {
+ DCHECK(data_source_);
+
+ // Drag'n'drop manuals usually suggest putting data in order so the more
+ // specific a MIME type is, the earlier it occurs in the list. Wayland
+ // specs don't say anything like that, but here we follow that common
+ // practice: begin with URIs and end with plain text. Just in case.
+ std::vector<std::string> mime_types;
+ if (data.HasFile()) {
+ mime_types.push_back(kMimeTypeURIList);
+ }
+ if (data.HasURL(FilenameToURLPolicy::CONVERT_FILENAMES)) {
+ mime_types.push_back(kMimeTypeMozillaURL);
+ }
+ if (data.HasHtml()) {
+ mime_types.push_back(kMimeTypeHTML);
+ }
+ if (data.HasString()) {
+ mime_types.push_back(kMimeTypeTextUtf8);
+ mime_types.push_back(kMimeTypeText);
+ }
+
+ DCHECK(!mime_types.empty());
+ data_source_->Offer(mime_types);
+ data_source_->SetAction(operation);
+}
+
+wl_surface* WaylandDataDragController::CreateIconSurfaceIfNeeded(
+ const OSExchangeData& data) {
+ icon_bitmap_ = GetDragImage(data);
+ return icon_bitmap_ ? wl_compositor_create_surface(connection_->compositor())
+ : nullptr;
+}
+
+// Asynchronously requests and reads data for every negotiated/supported mime
+// type, one after another, OnMimeTypeDataTransferred calls back into this
+// function once it finishes reading data for each mime type, until there is no
+// more unprocessed mime types on the |unprocessed_mime_types_| queue. Once this
+// process is finished, OnDataTransferFinished is called to deliver the
+// |received_data_| to the drop handler.
+void WaylandDataDragController::HandleUnprocessedMimeTypes() {
+ DCHECK_EQ(state_, State::kTransferring);
+ std::string mime_type = GetNextUnprocessedMimeType();
+ if (mime_type.empty()) {
+ OnDataTransferFinished(std::move(received_data_));
+ } else {
+ DCHECK(data_offer_);
+ data_device_->RequestData(
+ data_offer_.get(), mime_type,
+ base::BindOnce(&WaylandDataDragController::OnMimeTypeDataTransferred,
+ weak_factory_.GetWeakPtr()));
+ }
+}
+
+void WaylandDataDragController::OnMimeTypeDataTransferred(
+ const PlatformClipboard::Data& contents) {
+ DCHECK_EQ(state_, State::kTransferring);
+ if (!contents.empty()) {
+ std::string mime_type = unprocessed_mime_types_.front();
+ wl::AddToOSExchangeData(contents, mime_type, received_data_.get());
+ }
+ unprocessed_mime_types_.pop_front();
+
+ // Continue reading data for other negotiated mime types.
+ HandleUnprocessedMimeTypes();
+}
+
+void WaylandDataDragController::OnDataTransferFinished(
+ std::unique_ptr<OSExchangeData> received_data) {
+ data_offer_->FinishOffer();
+ window_->OnDragDrop(std::move(received_data));
+
+ unprocessed_mime_types_.clear();
+ state_ = State::kIdle;
+
+ // If |is_leave_pending_| is set, it means a 'leave' event was fired while
+ // data was on transit, so process it here (See OnDragLeave for more context).
+ if (is_leave_pending_)
+ OnDragLeave();
+}
+
+// Returns the next MIME type to be received from the source process, or an
+// empty string if there are no more interesting MIME types left to process.
+std::string WaylandDataDragController::GetNextUnprocessedMimeType() {
+ while (!unprocessed_mime_types_.empty()) {
+ const std::string& mime_type = unprocessed_mime_types_.front();
+ // Skip unsupported or already processed mime types.
+ if (!wl::IsMimeTypeSupported(mime_type) ||
+ wl::ContainsMimeType(*received_data_, mime_type)) {
+ unprocessed_mime_types_.pop_front();
+ continue;
+ }
+ return mime_type;
+ }
+ return {};
+}
+
+void WaylandDataDragController::SetOperation(const int operation) {
+ uint32_t dnd_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+ uint32_t preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+
+ if (operation & DragDropTypes::DRAG_COPY) {
+ dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+ preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+ }
+
+ if (operation & DragDropTypes::DRAG_MOVE) {
+ dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
+ if (preferred_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE)
+ preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
+ }
+ data_offer_->SetAction(dnd_actions, preferred_action);
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
new file mode 100644
index 00000000000..2d1e1b09d6d
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
@@ -0,0 +1,136 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_DRAG_CONTROLLER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_DRAG_CONTROLLER_H_
+
+#include <list>
+#include <memory>
+#include <string>
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
+
+struct wl_surface;
+class SkBitmap;
+
+namespace ui {
+
+class OSExchangeData;
+class WaylandConnection;
+class WaylandDataDeviceManager;
+class WaylandDataOffer;
+class WaylandWindow;
+class WaylandWindowManager;
+class WaylandShmBuffer;
+
+// WaylandDataDragController implements regular data exchanging between Chromium
+// and other client applications on top of the Wayland Drag and Drop protocol.
+// By implementing both DataDevice::DragDelegate and DataSource::Delegate,
+// it is responsible for handling both DND sessions initiated from Chromium
+// windows as well as those triggered by other clients.
+class WaylandDataDragController : public WaylandDataDevice::DragDelegate,
+ public WaylandDataSource::Delegate {
+ public:
+ enum class State { kIdle, kStarted, kTransferring };
+
+ WaylandDataDragController(WaylandConnection* connection,
+ WaylandDataDeviceManager* data_device_manager);
+ WaylandDataDragController(const WaylandDataDragController&) = delete;
+ WaylandDataDragController& operator=(const WaylandDataDragController&) =
+ delete;
+ ~WaylandDataDragController() override;
+
+ // Starts a data drag and drop session for |data|. Only one DND session can
+ // run at a given time.
+ void StartSession(const ui::OSExchangeData& data, int operation);
+
+ State state() const { return state_; }
+
+ // TODO(crbug.com/896640): Remove once focus is fixed during DND sessions.
+ WaylandWindow* entered_window() const { return window_; }
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(WaylandDataDragControllerTest, ReceiveDrag);
+ FRIEND_TEST_ALL_PREFIXES(WaylandDataDragControllerTest, StartDrag);
+ FRIEND_TEST_ALL_PREFIXES(WaylandDataDragControllerTest, StartDragWithText);
+ FRIEND_TEST_ALL_PREFIXES(WaylandDataDragControllerTest,
+ StartDragWithWrongMimeType);
+
+ // WaylandDataDevice::DragDelegate:
+ bool IsDragSource() const override;
+ void DrawIcon() override;
+ void OnDragOffer(std::unique_ptr<WaylandDataOffer> offer) override;
+ void OnDragEnter(WaylandWindow* window,
+ const gfx::PointF& location,
+ uint32_t serial) override;
+ void OnDragMotion(const gfx::PointF& location) override;
+ void OnDragLeave() override;
+ void OnDragDrop() override;
+
+ // WaylandDataSource::Delegate:
+ void OnDataSourceFinish(bool completed) override;
+ void OnDataSourceSend(const std::string& mime_type,
+ std::string* contents) override;
+
+ void Offer(const OSExchangeData& data, int operation);
+ wl_surface* CreateIconSurfaceIfNeeded(const OSExchangeData& data);
+ void HandleUnprocessedMimeTypes();
+ void OnMimeTypeDataTransferred(const PlatformClipboard::Data& contents);
+ void OnDataTransferFinished(
+ std::unique_ptr<ui::OSExchangeData> received_data);
+ std::string GetNextUnprocessedMimeType();
+ void SetOperation(const int operation);
+
+ WaylandConnection* const connection_;
+ WaylandDataDeviceManager* const data_device_manager_;
+ WaylandDataDevice* const data_device_;
+ WaylandWindowManager* const window_manager_;
+
+ State state_ = State::kIdle;
+
+ std::unique_ptr<WaylandDataSource> data_source_;
+
+ // When dragging is started from Chromium, |data_| holds the data to be sent
+ // through wl_data_device instance.
+ std::unique_ptr<ui::OSExchangeData> data_;
+
+ // Offer to receive data from another process via drag-and-drop, or null if
+ // no drag-and-drop from another process is in progress.
+ //
+ // The data offer from another Wayland client through wl_data_device, that
+ // triggered the current drag and drop session. If null, either there is no
+ // dnd session running or Chromium is the data source.
+ std::unique_ptr<WaylandDataOffer> data_offer_;
+
+ // Mime types to be handled.
+ std::list<std::string> unprocessed_mime_types_;
+
+ // The window that initiated the drag session. Can be null when the session
+ // has been started by an external Wayland client.
+ WaylandWindow* origin_window_ = nullptr;
+
+ // Current window under pointer.
+ WaylandWindow* window_ = nullptr;
+
+ // The data delivered from Wayland
+ std::unique_ptr<ui::OSExchangeData> received_data_;
+
+ // Set when 'leave' event is fired while data is being transferred.
+ bool is_leave_pending_ = false;
+
+ // Drag icon related variables.
+ wl::Object<wl_surface> icon_surface_;
+ std::unique_ptr<WaylandShmBuffer> shm_buffer_;
+ const SkBitmap* icon_bitmap_ = nullptr;
+
+ base::WeakPtrFactory<WaylandDataDragController> weak_factory_{this};
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_DRAG_CONTROLLER_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
new file mode 100644
index 00000000000..a320c70dd1d
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
@@ -0,0 +1,406 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <wayland-server.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/containers/flat_set.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/clipboard/clipboard_constants.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/file_info/file_info.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/ozone/platform/wayland/common/data_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
+#include "ui/ozone/platform/wayland/test/constants.h"
+#include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/test_data_device.h"
+#include "ui/ozone/platform/wayland/test/test_data_device_manager.h"
+#include "ui/ozone/platform/wayland/test/test_data_offer.h"
+#include "ui/ozone/platform/wayland/test/test_data_source.h"
+#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
+#include "ui/ozone/public/platform_clipboard.h"
+#include "ui/platform_window/platform_window_handler/wm_drop_handler.h"
+#include "url/gurl.h"
+
+using testing::_;
+using testing::Mock;
+
+namespace ui {
+
+namespace {
+
+constexpr FilenameToURLPolicy kFilenameToURLPolicy =
+ FilenameToURLPolicy::CONVERT_FILENAMES;
+
+template <typename StringType>
+PlatformClipboard::Data ToClipboardData(const StringType& data_string) {
+ PlatformClipboard::Data result;
+ auto* begin =
+ reinterpret_cast<typename PlatformClipboard::Data::const_pointer>(
+ data_string.data());
+ result.assign(begin, begin + (data_string.size() *
+ sizeof(typename StringType::value_type)));
+ return result;
+}
+
+} // namespace
+
+class MockDropHandler : public WmDropHandler {
+ public:
+ MockDropHandler() = default;
+ ~MockDropHandler() override = default;
+
+ MOCK_METHOD3(OnDragEnter,
+ void(const gfx::PointF& point,
+ std::unique_ptr<OSExchangeData> data,
+ int operation));
+ MOCK_METHOD2(OnDragMotion, int(const gfx::PointF& point, int operation));
+ MOCK_METHOD0(MockOnDragDrop, void());
+ MOCK_METHOD0(OnDragLeave, void());
+
+ void SetOnDropClosure(base::RepeatingClosure closure) {
+ on_drop_closure_ = closure;
+ }
+
+ OSExchangeData* dropped_data() { return dropped_data_.get(); }
+
+ protected:
+ void OnDragDrop(std::unique_ptr<OSExchangeData> data) override {
+ dropped_data_ = std::move(data);
+ MockOnDragDrop();
+ on_drop_closure_.Run();
+ on_drop_closure_.Reset();
+ }
+
+ private:
+ base::RepeatingClosure on_drop_closure_;
+
+ std::unique_ptr<OSExchangeData> dropped_data_;
+};
+
+class WaylandDataDragControllerTest : public WaylandTest {
+ public:
+ WaylandDataDragControllerTest() = default;
+
+ void SetUp() override {
+ WaylandTest::SetUp();
+
+ Sync();
+
+ data_device_manager_ = server_.data_device_manager();
+ DCHECK(data_device_manager_);
+
+ drop_handler_ = std::make_unique<MockDropHandler>();
+ SetWmDropHandler(window_.get(), drop_handler_.get());
+ }
+
+ WaylandDataDragController* drag_controller() const {
+ return connection_->data_drag_controller();
+ }
+
+ WaylandDataDevice* data_device() const {
+ return connection_->data_device_manager()->GetDevice();
+ }
+
+ base::string16 sample_text_for_dnd() const {
+ static auto text = base::ASCIIToUTF16(wl::kSampleTextForDragAndDrop);
+ return text;
+ }
+
+ protected:
+ wl::TestDataDeviceManager* data_device_manager_;
+ std::unique_ptr<MockDropHandler> drop_handler_;
+};
+
+TEST_P(WaylandDataDragControllerTest, StartDrag) {
+ bool restored_focus = window_->has_pointer_focus();
+ window_->SetPointerFocus(true);
+
+ // The client starts dragging.
+ OSExchangeData os_exchange_data;
+ os_exchange_data.SetString(sample_text_for_dnd());
+ int operation = DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE;
+ drag_controller()->StartSession(os_exchange_data, operation);
+ Sync();
+
+ // The server reads the data and the callback gets it.
+ base::RunLoop run_loop;
+ auto callback = base::BindOnce(
+ [](base::RunLoop* loop, PlatformClipboard::Data&& data) {
+ std::string result(data.begin(), data.end());
+ EXPECT_EQ(wl::kSampleTextForDragAndDrop, result);
+ loop->Quit();
+ },
+ &run_loop);
+ data_device_manager_->data_source()->ReadData(wl::kTextMimeTypeUtf8,
+ std::move(callback));
+ run_loop.Run();
+ window_->SetPointerFocus(restored_focus);
+}
+
+TEST_P(WaylandDataDragControllerTest, StartDragWithWrongMimeType) {
+ bool restored_focus = window_->has_pointer_focus();
+ window_->SetPointerFocus(true);
+
+ // The client starts dragging offering data with |kMimeTypeHTML|
+ OSExchangeData os_exchange_data;
+ os_exchange_data.SetHtml(sample_text_for_dnd(), {});
+ int operation = DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE;
+ drag_controller()->StartSession(os_exchange_data, operation);
+ Sync();
+
+ // The server should get an empty data buffer in ReadData callback when trying
+ // to read it with a different mime type.
+ base::RunLoop run_loop;
+ auto callback = base::BindOnce(
+ [](base::RunLoop* loop, PlatformClipboard::Data&& data) {
+ std::string result(data.begin(), data.end());
+ EXPECT_TRUE(result.empty());
+ loop->Quit();
+ },
+ &run_loop);
+ data_device_manager_->data_source()->ReadData(kMimeTypeText,
+ std::move(callback));
+ run_loop.Run();
+ window_->SetPointerFocus(restored_focus);
+}
+
+TEST_P(WaylandDataDragControllerTest, StartDragWithText) {
+ bool restored_focus = window_->has_pointer_focus();
+ window_->SetPointerFocus(true);
+
+ // The client starts dragging offering text mime type.
+ OSExchangeData os_exchange_data;
+ os_exchange_data.SetString(sample_text_for_dnd());
+ int operation = DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE;
+ drag_controller()->StartSession(os_exchange_data, operation);
+ Sync();
+
+ // The server should get a "text" representation in ReadData callback when
+ // trying to read it as mime type other than |kMimeTypeText| and
+ // |kTextMimeTypeUtf8|.
+ base::RunLoop run_loop;
+ auto callback = base::BindOnce(
+ [](base::RunLoop* loop, PlatformClipboard::Data&& data) {
+ std::string result(data.begin(), data.end());
+ EXPECT_EQ(wl::kSampleTextForDragAndDrop, result);
+ loop->Quit();
+ },
+ &run_loop);
+ data_device_manager_->data_source()->ReadData(kMimeTypeMozillaURL,
+ std::move(callback));
+ run_loop.Run();
+ window_->SetPointerFocus(restored_focus);
+}
+
+TEST_P(WaylandDataDragControllerTest, ReceiveDrag) {
+ auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
+ data_offer->OnOffer(
+ kMimeTypeText,
+ ToClipboardData(std::string(wl::kSampleTextForDragAndDrop)));
+
+ gfx::Point entered_point(10, 10);
+ // The server sends an enter event.
+ data_device_manager_->data_device()->OnEnter(
+ 1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
+ wl_fixed_from_int(entered_point.y()), data_offer);
+
+ int64_t time =
+ (EventTimeForNow() - base::TimeTicks()).InMilliseconds() & UINT32_MAX;
+ gfx::Point motion_point(11, 11);
+
+ // The server sends an motion event.
+ data_device_manager_->data_device()->OnMotion(
+ time, wl_fixed_from_int(motion_point.x()),
+ wl_fixed_from_int(motion_point.y()));
+
+ Sync();
+
+ auto callback = base::BindOnce([](const PlatformClipboard::Data& contents) {
+ std::string result;
+ result.assign(reinterpret_cast<std::string::const_pointer>(&contents[0]),
+ contents.size());
+ EXPECT_EQ(wl::kSampleTextForDragAndDrop, result);
+ });
+
+ // The client requests the data and gets callback with it.
+ data_device()->RequestData(drag_controller()->data_offer_.get(),
+ kMimeTypeText, std::move(callback));
+ Sync();
+
+ data_device_manager_->data_device()->OnLeave();
+}
+
+TEST_P(WaylandDataDragControllerTest, DropSeveralMimeTypes) {
+ auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
+ data_offer->OnOffer(
+ kMimeTypeText,
+ ToClipboardData(std::string(wl::kSampleTextForDragAndDrop)));
+ data_offer->OnOffer(kMimeTypeMozillaURL, ToClipboardData(base::UTF8ToUTF16(
+ "https://sample.com/\r\n"
+ "Sample")));
+ data_offer->OnOffer(
+ kMimeTypeURIList,
+ ToClipboardData(std::string("file:///home/user/file\r\n")));
+
+ EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _)).Times(1);
+ gfx::Point entered_point(10, 10);
+ data_device_manager_->data_device()->OnEnter(
+ 1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
+ wl_fixed_from_int(entered_point.y()), data_offer);
+ Sync();
+ Mock::VerifyAndClearExpectations(drop_handler_.get());
+
+ EXPECT_CALL(*drop_handler_, MockOnDragDrop()).Times(1);
+ base::RunLoop loop;
+ drop_handler_->SetOnDropClosure(loop.QuitClosure());
+ data_device_manager_->data_device()->OnDrop();
+
+ // Here we are expecting three data items, so there will be three roundtrips
+ // to the Wayland and back. Hence Sync() three times.
+ Sync();
+ Sync();
+ Sync();
+ loop.Run();
+ Mock::VerifyAndClearExpectations(drop_handler_.get());
+
+ EXPECT_TRUE(drop_handler_->dropped_data()->HasString());
+ EXPECT_TRUE(drop_handler_->dropped_data()->HasFile());
+ EXPECT_TRUE(drop_handler_->dropped_data()->HasURL(kFilenameToURLPolicy));
+
+ data_device_manager_->data_device()->OnLeave();
+}
+
+// Tests URI validation for text/uri-list MIME type. Log warnings rendered in
+// the console when this test is running are the expected and valid side effect.
+TEST_P(WaylandDataDragControllerTest, ValidateDroppedUriList) {
+ const struct {
+ std::string content;
+ base::flat_set<std::string> expected_uris;
+ } kCases[] = {{{}, {}},
+ {"file:///home/user/file\r\n", {"/home/user/file"}},
+ {"# Comment\r\n"
+ "file:///home/user/file\r\n"
+ "file:///home/guest/file\r\n"
+ "not a filename at all\r\n"
+ "https://valid.url/but/scheme/is/not/file/so/invalid\r\n",
+ {"/home/user/file", "/home/guest/file"}}};
+
+ for (const auto& kCase : kCases) {
+ auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
+ data_offer->OnOffer(kMimeTypeURIList, ToClipboardData(kCase.content));
+
+ EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _)).Times(1);
+ gfx::Point entered_point(10, 10);
+ data_device_manager_->data_device()->OnEnter(
+ 1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
+ wl_fixed_from_int(entered_point.y()), data_offer);
+ Sync();
+ Mock::VerifyAndClearExpectations(drop_handler_.get());
+
+ EXPECT_CALL(*drop_handler_, MockOnDragDrop()).Times(1);
+ base::RunLoop loop;
+ drop_handler_->SetOnDropClosure(loop.QuitClosure());
+ data_device_manager_->data_device()->OnDrop();
+
+ Sync();
+ loop.Run();
+ Mock::VerifyAndClearExpectations(drop_handler_.get());
+
+ if (kCase.expected_uris.empty()) {
+ EXPECT_FALSE(drop_handler_->dropped_data()->HasFile());
+ } else {
+ EXPECT_TRUE(drop_handler_->dropped_data()->HasFile());
+ std::vector<FileInfo> filenames;
+ EXPECT_TRUE(drop_handler_->dropped_data()->GetFilenames(&filenames));
+ EXPECT_EQ(filenames.size(), kCase.expected_uris.size());
+ for (const auto& filename : filenames)
+ EXPECT_EQ(kCase.expected_uris.count(filename.path.AsUTF8Unsafe()), 1U);
+ }
+
+ EXPECT_CALL(*drop_handler_, OnDragLeave()).Times(1);
+ data_device_manager_->data_device()->OnLeave();
+ Sync();
+ Mock::VerifyAndClearExpectations(drop_handler_.get());
+ }
+}
+
+// Tests URI validation for text/x-moz-url MIME type. Log warnings rendered in
+// the console when this test is running are the expected and valid side effect.
+TEST_P(WaylandDataDragControllerTest, ValidateDroppedXMozUrl) {
+ const struct {
+ std::string content;
+ std::string expected_url;
+ std::string expected_title;
+ } kCases[] = {
+ {{}, {}, {}},
+ {"http://sample.com/\r\nSample", "http://sample.com/", "Sample"},
+ {"http://title.must.be.set/", {}, {}},
+ {"url.must.be.valid/and/have.scheme\r\nInvalid URL", {}, {}},
+ {"file:///files/are/ok\r\nThe policy allows that", "file:///files/are/ok",
+ "The policy allows that"}};
+
+ for (const auto& kCase : kCases) {
+ auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
+ data_offer->OnOffer(kMimeTypeMozillaURL,
+ ToClipboardData(base::UTF8ToUTF16(kCase.content)));
+
+ EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _)).Times(1);
+ gfx::Point entered_point(10, 10);
+ data_device_manager_->data_device()->OnEnter(
+ 1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
+ wl_fixed_from_int(entered_point.y()), data_offer);
+ Sync();
+ Mock::VerifyAndClearExpectations(drop_handler_.get());
+
+ EXPECT_CALL(*drop_handler_, MockOnDragDrop()).Times(1);
+ base::RunLoop loop;
+ drop_handler_->SetOnDropClosure(loop.QuitClosure());
+ data_device_manager_->data_device()->OnDrop();
+
+ Sync();
+ loop.Run();
+ Mock::VerifyAndClearExpectations(drop_handler_.get());
+
+ const auto* const dropped_data = drop_handler_->dropped_data();
+ if (kCase.expected_url.empty()) {
+ EXPECT_FALSE(dropped_data->HasURL(kFilenameToURLPolicy));
+ } else {
+ EXPECT_TRUE(dropped_data->HasURL(kFilenameToURLPolicy));
+ GURL url;
+ base::string16 title;
+ EXPECT_TRUE(
+ dropped_data->GetURLAndTitle(kFilenameToURLPolicy, &url, &title));
+ EXPECT_EQ(url.spec(), kCase.expected_url);
+ EXPECT_EQ(title, base::UTF8ToUTF16(kCase.expected_title));
+ }
+
+ EXPECT_CALL(*drop_handler_, OnDragLeave()).Times(1);
+ data_device_manager_->data_device()->OnLeave();
+ Sync();
+ Mock::VerifyAndClearExpectations(drop_handler_.get());
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
+ WaylandDataDragControllerTest,
+ ::testing::Values(kXdgShellStable));
+
+INSTANTIATE_TEST_SUITE_P(XdgVersionV6Test,
+ WaylandDataDragControllerTest,
+ ::testing::Values(kXdgShellV6));
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_source.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_source.cc
index 0b92ceaeba7..1d66a9f74cb 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_source.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_source.cc
@@ -4,156 +4,148 @@
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
+#include <gtk-primary-selection-client-protocol.h>
+#include <wayland-client-protocol.h>
+
+#include <cstdint>
#include <vector>
#include "base/files/file_util.h"
-#include "base/optional.h"
-#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
-#include "ui/ozone/platform/wayland/host/wayland_window.h"
-namespace ui {
+namespace wl {
-WaylandDataSource::WaylandDataSource(wl_data_source* data_source,
- WaylandConnection* connection)
- : data_source_(data_source), connection_(connection) {
- static const struct wl_data_source_listener kDataSourceListener = {
- WaylandDataSource::OnTarget, WaylandDataSource::OnSend,
- WaylandDataSource::OnCancel, WaylandDataSource::OnDnDDropPerformed,
- WaylandDataSource::OnDnDFinished, WaylandDataSource::OnAction};
- wl_data_source_add_listener(data_source, &kDataSourceListener, this);
+template <typename T>
+DataSource<T>::DataSource(T* data_source,
+ ui::WaylandConnection* connection,
+ Delegate* delegate)
+ : data_source_(data_source), connection_(connection), delegate_(delegate) {
+ DCHECK(data_source_);
+ DCHECK(connection_);
+ DCHECK(delegate_);
+
+ Initialize();
}
-WaylandDataSource::~WaylandDataSource() = default;
+template <typename T>
+void DataSource<T>::HandleFinishEvent(bool completed) {
+ delegate_->OnDataSourceFinish(/*completed=*/false);
+}
-void WaylandDataSource::WriteToClipboard(
- const PlatformClipboard::DataMap& data_map) {
- for (const auto& data : data_map) {
- wl_data_source_offer(data_source_.get(), data.first.c_str());
- if (strcmp(data.first.c_str(), kMimeTypeText) == 0)
- wl_data_source_offer(data_source_.get(), kMimeTypeTextUtf8);
- }
- wl_data_device_set_selection(connection_->data_device(), data_source_.get(),
- connection_->serial());
+template <typename T>
+void DataSource<T>::HandleSendEvent(const std::string& mime_type, int32_t fd) {
+ std::string contents;
+ delegate_->OnDataSourceSend(mime_type, &contents);
+ bool done = base::WriteFileDescriptor(fd, contents.data(), contents.length());
+ DCHECK(done);
+ close(fd);
+}
- connection_->ScheduleFlush();
+// static
+template <typename T>
+void DataSource<T>::OnSend(void* data,
+ T* source,
+ const char* mime_type,
+ int32_t fd) {
+ auto* self = static_cast<DataSource<T>*>(data);
+ self->HandleSendEvent(mime_type, fd);
}
-void WaylandDataSource::Offer(const ui::OSExchangeData& data) {
- // Drag'n'drop manuals usually suggest putting data in order so the more
- // specific a MIME type is, the earlier it occurs in the list. Wayland specs
- // don't say anything like that, but here we follow that common practice:
- // begin with URIs and end with plain text. Just in case.
- std::vector<std::string> mime_types;
- if (data.HasFile()) {
- mime_types.push_back(kMimeTypeURIList);
- }
- if (data.HasURL(ui::CONVERT_FILENAMES)) {
- mime_types.push_back(kMimeTypeMozillaURL);
- }
- if (data.HasHtml()) {
- mime_types.push_back(kMimeTypeHTML);
- }
- if (data.HasString()) {
- mime_types.push_back(kMimeTypeTextUtf8);
- mime_types.push_back(kMimeTypeText);
- }
+template <typename T>
+void DataSource<T>::OnCancel(void* data, T* source) {
+ auto* self = static_cast<DataSource<T>*>(data);
+ self->HandleFinishEvent(/*completed=*/false);
+}
- source_window_ =
- connection_->wayland_window_manager()->GetCurrentFocusedWindow();
- for (auto& mime_type : mime_types)
- wl_data_source_offer(data_source_.get(), mime_type.data());
+template <typename T>
+void DataSource<T>::OnDnDFinished(void* data, T* source) {
+ auto* self = static_cast<DataSource<T>*>(data);
+ self->HandleFinishEvent(/*completed=*/true);
}
-void WaylandDataSource::SetDragData(const DragDataMap& data_map) {
- DCHECK(drag_data_map_.empty());
- drag_data_map_ = data_map;
+template <typename T>
+void DataSource<T>::OnAction(void* data, T* source, uint32_t dnd_action) {
+ auto* self = static_cast<DataSource<T>*>(data);
+ self->dnd_action_ = dnd_action;
}
-void WaylandDataSource::SetAction(int operation) {
- if (wl_data_source_get_version(data_source_.get()) >=
- WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION) {
- uint32_t dnd_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
- if (operation & DragDropTypes::DRAG_COPY)
- dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
- if (operation & DragDropTypes::DRAG_MOVE)
- dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
- wl_data_source_set_actions(data_source_.get(), dnd_actions);
- }
+template <typename T>
+void DataSource<T>::OnTarget(void* data, T* source, const char* mime_type) {
+ NOTIMPLEMENTED_LOG_ONCE();
}
-// static
-void WaylandDataSource::OnTarget(void* data,
- wl_data_source* source,
- const char* mime_type) {
+template <typename T>
+void DataSource<T>::OnDnDDropPerformed(void* data, T* source) {
NOTIMPLEMENTED_LOG_ONCE();
}
-// static
-void WaylandDataSource::OnSend(void* data,
- wl_data_source* source,
- const char* mime_type,
- int32_t fd) {
- WaylandDataSource* self = static_cast<WaylandDataSource*>(data);
- std::string contents;
- if (self->source_window_) {
- // If |source_window_| is valid when OnSend() is called, it means that DnD
- // is working.
- self->GetDragData(mime_type, &contents);
- } else {
- base::Optional<std::vector<uint8_t>> mime_data;
- self->GetClipboardData(mime_type, &mime_data);
- if (!mime_data.has_value() && strcmp(mime_type, kMimeTypeTextUtf8) == 0)
- self->GetClipboardData(kMimeTypeText, &mime_data);
- contents.assign(mime_data->begin(), mime_data->end());
- }
- bool result =
- base::WriteFileDescriptor(fd, contents.data(), contents.length());
- DCHECK(result);
- close(fd);
+//////////////////////////////////////////////////////////////////////////////
+// wl_data_source specializations and instantiation
+//////////////////////////////////////////////////////////////////////////////
+
+template <>
+void DataSource<wl_data_source>::Initialize() {
+ static const struct wl_data_source_listener kDataSourceListener = {
+ DataSource<wl_data_source>::OnTarget,
+ DataSource<wl_data_source>::OnSend,
+ DataSource<wl_data_source>::OnCancel,
+ DataSource<wl_data_source>::OnDnDDropPerformed,
+ DataSource<wl_data_source>::OnDnDFinished,
+ DataSource<wl_data_source>::OnAction};
+ wl_data_source_add_listener(data_source_.get(), &kDataSourceListener, this);
}
-// static
-void WaylandDataSource::OnCancel(void* data, wl_data_source* source) {
- WaylandDataSource* self = static_cast<WaylandDataSource*>(data);
- if (self->source_window_) {
- // If it has |source_window_|, it is in the middle of 'drag and drop'. it
- // cancels 'drag and drop'.
- self->connection_->FinishDragSession(self->dnd_action_,
- self->source_window_);
- } else {
- self->connection_->clipboard()->DataSourceCancelled(
- ClipboardBuffer::kCopyPaste);
- }
+template <>
+void DataSource<wl_data_source>::Offer(
+ const std::vector<std::string>& mime_types) {
+ for (auto& mime_type : mime_types)
+ wl_data_source_offer(data_source_.get(), mime_type.c_str());
+ connection_->ScheduleFlush();
}
-void WaylandDataSource::OnDnDDropPerformed(void* data, wl_data_source* source) {
+template <typename T>
+void DataSource<T>::SetAction(int operation) {
NOTIMPLEMENTED_LOG_ONCE();
}
-void WaylandDataSource::OnDnDFinished(void* data, wl_data_source* source) {
- WaylandDataSource* self = static_cast<WaylandDataSource*>(data);
- self->connection_->FinishDragSession(self->dnd_action_, self->source_window_);
+template <>
+void DataSource<wl_data_source>::SetAction(int operation) {
+ if (wl_data_source_get_version(data_source_.get()) >=
+ WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION) {
+ uint32_t dnd_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+ if (operation & ui::DragDropTypes::DRAG_COPY)
+ dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+ if (operation & ui::DragDropTypes::DRAG_MOVE)
+ dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
+ wl_data_source_set_actions(data_source_.get(), dnd_actions);
+ }
}
-void WaylandDataSource::OnAction(void* data,
- wl_data_source* source,
- uint32_t dnd_action) {
- WaylandDataSource* self = static_cast<WaylandDataSource*>(data);
- self->dnd_action_ = dnd_action;
-}
+template class DataSource<wl_data_source>;
-void WaylandDataSource::GetDragData(const std::string& mime_type,
- std::string* contents) {
- auto it = drag_data_map_.find(mime_type);
- if (it != drag_data_map_.end()) {
- *contents = it->second;
- return;
- }
+//////////////////////////////////////////////////////////////////////////////
+// gtk_primary_selection_source specializations and instantiation
+//////////////////////////////////////////////////////////////////////////////
+
+template <>
+void DataSource<gtk_primary_selection_source>::Initialize() {
+ static const struct gtk_primary_selection_source_listener
+ kDataSourceListener = {
+ DataSource<gtk_primary_selection_source>::OnSend,
+ DataSource<gtk_primary_selection_source>::OnCancel};
+ gtk_primary_selection_source_add_listener(data_source_.get(),
+ &kDataSourceListener, this);
+}
- connection_->DeliverDragData(mime_type, contents);
+template <>
+void DataSource<gtk_primary_selection_source>::Offer(
+ const std::vector<std::string>& mime_types) {
+ for (const auto& mime_type : mime_types)
+ gtk_primary_selection_source_offer(data_source_.get(), mime_type.c_str());
+ connection_->ScheduleFlush();
}
-} // namespace ui
+template class DataSource<gtk_primary_selection_source>;
+
+} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_source.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_source.h
index 4f66465a699..2bcee213cc5 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_source.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_source.h
@@ -5,76 +5,98 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_SOURCE_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_SOURCE_H_
-#include <wayland-client.h>
-
-#include <map>
+#include <cstdint>
#include <string>
+#include <vector>
-#include "base/logging.h"
#include "base/macros.h"
-#include "base/optional.h"
+#include "base/notreached.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
-#include "ui/ozone/platform/wayland/host/wayland_data_source_base.h"
-#include "ui/ozone/public/platform_clipboard.h"
+
+struct wl_data_source;
+struct gtk_primary_selection_source;
+
+namespace wl {
+template <typename T>
+class DataSource;
+} // namespace wl
namespace ui {
-class OSExchangeData;
class WaylandConnection;
-class WaylandWindow;
-
-// The WaylandDataSource object represents the source side of a
-// WaylandDataOffer. It is created by the source client in a data
-// transfer and provides a way to describe the offered data
-// (wl_data_source_offer) // and a way to respond to requests to
-// transfer the data (OnSend listener).
-class WaylandDataSource : public WaylandDataSourceBase {
- public:
- using DragDataMap = std::map<std::string, std::string>;
- // Takes ownership of data_source.
- explicit WaylandDataSource(wl_data_source* data_source,
- WaylandConnection* connection);
- ~WaylandDataSource() override;
+// DataSource represents the source side of a DataOffer. It is created by the
+// source client in a data transfer and provides a way to describe the offered
+// data and a way to respond to requests to transfer the data. There are a few
+// variants of Wayland protocol objects and extensions supporting different
+// features. E.g: regular copy/paste and drag operations are implemented by
+// wl_data_source (along with its _device and _offer counterparts), etc.
+// Implementation wise, these variants are share a single class template, with
+// specializations defined for each underlying supported extensions. Below are
+// the type aliases for the variants currently supported.
+//
+// TODO(crbug.com/1088132): Support standard primary selection extension.
+
+using WaylandDataSource = wl::DataSource<wl_data_source>;
+
+using GtkPrimarySelectionSource = wl::DataSource<gtk_primary_selection_source>;
+
+} // namespace ui
- void set_connection(WaylandConnection* connection) {
- DCHECK(connection);
- connection_ = connection;
- }
+namespace wl {
- void WriteToClipboard(const PlatformClipboard::DataMap& data_map) override;
- void Offer(const ui::OSExchangeData& data);
+// Template class implementing DataSource, whereas T is the underlying source
+// type, e.g: wl_data_source, gtk_primary_selection_source, etc. This class
+// is not supposed to be used directly, instead use the aliases defined above.
+template <typename T>
+class DataSource {
+ public:
+ class Delegate {
+ public:
+ virtual void OnDataSourceFinish(bool completed) = 0;
+ virtual void OnDataSourceSend(const std::string& mime_type,
+ std::string* contents) = 0;
+
+ protected:
+ virtual ~Delegate() = default;
+ };
+
+ // Takes ownership of |data_source|.
+ DataSource(T* data_source,
+ ui::WaylandConnection* connection,
+ Delegate* delegate);
+ DataSource(const DataSource<T>&) = delete;
+ DataSource& operator=(const DataSource<T>&) = delete;
+ ~DataSource() = default;
+
+ void Initialize();
+ void Offer(const std::vector<std::string>& mime_types);
void SetAction(int operation);
- void SetDragData(const DragDataMap& data_map);
- wl_data_source* data_source() const { return data_source_.get(); }
+ uint32_t dnd_action() const { return dnd_action_; }
+ T* data_source() const { return data_source_.get(); }
private:
- static void OnTarget(void* data,
- wl_data_source* source,
- const char* mime_type);
- static void OnSend(void* data,
- wl_data_source* source,
- const char* mime_type,
- int32_t fd);
- static void OnCancel(void* data, wl_data_source* source);
- static void OnDnDDropPerformed(void* data, wl_data_source* source);
- static void OnDnDFinished(void* data, wl_data_source* source);
- static void OnAction(void* data, wl_data_source* source, uint32_t dnd_action);
-
- void GetDragData(const std::string& mime_type, std::string* contents);
-
- wl::Object<wl_data_source> data_source_;
- WaylandConnection* connection_ = nullptr;
- WaylandWindow* source_window_ = nullptr;
-
- DragDataMap drag_data_map_;
+ void HandleFinishEvent(bool completed);
+ void HandleSendEvent(const std::string& mime_type, int32_t fd);
+
+ static void OnSend(void* data, T* source, const char* mime_type, int32_t fd);
+ static void OnCancel(void* data, T* source);
+ static void OnDnDFinished(void* data, T* source);
+ static void OnAction(void* data, T* source, uint32_t dnd_action);
+ static void OnTarget(void* data, T* source, const char* mime_type);
+ static void OnDnDDropPerformed(void* data, T* source);
+
+ wl::Object<T> data_source_;
+
+ ui::WaylandConnection* const connection_;
+
+ Delegate* const delegate_;
+
// Action selected by the compositor
uint32_t dnd_action_;
-
- DISALLOW_COPY_AND_ASSIGN(WaylandDataSource);
};
-} // namespace ui
+} // namespace wl
#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_SOURCE_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_source_base.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_source_base.cc
deleted file mode 100644
index c7bba1d2538..00000000000
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_source_base.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/ozone/platform/wayland/host/wayland_data_source_base.h"
-
-namespace ui {
-
-WaylandDataSourceBase::WaylandDataSourceBase() = default;
-WaylandDataSourceBase::~WaylandDataSourceBase() = default;
-
-void WaylandDataSourceBase::GetClipboardData(
- const std::string& mime_type,
- base::Optional<std::vector<uint8_t>>* data) const {
- auto it = data_map_.find(mime_type);
- if (it == data_map_.end())
- return;
- data->emplace(it->second);
-}
-
-} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_source_base.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_source_base.h
deleted file mode 100644
index 4e4d66b1607..00000000000
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_source_base.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_SOURCE_BASE_H_
-#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_SOURCE_BASE_H_
-
-#include "base/macros.h"
-#include "ui/ozone/public/platform_clipboard.h"
-
-namespace ui {
-
-// Implements high level (protocol-agnostic) interface to a Wayland data source.
-class WaylandDataSourceBase {
- public:
- WaylandDataSourceBase();
- virtual ~WaylandDataSourceBase();
-
- void set_data_map(const PlatformClipboard::DataMap& data_map) {
- data_map_ = data_map;
- }
-
- // Writes data to the system clipboard using the protocol-defined data source.
- virtual void WriteToClipboard(const PlatformClipboard::DataMap& data_map) = 0;
-
- protected:
- void GetClipboardData(const std::string& mime_type,
- base::Optional<std::vector<uint8_t>>* data) const;
-
- private:
- PlatformClipboard::DataMap data_map_;
-
- DISALLOW_COPY_AND_ASSIGN(WaylandDataSourceBase);
-};
-
-} // namespace ui
-
-#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_SOURCE_BASE_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_drm.cc b/chromium/ui/ozone/platform/wayland/host/wayland_drm.cc
index 12a91eed83a..e387e48c686 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_drm.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_drm.cc
@@ -8,6 +8,7 @@
#include <xf86drm.h>
#include "base/files/scoped_file.h"
+#include "base/logging.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/linux/drm_util_linux.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc
index a83c0bfe87c..48d500ae5fb 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc
@@ -96,21 +96,21 @@ void WaylandEventSource::OnKeyboardModifiersChanged(int modifiers) {
keyboard_modifiers_ = modifiers;
}
-void WaylandEventSource::OnKeyboardKeyEvent(EventType type,
- DomCode dom_code,
- DomKey dom_key,
- KeyboardCode key_code,
- bool repeat,
- base::TimeTicks timestamp) {
+uint32_t WaylandEventSource::OnKeyboardKeyEvent(EventType type,
+ DomCode dom_code,
+ DomKey dom_key,
+ KeyboardCode key_code,
+ bool repeat,
+ base::TimeTicks timestamp) {
DCHECK(type == ET_KEY_PRESSED || type == ET_KEY_RELEASED);
if (!keyboard_)
- return;
+ return POST_DISPATCH_NONE;
// try to decode key, if not yet.
if (dom_key == DomKey::NONE &&
!keyboard_->Decode(dom_code, keyboard_modifiers_, &dom_key, &key_code)) {
LOG(ERROR) << "Failed to decode key event.";
- return;
+ return POST_DISPATCH_NONE;
}
if (!repeat) {
@@ -121,7 +121,7 @@ void WaylandEventSource::OnKeyboardKeyEvent(EventType type,
KeyEvent event(type, key_code, dom_code, keyboard_modifiers_, dom_key,
timestamp);
event.set_source_device_id(keyboard_->device_id());
- DispatchEvent(&event);
+ return DispatchEvent(&event);
}
void WaylandEventSource::OnPointerCreated(WaylandPointer* pointer) {
@@ -133,15 +133,13 @@ void WaylandEventSource::OnPointerDestroyed(WaylandPointer* pointer) {
DCHECK_EQ(pointer_, pointer);
// Clear focused window, if any.
- if (auto* focused_window = window_manager_->GetCurrentFocusedWindow())
- HandlePointerFocusChange(focused_window, false);
+ HandlePointerFocusChange(nullptr);
ResetPointerFlags();
pointer_ = nullptr;
}
void WaylandEventSource::OnPointerFocusChanged(WaylandWindow* window,
- bool focused,
const gfx::PointF& location) {
if (!pointer_)
return;
@@ -149,8 +147,9 @@ void WaylandEventSource::OnPointerFocusChanged(WaylandWindow* window,
// Save new pointer location.
pointer_location_ = location;
+ bool focused = !!window;
if (focused)
- HandlePointerFocusChange(window, focused);
+ HandlePointerFocusChange(window);
EventType type = focused ? ET_MOUSE_ENTERED : ET_MOUSE_EXITED;
MouseEvent event(type, location, location, EventTimeForNow(), pointer_flags_,
@@ -158,7 +157,7 @@ void WaylandEventSource::OnPointerFocusChanged(WaylandWindow* window,
DispatchEvent(&event);
if (!focused)
- HandlePointerFocusChange(window, focused);
+ HandlePointerFocusChange(nullptr);
}
void WaylandEventSource::OnPointerButtonEvent(EventType type,
@@ -172,6 +171,7 @@ void WaylandEventSource::OnPointerButtonEvent(EventType type,
pointer_flags_ = type == ET_MOUSE_PRESSED
? (pointer_flags_ | changed_button)
: (pointer_flags_ & ~changed_button);
+ last_pointer_button_pressed_ = changed_button;
// MouseEvent's flags should contain the button that was released too.
int flags = pointer_flags_ | keyboard_modifiers_ | changed_button;
MouseEvent event(type, pointer_location_, pointer_location_,
@@ -322,22 +322,16 @@ void WaylandEventSource::HandleKeyboardFocusChange(WaylandWindow* window,
window->set_keyboard_focus(focused);
}
-void WaylandEventSource::HandlePointerFocusChange(WaylandWindow* window,
- bool focused) {
- // window can be null on wl_pointer::leave events, for example.
- if (window)
- window->SetPointerFocus(focused);
-
- if (focused) {
- DCHECK(window);
- window_with_pointer_focus_ = window;
- } else {
- // Focused window might have been destroyed at this point (eg: context
- // menus), in this case, |window| is null, otherwise it must be equal to
- // |window_with_pointer_focus_|. In both cases, they must be equal.
- DCHECK_EQ(window_with_pointer_focus_, window);
- window_with_pointer_focus_ = nullptr;
- }
+void WaylandEventSource::HandlePointerFocusChange(WaylandWindow* window) {
+ // Focused window might have been destroyed at this point (eg: context menus),
+ // in this case, |window| is null.
+ if (window_with_pointer_focus_)
+ window_with_pointer_focus_->SetPointerFocus(false);
+
+ window_with_pointer_focus_ = window;
+
+ if (window_with_pointer_focus_)
+ window_with_pointer_focus_->SetPointerFocus(true);
}
void WaylandEventSource::HandleTouchFocusChange(WaylandWindow* window,
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h
index 7f1a565c613..7c9c409e702 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h
@@ -55,6 +55,10 @@ class WaylandEventSource : public PlatformEventSource,
WaylandEventSource& operator=(const WaylandEventSource&) = delete;
~WaylandEventSource() override;
+ int last_pointer_button_pressed() const {
+ return last_pointer_button_pressed_;
+ }
+
// Starts polling for events from the wayland connection file descriptor.
// This method assumes connection is already estabilished and input objects
// are already bound and properly initialized.
@@ -76,18 +80,17 @@ class WaylandEventSource : public PlatformEventSource,
void OnKeyboardDestroyed(WaylandKeyboard* keyboard) override;
void OnKeyboardFocusChanged(WaylandWindow* window, bool focused) override;
void OnKeyboardModifiersChanged(int modifiers) override;
- void OnKeyboardKeyEvent(EventType type,
- DomCode dom_code,
- DomKey dom_key,
- KeyboardCode key_code,
- bool repeat,
- base::TimeTicks timestamp) override;
+ uint32_t OnKeyboardKeyEvent(EventType type,
+ DomCode dom_code,
+ DomKey dom_key,
+ KeyboardCode key_code,
+ bool repeat,
+ base::TimeTicks timestamp) override;
// WaylandPointer::Delegate
void OnPointerCreated(WaylandPointer* pointer) override;
void OnPointerDestroyed(WaylandPointer* pointer) override;
void OnPointerFocusChanged(WaylandWindow* window,
- bool focused,
const gfx::PointF& location) override;
void OnPointerButtonEvent(EventType evtype, int changed_button) override;
void OnPointerMotionEvent(const gfx::PointF& location) override;
@@ -117,7 +120,7 @@ class WaylandEventSource : public PlatformEventSource,
void UpdateKeyboardModifiers(int modifier, bool down);
void HandleKeyboardFocusChange(WaylandWindow* window, bool focused);
- void HandlePointerFocusChange(WaylandWindow* window, bool focused);
+ void HandlePointerFocusChange(WaylandWindow* window);
void HandleTouchFocusChange(WaylandWindow* window,
bool focused,
base::Optional<PointerId> id = base::nullopt);
@@ -133,6 +136,9 @@ class WaylandEventSource : public PlatformEventSource,
// Bitmask of EventFlags used to keep track of the the pointer state.
int pointer_flags_ = 0;
+ // Bitmask of EventFlags used to keep track of the last changed button.
+ int last_pointer_button_pressed_ = 0;
+
// Bitmask of EventFlags used to keep track of the the keyboard state.
int keyboard_modifiers_ = 0;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc
index 0258d157776..7de0fe694d7 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc
@@ -34,10 +34,12 @@ const wl_callback_listener WaylandKeyboard::callback_listener_ = {
WaylandKeyboard::SyncCallback,
};
-WaylandKeyboard::WaylandKeyboard(wl_keyboard* keyboard,
- WaylandConnection* connection,
- KeyboardLayoutEngine* layout_engine,
- Delegate* delegate)
+WaylandKeyboard::WaylandKeyboard(
+ wl_keyboard* keyboard,
+ zcr_keyboard_extension_v1* keyboard_extension_v1,
+ WaylandConnection* connection,
+ KeyboardLayoutEngine* layout_engine,
+ Delegate* delegate)
: obj_(keyboard),
connection_(connection),
delegate_(delegate),
@@ -58,6 +60,10 @@ WaylandKeyboard::WaylandKeyboard(wl_keyboard* keyboard,
wl_keyboard_add_listener(obj_.get(), &listener, this);
// TODO(tonikitoo): Default auto-repeat to ON here?
+
+ if (keyboard_extension_v1)
+ extended_keyboard_v1_.reset(zcr_keyboard_extension_v1_get_extended_keyboard(
+ keyboard_extension_v1, obj_.get()));
}
WaylandKeyboard::~WaylandKeyboard() {
@@ -193,9 +199,15 @@ void WaylandKeyboard::DispatchKey(uint32_t key,
// Pass empty DomKey and KeyboardCode here so the delegate can pre-process
// and decode it when needed.
- delegate_->OnKeyboardKeyEvent(down ? ET_KEY_PRESSED : ET_KEY_RELEASED,
- dom_code, DomKey::NONE,
- KeyboardCode::VKEY_UNKNOWN, repeat, timestamp);
+ uint32_t result = delegate_->OnKeyboardKeyEvent(
+ down ? ET_KEY_PRESSED : ET_KEY_RELEASED, dom_code, DomKey::NONE,
+ KeyboardCode::VKEY_UNKNOWN, repeat, timestamp);
+
+ if (extended_keyboard_v1_) {
+ bool handled = result & POST_DISPATCH_STOP_PROPAGATION;
+ zcr_extended_keyboard_v1_ack_key(extended_keyboard_v1_.get(),
+ connection_->serial(), handled);
+ }
}
bool WaylandKeyboard::Decode(DomCode dom_code,
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h
index 1630d8aa681..e449da0be85 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h
@@ -5,6 +5,7 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_KEYBOARD_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_KEYBOARD_H_
+#include <keyboard-extension-unstable-v1-client-protocol.h>
#include <wayland-client.h>
#include "base/time/time.h"
@@ -30,6 +31,7 @@ class WaylandKeyboard : public EventAutoRepeatHandler::Delegate {
class Delegate;
WaylandKeyboard(wl_keyboard* keyboard,
+ zcr_keyboard_extension_v1* keyboard_extension_v1,
WaylandConnection* connection,
KeyboardLayoutEngine* keyboard_layout_engine,
Delegate* delegate);
@@ -88,6 +90,7 @@ class WaylandKeyboard : public EventAutoRepeatHandler::Delegate {
int flags) override;
wl::Object<wl_keyboard> obj_;
+ wl::Object<zcr_extended_keyboard_v1> extended_keyboard_v1_;
WaylandConnection* const connection_;
Delegate* const delegate_;
@@ -110,12 +113,18 @@ class WaylandKeyboard::Delegate {
virtual void OnKeyboardDestroyed(WaylandKeyboard* keyboard) = 0;
virtual void OnKeyboardFocusChanged(WaylandWindow* window, bool focused) = 0;
virtual void OnKeyboardModifiersChanged(int modifiers) = 0;
- virtual void OnKeyboardKeyEvent(EventType type,
- DomCode dom_code,
- DomKey dom_key,
- KeyboardCode key_code,
- bool repeat,
- base::TimeTicks timestamp) = 0;
+ // Returns a mask of ui::PostDispatchAction indicating how the event was
+ // dispatched.
+ virtual uint32_t OnKeyboardKeyEvent(EventType type,
+ DomCode dom_code,
+ DomKey dom_key,
+ KeyboardCode key_code,
+ bool repeat,
+ base::TimeTicks timestamp) = 0;
+
+ protected:
+ // Prevent deletion through a WaylandKeyboard::Delegate pointer.
+ virtual ~Delegate() = default;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc
index 8a2da9f409a..1658a68cc93 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc
@@ -45,10 +45,10 @@ void WaylandPointer::Enter(void* data,
wl_fixed_t surface_y) {
DCHECK(data);
WaylandPointer* pointer = static_cast<WaylandPointer*>(data);
- gfx::PointF location(wl_fixed_to_double(surface_x),
- wl_fixed_to_double(surface_y));
- pointer->delegate_->OnPointerFocusChanged(WaylandWindow::FromSurface(surface),
- /*focused=*/true, location);
+ WaylandWindow* window = WaylandWindow::FromSurface(surface);
+ gfx::PointF location{wl_fixed_to_double(surface_x),
+ wl_fixed_to_double(surface_y)};
+ pointer->delegate_->OnPointerFocusChanged(window, location);
}
// static
@@ -58,8 +58,7 @@ void WaylandPointer::Leave(void* data,
wl_surface* surface) {
DCHECK(data);
WaylandPointer* pointer = static_cast<WaylandPointer*>(data);
- pointer->delegate_->OnPointerFocusChanged(WaylandWindow::FromSurface(surface),
- /*focused=*/false, {});
+ pointer->delegate_->OnPointerFocusChanged(nullptr, {});
}
// static
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h
index c4c9ecfbc35..b3f3a6ccbfa 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h
@@ -73,7 +73,6 @@ class WaylandPointer::Delegate {
virtual void OnPointerCreated(WaylandPointer* pointer) = 0;
virtual void OnPointerDestroyed(WaylandPointer* pointer) = 0;
virtual void OnPointerFocusChanged(WaylandWindow* window,
- bool focused,
const gfx::PointF& location) = 0;
virtual void OnPointerButtonEvent(EventType evtype, int changed_button) = 0;
virtual void OnPointerMotionEvent(const gfx::PointF& location) = 0;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
index f20ee54c250..cf12f91f1b7 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
@@ -237,7 +237,7 @@ TEST_P(WaylandPointerTest, SetBitmapOnPointerFocus) {
BitmapCursorFactoryOzone cursor_factory;
PlatformCursor cursor =
- cursor_factory.CreateImageCursor(dummy_cursor, gfx::Point(5, 8), 1.0f);
+ cursor_factory.CreateImageCursor(dummy_cursor, gfx::Point(5, 8));
scoped_refptr<BitmapCursorOzone> bitmap =
BitmapCursorFactoryOzone::GetBitmapCursor(cursor);
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc b/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc
index 116c7be47d1..ba52979990a 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc
@@ -144,9 +144,7 @@ bool WaylandPopup::OnInitialize(PlatformWindowInitProperties properties) {
}
gfx::Rect WaylandPopup::AdjustPopupWindowPosition() {
- auto* top_level_parent = wl::IsMenuType(parent_window()->type())
- ? parent_window()->parent_window()
- : parent_window();
+ auto* top_level_parent = GetRootParentWindow();
DCHECK(top_level_parent);
DCHECK(buffer_scale() == top_level_parent->buffer_scale());
DCHECK(ui_scale() == top_level_parent->ui_scale());
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.cc b/chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.cc
index 298ea68b29f..e4fa21fa09a 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.cc
@@ -4,6 +4,7 @@
#include "ui/ozone/platform/wayland/host/wayland_shm_buffer.h"
+#include "base/logging.h"
#include "base/memory/platform_shared_memory_region.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "ui/gfx/skia_util.h"
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc
index 28f435f39de..e76aa6376dd 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc
@@ -7,6 +7,7 @@
#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h"
#include "ui/ozone/platform/wayland/host/wayland_window_manager.h"
namespace ui {
@@ -15,7 +16,7 @@ namespace {
gfx::Rect AdjustSubsurfaceBounds(const gfx::Rect& bounds_px,
const gfx::Rect& parent_bounds_px,
- int32_t ui_scale,
+ float ui_scale,
int32_t buffer_scale) {
const auto parent_bounds_dip =
gfx::ScaleToRoundedRect(parent_bounds_px, 1.0 / ui_scale);
@@ -78,7 +79,7 @@ void WaylandSubsurface::CreateSubsurface() {
// windows. If we are in a drag process, use the entered window. Otherwise,
// it must be a tooltip.
if (connection()->IsDragInProgress()) {
- parent = connection()->wayland_data_device()->entered_window();
+ parent = connection()->data_drag_controller()->entered_window();
set_parent_window(parent);
} else {
// If Aura does not not provide a reference parent window, needed by
@@ -114,6 +115,11 @@ void WaylandSubsurface::CreateSubsurface() {
wl_subsurface_set_desync(subsurface_.get());
wl_surface_commit(parent->surface());
connection()->ScheduleFlush();
+
+ // Notify the observers the window has been configured. Please note that
+ // subsurface doesn't send ack configure events. Thus, notify the observers as
+ // soon as the subsurface is created.
+ connection()->wayland_window_manager()->NotifyWindowConfigured(this);
}
bool WaylandSubsurface::OnInitialize(PlatformWindowInitProperties properties) {
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc b/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc
index 6f72776d0d3..c2cf21baf62 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc
@@ -4,350 +4,21 @@
#include "ui/ozone/platform/wayland/host/wayland_surface.h"
-#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/dragdrop/os_exchange_data.h"
-#include "ui/base/hit_test.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/ozone/platform/wayland/host/shell_object_factory.h"
-#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
-#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
-#include "ui/ozone/platform/wayland/host/wayland_connection.h"
-#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
-#include "ui/platform_window/platform_window_handler/wm_drop_handler.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
namespace ui {
-WaylandSurface::WaylandSurface(PlatformWindowDelegate* delegate,
- WaylandConnection* connection)
- : WaylandWindow(delegate, connection),
- state_(PlatformWindowState::kNormal) {
- // Set a class property key, which allows |this| to be used for interactive
- // events, e.g. move or resize.
- SetWmMoveResizeHandler(this, AsWmMoveResizeHandler());
+WaylandSurface::WaylandSurface() = default;
+WaylandSurface::~WaylandSurface() = default;
- // Set a class property key, which allows |this| to be used for drag action.
- SetWmDragHandler(this, this);
+gfx::AcceleratedWidget WaylandSurface::GetWidget() const {
+ if (!surface_)
+ return gfx::kNullAcceleratedWidget;
+ return surface_.id();
}
-WaylandSurface::~WaylandSurface() {
- if (drag_closed_callback_) {
- std::move(drag_closed_callback_)
- .Run(DragDropTypes::DragOperation::DRAG_NONE);
- }
-}
-
-bool WaylandSurface::CreateShellSurface() {
- ShellObjectFactory factory;
- shell_surface_ = factory.CreateShellSurfaceWrapper(connection(), this);
- if (!shell_surface_) {
- LOG(ERROR) << "Failed to create a ShellSurface.";
- return false;
- }
-
- shell_surface_->SetAppId(app_id_);
- shell_surface_->SetTitle(window_title_);
- SetSizeConstraints();
- TriggerStateChanges();
- return true;
-}
-
-void WaylandSurface::ApplyPendingBounds() {
- if (pending_bounds_dip_.IsEmpty())
- return;
- DCHECK(shell_surface_);
-
- SetBoundsDip(pending_bounds_dip_);
- shell_surface_->SetWindowGeometry(pending_bounds_dip_);
- pending_bounds_dip_ = gfx::Rect();
- connection()->ScheduleFlush();
-}
-
-void WaylandSurface::DispatchHostWindowDragMovement(
- int hittest,
- const gfx::Point& pointer_location_in_px) {
- DCHECK(shell_surface_);
-
- connection()->event_source()->ResetPointerFlags();
- if (hittest == HTCAPTION)
- shell_surface_->SurfaceMove(connection());
- else
- shell_surface_->SurfaceResize(connection(), hittest);
-
- connection()->ScheduleFlush();
-}
-
-void WaylandSurface::StartDrag(const ui::OSExchangeData& data,
- int operation,
- gfx::NativeCursor cursor,
- base::OnceCallback<void(int)> callback) {
- DCHECK(!drag_closed_callback_);
- drag_closed_callback_ = std::move(callback);
- connection()->StartDrag(data, operation);
-}
-
-void WaylandSurface::Show(bool inactive) {
- if (shell_surface_)
- return;
-
- if (!CreateShellSurface()) {
- Close();
- return;
- }
-
- UpdateBufferScale(false);
-}
-
-void WaylandSurface::Hide() {
- if (!shell_surface_)
- return;
-
- if (child_window()) {
- child_window()->Hide();
- set_child_window(nullptr);
- }
-
- shell_surface_.reset();
- connection()->ScheduleFlush();
-
- // Detach buffer from surface in order to completely shutdown menus and
- // tooltips, and release resources.
- connection()->buffer_manager_host()->ResetSurfaceContents(GetWidget());
-}
-
-bool WaylandSurface::IsVisible() const {
- // X and Windows return true if the window is minimized. For consistency, do
- // the same.
- return !!shell_surface_ || state_ == PlatformWindowState::kMinimized;
-}
-
-void WaylandSurface::SetTitle(const base::string16& title) {
- if (window_title_ == title)
- return;
-
- window_title_ = title;
-
- if (shell_surface_) {
- shell_surface_->SetTitle(title);
- connection()->ScheduleFlush();
- }
-}
-
-void WaylandSurface::ToggleFullscreen() {
- // TODO(msisov, tonikitoo): add multiscreen support. As the documentation says
- // if xdg_toplevel_set_fullscreen() is not provided with wl_output, it's up
- // to the compositor to choose which display will be used to map this surface.
-
- // We must track the previous state to correctly say our state as long as it
- // can be the maximized instead of normal one.
- PlatformWindowState new_state = PlatformWindowState::kUnknown;
- if (state_ == PlatformWindowState::kFullScreen) {
- if (previous_state_ == PlatformWindowState::kMaximized)
- new_state = previous_state_;
- else
- new_state = PlatformWindowState::kNormal;
- } else {
- new_state = PlatformWindowState::kFullScreen;
- }
-
- SetWindowState(new_state);
-}
-
-void WaylandSurface::Maximize() {
- SetWindowState(PlatformWindowState::kMaximized);
-}
-
-void WaylandSurface::Minimize() {
- SetWindowState(PlatformWindowState::kMinimized);
-}
-
-void WaylandSurface::Restore() {
- DCHECK(shell_surface_);
- SetWindowState(PlatformWindowState::kNormal);
-}
-
-PlatformWindowState WaylandSurface::GetPlatformWindowState() const {
- return state_;
-}
-
-void WaylandSurface::SizeConstraintsChanged() {
- // Size constraints only make sense for normal windows.
- if (!shell_surface_)
- return;
-
- DCHECK(delegate());
- min_size_ = delegate()->GetMinimumSizeForWindow();
- max_size_ = delegate()->GetMaximumSizeForWindow();
- SetSizeConstraints();
-}
-
-void WaylandSurface::HandleSurfaceConfigure(int32_t width,
- int32_t height,
- bool is_maximized,
- bool is_fullscreen,
- bool is_activated) {
- // Store the old state to propagte state changes if Wayland decides to change
- // the state to something else.
- PlatformWindowState old_state = state_;
- if (state_ == PlatformWindowState::kMinimized && !is_activated) {
- state_ = PlatformWindowState::kMinimized;
- } else if (is_fullscreen) {
- state_ = PlatformWindowState::kFullScreen;
- } else if (is_maximized) {
- state_ = PlatformWindowState::kMaximized;
- } else {
- state_ = PlatformWindowState::kNormal;
- }
-
- const bool state_changed = old_state != state_;
- const bool is_normal = state_ == PlatformWindowState::kNormal;
-
- // Update state before notifying delegate.
- const bool did_active_change = is_active_ != is_activated;
- is_active_ = is_activated;
-
- // Rather than call SetBounds here for every configure event, just save the
- // most recent bounds, and have WaylandConnection call ApplyPendingBounds
- // when it has finished processing events. We may get many configure events
- // in a row during an interactive resize, and only the last one matters.
- //
- // Width or height set to 0 means that we should decide on width and height by
- // ourselves, but we don't want to set them to anything else. Use restored
- // bounds size or the current bounds iff the current state is normal (neither
- // maximized nor fullscreen).
- //
- // Note: if the browser was started with --start-fullscreen and a user exits
- // the fullscreen mode, wayland may set the width and height to be 1. Instead,
- // explicitly set the bounds to the current desired ones or the previous
- // bounds.
- if (width > 1 && height > 1) {
- pending_bounds_dip_ = gfx::Rect(0, 0, width, height);
- } else if (is_normal) {
- pending_bounds_dip_.set_size(
- gfx::ScaleToRoundedSize(GetRestoredBoundsInPixels().IsEmpty()
- ? GetBounds().size()
- : GetRestoredBoundsInPixels().size(),
-
- 1.0 / buffer_scale()));
- }
-
- // Store the restored bounds of current state differs from the normal state.
- // It can be client or compositor side change from normal to something else.
- // Thus, we must store previous bounds to restore later.
- SetOrResetRestoredBounds();
- ApplyPendingBounds();
-
- if (state_changed)
- delegate()->OnWindowStateChanged(state_);
-
- if (did_active_change)
- delegate()->OnActivationChanged(is_active_);
-}
-
-void WaylandSurface::OnDragEnter(const gfx::PointF& point,
- std::unique_ptr<OSExchangeData> data,
- int operation) {
- WmDropHandler* drop_handler = GetWmDropHandler(*this);
- if (!drop_handler)
- return;
-
- // Wayland sends locations in DIP so they need to be translated to
- // physical pixels.
- drop_handler->OnDragEnter(
- gfx::ScalePoint(point, buffer_scale(), buffer_scale()), std::move(data),
- operation);
-}
-
-int WaylandSurface::OnDragMotion(const gfx::PointF& point,
- uint32_t time,
- int operation) {
- WmDropHandler* drop_handler = GetWmDropHandler(*this);
- if (!drop_handler)
- return 0;
-
- // Wayland sends locations in DIP so they need to be translated to
- // physical pixels.
- return drop_handler->OnDragMotion(
- gfx::ScalePoint(point, buffer_scale(), buffer_scale()), operation);
-}
-
-void WaylandSurface::OnDragDrop(std::unique_ptr<OSExchangeData> data) {
- WmDropHandler* drop_handler = GetWmDropHandler(*this);
- if (!drop_handler)
- return;
- drop_handler->OnDragDrop(std::move(data));
-}
-
-void WaylandSurface::OnDragLeave() {
- WmDropHandler* drop_handler = GetWmDropHandler(*this);
- if (!drop_handler)
- return;
- drop_handler->OnDragLeave();
-}
-
-void WaylandSurface::OnDragSessionClose(uint32_t dnd_action) {
- std::move(drag_closed_callback_).Run(dnd_action);
- connection()->event_source()->ResetPointerFlags();
-}
-
-bool WaylandSurface::OnInitialize(PlatformWindowInitProperties properties) {
- app_id_ = properties.wm_class_class;
- return true;
-}
-
-void WaylandSurface::TriggerStateChanges() {
- if (!shell_surface_)
- return;
-
- if (state_ == PlatformWindowState::kFullScreen)
- shell_surface_->SetFullscreen();
- else
- shell_surface_->UnSetFullscreen();
-
- // Call UnSetMaximized only if current state is normal. Otherwise, if the
- // current state is fullscreen and the previous is maximized, calling
- // UnSetMaximized may result in wrong restored window position that clients
- // are not allowed to know about.
- if (state_ == PlatformWindowState::kMaximized)
- shell_surface_->SetMaximized();
- else if (state_ == PlatformWindowState::kNormal)
- shell_surface_->UnSetMaximized();
-
- if (state_ == PlatformWindowState::kMinimized)
- shell_surface_->SetMinimized();
-
- connection()->ScheduleFlush();
-}
-
-void WaylandSurface::SetWindowState(PlatformWindowState state) {
- previous_state_ = state_;
- state_ = state;
- TriggerStateChanges();
-}
-
-WmMoveResizeHandler* WaylandSurface::AsWmMoveResizeHandler() {
- return static_cast<WmMoveResizeHandler*>(this);
-}
-
-void WaylandSurface::SetSizeConstraints() {
- if (min_size_.has_value())
- shell_surface_->SetMinSize(min_size_->width(), min_size_->height());
- if (max_size_.has_value())
- shell_surface_->SetMaxSize(max_size_->width(), max_size_->height());
-
- connection()->ScheduleFlush();
-}
-
-void WaylandSurface::SetOrResetRestoredBounds() {
- // The |restored_bounds_| are used when the window gets back to normal
- // state after it went maximized or fullscreen. So we reset these if the
- // window has just become normal and store the current bounds if it is
- // either going out of normal state or simply changes the state and we don't
- // have any meaningful value stored.
- if (GetPlatformWindowState() == PlatformWindowState::kNormal) {
- SetRestoredBoundsInPixels({});
- } else if (GetRestoredBoundsInPixels().IsEmpty()) {
- SetRestoredBoundsInPixels(GetBounds());
- }
+gfx::AcceleratedWidget WaylandSurface::GetRootWidget() const {
+ return root_window_->GetWidget();
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_surface.h b/chromium/ui/ozone/platform/wayland/host/wayland_surface.h
index ceda32d24a7..e432ceb7e7d 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_surface.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_surface.h
@@ -5,121 +5,38 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SURFACE_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SURFACE_H_
-#include "ui/ozone/platform/wayland/host/wayland_window.h"
-
-#include "ui/platform_window/platform_window_handler/wm_drag_handler.h"
-#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
namespace ui {
-class ShellSurfaceWrapper;
+class WaylandWindow;
-class WaylandSurface : public WaylandWindow,
- public WmMoveResizeHandler,
- public WmDragHandler {
+// Wrapper of a wl_surface, owned by a WaylandWindow or a WlSubsurface.
+class WaylandSurface {
public:
- WaylandSurface(PlatformWindowDelegate* delegate,
- WaylandConnection* connection);
- ~WaylandSurface() override;
-
- ShellSurfaceWrapper* shell_surface() const { return shell_surface_.get(); }
-
- // Apply the bounds specified in the most recent configure event. This should
- // be called after processing all pending events in the wayland connection.
- void ApplyPendingBounds();
+ WaylandSurface();
+ WaylandSurface(const WaylandSurface&) = delete;
+ WaylandSurface& operator=(const WaylandSurface&) = delete;
+ ~WaylandSurface();
- // WmMoveResizeHandler
- void DispatchHostWindowDragMovement(
- int hittest,
- const gfx::Point& pointer_location_in_px) override;
+ WaylandWindow* root_window() const { return root_window_; }
+ wl_surface* surface() const { return surface_.get(); }
+ int32_t buffer_scale() const { return buffer_scale_; }
- // WmDragHandler
- void StartDrag(const ui::OSExchangeData& data,
- int operation,
- gfx::NativeCursor cursor,
- base::OnceCallback<void(int)> callback) override;
-
- // PlatformWindow
- void Show(bool inactive) override;
- void Hide() override;
- bool IsVisible() const override;
- void SetTitle(const base::string16& title) override;
- void ToggleFullscreen() override;
- void Maximize() override;
- void Minimize() override;
- void Restore() override;
- PlatformWindowState GetPlatformWindowState() const override;
- void SizeConstraintsChanged() override;
+ // gfx::AcceleratedWidget identifies a wl_surface or a ui::WaylandWindow. Note
+ // that GetWidget() and GetRootWidget() do not necessarily return the same
+ // result.
+ gfx::AcceleratedWidget GetWidget() const;
+ gfx::AcceleratedWidget GetRootWidget() const;
private:
- // WaylandWindow overrides:
- void HandleSurfaceConfigure(int32_t widht,
- int32_t height,
- bool is_maximized,
- bool is_fullscreen,
- bool is_activated) override;
- void OnDragEnter(const gfx::PointF& point,
- std::unique_ptr<OSExchangeData> data,
- int operation) override;
- int OnDragMotion(const gfx::PointF& point,
- uint32_t time,
- int operation) override;
- void OnDragDrop(std::unique_ptr<OSExchangeData> data) override;
- void OnDragLeave() override;
- void OnDragSessionClose(uint32_t dnd_action) override;
- bool OnInitialize(PlatformWindowInitProperties properties) override;
-
- void TriggerStateChanges();
- void SetWindowState(PlatformWindowState state);
-
- // Creates a surface window, which is visible as a main window.
- bool CreateShellSurface();
-
- WmMoveResizeHandler* AsWmMoveResizeHandler();
-
- // Propagates the |min_size_| and |max_size_| to the ShellSurface.
- void SetSizeConstraints();
-
- void SetOrResetRestoredBounds();
-
- // Wrappers around shell surface.
- std::unique_ptr<ShellSurfaceWrapper> shell_surface_;
-
- base::OnceCallback<void(int)> drag_closed_callback_;
-
- // These bounds attributes below have suffices that indicate units used.
- // Wayland operates in DIP but the platform operates in physical pixels so
- // our WaylandSurface is the link that has to translate the units. See also
- // comments in the implementation.
- //
- // Bounds that will be applied when the window state is finalized. The window
- // may get several configuration events that update the pending bounds, and
- // only upon finalizing the state is the latest value stored as the current
- // bounds via |ApplyPendingBounds|. Measured in DIP because updated in the
- // handler that receives DIP from Wayland.
- gfx::Rect pending_bounds_dip_;
-
- // Contains the current state of the window.
- PlatformWindowState state_;
- // Contains the previous state of the window.
- PlatformWindowState previous_state_;
-
- bool is_active_ = false;
-
- // Id of the chromium app passed through
- // PlatformWindowInitProperties::wm_class_class. This is used by Wayland
- // compositor to identify the app, unite it's windows into the same stack of
- // windows and find *.desktop file to set various preferences including icons.
- std::string app_id_;
-
- // Title of the ShellSurface.
- base::string16 window_title_;
-
- // Max and min sizes of the WaylandSurface window.
- base::Optional<gfx::Size> min_size_;
- base::Optional<gfx::Size> max_size_;
-
- DISALLOW_COPY_AND_ASSIGN(WaylandSurface);
+ WaylandWindow* root_window_ = nullptr;
+ wl::Object<wl_surface> surface_;
+ // Wayland's scale factor for the output that this window currently belongs
+ // to.
+ int32_t buffer_scale_ = 1;
+ friend class WaylandWindow;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
new file mode 100644
index 00000000000..10ecbcf7b47
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
@@ -0,0 +1,368 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
+
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/base/hit_test.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/wayland/host/shell_object_factory.h"
+#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
+#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h"
+#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_window_drag_controller.h"
+#include "ui/platform_window/platform_window_handler/wm_drop_handler.h"
+
+namespace ui {
+
+WaylandToplevelWindow::WaylandToplevelWindow(PlatformWindowDelegate* delegate,
+ WaylandConnection* connection)
+ : WaylandWindow(delegate, connection),
+ state_(PlatformWindowState::kNormal) {
+ // Set a class property key, which allows |this| to be used for interactive
+ // events, e.g. move or resize.
+ SetWmMoveResizeHandler(this, AsWmMoveResizeHandler());
+
+ // Set a class property key, which allows |this| to be used for drag action.
+ SetWmDragHandler(this, this);
+}
+
+WaylandToplevelWindow::~WaylandToplevelWindow() {
+ if (drag_handler_delegate_) {
+ drag_handler_delegate_->OnDragFinished(
+ DragDropTypes::DragOperation::DRAG_NONE);
+ }
+}
+
+bool WaylandToplevelWindow::CreateShellSurface() {
+ ShellObjectFactory factory;
+ shell_surface_ = factory.CreateShellSurfaceWrapper(connection(), this);
+ if (!shell_surface_) {
+ LOG(ERROR) << "Failed to create a ShellSurface.";
+ return false;
+ }
+
+ shell_surface_->SetAppId(app_id_);
+ shell_surface_->SetTitle(window_title_);
+ SetSizeConstraints();
+ TriggerStateChanges();
+ return true;
+}
+
+void WaylandToplevelWindow::ApplyPendingBounds() {
+ if (pending_bounds_dip_.IsEmpty())
+ return;
+ DCHECK(shell_surface_);
+
+ SetBoundsDip(pending_bounds_dip_);
+ shell_surface_->SetWindowGeometry(pending_bounds_dip_);
+ pending_bounds_dip_ = gfx::Rect();
+ connection()->ScheduleFlush();
+}
+
+void WaylandToplevelWindow::DispatchHostWindowDragMovement(
+ int hittest,
+ const gfx::Point& pointer_location_in_px) {
+ DCHECK(shell_surface_);
+
+ connection()->event_source()->ResetPointerFlags();
+ if (hittest == HTCAPTION)
+ shell_surface_->SurfaceMove(connection());
+ else
+ shell_surface_->SurfaceResize(connection(), hittest);
+
+ connection()->ScheduleFlush();
+}
+
+void WaylandToplevelWindow::StartDrag(const ui::OSExchangeData& data,
+ int operation,
+ gfx::NativeCursor cursor,
+ WmDragHandler::Delegate* delegate) {
+ DCHECK(!drag_handler_delegate_);
+ drag_handler_delegate_ = delegate;
+ connection()->data_drag_controller()->StartSession(data, operation);
+}
+
+void WaylandToplevelWindow::Show(bool inactive) {
+ if (shell_surface_)
+ return;
+
+ if (!CreateShellSurface()) {
+ Close();
+ return;
+ }
+
+ UpdateBufferScale(false);
+}
+
+void WaylandToplevelWindow::Hide() {
+ if (!shell_surface_)
+ return;
+
+ if (child_window()) {
+ child_window()->Hide();
+ set_child_window(nullptr);
+ }
+
+ shell_surface_.reset();
+ connection()->ScheduleFlush();
+
+ // Detach buffer from surface in order to completely shutdown menus and
+ // tooltips, and release resources.
+ connection()->buffer_manager_host()->ResetSurfaceContents(GetWidget());
+}
+
+bool WaylandToplevelWindow::IsVisible() const {
+ // X and Windows return true if the window is minimized. For consistency, do
+ // the same.
+ return !!shell_surface_ || state_ == PlatformWindowState::kMinimized;
+}
+
+void WaylandToplevelWindow::SetTitle(const base::string16& title) {
+ if (window_title_ == title)
+ return;
+
+ window_title_ = title;
+
+ if (shell_surface_) {
+ shell_surface_->SetTitle(title);
+ connection()->ScheduleFlush();
+ }
+}
+
+void WaylandToplevelWindow::ToggleFullscreen() {
+ // TODO(msisov, tonikitoo): add multiscreen support. As the documentation says
+ // if xdg_toplevel_set_fullscreen() is not provided with wl_output, it's up
+ // to the compositor to choose which display will be used to map this surface.
+
+ // We must track the previous state to correctly say our state as long as it
+ // can be the maximized instead of normal one.
+ PlatformWindowState new_state = PlatformWindowState::kUnknown;
+ if (state_ == PlatformWindowState::kFullScreen) {
+ if (previous_state_ == PlatformWindowState::kMaximized)
+ new_state = previous_state_;
+ else
+ new_state = PlatformWindowState::kNormal;
+ } else {
+ new_state = PlatformWindowState::kFullScreen;
+ }
+
+ SetWindowState(new_state);
+}
+
+void WaylandToplevelWindow::Maximize() {
+ SetWindowState(PlatformWindowState::kMaximized);
+}
+
+void WaylandToplevelWindow::Minimize() {
+ SetWindowState(PlatformWindowState::kMinimized);
+}
+
+void WaylandToplevelWindow::Restore() {
+ DCHECK(shell_surface_);
+ SetWindowState(PlatformWindowState::kNormal);
+}
+
+PlatformWindowState WaylandToplevelWindow::GetPlatformWindowState() const {
+ return state_;
+}
+
+void WaylandToplevelWindow::SizeConstraintsChanged() {
+ // Size constraints only make sense for normal windows.
+ if (!shell_surface_)
+ return;
+
+ DCHECK(delegate());
+ min_size_ = delegate()->GetMinimumSizeForWindow();
+ max_size_ = delegate()->GetMaximumSizeForWindow();
+ SetSizeConstraints();
+}
+
+void WaylandToplevelWindow::HandleSurfaceConfigure(int32_t width,
+ int32_t height,
+ bool is_maximized,
+ bool is_fullscreen,
+ bool is_activated) {
+ // Store the old state to propagte state changes if Wayland decides to change
+ // the state to something else.
+ PlatformWindowState old_state = state_;
+ if (state_ == PlatformWindowState::kMinimized && !is_activated) {
+ state_ = PlatformWindowState::kMinimized;
+ } else if (is_fullscreen) {
+ state_ = PlatformWindowState::kFullScreen;
+ } else if (is_maximized) {
+ state_ = PlatformWindowState::kMaximized;
+ } else {
+ state_ = PlatformWindowState::kNormal;
+ }
+
+ const bool state_changed = old_state != state_;
+ const bool is_normal = state_ == PlatformWindowState::kNormal;
+
+ // Update state before notifying delegate.
+ const bool did_active_change = is_active_ != is_activated;
+ is_active_ = is_activated;
+
+ // Rather than call SetBounds here for every configure event, just save the
+ // most recent bounds, and have WaylandConnection call ApplyPendingBounds
+ // when it has finished processing events. We may get many configure events
+ // in a row during an interactive resize, and only the last one matters.
+ //
+ // Width or height set to 0 means that we should decide on width and height by
+ // ourselves, but we don't want to set them to anything else. Use restored
+ // bounds size or the current bounds iff the current state is normal (neither
+ // maximized nor fullscreen).
+ //
+ // Note: if the browser was started with --start-fullscreen and a user exits
+ // the fullscreen mode, wayland may set the width and height to be 1. Instead,
+ // explicitly set the bounds to the current desired ones or the previous
+ // bounds.
+ if (width > 1 && height > 1) {
+ pending_bounds_dip_ = gfx::Rect(0, 0, width, height);
+ } else if (is_normal) {
+ pending_bounds_dip_.set_size(
+ gfx::ScaleToRoundedSize(GetRestoredBoundsInPixels().IsEmpty()
+ ? GetBounds().size()
+ : GetRestoredBoundsInPixels().size(),
+
+ 1.0 / buffer_scale()));
+ }
+
+ // Store the restored bounds of current state differs from the normal state.
+ // It can be client or compositor side change from normal to something else.
+ // Thus, we must store previous bounds to restore later.
+ SetOrResetRestoredBounds();
+ ApplyPendingBounds();
+
+ if (state_changed)
+ delegate()->OnWindowStateChanged(state_);
+
+ if (did_active_change)
+ delegate()->OnActivationChanged(is_active_);
+}
+
+void WaylandToplevelWindow::OnDragEnter(const gfx::PointF& point,
+ std::unique_ptr<OSExchangeData> data,
+ int operation) {
+ WmDropHandler* drop_handler = GetWmDropHandler(*this);
+ if (!drop_handler)
+ return;
+
+ // Wayland sends locations in DIP so they need to be translated to
+ // physical pixels.
+ drop_handler->OnDragEnter(
+ gfx::ScalePoint(point, buffer_scale(), buffer_scale()), std::move(data),
+ operation);
+}
+
+int WaylandToplevelWindow::OnDragMotion(const gfx::PointF& point,
+ int operation) {
+ WmDropHandler* drop_handler = GetWmDropHandler(*this);
+ if (!drop_handler)
+ return 0;
+
+ // Wayland sends locations in DIP so they need to be translated to
+ // physical pixels.
+ return drop_handler->OnDragMotion(
+ gfx::ScalePoint(point, buffer_scale(), buffer_scale()), operation);
+}
+
+void WaylandToplevelWindow::OnDragDrop(std::unique_ptr<OSExchangeData> data) {
+ WmDropHandler* drop_handler = GetWmDropHandler(*this);
+ if (!drop_handler)
+ return;
+ drop_handler->OnDragDrop(std::move(data));
+}
+
+void WaylandToplevelWindow::OnDragLeave() {
+ WmDropHandler* drop_handler = GetWmDropHandler(*this);
+ if (!drop_handler)
+ return;
+ drop_handler->OnDragLeave();
+}
+
+void WaylandToplevelWindow::OnDragSessionClose(uint32_t dnd_action) {
+ DCHECK(drag_handler_delegate_);
+ drag_handler_delegate_->OnDragFinished(dnd_action);
+ drag_handler_delegate_ = nullptr;
+ connection()->event_source()->ResetPointerFlags();
+}
+
+bool WaylandToplevelWindow::OnInitialize(
+ PlatformWindowInitProperties properties) {
+ app_id_ = properties.wm_class_class;
+ SetWmMoveLoopHandler(this, static_cast<WmMoveLoopHandler*>(this));
+ return true;
+}
+
+bool WaylandToplevelWindow::RunMoveLoop(const gfx::Vector2d& drag_offset) {
+ DCHECK(connection()->window_drag_controller());
+ return connection()->window_drag_controller()->Drag(this, drag_offset);
+}
+
+void WaylandToplevelWindow::EndMoveLoop() {
+ DCHECK(connection()->window_drag_controller());
+ connection()->window_drag_controller()->StopDragging();
+}
+
+void WaylandToplevelWindow::TriggerStateChanges() {
+ if (!shell_surface_)
+ return;
+
+ if (state_ == PlatformWindowState::kFullScreen)
+ shell_surface_->SetFullscreen();
+ else
+ shell_surface_->UnSetFullscreen();
+
+ // Call UnSetMaximized only if current state is normal. Otherwise, if the
+ // current state is fullscreen and the previous is maximized, calling
+ // UnSetMaximized may result in wrong restored window position that clients
+ // are not allowed to know about.
+ if (state_ == PlatformWindowState::kMaximized)
+ shell_surface_->SetMaximized();
+ else if (state_ == PlatformWindowState::kNormal)
+ shell_surface_->UnSetMaximized();
+
+ if (state_ == PlatformWindowState::kMinimized)
+ shell_surface_->SetMinimized();
+
+ connection()->ScheduleFlush();
+}
+
+void WaylandToplevelWindow::SetWindowState(PlatformWindowState state) {
+ previous_state_ = state_;
+ state_ = state;
+ TriggerStateChanges();
+}
+
+WmMoveResizeHandler* WaylandToplevelWindow::AsWmMoveResizeHandler() {
+ return static_cast<WmMoveResizeHandler*>(this);
+}
+
+void WaylandToplevelWindow::SetSizeConstraints() {
+ if (min_size_.has_value())
+ shell_surface_->SetMinSize(min_size_->width(), min_size_->height());
+ if (max_size_.has_value())
+ shell_surface_->SetMaxSize(max_size_->width(), max_size_->height());
+
+ connection()->ScheduleFlush();
+}
+
+void WaylandToplevelWindow::SetOrResetRestoredBounds() {
+ // The |restored_bounds_| are used when the window gets back to normal
+ // state after it went maximized or fullscreen. So we reset these if the
+ // window has just become normal and store the current bounds if it is
+ // either going out of normal state or simply changes the state and we don't
+ // have any meaningful value stored.
+ if (GetPlatformWindowState() == PlatformWindowState::kNormal) {
+ SetRestoredBoundsInPixels({});
+ } else if (GetRestoredBoundsInPixels().IsEmpty()) {
+ SetRestoredBoundsInPixels(GetBounds());
+ }
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
new file mode 100644
index 00000000000..0455078ee38
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
@@ -0,0 +1,131 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_TOPLEVEL_WINDOW_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_TOPLEVEL_WINDOW_H_
+
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/platform_window/platform_window_handler/wm_drag_handler.h"
+#include "ui/platform_window/platform_window_handler/wm_move_loop_handler.h"
+#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h"
+
+namespace ui {
+
+class ShellSurfaceWrapper;
+
+class WaylandToplevelWindow : public WaylandWindow,
+ public WmMoveResizeHandler,
+ public WmDragHandler,
+ public WmMoveLoopHandler {
+ public:
+ WaylandToplevelWindow(PlatformWindowDelegate* delegate,
+ WaylandConnection* connection);
+ WaylandToplevelWindow(const WaylandToplevelWindow&) = delete;
+ WaylandToplevelWindow& operator=(const WaylandToplevelWindow&) = delete;
+ ~WaylandToplevelWindow() override;
+
+ ShellSurfaceWrapper* shell_surface() const { return shell_surface_.get(); }
+
+ // Apply the bounds specified in the most recent configure event. This should
+ // be called after processing all pending events in the wayland connection.
+ void ApplyPendingBounds();
+
+ // WmMoveResizeHandler
+ void DispatchHostWindowDragMovement(
+ int hittest,
+ const gfx::Point& pointer_location_in_px) override;
+
+ // WmDragHandler
+ void StartDrag(const ui::OSExchangeData& data,
+ int operation,
+ gfx::NativeCursor cursor,
+ WmDragHandler::Delegate* delegate) override;
+
+ // PlatformWindow
+ void Show(bool inactive) override;
+ void Hide() override;
+ bool IsVisible() const override;
+ void SetTitle(const base::string16& title) override;
+ void ToggleFullscreen() override;
+ void Maximize() override;
+ void Minimize() override;
+ void Restore() override;
+ PlatformWindowState GetPlatformWindowState() const override;
+ void SizeConstraintsChanged() override;
+
+ private:
+ // WaylandWindow overrides:
+ void HandleSurfaceConfigure(int32_t widht,
+ int32_t height,
+ bool is_maximized,
+ bool is_fullscreen,
+ bool is_activated) override;
+ void OnDragEnter(const gfx::PointF& point,
+ std::unique_ptr<OSExchangeData> data,
+ int operation) override;
+ int OnDragMotion(const gfx::PointF& point, int operation) override;
+ void OnDragDrop(std::unique_ptr<OSExchangeData> data) override;
+ void OnDragLeave() override;
+ void OnDragSessionClose(uint32_t dnd_action) override;
+ bool OnInitialize(PlatformWindowInitProperties properties) override;
+
+ // WmMoveLoopHandler:
+ bool RunMoveLoop(const gfx::Vector2d& drag_offset) override;
+ void EndMoveLoop() override;
+
+ void TriggerStateChanges();
+ void SetWindowState(PlatformWindowState state);
+
+ // Creates a surface window, which is visible as a main window.
+ bool CreateShellSurface();
+
+ WmMoveResizeHandler* AsWmMoveResizeHandler();
+
+ // Propagates the |min_size_| and |max_size_| to the ShellSurface.
+ void SetSizeConstraints();
+
+ void SetOrResetRestoredBounds();
+
+ // Wrappers around shell surface.
+ std::unique_ptr<ShellSurfaceWrapper> shell_surface_;
+
+ WmDragHandler::Delegate* drag_handler_delegate_ = nullptr;
+
+ // These bounds attributes below have suffices that indicate units used.
+ // Wayland operates in DIP but the platform operates in physical pixels so
+ // our WaylandToplevelWindow is the link that has to translate the units. See
+ // also comments in the implementation.
+ //
+ // Bounds that will be applied when the window state is finalized. The window
+ // may get several configuration events that update the pending bounds, and
+ // only upon finalizing the state is the latest value stored as the current
+ // bounds via |ApplyPendingBounds|. Measured in DIP because updated in the
+ // handler that receives DIP from Wayland.
+ gfx::Rect pending_bounds_dip_;
+
+ // Contains the current state of the window.
+ PlatformWindowState state_;
+ // Contains the previous state of the window.
+ PlatformWindowState previous_state_;
+
+ bool is_active_ = false;
+
+ // Id of the chromium app passed through
+ // PlatformWindowInitProperties::wm_class_class. This is used by Wayland
+ // compositor to identify the app, unite it's windows into the same stack of
+ // windows and find *.desktop file to set various preferences including icons.
+ std::string app_id_;
+
+ // Title of the ShellSurface.
+ base::string16 window_title_;
+
+ // Max and min sizes of the WaylandToplevelWindow window.
+ base::Optional<gfx::Size> min_size_;
+ base::Optional<gfx::Size> max_size_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_TOPLEVEL_WINDOW_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window.cc
index 9298cb3acbc..21ebb192e5a 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -30,7 +30,7 @@ WaylandWindow::WaylandWindow(PlatformWindowDelegate* delegate,
WaylandWindow::~WaylandWindow() {
PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
- if (surface_)
+ if (surface())
connection_->wayland_window_manager()->RemoveWindow(GetWidget());
if (parent_window_)
@@ -61,7 +61,7 @@ void WaylandWindow::UpdateBufferScale(bool update_bounds) {
int32_t new_scale = 0;
if (parent_window_) {
- new_scale = parent_window_->buffer_scale_;
+ new_scale = parent_window_->buffer_scale();
ui_scale_ = parent_window_->ui_scale_;
} else {
const auto display = (widget == gfx::kNullAcceleratedWidget)
@@ -80,9 +80,7 @@ void WaylandWindow::UpdateBufferScale(bool update_bounds) {
}
gfx::AcceleratedWidget WaylandWindow::GetWidget() const {
- if (!surface_)
- return gfx::kNullAcceleratedWidget;
- return surface_.id();
+ return wayland_surface_.GetWidget();
}
void WaylandWindow::SetPointerFocus(bool focus) {
has_pointer_focus_ = focus;
@@ -163,7 +161,7 @@ void WaylandWindow::Restore() {}
PlatformWindowState WaylandWindow::GetPlatformWindowState() const {
// Remove normal state for all the other types of windows as it's only the
- // WaylandSurface that supports state changes.
+ // WaylandToplevelWindow that supports state changes.
return PlatformWindowState::kNormal;
}
@@ -250,6 +248,12 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) {
auto* event_grabber =
connection_->wayland_window_manager()->located_events_grabber();
auto* root_parent_window = GetRootParentWindow();
+
+ // Wayland sends locations in DIP so they need to be translated to
+ // physical pixels.
+ event->AsLocatedEvent()->set_location_f(gfx::ScalePoint(
+ event->AsLocatedEvent()->location_f(), buffer_scale(), buffer_scale()));
+
// We must reroute the events to the event grabber iff these windows belong
// to the same root parent window. For example, there are 2 top level
// Wayland windows. One of them (window_1) has a child menu window that is
@@ -297,9 +301,7 @@ void WaylandWindow::OnDragEnter(const gfx::PointF& point,
std::unique_ptr<OSExchangeData> data,
int operation) {}
-int WaylandWindow::OnDragMotion(const gfx::PointF& point,
- uint32_t time,
- int operation) {
+int WaylandWindow::OnDragMotion(const gfx::PointF& point, int operation) {
return -1;
}
@@ -310,24 +312,26 @@ void WaylandWindow::OnDragLeave() {}
void WaylandWindow::OnDragSessionClose(uint32_t dnd_action) {}
void WaylandWindow::SetBoundsDip(const gfx::Rect& bounds_dip) {
- SetBounds(gfx::ScaleToRoundedRect(bounds_dip, buffer_scale_));
+ SetBounds(gfx::ScaleToRoundedRect(bounds_dip, buffer_scale()));
}
bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
// Properties contain DIP bounds but the buffer scale is initially 1 so it's
// OK to assign. The bounds will be recalculated when the buffer scale
// changes.
- DCHECK_EQ(buffer_scale_, 1);
+ DCHECK_EQ(buffer_scale(), 1);
bounds_px_ = properties.bounds;
opacity_ = properties.opacity;
type_ = properties.type;
- surface_.reset(wl_compositor_create_surface(connection_->compositor()));
- if (!surface_) {
+ wayland_surface_.surface_.reset(
+ wl_compositor_create_surface(connection_->compositor()));
+ wayland_surface_.root_window_ = this;
+ if (!surface()) {
LOG(ERROR) << "Failed to create wl_surface";
return false;
}
- wl_surface_set_user_data(surface_.get(), this);
+ wl_surface_set_user_data(surface(), this);
AddSurfaceListener();
connection_->wayland_window_manager()->AddWindow(GetWidget(), this);
@@ -350,16 +354,16 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
void WaylandWindow::SetBufferScale(int32_t new_scale, bool update_bounds) {
DCHECK_GT(new_scale, 0);
- if (new_scale == buffer_scale_)
+ if (new_scale == buffer_scale())
return;
- auto old_scale = buffer_scale_;
- buffer_scale_ = new_scale;
+ auto old_scale = buffer_scale();
+ wayland_surface_.buffer_scale_ = new_scale;
if (update_bounds)
SetBoundsDip(gfx::ScaleToRoundedRect(bounds_px_, 1.0 / old_scale));
DCHECK(surface());
- wl_surface_set_buffer_scale(surface(), buffer_scale_);
+ wl_surface_set_buffer_scale(surface(), buffer_scale());
connection_->ScheduleFlush();
}
@@ -377,11 +381,12 @@ WaylandWindow* WaylandWindow::GetParentWindow(
// Another case is a notifcation window or a drop down window, which do not
// have a parent in aura. In this case, take the current focused window as a
// parent.
- if (parent_window && parent_window->child_window_)
- return parent_window->child_window_;
+
if (!parent_window)
- return connection_->wayland_window_manager()->GetCurrentFocusedWindow();
- return parent_window;
+ parent_window =
+ connection_->wayland_window_manager()->GetCurrentFocusedWindow();
+
+ return parent_window ? parent_window->GetTopMostChildWindow() : nullptr;
}
WaylandWindow* WaylandWindow::GetRootParentWindow() {
@@ -393,7 +398,7 @@ void WaylandWindow::AddSurfaceListener() {
&WaylandWindow::Enter,
&WaylandWindow::Leave,
};
- wl_surface_add_listener(surface_.get(), &surface_listener, this);
+ wl_surface_add_listener(surface(), &surface_listener, this);
}
void WaylandWindow::AddEnteredOutputId(struct wl_output* output) {
@@ -468,6 +473,10 @@ WaylandWindow* WaylandWindow::GetTopLevelWindow() {
return parent_window_ ? parent_window_->GetTopLevelWindow() : this;
}
+WaylandWindow* WaylandWindow::GetTopMostChildWindow() {
+ return child_window_ ? child_window_->GetTopMostChildWindow() : this;
+}
+
void WaylandWindow::MaybeUpdateOpaqueRegion() {
if (!IsOpaqueWindow())
return;
@@ -490,10 +499,10 @@ uint32_t WaylandWindow::DispatchEventToDelegate(
if (event->IsLocatedEvent())
UpdateCursorPositionFromEvent(Event::Clone(*event));
- DispatchEventFromNativeUiEvent(
+ bool handled = DispatchEventFromNativeUiEvent(
native_event, base::BindOnce(&PlatformWindowDelegate::DispatchEvent,
base::Unretained(delegate_)));
- return POST_DISPATCH_STOP_PROPAGATION;
+ return handled ? POST_DISPATCH_STOP_PROPAGATION : POST_DISPATCH_NONE;
}
// static
@@ -502,7 +511,7 @@ void WaylandWindow::Enter(void* data,
struct wl_output* output) {
auto* window = static_cast<WaylandWindow*>(data);
if (window) {
- DCHECK(window->surface_.get() == wl_surface);
+ DCHECK(window->surface() == wl_surface);
window->AddEnteredOutputId(output);
}
}
@@ -513,7 +522,7 @@ void WaylandWindow::Leave(void* data,
struct wl_output* output) {
auto* window = static_cast<WaylandWindow*>(data);
if (window) {
- DCHECK(window->surface_.get() == wl_surface);
+ DCHECK(window->surface() == wl_surface);
window->RemoveEnteredOutputId(output);
}
}
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window.h b/chromium/ui/ozone/platform/wayland/host/wayland_window.h
index 43cfa54d4cc..9c42eb59c80 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window.h
@@ -17,6 +17,7 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/wayland_surface.h"
#include "ui/platform_window/platform_window.h"
#include "ui/platform_window/platform_window_delegate.h"
#include "ui/platform_window/platform_window_init_properties.h"
@@ -36,7 +37,7 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
~WaylandWindow() override;
// A factory method that can create any of the derived types of WaylandWindow
- // (WaylandSurface, WaylandPopup and WaylandSubsurface).
+ // (WaylandToplevelWindow, WaylandPopup and WaylandSubsurface).
static std::unique_ptr<WaylandWindow> Create(
PlatformWindowDelegate* delegate,
WaylandConnection* connection,
@@ -53,7 +54,8 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// to do so (this is not needed upon window initialization).
void UpdateBufferScale(bool update_bounds);
- wl_surface* surface() const { return surface_.get(); }
+ WaylandSurface* wayland_surface() { return &wayland_surface_; }
+ wl_surface* surface() const { return wayland_surface_.surface(); }
void set_parent_window(WaylandWindow* parent_window) {
parent_window_ = parent_window;
@@ -80,7 +82,7 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
void set_child_window(WaylandWindow* window) { child_window_ = window; }
WaylandWindow* child_window() const { return child_window_; }
- int32_t buffer_scale() const { return buffer_scale_; }
+ int32_t buffer_scale() const { return wayland_surface_.buffer_scale(); }
int32_t ui_scale() const { return ui_scale_; }
const base::flat_set<uint32_t>& entered_outputs_ids() const {
@@ -144,12 +146,17 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
std::unique_ptr<OSExchangeData> data,
int operation);
virtual int OnDragMotion(const gfx::PointF& point,
- uint32_t time,
int operation);
virtual void OnDragDrop(std::unique_ptr<OSExchangeData> data);
virtual void OnDragLeave();
virtual void OnDragSessionClose(uint32_t dnd_action);
+ // Returns a root parent window within the same hierarchy.
+ WaylandWindow* GetRootParentWindow();
+
+ // Returns a top most child window within the same hierarchy.
+ WaylandWindow* GetTopMostChildWindow();
+
protected:
WaylandWindow(PlatformWindowDelegate* delegate,
WaylandConnection* connection);
@@ -175,9 +182,6 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// Initializes the WaylandWindow with supplied properties.
bool Initialize(PlatformWindowInitProperties properties);
- // Returns a root parent window.
- WaylandWindow* GetRootParentWindow();
-
// Install a surface listener and start getting wl_output enter/leave events.
void AddSurfaceListener();
@@ -212,7 +216,7 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
WaylandWindow* parent_window_ = nullptr;
WaylandWindow* child_window_ = nullptr;
- wl::Object<wl_surface> surface_;
+ WaylandSurface wayland_surface_;
// The current cursor bitmap (immutable).
scoped_refptr<BitmapCursorOzone> bitmap_;
@@ -225,9 +229,6 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
bool has_pointer_focus_ = false;
bool has_keyboard_focus_ = false;
bool has_touch_focus_ = false;
- // Wayland's scale factor for the output that this window currently belongs
- // to.
- int32_t buffer_scale_ = 1;
// The UI scale may be forced through the command line, which means that it
// replaces the default value that is equal to the natural device scale.
// We need it to place and size the menus properly.
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
new file mode 100644
index 00000000000..08d5cb633ca
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
@@ -0,0 +1,325 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/host/wayland_window_drag_controller.h"
+
+#include <cstdint>
+#include <memory>
+#include <ostream>
+#include <utility>
+
+#include "base/callback.h"
+#include "base/check.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop_current.h"
+#include "base/notreached.h"
+#include "base/run_loop.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/events/platform/scoped_event_dispatcher.h"
+#include "ui/events/platform_event.h"
+#include "ui/events/types/event_type.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_cursor_position.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_offer.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
+#include "ui/ozone/platform/wayland/host/wayland_surface.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_window_manager.h"
+
+namespace ui {
+
+namespace {
+
+// Custom mime type used for window dragging DND sessions.
+constexpr char kMimeTypeChromiumWindow[] = "chromium/x-window";
+
+// DND action used in window dragging DND sessions.
+constexpr uint32_t kDndActionWindowDrag =
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
+
+} // namespace
+
+WaylandWindowDragController::WaylandWindowDragController(
+ WaylandConnection* connection,
+ WaylandDataDeviceManager* device_manager,
+ WaylandPointer::Delegate* pointer_delegate)
+ : connection_(connection),
+ data_device_manager_(device_manager),
+ data_device_(device_manager->GetDevice()),
+ window_manager_(connection_->wayland_window_manager()),
+ pointer_delegate_(pointer_delegate) {
+ DCHECK(data_device_);
+ DCHECK(pointer_delegate_);
+}
+
+WaylandWindowDragController::~WaylandWindowDragController() = default;
+
+bool WaylandWindowDragController::Drag(WaylandToplevelWindow* window,
+ const gfx::Vector2d& offset) {
+ DCHECK_LE(state_, State::kAttached);
+ DCHECK(window);
+
+ if (!OfferWindow())
+ return false;
+
+ DCHECK_EQ(state_, State::kAttached);
+ dragged_window_ = window;
+ drag_offset_ = offset;
+ RunLoop();
+
+ DCHECK(state_ == State::kAttached || state_ == State::kDropped);
+ bool dropped = state_ == State::kDropped;
+ if (dropped)
+ HandleDropAndResetState();
+ return dropped;
+}
+
+void WaylandWindowDragController::StopDragging() {
+ if (state_ != State::kDetached)
+ return;
+
+ VLOG(1) << "End drag loop requested. state=" << state_;
+
+ // This function is supposed to be called to indicate that the window was just
+ // snapped into a tab strip. So switch to |kAttached| state and ask to quit
+ // the nested loop.
+ state_ = State::kAttached;
+ QuitLoop();
+}
+
+bool WaylandWindowDragController::IsDragSource() const {
+ DCHECK(data_source_);
+ return true;
+}
+
+// Icon drawing and update for window/tab dragging is handled by buffer manager.
+void WaylandWindowDragController::DrawIcon() {}
+
+void WaylandWindowDragController::OnDragOffer(
+ std::unique_ptr<WaylandDataOffer> offer) {
+ DCHECK_GE(state_, State::kAttached);
+ DCHECK(offer);
+ DCHECK(!data_offer_);
+ data_offer_ = std::move(offer);
+}
+
+void WaylandWindowDragController::OnDragEnter(WaylandWindow* window,
+ const gfx::PointF& location,
+ uint32_t serial) {
+ DCHECK_GE(state_, State::kAttached);
+ DCHECK(window);
+
+ // Forward focus change event to the input delegate, so other components, such
+ // as WaylandScreen, are able to properly retrieve focus related info during
+ // window dragging sesstions.
+ pointer_delegate_->OnPointerFocusChanged(window, location);
+
+ VLOG(1) << "OnEnter. widget=" << window->GetWidget();
+
+ // Ensure this is a valid "window drag" offer.
+ DCHECK(data_offer_);
+ DCHECK_EQ(data_offer_->mime_types().size(), 1u);
+ DCHECK_EQ(data_offer_->mime_types().front(), kMimeTypeChromiumWindow);
+
+ // Accept the offer and set the dnd action.
+ data_offer_->SetAction(kDndActionWindowDrag, kDndActionWindowDrag);
+ data_offer_->Accept(serial, kMimeTypeChromiumWindow);
+}
+
+void WaylandWindowDragController::OnDragMotion(const gfx::PointF& location) {
+ DCHECK_GE(state_, State::kAttached);
+ VLOG(2) << "OnMotion. location=" << location.ToString();
+
+ // Forward cursor location update info to the input handling delegate.
+ pointer_delegate_->OnPointerMotionEvent(location);
+}
+
+void WaylandWindowDragController::OnDragLeave() {
+ DCHECK_GE(state_, State::kAttached);
+ DCHECK_LE(state_, State::kDetached);
+
+ // In order to guarantee ET_MOUSE_RELEASED event is delivered once the DND
+ // session finishes, the focused window is not reset here. This is similar to
+ // the "implicit grab" behavior implemented by Wayland compositors for
+ // wl_pointer events. Additionally, this makes it possible for the drag
+ // controller to overcome deviations in the order that wl_data_source and
+ // wl_pointer events arrive when the drop happens. For example, unlike Weston
+ // and Sway, Gnome Shell <= 2.26 sends them in the following order:
+ //
+ // wl_data_device.leave > wl_pointer.enter > wl_data_source.cancel/finish
+ //
+ // which would require hacky workarounds in HandleDropAndResetState function
+ // to properly detect and handle such cases.
+
+ VLOG(1) << "OnLeave";
+
+ data_offer_.reset();
+}
+
+void WaylandWindowDragController::OnDragDrop() {
+ // Not used for window dragging sessions. Handling of drop events is fully
+ // done at OnDataSourceFinish function, i.e: wl_data_source::{cancel,finish}.
+}
+
+void WaylandWindowDragController::OnDataSourceFinish(bool completed) {
+ DCHECK_GE(state_, State::kAttached);
+ DCHECK(data_source_);
+
+ VLOG(1) << "Drop received. state=" << state_;
+
+ // Release DND objects.
+ data_offer_.reset();
+ data_source_.reset();
+ icon_surface_.reset();
+ dragged_window_ = nullptr;
+
+ // Transition to |kDropped| state and determine the next action to take. If
+ // drop happened while the move loop was running (i.e: kDetached), ask to quit
+ // the loop, otherwise notify session end and reset state right away.
+ State state_when_dropped = std::exchange(state_, State::kDropped);
+ if (state_when_dropped == State::kDetached)
+ QuitLoop();
+ else
+ HandleDropAndResetState();
+
+ data_device_->ResetDragDelegate();
+}
+
+void WaylandWindowDragController::OnDataSourceSend(const std::string& mime_type,
+ std::string* contents) {
+ // There is no actual data exchange in DnD window dragging sessions. Window
+ // snapping, for example, is supposed to be handled at higher level UI layers.
+}
+
+bool WaylandWindowDragController::CanDispatchEvent(const PlatformEvent& event) {
+ return state_ == State::kDetached;
+}
+
+uint32_t WaylandWindowDragController::DispatchEvent(
+ const PlatformEvent& event) {
+ DCHECK_EQ(state_, State::kDetached);
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
+
+ VLOG(2) << "Dispatch. event=" << event->GetName();
+
+ if (event->type() == ET_MOUSE_MOVED || event->type() == ET_MOUSE_DRAGGED) {
+ HandleMotionEvent(event->AsMouseEvent());
+ return POST_DISPATCH_STOP_PROPAGATION;
+ }
+ return POST_DISPATCH_PERFORM_DEFAULT;
+}
+
+bool WaylandWindowDragController::OfferWindow() {
+ DCHECK_LE(state_, State::kAttached);
+
+ auto* window = window_manager_->GetCurrentFocusedWindow();
+ if (!window) {
+ LOG(ERROR) << "Failed to get focused window.";
+ return false;
+ }
+
+ if (!data_source_)
+ data_source_ = data_device_manager_->CreateSource(this);
+
+ if (state_ == State::kIdle) {
+ DCHECK(!icon_surface_);
+ icon_surface_.reset(
+ wl_compositor_create_surface(connection_->compositor()));
+
+ VLOG(1) << "Starting DND session.";
+ state_ = State::kAttached;
+ data_source_->Offer({kMimeTypeChromiumWindow});
+ data_source_->SetAction(DragDropTypes::DRAG_MOVE);
+ data_device_->StartDrag(*data_source_, *window, icon_surface_.get(), this);
+ }
+ return true;
+}
+
+void WaylandWindowDragController::HandleMotionEvent(MouseEvent* event) {
+ DCHECK_EQ(state_, State::kDetached);
+ DCHECK(dragged_window_);
+ DCHECK(event);
+
+ // Update current cursor position, so it can be retrieved later on through
+ // |Screen::GetCursorScreenPoint| API.
+ int32_t scale = dragged_window_->buffer_scale();
+ gfx::PointF scaled_location =
+ gfx::ScalePoint(event->location_f(), scale, scale);
+ connection_->wayland_cursor_position()->OnCursorPositionChanged(
+ gfx::ToFlooredPoint(scaled_location));
+
+ // Notify listeners about window bounds change (i.e: re-positioning) event.
+ // To do so, set the new bounds as per the motion event location and the drag
+ // offset. Note that setting a new location (i.e: bounds.origin()) for a
+ // surface has no visual effect in ozone/wayland backend. Actual window
+ // re-positioning during dragging session is done through the drag icon.
+ gfx::Point new_location = event->location() - drag_offset_;
+ gfx::Size size = dragged_window_->GetBounds().size();
+ dragged_window_->SetBounds({new_location, size});
+}
+
+// Dispatch mouse release event (to tell clients that the drop just happened)
+// clear focus and reset internal state. Must be called when the session is
+// about to finish.
+void WaylandWindowDragController::HandleDropAndResetState() {
+ DCHECK_EQ(state_, State::kDropped);
+ DCHECK(window_manager_->GetCurrentFocusedWindow());
+ VLOG(1) << "Notifying drop. window="
+ << window_manager_->GetCurrentFocusedWindow();
+
+ EventFlags pointer_button = EF_LEFT_MOUSE_BUTTON;
+ DCHECK(connection_->event_source()->IsPointerButtonPressed(pointer_button));
+ pointer_delegate_->OnPointerButtonEvent(ET_MOUSE_RELEASED, pointer_button);
+
+ state_ = State::kIdle;
+}
+
+void WaylandWindowDragController::RunLoop() {
+ DCHECK_EQ(state_, State::kAttached);
+ DCHECK(dragged_window_);
+
+ VLOG(1) << "Starting drag loop. widget=" << dragged_window_->GetWidget();
+
+ // TODO(crbug.com/896640): Handle cursor
+ auto old_dispatcher = std::move(nested_dispatcher_);
+ nested_dispatcher_ =
+ PlatformEventSource::GetInstance()->OverrideDispatcher(this);
+
+ base::WeakPtr<WaylandWindowDragController> alive(weak_factory_.GetWeakPtr());
+
+ state_ = State::kDetached;
+ base::RunLoop loop(base::RunLoop::Type::kNestableTasksAllowed);
+ quit_loop_closure_ = loop.QuitClosure();
+ loop.Run();
+
+ if (!alive)
+ return;
+
+ nested_dispatcher_ = std::move(old_dispatcher);
+
+ VLOG(1) << "Quitting drag loop " << state_;
+}
+
+void WaylandWindowDragController::QuitLoop() {
+ DCHECK(!quit_loop_closure_.is_null());
+
+ nested_dispatcher_.reset();
+ std::move(quit_loop_closure_).Run();
+}
+
+std::ostream& operator<<(std::ostream& out,
+ WaylandWindowDragController::State state) {
+ return out << static_cast<int>(state);
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h
new file mode 100644
index 00000000000..071cc9672bc
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h
@@ -0,0 +1,126 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_WINDOW_DRAG_CONTROLLER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_WINDOW_DRAG_CONTROLLER_H_
+
+#include <cstdint>
+#include <iosfwd>
+#include <memory>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/events/event.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/events/platform/scoped_event_dispatcher.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/ozone/platform/wayland/gpu/wayland_surface_factory.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
+#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
+
+namespace ui {
+
+class WaylandConnection;
+class WaylandDataDeviceManager;
+class WaylandDataOffer;
+class WaylandWindow;
+class WaylandWindowManager;
+
+// Drag controller implementation that drives window moving sessions (aka: tab
+// dragging). Wayland Drag and Drop protocol is used, under the hood, to keep
+// track of cursor location and surface focus.
+//
+// TODO(crbug.com/896640): Use drag icon to emulate window moving.
+class WaylandWindowDragController : public WaylandDataDevice::DragDelegate,
+ public WaylandDataSource::Delegate,
+ public PlatformEventDispatcher {
+ public:
+ // Constants used to keep track of the drag controller state.
+ enum class State {
+ kIdle, // No DnD session nor drag loop running.
+ kAttached, // DnD session ongoing but no drag loop running.
+ kDetached, // Drag loop running. ie: blocked in a Drag() call.
+ kDropped // Drop event was just received.
+ };
+
+ WaylandWindowDragController(WaylandConnection* connection,
+ WaylandDataDeviceManager* device_manager,
+ WaylandPointer::Delegate* pointer_delegate);
+ WaylandWindowDragController(const WaylandWindowDragController&) = delete;
+ WaylandWindowDragController& operator=(const WaylandWindowDragController&) =
+ delete;
+ ~WaylandWindowDragController() override;
+
+ bool Drag(WaylandToplevelWindow* surface, const gfx::Vector2d& offset);
+ void StopDragging();
+
+ State state() const { return state_; }
+
+ private:
+ // WaylandDataDevice::DragDelegate:
+ bool IsDragSource() const override;
+ void DrawIcon() override;
+ void OnDragOffer(std::unique_ptr<WaylandDataOffer> offer) override;
+ void OnDragEnter(WaylandWindow* window,
+ const gfx::PointF& location,
+ uint32_t serial) override;
+ void OnDragMotion(const gfx::PointF& location) override;
+ void OnDragLeave() override;
+ void OnDragDrop() override;
+
+ // WaylandDataSource::Delegate
+ void OnDataSourceFinish(bool completed) override;
+ void OnDataSourceSend(const std::string& mime_type,
+ std::string* contents) override;
+
+ // PlatformEventDispatcher
+ bool CanDispatchEvent(const PlatformEvent& event) override;
+ uint32_t DispatchEvent(const PlatformEvent& event) override;
+
+ // Offers the focused window as available to be dragged. A new data source is
+ // setup and the underlying DnD session is started, if not done yet.
+ bool OfferWindow();
+ // Handles drag/move mouse |event|, while in |kDetached| mode, forwarding it
+ // as a bounds change event to the upper layer handlers.
+ void HandleMotionEvent(MouseEvent* event);
+ // Handles the mouse button release (i.e: drop). Dispatches the required
+ // events and resets the internal state.
+ void HandleDropAndResetState();
+ // Registers as the top level PlatformEvent dispatcher and runs a nested
+ // RunLoop, which blocks until the DnD session finishes.
+ void RunLoop();
+ // Unregisters the internal event dispatcher and asks to quit the nested loop.
+ void QuitLoop();
+
+ WaylandConnection* const connection_;
+ WaylandDataDeviceManager* const data_device_manager_;
+ WaylandDataDevice* const data_device_;
+ WaylandWindowManager* const window_manager_;
+ WaylandPointer::Delegate* const pointer_delegate_;
+
+ State state_ = State::kIdle;
+ WaylandToplevelWindow* dragged_window_ = nullptr;
+ gfx::Vector2d drag_offset_;
+
+ std::unique_ptr<WaylandDataSource> data_source_;
+ std::unique_ptr<WaylandDataOffer> data_offer_;
+ wl::Object<wl_surface> icon_surface_;
+
+ std::unique_ptr<ScopedEventDispatcher> nested_dispatcher_;
+ base::OnceClosure quit_loop_closure_;
+
+ base::WeakPtrFactory<WaylandWindowDragController> weak_factory_{this};
+};
+
+// Stream operator so WaylandWindowDragController::State can be used in
+// log/assertion statements.
+std::ostream& operator<<(std::ostream& out,
+ WaylandWindowDragController::State state);
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_WINDOW_DRAG_CONTROLLER_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
new file mode 100644
index 00000000000..56a13b46e48
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
@@ -0,0 +1,519 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <linux/input-event-codes.h>
+#include <wayland-server-protocol.h>
+#include <wayland-server.h>
+#include <wayland-util.h>
+
+#include <cstdint>
+
+#include "base/notreached.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/events/event.h"
+#include "ui/events/types/event_type.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
+#include "ui/ozone/platform/wayland/host/wayland_screen.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_window_drag_controller.h"
+#include "ui/ozone/platform/wayland/host/wayland_window_manager.h"
+#include "ui/ozone/platform/wayland/test/constants.h"
+#include "ui/ozone/platform/wayland/test/mock_pointer.h"
+#include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/test_data_device.h"
+#include "ui/ozone/platform/wayland/test/test_data_device_manager.h"
+#include "ui/ozone/platform/wayland/test/test_data_offer.h"
+#include "ui/ozone/platform/wayland/test/test_data_source.h"
+#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
+#include "ui/ozone/test/mock_platform_window_delegate.h"
+#include "ui/platform_window/platform_window_delegate.h"
+#include "ui/platform_window/platform_window_handler/wm_move_loop_handler.h"
+
+using testing::_;
+using testing::Mock;
+
+namespace ui {
+
+class WaylandWindowDragControllerTest : public WaylandTest,
+ public wl::TestDataDevice::Delegate {
+ public:
+ WaylandWindowDragControllerTest() = default;
+ ~WaylandWindowDragControllerTest() override = default;
+
+ void SetUp() override {
+ WaylandTest::SetUp();
+ screen_ = std::make_unique<WaylandScreen>(connection_.get());
+
+ wl_seat_send_capabilities(server_.seat()->resource(),
+ WL_SEAT_CAPABILITY_POINTER);
+ Sync();
+ pointer_ = server_.seat()->pointer();
+ ASSERT_TRUE(pointer_);
+
+ EXPECT_FALSE(window_->has_pointer_focus());
+ EXPECT_EQ(State::kIdle, drag_controller()->state());
+
+ data_device_manager_ = server_.data_device_manager();
+ DCHECK(data_device_manager_);
+
+ source_ = nullptr;
+ data_device_manager_->data_device()->set_delegate(this);
+ }
+
+ void TearDown() override {
+ data_device_manager_->data_device()->set_delegate(nullptr);
+ }
+
+ WaylandWindowDragController* drag_controller() const {
+ return connection_->window_drag_controller();
+ }
+
+ WaylandWindowManager* window_manager() const {
+ return connection_->wayland_window_manager();
+ }
+
+ uint32_t NextSerial() const {
+ static uint32_t serial = 0;
+ return ++serial;
+ }
+
+ uint32_t NextTime() const {
+ static uint32_t timestamp = 0;
+ return ++timestamp;
+ }
+
+ protected:
+ using State = WaylandWindowDragController::State;
+
+ // wl::TestDataDevice::Delegate:
+ void StartDrag(wl::TestDataSource* source,
+ wl::MockSurface* origin,
+ uint32_t serial) override {
+ EXPECT_FALSE(source_);
+ source_ = source;
+ OfferAndEnter(origin);
+ }
+
+ // Helper functions
+ void SendDndMotion(const gfx::Point& location) {
+ EXPECT_TRUE(source_);
+ wl_fixed_t x = wl_fixed_from_int(location.x());
+ wl_fixed_t y = wl_fixed_from_int(location.y());
+ data_device_manager_->data_device()->OnMotion(NextTime(), x, y);
+ }
+
+ void SendDndEnter(WaylandWindow* window) {
+ EXPECT_TRUE(window);
+ OfferAndEnter(server_.GetObject<wl::MockSurface>(window->GetWidget()));
+ }
+
+ void SendDndLeave() {
+ EXPECT_TRUE(source_);
+ data_device_manager_->data_device()->OnLeave();
+ }
+
+ void SendDndDrop() {
+ EXPECT_TRUE(source_);
+ source_->OnCancelled();
+ }
+
+ void SendPointerEnter(WaylandWindow* window,
+ MockPlatformWindowDelegate* delegate) {
+ auto* surface = server_.GetObject<wl::MockSurface>(window->GetWidget());
+ wl_pointer_send_enter(pointer_->resource(), NextSerial(),
+ surface->resource(), 0, 0);
+ EXPECT_CALL(*delegate, DispatchEvent(_)).Times(1);
+ Sync();
+
+ EXPECT_EQ(window, window_manager()->GetCurrentFocusedWindow());
+ }
+
+ void SendPointerPress(WaylandWindow* window,
+ MockPlatformWindowDelegate* delegate,
+ int button) {
+ wl_pointer_send_button(pointer_->resource(), NextSerial(), NextTime(),
+ button, WL_POINTER_BUTTON_STATE_PRESSED);
+ EXPECT_CALL(*delegate, DispatchEvent(_)).Times(1);
+ Sync();
+
+ EXPECT_EQ(window, window_manager()->GetCurrentFocusedWindow());
+ }
+
+ void SendPointerMotion(WaylandWindow* window,
+ MockPlatformWindowDelegate* delegate,
+ gfx::Point location) {
+ wl_fixed_t x = wl_fixed_from_int(location.x());
+ wl_fixed_t y = wl_fixed_from_int(location.y());
+ wl_pointer_send_motion(pointer_->resource(), NextTime(), x, y);
+ EXPECT_CALL(*delegate, DispatchEvent(_)).WillOnce([](Event* event) {
+ EXPECT_TRUE(event->IsMouseEvent());
+ EXPECT_EQ(ET_MOUSE_DRAGGED, event->type());
+ });
+ Sync();
+
+ EXPECT_EQ(window->GetWidget(),
+ screen_->GetLocalProcessWidgetAtPoint(location, {}));
+ }
+
+ void OfferAndEnter(wl::MockSurface* surface) {
+ EXPECT_TRUE(source_);
+ auto* data_device = data_device_manager_->data_device();
+ auto* offer = data_device->OnDataOffer();
+ EXPECT_EQ(1u, source_->mime_types().size());
+ for (const auto& mime_type : source_->mime_types())
+ offer->OnOffer(mime_type, {});
+
+ wl_data_device_send_enter(data_device->resource(), NextSerial(),
+ surface->resource(), 0, 0, offer->resource());
+ }
+
+ // client objects
+ std::unique_ptr<WaylandScreen> screen_;
+
+ // server objects
+ wl::TestDataDeviceManager* data_device_manager_;
+ wl::TestDataSource* source_;
+ wl::MockPointer* pointer_;
+};
+
+// Check the following flow works as expected:
+// 1. With a single 1 window open,
+// 2. Move pointer into it, press left button, move cursor a bit (drag),
+// 3. Run move loop, drag it within the window bounds and drop.
+TEST_P(WaylandWindowDragControllerTest, DragInsideWindowAndDrop) {
+ // Ensure there is no window currently focused
+ EXPECT_FALSE(window_manager()->GetCurrentFocusedWindow());
+ EXPECT_EQ(gfx::kNullAcceleratedWidget,
+ screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
+
+ SendPointerEnter(window_.get(), &delegate_);
+ SendPointerPress(window_.get(), &delegate_, BTN_LEFT);
+ SendPointerMotion(window_.get(), &delegate_, {10, 10});
+
+ // Set up an "interaction flow" and RunMoveLoop:
+ // - Event dispatching and bounds changes are monitored
+ // - At each event, emulates a new event at server side and proceeds to the
+ // next test step.
+ auto* move_loop_handler = GetWmMoveLoopHandler(*window_);
+ DCHECK(move_loop_handler);
+
+ enum { kStarted, kDragging, kDropping, kDone } test_step = kStarted;
+
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillRepeatedly([&](Event* event) {
+ EXPECT_TRUE(event->IsMouseEvent());
+ switch (test_step) {
+ case kStarted:
+ EXPECT_EQ(ET_MOUSE_ENTERED, event->type());
+ EXPECT_EQ(State::kDetached, drag_controller()->state());
+ // Ensure PlatformScreen keeps consistent.
+ EXPECT_EQ(window_->GetWidget(),
+ screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
+ // Drag it a bit more.
+ SendDndMotion({20, 20});
+ test_step = kDragging;
+ break;
+ case kDropping:
+ EXPECT_EQ(ET_MOUSE_RELEASED, event->type());
+ EXPECT_EQ(State::kDropped, drag_controller()->state());
+ // Ensure PlatformScreen keeps consistent.
+ EXPECT_EQ(gfx::Point(20, 20), screen_->GetCursorScreenPoint());
+ EXPECT_EQ(window_->GetWidget(),
+ screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
+ test_step = kDone;
+ break;
+ case kDone:
+ EXPECT_EQ(ET_MOUSE_EXITED, event->type());
+ EXPECT_EQ(window_->GetWidget(),
+ screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
+ break;
+ case kDragging:
+ default:
+ FAIL() << " event=" << event->GetName()
+ << " state=" << drag_controller()->state()
+ << " step=" << static_cast<int>(test_step);
+ return;
+ }
+ });
+
+ EXPECT_CALL(delegate_, OnBoundsChanged(_))
+ .WillOnce([&](const gfx::Rect& bounds) {
+ EXPECT_EQ(State::kDetached, drag_controller()->state());
+ EXPECT_EQ(kDragging, test_step);
+ EXPECT_EQ(gfx::Point(20, 20), bounds.origin());
+
+ SendDndDrop();
+ test_step = kDropping;
+ });
+
+ // RunMoveLoop() blocks until the dragging session ends, so resume test
+ // server's run loop until it returns.
+ server_.Resume();
+ move_loop_handler->RunMoveLoop({});
+ server_.Pause();
+
+ SendPointerEnter(window_.get(), &delegate_);
+ Sync();
+
+ EXPECT_EQ(State::kIdle, drag_controller()->state());
+ EXPECT_EQ(window_.get(), window_manager()->GetCurrentFocusedWindow());
+ EXPECT_EQ(window_->GetWidget(),
+ screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
+}
+
+// Check the following flow works as expected:
+// 1. With only 1 window open;
+// 2. Move pointer into it, press left button, move cursor a bit (drag);
+// 3. Run move loop,
+// 4. Drag pointer to outside the window and release the mouse button, and make
+// sure RELEASE and EXIT mouse events are delivered even when the drop
+// happens outside the bounds of any surface.
+TEST_P(WaylandWindowDragControllerTest, DragExitWindowAndDrop) {
+ // Ensure there is no window currently focused
+ EXPECT_FALSE(window_manager()->GetCurrentFocusedWindow());
+ EXPECT_EQ(gfx::kNullAcceleratedWidget,
+ screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
+
+ SendPointerEnter(window_.get(), &delegate_);
+ SendPointerPress(window_.get(), &delegate_, BTN_LEFT);
+ SendPointerMotion(window_.get(), &delegate_, {10, 10});
+
+ // Sets up an "interaction flow" and RunMoveLoop:
+ // - Event dispatching and bounds changes are monitored
+ // - At each event, emulates a new event on server side and proceeds to the
+ // next test step.
+ auto* move_loop_handler = GetWmMoveLoopHandler(*window_);
+ DCHECK(move_loop_handler);
+
+ enum {
+ kStarted,
+ kDragging,
+ kExitedWindow,
+ kDropping,
+ kDone
+ } test_step = kStarted;
+
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillRepeatedly([&](Event* event) {
+ EXPECT_TRUE(event->IsMouseEvent());
+ switch (test_step) {
+ case kStarted:
+ EXPECT_EQ(ET_MOUSE_ENTERED, event->type());
+ EXPECT_EQ(State::kDetached, drag_controller()->state());
+ // Ensure PlatformScreen keeps consistent.
+ EXPECT_EQ(window_->GetWidget(),
+ screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
+ // Drag window a bit more.
+ SendDndMotion({20, 20});
+ test_step = kDragging;
+ break;
+ case kExitedWindow:
+ EXPECT_EQ(ET_MOUSE_EXITED, event->type());
+ // Release mouse button with no window foucsed.
+ SendDndDrop();
+ test_step = kDropping;
+ break;
+ case kDropping:
+ EXPECT_EQ(ET_MOUSE_RELEASED, event->type());
+ EXPECT_EQ(State::kDropped, drag_controller()->state());
+ // Ensure PlatformScreen keeps consistent.
+ EXPECT_EQ(gfx::Point(20, 20), screen_->GetCursorScreenPoint());
+ EXPECT_EQ(window_->GetWidget(),
+ screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
+ test_step = kDone;
+ break;
+ case kDone:
+ EXPECT_EQ(ET_MOUSE_EXITED, event->type());
+ break;
+ case kDragging:
+ default:
+ FAIL() << " event=" << event->GetName()
+ << " state=" << drag_controller()->state()
+ << " step=" << static_cast<int>(test_step);
+ return;
+ }
+ });
+
+ EXPECT_CALL(delegate_, OnBoundsChanged(_))
+ .WillOnce([&](const gfx::Rect& bounds) {
+ EXPECT_EQ(State::kDetached, drag_controller()->state());
+ EXPECT_EQ(kDragging, test_step);
+ EXPECT_EQ(gfx::Point(20, 20), bounds.origin());
+
+ SendDndDrop();
+ test_step = kDropping;
+ });
+
+ // RunMoveLoop() blocks until the dragging sessions ends, so resume test
+ // server's run loop until it returns.
+ server_.Resume();
+ move_loop_handler->RunMoveLoop({});
+ server_.Pause();
+
+ SendPointerEnter(window_.get(), &delegate_);
+ Sync();
+
+ EXPECT_EQ(State::kIdle, drag_controller()->state());
+ EXPECT_EQ(window_.get(), window_manager()->GetCurrentFocusedWindow());
+ EXPECT_EQ(window_->GetWidget(),
+ screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
+}
+
+// Check the following flow works as expected:
+// 1. With 2 windows open,
+// 2. Focus window 1, starts dragging,
+// 3. Run move loop,
+// 4. Drag the pointer out of window 1 and then into window 2,
+// 5. Drag it a bit more (within window 2) and then calls EndMoveLoop(),
+// emulating a window snap), and then
+// 6. With the window in "snapped" state, drag it further and then drop.
+TEST_P(WaylandWindowDragControllerTest, DragToOtherWindowSnapDragDrop) {
+ // Init and open |target_window|.
+ PlatformWindowInitProperties properties{gfx::Rect{80, 80}};
+ properties.type = PlatformWindowType::kWindow;
+ EXPECT_CALL(delegate_, OnAcceleratedWidgetAvailable(_)).Times(1);
+ auto window_2 = WaylandWindow::Create(&delegate_, connection_.get(),
+ std::move(properties));
+ ASSERT_NE(gfx::kNullAcceleratedWidget, window_2->GetWidget());
+ Sync();
+
+ // Ensure there is no window currently focused
+ EXPECT_FALSE(window_manager()->GetCurrentFocusedWindow());
+ EXPECT_EQ(gfx::kNullAcceleratedWidget,
+ screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
+
+ auto* source_window = window_.get();
+ auto* target_window = window_2.get();
+ EXPECT_TRUE(source_window);
+ EXPECT_TRUE(target_window);
+
+ SendPointerEnter(source_window, &delegate_);
+ SendPointerPress(source_window, &delegate_, BTN_LEFT);
+ SendPointerMotion(source_window, &delegate_, {10, 10});
+
+ // Sets up an "interaction flow" and RunMoveLoop:
+ // - Event dispatching and bounds changes are monitored
+ // - At each event, emulates a new event on server side and proceeds to the
+ // next test step.
+ auto* move_loop_handler = GetWmMoveLoopHandler(*window_);
+ DCHECK(move_loop_handler);
+
+ enum {
+ kStarted,
+ kDragging,
+ kEnteredTarget,
+ kSnapped,
+ kDone
+ } test_step = kStarted;
+
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillRepeatedly([&](Event* event) {
+ EXPECT_TRUE(event->IsMouseEvent());
+ switch (test_step) {
+ case kStarted:
+ EXPECT_EQ(ET_MOUSE_ENTERED, event->type());
+ EXPECT_EQ(State::kDetached, drag_controller()->state());
+ // Ensure PlatformScreen keeps consistent.
+ EXPECT_EQ(source_window->GetWidget(),
+ screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
+ // Drag window a bit more.
+ SendDndMotion({50, 50});
+ test_step = kDragging;
+ break;
+ case kEnteredTarget:
+ EXPECT_EQ(ET_MOUSE_ENTERED, event->type());
+ EXPECT_EQ(State::kDetached, drag_controller()->state());
+ // Ensure PlatformScreen keeps consistent.
+ EXPECT_EQ(target_window->GetWidget(),
+ screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
+
+ move_loop_handler->EndMoveLoop();
+ test_step = kSnapped;
+ break;
+ default:
+ FAIL() << " event=" << event->GetName()
+ << " state=" << drag_controller()->state()
+ << " step=" << static_cast<int>(test_step);
+ return;
+ }
+ });
+
+ EXPECT_CALL(delegate_, OnBoundsChanged(_))
+ .WillOnce([&](const gfx::Rect& bounds) {
+ EXPECT_EQ(State::kDetached, drag_controller()->state());
+ EXPECT_EQ(kDragging, test_step);
+ EXPECT_EQ(gfx::Point(50, 50), bounds.origin());
+
+ // Exit |source_window| and enter the |target_window|.
+ SendDndLeave();
+ SendDndEnter(target_window);
+ test_step = kEnteredTarget;
+ });
+
+ // RunMoveLoop() blocks until the dragging sessions ends, so resume test
+ // server's run loop until it returns.
+ server_.Resume();
+ move_loop_handler->RunMoveLoop({});
+ server_.Pause();
+
+ // Continue the dragging session after "snapping" the window. At this point,
+ // the DND session is expected to be still alive and responding normally to
+ // data object events.
+ EXPECT_EQ(State::kAttached, drag_controller()->state());
+ EXPECT_EQ(kSnapped, test_step);
+
+ // Drag the pointer a bit more within |target_window| and then releases the
+ // mouse button and ensures drag controller delivers the events properly and
+ // exit gracefully.
+ SendDndMotion({30, 30});
+ SendDndMotion({30, 33});
+ SendDndMotion({30, 36});
+ SendDndMotion({30, 39});
+ SendDndMotion({30, 42});
+ EXPECT_CALL(delegate_, DispatchEvent(_)).Times(5);
+ Sync();
+
+ EXPECT_EQ(gfx::Point(30, 42), screen_->GetCursorScreenPoint());
+ EXPECT_EQ(target_window->GetWidget(),
+ screen_->GetLocalProcessWidgetAtPoint({50, 50}, {}));
+
+ SendDndDrop();
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillRepeatedly([&](Event* event) {
+ EXPECT_TRUE(event->IsMouseEvent());
+ switch (test_step) {
+ case kSnapped:
+ EXPECT_EQ(ET_MOUSE_RELEASED, event->type());
+ EXPECT_EQ(State::kDropped, drag_controller()->state());
+ test_step = kDone;
+ break;
+ case kDone:
+ EXPECT_EQ(ET_MOUSE_EXITED, event->type());
+ EXPECT_EQ(target_window->GetWidget(),
+ screen_->GetLocalProcessWidgetAtPoint({30, 42}, {}));
+ break;
+ default:
+ FAIL() << " event=" << event->GetName()
+ << " state=" << drag_controller()->state()
+ << " step=" << static_cast<int>(test_step);
+ return;
+ }
+ });
+ Sync();
+
+ SendPointerEnter(target_window, &delegate_);
+ EXPECT_EQ(target_window, window_manager()->GetCurrentFocusedWindow());
+ EXPECT_EQ(target_window->GetWidget(),
+ screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
+}
+
+INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
+ WaylandWindowDragControllerTest,
+ ::testing::Values(kXdgShellStable));
+
+INSTANTIATE_TEST_SUITE_P(XdgVersionV6Test,
+ WaylandWindowDragControllerTest,
+ ::testing::Values(kXdgShellV6));
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc
index f74df68dbff..29d70dbdc39 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc
@@ -8,7 +8,7 @@
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_popup.h"
#include "ui/ozone/platform/wayland/host/wayland_subsurface.h"
-#include "ui/ozone/platform/wayland/host/wayland_surface.h"
+#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
namespace ui {
@@ -26,7 +26,7 @@ std::unique_ptr<WaylandWindow> WaylandWindow::Create(
// parent window to be set. Thus, create a normal window instead then.
if (properties.parent_widget == gfx::kNullAcceleratedWidget &&
!connection->wayland_window_manager()->GetCurrentFocusedWindow()) {
- window.reset(new WaylandSurface(delegate, connection));
+ window.reset(new WaylandToplevelWindow(delegate, connection));
} else if (connection->IsDragInProgress()) {
// We are in the process of drag and requested a popup. Most probably,
// it is an arrow window.
@@ -43,7 +43,7 @@ std::unique_ptr<WaylandWindow> WaylandWindow::Create(
case PlatformWindowType::kDrag:
// TODO(msisov): Figure out what kind of surface we need to create for
// bubble and drag windows.
- window.reset(new WaylandSurface(delegate, connection));
+ window.reset(new WaylandToplevelWindow(delegate, connection));
break;
default:
NOTREACHED();
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc
index bd7050813b2..51f07bbc27a 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc
@@ -20,6 +20,11 @@ void WaylandWindowManager::RemoveObserver(WaylandWindowObserver* observer) {
observers_.RemoveObserver(observer);
}
+void WaylandWindowManager::NotifyWindowConfigured(WaylandWindow* window) {
+ for (WaylandWindowObserver& observer : observers_)
+ observer.OnWindowConfigured(window);
+}
+
void WaylandWindowManager::GrabLocatedEvents(WaylandWindow* window) {
DCHECK_NE(located_events_grabber_, window);
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.h b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.h
index 1873c907a68..1f4cad045ca 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.h
@@ -27,6 +27,10 @@ class WaylandWindowManager {
void AddObserver(WaylandWindowObserver* observer);
void RemoveObserver(WaylandWindowObserver* observer);
+ // Notifies observers that the Window has been ack configured and
+ // WaylandBufferManagerHost can start attaching buffers to the |surface_|.
+ void NotifyWindowConfigured(WaylandWindow* window);
+
// Stores the window that should grab the located events.
void GrabLocatedEvents(WaylandWindow* event_grabber);
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.cc
index d81f991e080..e289ea88e3d 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.cc
@@ -12,4 +12,6 @@ void WaylandWindowObserver::OnWindowAdded(WaylandWindow* window) {}
void WaylandWindowObserver::OnWindowRemoved(WaylandWindow* window) {}
+void WaylandWindowObserver::OnWindowConfigured(WaylandWindow* window) {}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.h b/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.h
index 0f81b8b5731..c461b03114e 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.h
@@ -20,6 +20,9 @@ class WaylandWindowObserver : public base::CheckedObserver {
// Called when |window| has been removed.
virtual void OnWindowRemoved(WaylandWindow* window);
+ // Called when |window| has been ack configured.
+ virtual void OnWindowConfigured(WaylandWindow* window);
+
protected:
~WaylandWindowObserver() override;
};
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
index 9a1112a1bd8..d7c533edc09 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
@@ -98,25 +98,6 @@ class WaylandWindowTest : public WaylandTest {
}
protected:
- void SendConfigureEvent(int width,
- int height,
- uint32_t serial,
- struct wl_array* states) {
- // In xdg_shell_v6+, both surfaces send serial configure event and toplevel
- // surfaces send other data like states, heights and widths.
- if (GetParam() == kXdgShellV6) {
- zxdg_surface_v6_send_configure(xdg_surface_->resource(), serial);
- ASSERT_TRUE(xdg_surface_->xdg_toplevel());
- zxdg_toplevel_v6_send_configure(xdg_surface_->xdg_toplevel()->resource(),
- width, height, states);
- } else {
- xdg_surface_send_configure(xdg_surface_->resource(), serial);
- ASSERT_TRUE(xdg_surface_->xdg_toplevel());
- xdg_toplevel_send_configure(xdg_surface_->xdg_toplevel()->resource(),
- width, height, states);
- }
- }
-
void SendConfigureEventPopup(gfx::AcceleratedWidget menu_widget,
const gfx::Rect bounds) {
auto* popup = GetPopupByWidget(menu_widget);
@@ -253,12 +234,20 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) {
const auto kNormalBounds = gfx::Rect{0, 0, 500, 300};
const auto kMaximizedBounds = gfx::Rect{0, 0, 800, 600};
+ uint32_t serial = 0;
+
// Make sure the window has normal state initially.
EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds));
window_->SetBounds(kNormalBounds);
EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
VerifyAndClearExpectations();
+ // Deactivate the surface.
+ auto empty_state = MakeStateArray({});
+ SendConfigureEvent(xdg_surface_, 0, 0, ++serial, empty_state.get());
+
+ Sync();
+
auto active_maximized = MakeStateArray(
{XDG_TOPLEVEL_STATE_ACTIVATED, XDG_TOPLEVEL_STATE_MAXIMIZED});
EXPECT_CALL(*GetXdgToplevel(), SetMaximized());
@@ -268,7 +257,8 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) {
EXPECT_CALL(delegate_, OnBoundsChanged(kMaximizedBounds));
EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
window_->Maximize();
- SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 1,
+ SendConfigureEvent(xdg_surface_, kMaximizedBounds.width(),
+ kMaximizedBounds.height(), ++serial,
active_maximized.get());
Sync();
VerifyAndClearExpectations();
@@ -278,7 +268,8 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) {
kMaximizedBounds.height()));
EXPECT_CALL(delegate_, OnActivationChanged(Eq(false)));
EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0);
- SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 2,
+ SendConfigureEvent(xdg_surface_, kMaximizedBounds.width(),
+ kMaximizedBounds.height(), ++serial,
inactive_maximized.get());
Sync();
VerifyAndClearExpectations();
@@ -287,7 +278,8 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) {
kMaximizedBounds.height()));
EXPECT_CALL(delegate_, OnActivationChanged(Eq(true)));
EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0);
- SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 3,
+ SendConfigureEvent(xdg_surface_, kMaximizedBounds.width(),
+ kMaximizedBounds.height(), ++serial,
active_maximized.get());
Sync();
VerifyAndClearExpectations();
@@ -301,7 +293,7 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) {
window_->Restore();
// Reinitialize wl_array, which removes previous old states.
auto active = InitializeWlArrayWithActivatedState();
- SendConfigureEvent(0, 0, 4, active.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, ++serial, active.get());
Sync();
}
@@ -310,7 +302,7 @@ TEST_P(WaylandWindowTest, Minimize) {
// Make sure the window is initialized to normal state from the beginning.
EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
- SendConfigureEvent(0, 0, 1, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 1, states.get());
Sync();
EXPECT_CALL(*GetXdgToplevel(), SetMinimized());
@@ -320,24 +312,24 @@ TEST_P(WaylandWindowTest, Minimize) {
// Reinitialize wl_array, which removes previous old states.
states = ScopedWlArray();
- SendConfigureEvent(0, 0, 2, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 2, states.get());
Sync();
// Wayland compositor doesn't notify clients about minimized state, but rather
- // if a window is not activated. Thus, a WaylandSurface marks itself as being
- // minimized and and sets state to minimized. Thus, the state mustn't change
- // after the configuration event is sent.
+ // if a window is not activated. Thus, a WaylandToplevelWindow marks itself as
+ // being minimized and and sets state to minimized. Thus, the state mustn't
+ // change after the configuration event is sent.
EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMinimized);
// Send one additional empty configuration event (which means the surface is
// not maximized, fullscreen or activated) to ensure, WaylandWindow stays in
// the same minimized state and doesn't notify its delegate.
EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
- SendConfigureEvent(0, 0, 3, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 3, states.get());
Sync();
// And one last time to ensure the behaviour.
- SendConfigureEvent(0, 0, 4, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 4, states.get());
Sync();
}
@@ -346,7 +338,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
ScopedWlArray states = InitializeWlArrayWithActivatedState();
- SendConfigureEvent(0, 0, 1, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 1, states.get());
Sync();
AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
@@ -358,7 +350,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
// comment in the WaylandWindow::ToggleFullscreen.
EXPECT_EQ(window_->GetPlatformWindowState(),
PlatformWindowState::kFullScreen);
- SendConfigureEvent(0, 0, 2, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 2, states.get());
Sync();
EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen());
@@ -367,7 +359,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal);
// Reinitialize wl_array, which removes previous old states.
states = InitializeWlArrayWithActivatedState();
- SendConfigureEvent(0, 0, 3, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 3, states.get());
Sync();
EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal);
}
@@ -408,7 +400,7 @@ TEST_P(WaylandWindowTest, StartWithFullscreen) {
// Activate the surface.
ScopedWlArray states = InitializeWlArrayWithActivatedState();
AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
- SendConfigureEvent(0, 0, 1, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 1, states.get());
Sync();
@@ -454,7 +446,7 @@ TEST_P(WaylandWindowTest, StartMaximized) {
// Activate the surface.
ScopedWlArray states = InitializeWlArrayWithActivatedState();
AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get());
- SendConfigureEvent(0, 0, 1, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 1, states.get());
Sync();
@@ -467,7 +459,7 @@ TEST_P(WaylandWindowTest, CompositorSideStateChanges) {
ScopedWlArray states = InitializeWlArrayWithActivatedState();
AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get());
- SendConfigureEvent(2000, 2000, 1, states.get());
+ SendConfigureEvent(xdg_surface_, 2000, 2000, 1, states.get());
EXPECT_CALL(delegate_,
OnWindowStateChanged(Eq(PlatformWindowState::kMaximized)))
@@ -480,7 +472,7 @@ TEST_P(WaylandWindowTest, CompositorSideStateChanges) {
// Unmaximize
states = InitializeWlArrayWithActivatedState();
- SendConfigureEvent(0, 0, 2, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 2, states.get());
EXPECT_CALL(delegate_, OnWindowStateChanged(Eq(PlatformWindowState::kNormal)))
.Times(1);
@@ -489,7 +481,7 @@ TEST_P(WaylandWindowTest, CompositorSideStateChanges) {
// Now, set to fullscreen.
AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
- SendConfigureEvent(2005, 2005, 3, states.get());
+ SendConfigureEvent(xdg_surface_, 2005, 2005, 3, states.get());
EXPECT_CALL(delegate_,
OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen)))
.Times(1);
@@ -499,7 +491,7 @@ TEST_P(WaylandWindowTest, CompositorSideStateChanges) {
// Unfullscreen
states = InitializeWlArrayWithActivatedState();
- SendConfigureEvent(0, 0, 4, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 4, states.get());
EXPECT_CALL(delegate_, OnWindowStateChanged(Eq(PlatformWindowState::kNormal)))
.Times(1);
@@ -511,7 +503,7 @@ TEST_P(WaylandWindowTest, CompositorSideStateChanges) {
// Now, maximize, fullscreen and restore.
states = InitializeWlArrayWithActivatedState();
AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get());
- SendConfigureEvent(2000, 2000, 1, states.get());
+ SendConfigureEvent(xdg_surface_, 2000, 2000, 1, states.get());
EXPECT_CALL(delegate_,
OnWindowStateChanged(Eq(PlatformWindowState::kMaximized)))
@@ -521,7 +513,7 @@ TEST_P(WaylandWindowTest, CompositorSideStateChanges) {
Sync();
AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
- SendConfigureEvent(2005, 2005, 1, states.get());
+ SendConfigureEvent(xdg_surface_, 2005, 2005, 1, states.get());
EXPECT_CALL(delegate_,
OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen)))
@@ -530,7 +522,7 @@ TEST_P(WaylandWindowTest, CompositorSideStateChanges) {
// Restore
states = InitializeWlArrayWithActivatedState();
- SendConfigureEvent(0, 0, 4, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 4, states.get());
EXPECT_CALL(delegate_, OnWindowStateChanged(Eq(PlatformWindowState::kNormal)))
.Times(1);
@@ -544,12 +536,19 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
const auto kNormalBounds = gfx::Rect{0, 0, 500, 300};
const auto kMaximizedBounds = gfx::Rect{0, 0, 800, 600};
+ uint32_t serial = 0;
+
// Make sure the window has normal state initially.
EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds));
window_->SetBounds(kNormalBounds);
EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
VerifyAndClearExpectations();
+ // Deactivate the surface.
+ ScopedWlArray empty_state;
+ SendConfigureEvent(xdg_surface_, 0, 0, ++serial, empty_state.get());
+ Sync();
+
auto active_maximized = MakeStateArray(
{XDG_TOPLEVEL_STATE_ACTIVATED, XDG_TOPLEVEL_STATE_MAXIMIZED});
EXPECT_CALL(*GetXdgToplevel(), SetMaximized());
@@ -561,7 +560,8 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
window_->Maximize();
// State changes are synchronous.
EXPECT_EQ(PlatformWindowState::kMaximized, window_->GetPlatformWindowState());
- SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 2,
+ SendConfigureEvent(xdg_surface_, kMaximizedBounds.width(),
+ kMaximizedBounds.height(), ++serial,
active_maximized.get());
Sync();
// Verify that the state has not been changed.
@@ -578,7 +578,8 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
EXPECT_EQ(PlatformWindowState::kFullScreen,
window_->GetPlatformWindowState());
AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, active_maximized.get());
- SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 3,
+ SendConfigureEvent(xdg_surface_, kMaximizedBounds.width(),
+ kMaximizedBounds.height(), ++serial,
active_maximized.get());
Sync();
// Verify that the state has not been changed.
@@ -596,7 +597,7 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
// Reinitialize wl_array, which removes previous old states.
auto active = InitializeWlArrayWithActivatedState();
- SendConfigureEvent(0, 0, 4, active.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, ++serial, active.get());
Sync();
EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
}
@@ -614,8 +615,8 @@ TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximize) {
EXPECT_CALL(delegate_, OnBoundsChanged(Eq(maximized_bounds)));
window_->Maximize();
AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get());
- SendConfigureEvent(maximized_bounds.width(), maximized_bounds.height(), 1,
- states.get());
+ SendConfigureEvent(xdg_surface_, maximized_bounds.width(),
+ maximized_bounds.height(), 1, states.get());
Sync();
restored_bounds = window_->GetRestoredBoundsInPixels();
EXPECT_EQ(bounds, restored_bounds);
@@ -629,7 +630,7 @@ TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximize) {
window_->Restore();
// Reinitialize wl_array, which removes previous old states.
states = InitializeWlArrayWithActivatedState();
- SendConfigureEvent(0, 0, 2, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 2, states.get());
Sync();
bounds = window_->GetBounds();
EXPECT_EQ(bounds, restored_bounds);
@@ -641,7 +642,7 @@ TEST_P(WaylandWindowTest, RestoreBoundsAfterFullscreen) {
const gfx::Rect current_bounds = window_->GetBounds();
ScopedWlArray states = InitializeWlArrayWithActivatedState();
- SendConfigureEvent(0, 0, 1, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 1, states.get());
Sync();
gfx::Rect restored_bounds = window_->GetRestoredBoundsInPixels();
@@ -652,8 +653,8 @@ TEST_P(WaylandWindowTest, RestoreBoundsAfterFullscreen) {
EXPECT_CALL(delegate_, OnBoundsChanged(Eq(fullscreen_bounds)));
window_->ToggleFullscreen();
AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
- SendConfigureEvent(fullscreen_bounds.width(), fullscreen_bounds.height(), 2,
- states.get());
+ SendConfigureEvent(xdg_surface_, fullscreen_bounds.width(),
+ fullscreen_bounds.height(), 2, states.get());
Sync();
restored_bounds = window_->GetRestoredBoundsInPixels();
EXPECT_EQ(bounds, restored_bounds);
@@ -667,7 +668,7 @@ TEST_P(WaylandWindowTest, RestoreBoundsAfterFullscreen) {
window_->Restore();
// Reinitialize wl_array, which removes previous old states.
states = InitializeWlArrayWithActivatedState();
- SendConfigureEvent(0, 0, 3, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 3, states.get());
Sync();
bounds = window_->GetBounds();
EXPECT_EQ(bounds, restored_bounds);
@@ -688,8 +689,8 @@ TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximizeAndFullscreen) {
EXPECT_CALL(delegate_, OnBoundsChanged(Eq(maximized_bounds)));
window_->Maximize();
AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get());
- SendConfigureEvent(maximized_bounds.width(), maximized_bounds.height(), 1,
- states.get());
+ SendConfigureEvent(xdg_surface_, maximized_bounds.width(),
+ maximized_bounds.height(), 1, states.get());
Sync();
restored_bounds = window_->GetRestoredBoundsInPixels();
EXPECT_EQ(bounds, restored_bounds);
@@ -698,8 +699,8 @@ TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximizeAndFullscreen) {
EXPECT_CALL(delegate_, OnBoundsChanged(Eq(fullscreen_bounds)));
window_->ToggleFullscreen();
AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
- SendConfigureEvent(fullscreen_bounds.width(), fullscreen_bounds.height(), 2,
- states.get());
+ SendConfigureEvent(xdg_surface_, fullscreen_bounds.width(),
+ fullscreen_bounds.height(), 2, states.get());
Sync();
gfx::Rect fullscreen_restore_bounds = window_->GetRestoredBoundsInPixels();
EXPECT_EQ(restored_bounds, fullscreen_restore_bounds);
@@ -709,8 +710,8 @@ TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximizeAndFullscreen) {
// Reinitialize wl_array, which removes previous old states.
states = InitializeWlArrayWithActivatedState();
AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get());
- SendConfigureEvent(maximized_bounds.width(), maximized_bounds.height(), 3,
- states.get());
+ SendConfigureEvent(xdg_surface_, maximized_bounds.width(),
+ maximized_bounds.height(), 3, states.get());
Sync();
restored_bounds = window_->GetRestoredBoundsInPixels();
EXPECT_EQ(restored_bounds, fullscreen_restore_bounds);
@@ -724,7 +725,7 @@ TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximizeAndFullscreen) {
window_->Restore();
// Reinitialize wl_array, which removes previous old states.
states = InitializeWlArrayWithActivatedState();
- SendConfigureEvent(0, 0, 4, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 4, states.get());
Sync();
bounds = window_->GetBounds();
EXPECT_EQ(bounds, restored_bounds);
@@ -747,7 +748,7 @@ TEST_P(WaylandWindowTest, SendsBoundsOnRequest) {
EXPECT_CALL(*xdg_surface_,
SetWindowGeometry(0, 0, new_bounds.width(), new_bounds.height()))
.Times(2);
- SendConfigureEvent(0, 0, 2, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 2, states.get());
Sync();
// Restored bounds should keep empty value.
@@ -757,7 +758,7 @@ TEST_P(WaylandWindowTest, SendsBoundsOnRequest) {
// Second case is when Wayland sends a configure event with 1, 1 height and
// width. It looks more like a bug in Gnome Shell with Wayland as long as the
// documentation says it must be set to 0, 0, when wayland requests bounds.
- SendConfigureEvent(0, 0, 3, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 3, states.get());
Sync();
// Restored bounds should keep empty value.
@@ -818,14 +819,14 @@ TEST_P(WaylandWindowTest, ConfigureEvent) {
// xdg_toplevel in xdg_shell_v6 and by xdg_surface_ in xdg_shell_v5.
EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 1000, 1000)).Times(1);
EXPECT_CALL(*xdg_surface_, AckConfigure(12));
- SendConfigureEvent(1000, 1000, 12, states.get());
+ SendConfigureEvent(xdg_surface_, 1000, 1000, 12, states.get());
Sync();
EXPECT_CALL(delegate_, OnBoundsChanged(Eq(gfx::Rect(0, 0, 1500, 1000))));
EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 1500, 1000)).Times(1);
EXPECT_CALL(*xdg_surface_, AckConfigure(13));
- SendConfigureEvent(1500, 1000, 13, states.get());
+ SendConfigureEvent(xdg_surface_, 1500, 1000, 13, states.get());
}
TEST_P(WaylandWindowTest, ConfigureEventWithNulledSize) {
@@ -834,7 +835,7 @@ TEST_P(WaylandWindowTest, ConfigureEventWithNulledSize) {
// If Wayland sends configure event with 0 width and 0 size, client should
// call back with desired sizes. In this case, that's the actual size of
// the window.
- SendConfigureEvent(0, 0, 14, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, 14, states.get());
// |xdg_surface_| must receive the following calls in both xdg_shell_v5 and
// xdg_shell_v6. Other calls like SetTitle or SetMaximized are recieved by
// xdg_toplevel in xdg_shell_v6 and by xdg_surface_ in xdg_shell_v5.
@@ -843,16 +844,23 @@ TEST_P(WaylandWindowTest, ConfigureEventWithNulledSize) {
}
TEST_P(WaylandWindowTest, OnActivationChanged) {
+ uint32_t serial = 0;
+
+ // Deactivate the surface.
+ ScopedWlArray empty_state;
+ SendConfigureEvent(xdg_surface_, 0, 0, ++serial, empty_state.get());
+ Sync();
+
{
ScopedWlArray states = InitializeWlArrayWithActivatedState();
EXPECT_CALL(delegate_, OnActivationChanged(Eq(true)));
- SendConfigureEvent(0, 0, 1, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, ++serial, states.get());
Sync();
}
ScopedWlArray states;
EXPECT_CALL(delegate_, OnActivationChanged(Eq(false)));
- SendConfigureEvent(0, 0, 2, states.get());
+ SendConfigureEvent(xdg_surface_, 0, 0, ++serial, states.get());
Sync();
}
@@ -1275,7 +1283,8 @@ TEST_P(WaylandWindowTest, CanDispatchEvent) {
TEST_P(WaylandWindowTest, DispatchWindowMove) {
EXPECT_CALL(*GetXdgToplevel(), Move(_));
- ui::GetWmMoveResizeHandler(*window_)->DispatchHostWindowDragMovement(HTCAPTION, gfx::Point());
+ ui::GetWmMoveResizeHandler(*window_)->DispatchHostWindowDragMovement(
+ HTCAPTION, gfx::Point());
}
// Makes sure hit tests are converted into right edges.
@@ -1482,7 +1491,7 @@ TEST_P(WaylandWindowTest, SetOpaqueRegion) {
gfx::Rect new_bounds(0, 0, 500, 600);
auto state_array = MakeStateArray({XDG_TOPLEVEL_STATE_ACTIVATED});
- SendConfigureEvent(new_bounds.width(), new_bounds.height(), 1,
+ SendConfigureEvent(xdg_surface_, new_bounds.width(), new_bounds.height(), 1,
state_array.get());
SkIRect rect =
@@ -1494,7 +1503,7 @@ TEST_P(WaylandWindowTest, SetOpaqueRegion) {
VerifyAndClearExpectations();
new_bounds.set_size(gfx::Size(1000, 534));
- SendConfigureEvent(new_bounds.width(), new_bounds.height(), 2,
+ SendConfigureEvent(xdg_surface_, new_bounds.width(), new_bounds.height(), 2,
state_array.get());
rect = SkIRect::MakeXYWH(0, 0, new_bounds.width(), new_bounds.height());
@@ -1922,8 +1931,8 @@ TEST_P(WaylandWindowTest, SetsPropertiesOnShow) {
// We can't mock all those methods above as long as the xdg_toplevel is
// created and destroyed on each show and hide call. However, it is the same
- // WaylandSurface object that cached the values we set and must restore them
- // on Show().
+ // WaylandToplevelWindow object that cached the values we set and must restore
+ // them on Show().
EXPECT_EQ(mock_xdg_toplevel->min_size(), min_size.value());
EXPECT_EQ(mock_xdg_toplevel->max_size(), max_size.value());
EXPECT_EQ(std::string(kAppId), mock_xdg_toplevel->app_id());
@@ -2018,6 +2027,59 @@ TEST_P(WaylandWindowTest, CreatesPopupOnTouchDownSerial) {
EXPECT_EQ(test_popup->grab_serial(), touch_down_serial);
}
+// Tests nested menu windows get the topmost window in the stack of windows
+// within the same family/tree.
+TEST_P(WaylandWindowTest, NestedPopupWindowsGetCorrectParent) {
+ VerifyAndClearExpectations();
+
+ gfx::Rect menu_window_bounds(gfx::Rect(10, 20, 20, 20));
+ std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds,
+ &delegate_);
+ EXPECT_TRUE(menu_window);
+
+ EXPECT_TRUE(menu_window->parent_window() == window_.get());
+
+ gfx::Rect menu_window_bounds2(gfx::Rect(20, 40, 30, 20));
+ std::unique_ptr<WaylandWindow> menu_window2 = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds2,
+ &delegate_);
+ EXPECT_TRUE(menu_window2);
+
+ EXPECT_TRUE(menu_window2->parent_window() == menu_window.get());
+
+ gfx::Rect menu_window_bounds3(gfx::Rect(30, 40, 30, 20));
+ std::unique_ptr<WaylandWindow> menu_window3 = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds3,
+ &delegate_);
+ EXPECT_TRUE(menu_window3);
+
+ EXPECT_TRUE(menu_window3->parent_window() == menu_window2.get());
+
+ gfx::Rect menu_window_bounds4(gfx::Rect(40, 40, 30, 20));
+ std::unique_ptr<WaylandWindow> menu_window4 = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds4,
+ &delegate_);
+ EXPECT_TRUE(menu_window4);
+
+ EXPECT_TRUE(menu_window4->parent_window() == menu_window3.get());
+}
+
+TEST_P(WaylandWindowTest, DoesNotGrabPopupIfNoSeat) {
+ // Create a popup window and verify the grab serial is not set.
+ MockPlatformWindowDelegate delegate;
+ auto popup = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, window_->GetWidget(), gfx::Rect(0, 0, 50, 50),
+ &delegate);
+ ASSERT_TRUE(popup);
+
+ Sync();
+
+ auto* test_popup = GetPopupByWidget(popup->GetWidget());
+ ASSERT_TRUE(test_popup);
+ EXPECT_EQ(test_popup->grab_serial(), 0u);
+}
+
INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
WaylandWindowTest,
::testing::Values(kXdgShellStable));
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
index 1e81f70b003..758ae1f222e 100644
--- a/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
@@ -18,7 +18,7 @@
#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
#include "ui/ozone/platform/wayland/host/wayland_popup.h"
-#include "ui/ozone/platform/wayland/host/wayland_surface.h"
+#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h"
namespace ui {
@@ -286,8 +286,8 @@ bool XDGPopupWrapperImpl::Initialize(WaylandConnection* connection,
static_cast<XDGPopupWrapperImpl*>(wayland_popup->shell_popup());
parent_xdg_surface = popup->xdg_surface();
} else {
- WaylandSurface* wayland_surface =
- static_cast<WaylandSurface*>(wayland_window_->parent_window());
+ WaylandToplevelWindow* wayland_surface =
+ static_cast<WaylandToplevelWindow*>(wayland_window_->parent_window());
parent_xdg_surface =
static_cast<XDGSurfaceWrapperImpl*>(wayland_surface->shell_surface());
}
@@ -324,41 +324,8 @@ bool XDGPopupWrapperImpl::InitializeStable(
xdg_positioner_destroy(positioner);
- // According to the spec, the grab call can only be done on a key press, mouse
- // press or touch down. However, there is a problem with popup windows and
- // touch events so long as Chromium creates them only on consequent touch up
- // events. That results in Wayland compositors dismissing popups. To fix
- // the issue, do not use grab with touch events. Please note that explicit
- // grab means that a Wayland compositor dismisses a popup whenever the user
- // clicks outside the created surfaces. If the explicit grab is not used, the
- // popups are not dismissed in such cases. What is more, current non-ozone X11
- // implementation does the same. This means there is no functionality changes
- // and we do things right.
- //
- // We cannot know what was the last event. Instead, we can check if the window
- // has pointer or keyboard focus. If so, the popup will be explicitly grabbed.
- //
- // There is a bug in the gnome/mutter - if explicit grab is not used,
- // unmapping of a wl_surface (aka destroying xdg_popup and surface) to hide a
- // window results in weird behaviour. That is, a popup continues to be visible
- // on a display and it results in a crash of the entire session. Thus, just
- // continue to use grab here and avoid showing popups for touch events on
- // gnome/mutter. That is better than crashing the entire system. Otherwise,
- // Chromium has to change the way how it reacts on touch events - instead of
- // creating a menu on touch up, it must do it on touch down events.
- // https://gitlab.gnome.org/GNOME/mutter/issues/698#note_562601.
- std::unique_ptr<base::Environment> env(base::Environment::Create());
- if ((base::nix::GetDesktopEnvironment(env.get()) ==
- base::nix::DESKTOP_ENVIRONMENT_GNOME) ||
- (wayland_window_->parent_window()->has_pointer_focus() ||
- wayland_window_->parent_window()->has_keyboard_focus())) {
- // When drag process starts, as described the protocol -
- // https://goo.gl/1Mskq3, the client must have an active implicit grab. If
- // we try to create a popup and grab it, it will be immediately dismissed.
- // Thus, do not take explicit grab during drag process.
- if (!connection->IsDragInProgress())
- xdg_popup_grab(xdg_popup_.get(), connection->seat(),
- connection->serial());
+ if (CanGrabPopup(connection)) {
+ xdg_popup_grab(xdg_popup_.get(), connection->seat(), connection->serial());
}
xdg_popup_add_listener(xdg_popup_.get(), &xdg_popup_listener, this);
@@ -375,18 +342,11 @@ struct xdg_positioner* XDGPopupWrapperImpl::CreatePositionerStable(
if (!positioner)
return nullptr;
- bool is_right_click_menu =
- connection->event_source()->IsPointerButtonPressed(EF_RIGHT_MOUSE_BUTTON);
+ auto menu_type = GetMenuTypeForPositioner(connection, parent_window);
- // Different types of menu require different anchors, constraint adjustments,
- // gravity and etc.
- MenuType menu_type = MenuType::TYPE_UNKNOWN;
- if (is_right_click_menu)
- menu_type = MenuType::TYPE_RIGHT_CLICK;
- else if (wl::IsMenuType(parent_window->type()))
- menu_type = MenuType::TYPE_3DOT_CHILD_MENU;
- else
- menu_type = MenuType::TYPE_3DOT_PARENT_MENU;
+ // The parent we got must be the topmost in the stack of the same family
+ // windows.
+ DCHECK_EQ(parent_window->GetTopMostChildWindow(), parent_window);
// Place anchor to the end of the possible position.
gfx::Rect anchor_rect = GetAnchorRect(
@@ -426,34 +386,7 @@ bool XDGPopupWrapperImpl::InitializeV6(
zxdg_positioner_v6_destroy(positioner);
- // According to the spec, the grab call can only be done on a key press, mouse
- // press or touch down. However, there is a problem with popup windows and
- // touch events so long as Chromium creates them only on consequent touch up
- // events. That results in Wayland compositors dismissing popups. To fix
- // the issue, do not use grab with touch events. Please note that explicit
- // grab means that a Wayland compositor dismisses a popup whenever the user
- // clicks outside the created surfaces. If the explicit grab is not used, the
- // popups are not dismissed in such cases. What is more, current non-ozone X11
- // implementation does the same. This means there is no functionality changes
- // and we do things right.
- //
- // We cannot know what was the last event. Instead, we can check if the window
- // has pointer or keyboard focus. If so, the popup will be explicitly grabbed.
- //
- // There is a bug in the gnome/mutter - if explicit grab is not used,
- // unmapping of a wl_surface (aka destroying xdg_popup and surface) to hide a
- // window results in weird behaviour. That is, a popup continues to be visible
- // on a display and it results in a crash of the entire session. Thus, just
- // continue to use grab here and avoid showing popups for touch events on
- // gnome/mutter. That is better than crashing the entire system. Otherwise,
- // Chromium has to change the way how it reacts on touch events - instead of
- // creating a menu on touch up, it must do it on touch down events.
- // https://gitlab.gnome.org/GNOME/mutter/issues/698#note_562601.
- std::unique_ptr<base::Environment> env(base::Environment::Create());
- if ((base::nix::GetDesktopEnvironment(env.get()) ==
- base::nix::DESKTOP_ENVIRONMENT_GNOME) ||
- (wayland_window_->parent_window()->has_pointer_focus() ||
- wayland_window_->parent_window()->has_keyboard_focus())) {
+ if (CanGrabPopup(connection)) {
zxdg_popup_v6_grab(zxdg_popup_v6_.get(), connection->seat(),
connection->serial());
}
@@ -473,18 +406,11 @@ zxdg_positioner_v6* XDGPopupWrapperImpl::CreatePositionerV6(
if (!positioner)
return nullptr;
- bool is_right_click_menu =
- connection->event_source()->IsPointerButtonPressed(EF_RIGHT_MOUSE_BUTTON);
+ auto menu_type = GetMenuTypeForPositioner(connection, parent_window);
- // Different types of menu require different anchors, constraint adjustments,
- // gravity and etc.
- MenuType menu_type = MenuType::TYPE_UNKNOWN;
- if (is_right_click_menu)
- menu_type = MenuType::TYPE_RIGHT_CLICK;
- else if (wl::IsMenuType(parent_window->type()))
- menu_type = MenuType::TYPE_3DOT_CHILD_MENU;
- else
- menu_type = MenuType::TYPE_3DOT_PARENT_MENU;
+ // The parent we got must be the topmost in the stack of the same family
+ // windows.
+ DCHECK_EQ(parent_window->GetTopMostChildWindow(), parent_window);
// Place anchor to the end of the possible position.
gfx::Rect anchor_rect = GetAnchorRect(
@@ -505,6 +431,61 @@ zxdg_positioner_v6* XDGPopupWrapperImpl::CreatePositionerV6(
return positioner;
}
+MenuType XDGPopupWrapperImpl::GetMenuTypeForPositioner(
+ WaylandConnection* connection,
+ WaylandWindow* parent_window) const {
+ bool is_right_click_menu =
+ connection->event_source()->last_pointer_button_pressed() &
+ EF_RIGHT_MOUSE_BUTTON;
+
+ // Different types of menu require different anchors, constraint adjustments,
+ // gravity and etc.
+ if (is_right_click_menu)
+ return MenuType::TYPE_RIGHT_CLICK;
+ else if (!wl::IsMenuType(parent_window->type()))
+ return MenuType::TYPE_3DOT_PARENT_MENU;
+ else
+ return MenuType::TYPE_3DOT_CHILD_MENU;
+}
+
+bool XDGPopupWrapperImpl::CanGrabPopup(WaylandConnection* connection) const {
+ // When drag process starts, as described the protocol -
+ // https://goo.gl/1Mskq3, the client must have an active implicit grab. If
+ // we try to create a popup and grab it, it will be immediately dismissed.
+ // Thus, do not take explicit grab during drag process.
+ if (connection->IsDragInProgress() || !connection->seat())
+ return false;
+
+ // According to the spec, the grab call can only be done on a key press, mouse
+ // press or touch down. However, there is a problem with popup windows and
+ // touch events so long as Chromium creates them only on consequent touch up
+ // events. That results in Wayland compositors dismissing popups. To fix the
+ // issue, do not use grab with touch events. Please note that explicit grab
+ // means that a Wayland compositor dismisses a popup whenever the user clicks
+ // outside the created surfaces. If the explicit grab is not used, the popups
+ // are not dismissed in such cases. What is more, current non-ozone X11
+ // implementation does the same. This means there is no functionality changes
+ // and we do things right.
+ //
+ // We cannot know what was the last event. Instead, we can check if the window
+ // has pointer or keyboard focus. If so, the popup will be explicitly grabbed.
+ //
+ // There is a bug in the gnome/mutter - if explicit grab is not used,
+ // unmapping of a wl_surface (aka destroying xdg_popup and surface) to hide a
+ // window results in weird behaviour. That is, a popup continues to be visible
+ // on a display and it results in a crash of the entire session. Thus, just
+ // continue to use grab here and avoid showing popups for touch events on
+ // gnome/mutter. That is better than crashing the entire system. Otherwise,
+ // Chromium has to change the way how it reacts on touch events - instead of
+ // creating a menu on touch up, it must do it on touch down events.
+ // https://gitlab.gnome.org/GNOME/mutter/issues/698#note_562601.
+ std::unique_ptr<base::Environment> env(base::Environment::Create());
+ return (base::nix::GetDesktopEnvironment(env.get()) ==
+ base::nix::DESKTOP_ENVIRONMENT_GNOME) ||
+ (wayland_window_->parent_window()->has_pointer_focus() ||
+ wayland_window_->parent_window()->has_keyboard_focus());
+}
+
void XDGPopupWrapperImpl::Configure(void* data,
int32_t x,
int32_t y,
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h
index c0479cfff7f..62f38a2dc6a 100644
--- a/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h
@@ -7,6 +7,7 @@
#include <memory>
+#include "base/macros.h"
#include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h"
namespace ui {
@@ -41,6 +42,11 @@ class XDGPopupWrapperImpl : public ShellPopupWrapper {
WaylandWindow* parent_window,
const gfx::Rect& bounds);
+ MenuType GetMenuTypeForPositioner(WaylandConnection* connection,
+ WaylandWindow* parent_window) const;
+
+ bool CanGrabPopup(WaylandConnection* connection) const;
+
// xdg_popup_listener
static void Configure(void* data,
int32_t x,
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
index e7df772ae47..ae1ca159fd4 100644
--- a/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
@@ -119,6 +119,8 @@ void XDGSurfaceWrapperImpl::AckConfigure() {
zxdg_surface_v6_ack_configure(zxdg_surface_v6_.get(),
pending_configure_serial_);
}
+ connection_->wayland_window_manager()->NotifyWindowConfigured(
+ wayland_window_);
}
void XDGSurfaceWrapperImpl::SetWindowGeometry(const gfx::Rect& bounds) {
diff --git a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
index 8ffb52c5213..894166db3f9 100644
--- a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -14,6 +14,7 @@
#include "base/message_loop/message_pump_type.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "ui/base/buildflags.h"
+#include "ui/base/cursor/cursor_factory.h"
#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
#include "ui/base/ime/linux/input_method_auralinux.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
@@ -98,9 +99,7 @@ class OzonePlatformWayland : public OzonePlatform {
return overlay_manager_.get();
}
- CursorFactoryOzone* GetCursorFactoryOzone() override {
- return cursor_factory_.get();
- }
+ CursorFactory* GetCursorFactory() override { return cursor_factory_.get(); }
InputController* GetInputController() override {
return input_controller_.get();
@@ -249,7 +248,7 @@ class OzonePlatformWayland : public OzonePlatform {
std::unique_ptr<KeyboardLayoutEngine> keyboard_layout_engine_;
std::unique_ptr<WaylandConnection> connection_;
std::unique_ptr<WaylandSurfaceFactory> surface_factory_;
- std::unique_ptr<BitmapCursorFactoryOzone> cursor_factory_;
+ std::unique_ptr<CursorFactory> cursor_factory_;
std::unique_ptr<StubOverlayManager> overlay_manager_;
std::unique_ptr<InputController> input_controller_;
std::unique_ptr<GpuPlatformSupportHost> gpu_platform_support_host_;
diff --git a/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.cc b/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.cc
index d24c13658aa..cd87cb8aafc 100644
--- a/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.cc
+++ b/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.cc
@@ -36,6 +36,12 @@ MockWpPresentation::MockWpPresentation()
MockWpPresentation::~MockWpPresentation() {}
+wl_resource* MockWpPresentation::ReleasePresentationCallback() {
+ auto* presentation_callback = presentation_callback_;
+ presentation_callback_ = nullptr;
+ return presentation_callback;
+}
+
void MockWpPresentation::SendPresentationCallback() {
if (!presentation_callback_)
return;
@@ -50,4 +56,14 @@ void MockWpPresentation::SendPresentationCallback() {
presentation_callback_ = nullptr;
}
+void MockWpPresentation::SendPresentationCallbackDiscarded() {
+ if (!presentation_callback_)
+ return;
+
+ wp_presentation_feedback_send_discarded(presentation_callback_);
+ wl_client_flush(wl_resource_get_client(presentation_callback_));
+ wl_resource_destroy(presentation_callback_);
+ presentation_callback_ = nullptr;
+}
+
} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.h b/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.h
index 616cd6e3fe1..64d09ab4f8e 100644
--- a/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.h
+++ b/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.h
@@ -7,7 +7,7 @@
#include <presentation-time-server-protocol.h>
-#include "base/logging.h"
+#include "base/check.h"
#include "base/macros.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "ui/ozone/platform/wayland/test/global_object.h"
@@ -34,7 +34,10 @@ class MockWpPresentation : public GlobalObject {
presentation_callback_ = callback_resource;
}
+ wl_resource* ReleasePresentationCallback();
+
void SendPresentationCallback();
+ void SendPresentationCallbackDiscarded();
private:
wl_resource* presentation_callback_ = nullptr;
diff --git a/chromium/ui/ozone/platform/wayland/test/scoped_wl_array.cc b/chromium/ui/ozone/platform/wayland/test/scoped_wl_array.cc
new file mode 100644
index 00000000000..9977ca1db17
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/test/scoped_wl_array.cc
@@ -0,0 +1,41 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/test/scoped_wl_array.h"
+
+#include <wayland-server-core.h>
+
+namespace wl {
+
+ScopedWlArray::ScopedWlArray(const std::vector<int32_t> states) {
+ wl_array_init(&array_);
+ for (const auto& state : states)
+ AddStateToWlArray(state);
+}
+
+ScopedWlArray::ScopedWlArray(ScopedWlArray&& rhs) {
+ array_ = rhs.array_;
+ // wl_array_init sets rhs.array_'s fields to nullptr, so that
+ // the free() in wl_array_release() is a no-op.
+ wl_array_init(&rhs.array_);
+}
+
+ScopedWlArray& ScopedWlArray::operator=(ScopedWlArray&& rhs) {
+ wl_array_release(&array_);
+ array_ = rhs.array_;
+ // wl_array_init sets rhs.array_'s fields to nullptr, so that
+ // the free() in wl_array_release() is a no-op.
+ wl_array_init(&rhs.array_);
+ return *this;
+}
+
+ScopedWlArray::~ScopedWlArray() {
+ wl_array_release(&array_);
+}
+
+void ScopedWlArray::AddStateToWlArray(uint32_t state) {
+ *static_cast<uint32_t*>(wl_array_add(&array_, sizeof array_)) = state;
+}
+
+} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/test/scoped_wl_array.h b/chromium/ui/ozone/platform/wayland/test/scoped_wl_array.h
new file mode 100644
index 00000000000..d9c86f99265
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/test/scoped_wl_array.h
@@ -0,0 +1,31 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_SCOPED_WL_ARRAY_H_
+#define UI_OZONE_PLATFORM_WAYLAND_TEST_SCOPED_WL_ARRAY_H_
+
+#include <wayland-server-core.h>
+
+#include <vector>
+
+namespace wl {
+
+class ScopedWlArray {
+ public:
+ explicit ScopedWlArray(const std::vector<int32_t> states);
+ ScopedWlArray(ScopedWlArray&& rhs);
+ ScopedWlArray& operator=(ScopedWlArray&& rhs);
+ ~ScopedWlArray();
+
+ wl_array* get() { return &array_; }
+
+ void AddStateToWlArray(uint32_t state);
+
+ private:
+ wl_array array_;
+};
+
+} // namespace wl
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_TEST_SCOPED_WL_ARRAY_H_
diff --git a/chromium/ui/ozone/platform/wayland/test/test_data_device.cc b/chromium/ui/ozone/platform/wayland/test/test_data_device.cc
index fcd71d6e9c5..6fc8a3e464d 100644
--- a/chromium/ui/ozone/platform/wayland/test/test_data_device.cc
+++ b/chromium/ui/ozone/platform/wayland/test/test_data_device.cc
@@ -6,8 +6,13 @@
#include <wayland-server-core.h>
+#include <cstdint>
+
#include "base/notreached.h"
+#include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/server_object.h"
#include "ui/ozone/platform/wayland/test/test_data_offer.h"
+#include "ui/ozone/platform/wayland/test/test_data_source.h"
namespace wl {
@@ -19,7 +24,11 @@ void DataDeviceStartDrag(wl_client* client,
wl_resource* origin,
wl_resource* icon,
uint32_t serial) {
- NOTIMPLEMENTED();
+ auto* data_source = GetUserDataAs<TestDataSource>(source);
+ auto* origin_surface = GetUserDataAs<MockSurface>(origin);
+
+ GetUserDataAs<TestDataDevice>(resource)->StartDrag(data_source,
+ origin_surface, serial);
}
void DataDeviceSetSelection(wl_client* client,
@@ -50,6 +59,16 @@ void TestDataDevice::SetSelection(TestDataSource* data_source,
NOTIMPLEMENTED();
}
+void TestDataDevice::StartDrag(TestDataSource* source,
+ MockSurface* origin,
+ uint32_t serial) {
+ DCHECK(source);
+ DCHECK(origin);
+ if (delegate_)
+ delegate_->StartDrag(source, origin, serial);
+ wl_client_flush(client_);
+}
+
TestDataOffer* TestDataDevice::OnDataOffer() {
wl_resource* data_offer_resource = CreateResourceWithImpl<TestDataOffer>(
client_, &wl_data_offer_interface, wl_resource_get_version(resource()),
diff --git a/chromium/ui/ozone/platform/wayland/test/test_data_device.h b/chromium/ui/ozone/platform/wayland/test/test_data_device.h
index 9ac3357ed53..85ad4af518a 100644
--- a/chromium/ui/ozone/platform/wayland/test/test_data_device.h
+++ b/chromium/ui/ozone/platform/wayland/test/test_data_device.h
@@ -7,7 +7,10 @@
#include <wayland-server-protocol.h>
+#include <cstdint>
+
#include "base/macros.h"
+#include "ui/ozone/platform/wayland/test/mock_surface.h"
#include "ui/ozone/platform/wayland/test/server_object.h"
struct wl_client;
@@ -22,10 +25,21 @@ class TestDataSource;
class TestDataDevice : public ServerObject {
public:
+ struct Delegate {
+ virtual void StartDrag(TestDataSource* source,
+ MockSurface* origin,
+ uint32_t serial) = 0;
+ };
+
TestDataDevice(wl_resource* resource, wl_client* client);
~TestDataDevice() override;
+ void set_delegate(Delegate* delegate) { delegate_ = delegate; }
+
void SetSelection(TestDataSource* data_source, uint32_t serial);
+ void StartDrag(TestDataSource* data_source,
+ MockSurface* origin,
+ uint32_t serial);
TestDataOffer* OnDataOffer();
void OnEnter(uint32_t serial,
@@ -41,6 +55,7 @@ class TestDataDevice : public ServerObject {
private:
TestDataOffer* data_offer_;
wl_client* client_ = nullptr;
+ Delegate* delegate_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(TestDataDevice);
};
diff --git a/chromium/ui/ozone/platform/wayland/test/test_data_source.cc b/chromium/ui/ozone/platform/wayland/test/test_data_source.cc
index 530a2e443c7..4d11ec8e9b1 100644
--- a/chromium/ui/ozone/platform/wayland/test/test_data_source.cc
+++ b/chromium/ui/ozone/platform/wayland/test/test_data_source.cc
@@ -5,6 +5,8 @@
#include "ui/ozone/platform/wayland/test/test_data_source.h"
#include <wayland-server-core.h>
+
+#include <cstdint>
#include <utility>
#include "base/bind.h"
@@ -51,16 +53,16 @@ void DataSourceDestroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
-void SetActions(wl_client* client,
- wl_resource* resource,
- uint32_t dnd_actions) {
- NOTIMPLEMENTED();
+void DataSourceSetActions(wl_client* client,
+ wl_resource* resource,
+ uint32_t dnd_actions) {
+ GetUserDataAs<TestDataSource>(resource)->SetActions(dnd_actions);
}
} // namespace
const struct wl_data_source_interface kTestDataSourceImpl = {
- DataSourceOffer, DataSourceDestroy, SetActions};
+ DataSourceOffer, DataSourceDestroy, DataSourceSetActions};
TestDataSource::TestDataSource(wl_resource* resource)
: ServerObject(resource),
@@ -70,7 +72,11 @@ TestDataSource::TestDataSource(wl_resource* resource)
TestDataSource::~TestDataSource() {}
void TestDataSource::Offer(const std::string& mime_type) {
- NOTIMPLEMENTED();
+ mime_types_.push_back(mime_type);
+}
+
+void TestDataSource::SetActions(uint32_t dnd_actions) {
+ actions_ |= dnd_actions;
}
void TestDataSource::ReadData(const std::string& mime_type,
diff --git a/chromium/ui/ozone/platform/wayland/test/test_data_source.h b/chromium/ui/ozone/platform/wayland/test/test_data_source.h
index 3cfdbff7a69..bcf66c3c26a 100644
--- a/chromium/ui/ozone/platform/wayland/test/test_data_source.h
+++ b/chromium/ui/ozone/platform/wayland/test/test_data_source.h
@@ -7,10 +7,12 @@
#include <wayland-server-protocol.h>
+#include <cstdint>
#include <memory>
#include <string>
#include <vector>
+#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "ui/ozone/platform/wayland/test/server_object.h"
@@ -31,15 +33,23 @@ class TestDataSource : public ServerObject {
~TestDataSource() override;
void Offer(const std::string& mime_type);
+ void SetActions(uint32_t dnd_actions);
using ReadDataCallback = base::OnceCallback<void(std::vector<uint8_t>&&)>;
void ReadData(const std::string& mime_type, ReadDataCallback callback);
void OnCancelled();
+ std::vector<std::string> mime_types() const { return mime_types_; }
+
+ uint32_t actions() const { return actions_; }
+
private:
const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ std::vector<std::string> mime_types_;
+ uint32_t actions_ = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+
DISALLOW_COPY_AND_ASSIGN(TestDataSource);
};
diff --git a/chromium/ui/ozone/platform/wayland/test/test_subsurface.cc b/chromium/ui/ozone/platform/wayland/test/test_subsurface.cc
index 1609bb2012a..73773c773b1 100644
--- a/chromium/ui/ozone/platform/wayland/test/test_subsurface.cc
+++ b/chromium/ui/ozone/platform/wayland/test/test_subsurface.cc
@@ -4,7 +4,7 @@
#include "ui/ozone/platform/wayland/test/mock_surface.h"
-#include "base/logging.h"
+#include "base/notreached.h"
namespace wl {
diff --git a/chromium/ui/ozone/platform/wayland/test/wayland_test.cc b/chromium/ui/ozone/platform/wayland/test/wayland_test.cc
index 2866ab6a07f..67c8f2bbaf2 100644
--- a/chromium/ui/ozone/platform/wayland/test/wayland_test.cc
+++ b/chromium/ui/ozone/platform/wayland/test/wayland_test.cc
@@ -10,6 +10,7 @@
#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_screen.h"
#include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/scoped_wl_array.h"
#include "ui/platform_window/platform_window_init_properties.h"
#if BUILDFLAG(USE_XKBCOMMON)
@@ -66,6 +67,11 @@ void WaylandTest::SetUp() {
surface_ = server_.GetObject<wl::MockSurface>(widget_);
ASSERT_TRUE(surface_);
+ // The surface must be activated before buffers are attached.
+ ActivateSurface(server_.GetObject<wl::MockSurface>(widget_)->xdg_surface());
+
+ Sync();
+
initialized_ = true;
}
@@ -86,4 +92,33 @@ void WaylandTest::Sync() {
server_.Pause();
}
+void WaylandTest::SendConfigureEvent(wl::MockXdgSurface* xdg_surface,
+ int width,
+ int height,
+ uint32_t serial,
+ struct wl_array* states) {
+ // In xdg_shell_v6+, both surfaces send serial configure event and toplevel
+ // surfaces send other data like states, heights and widths.
+ // Please note that toplevel surfaces may not exist if the surface was created
+ // for the popup role.
+ if (GetParam() == kXdgShellV6) {
+ zxdg_surface_v6_send_configure(xdg_surface->resource(), serial);
+ if (xdg_surface->xdg_toplevel()) {
+ zxdg_toplevel_v6_send_configure(xdg_surface->xdg_toplevel()->resource(),
+ width, height, states);
+ }
+ } else {
+ xdg_surface_send_configure(xdg_surface->resource(), serial);
+ if (xdg_surface->xdg_toplevel()) {
+ xdg_toplevel_send_configure(xdg_surface->xdg_toplevel()->resource(),
+ width, height, states);
+ }
+ }
+}
+
+void WaylandTest::ActivateSurface(wl::MockXdgSurface* xdg_surface) {
+ wl::ScopedWlArray state({XDG_TOPLEVEL_STATE_ACTIVATED});
+ SendConfigureEvent(xdg_surface, 0, 0, 1, state.get());
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/test/wayland_test.h b/chromium/ui/ozone/platform/wayland/test/wayland_test.h
index fc8161eb51d..97df3efbade 100644
--- a/chromium/ui/ozone/platform/wayland/test/wayland_test.h
+++ b/chromium/ui/ozone/platform/wayland/test/wayland_test.h
@@ -24,6 +24,7 @@
namespace wl {
class MockSurface;
+class MockXdgSurface;
} // namespace wl
namespace ui {
@@ -47,6 +48,18 @@ class WaylandTest : public ::testing::TestWithParam<uint32_t> {
void Sync();
protected:
+ // Sends configure event for the |xdg_surface|.
+ void SendConfigureEvent(wl::MockXdgSurface* xdg_surface,
+ int width,
+ int height,
+ uint32_t serial,
+ struct wl_array* states);
+
+ // Sends XDG_TOPLEVEL_STATE_ACTIVATED to the |xdg_surface| with width and
+ // height set to 0, which results in asking the client to set the width and
+ // height of the surface.
+ void ActivateSurface(wl::MockXdgSurface* xdg_surface);
+
base::test::TaskEnvironment task_environment_;
wl::TestWaylandServerThread server_;
diff --git a/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc b/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
index de10370fe69..acf7594d5e2 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
@@ -125,7 +125,7 @@ class WaylandBufferManagerTest : public WaylandTest {
}
}
- void CreateDmabufBasedBufferAndSetTerminateExpecation(
+ void CreateDmabufBasedBufferAndSetTerminateExpectation(
bool fail,
uint32_t buffer_id,
base::ScopedFD fd = base::ScopedFD(),
@@ -187,11 +187,14 @@ class WaylandBufferManagerTest : public WaylandTest {
}
}
- std::unique_ptr<WaylandWindow> CreateWindow() {
+ std::unique_ptr<WaylandWindow> CreateWindow(
+ PlatformWindowType type = PlatformWindowType::kWindow,
+ gfx::AcceleratedWidget parent_widget = gfx::kNullAcceleratedWidget) {
testing::Mock::VerifyAndClearExpectations(&delegate_);
PlatformWindowInitProperties properties;
properties.bounds = gfx::Rect(0, 0, 800, 600);
- properties.type = PlatformWindowType::kWindow;
+ properties.type = type;
+ properties.parent_widget = parent_widget;
auto new_window = WaylandWindow::Create(&delegate_, connection_.get(),
std::move(properties));
EXPECT_TRUE(new_window);
@@ -214,8 +217,8 @@ TEST_P(WaylandBufferManagerTest, CreateDmabufBasedBuffers) {
EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/,
- kDmabufBufferId);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
+ kDmabufBufferId);
DestroyBufferAndSetTerminateExpectation(gfx::kNullAcceleratedWidget,
kDmabufBufferId, false /*fail*/);
}
@@ -255,7 +258,7 @@ TEST_P(WaylandBufferManagerTest, VerifyModifiers) {
EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(
+ CreateDmabufBasedBufferAndSetTerminateExpectation(
false /*fail*/, kDmabufBufferId, base::ScopedFD(), kDefaultSize, {1}, {2},
{kFormatModiferLinear}, kFourccFormatR8, 1);
@@ -304,7 +307,7 @@ TEST_P(WaylandBufferManagerTest, ValidateDataFromGpu) {
for (const auto& bad : kBadInputs) {
EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(0);
base::ScopedFD dummy;
- CreateDmabufBasedBufferAndSetTerminateExpecation(
+ CreateDmabufBasedBufferAndSetTerminateExpectation(
true /*fail*/, bad.buffer_id,
bad.has_file ? MakeFD() : std::move(dummy), bad.size, bad.strides,
bad.offsets, bad.modifiers, bad.format, bad.planes_count);
@@ -321,25 +324,27 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) {
// id if they haven't been assigned to any surfaces yet.
{
EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(2);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/,
- kBufferId1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/,
- kBufferId2);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
+ kBufferId1);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
+ kBufferId2);
// Can't create buffer with existing id.
- CreateDmabufBasedBufferAndSetTerminateExpecation(true /*fail*/, kBufferId2);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(true /*fail*/,
+ kBufferId2);
}
// ... impossible to create buffers with the same id if one of them
// has already been attached to a surface.
{
EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/,
- kBufferId1);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
+ kBufferId1);
buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds());
- CreateDmabufBasedBufferAndSetTerminateExpecation(true /*fail*/, kBufferId1);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(true /*fail*/,
+ kBufferId1);
}
// ... impossible to destroy non-existing buffer.
@@ -356,8 +361,8 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) {
// specified.
{
EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/,
- kBufferId1);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
+ kBufferId1);
buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds());
@@ -369,22 +374,22 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) {
// widgets.
{
EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/,
- kBufferId1);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
+ kBufferId1);
DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/);
}
// ... impossible to destroy buffers twice.
{
EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(3);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/,
- kBufferId1);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
+ kBufferId1);
// Attach to a surface.
buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds());
// Created non-attached buffer as well.
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/,
- kBufferId2);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
+ kBufferId2);
DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/);
// Can't destroy the buffer with non-existing id (the manager cleared the
@@ -397,8 +402,8 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) {
kBufferId2, true /*fail*/);
// Create and destroy non-attached buffer twice.
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/,
- kBufferId2);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
+ kBufferId2);
DestroyBufferAndSetTerminateExpectation(gfx::kNullAcceleratedWidget,
kBufferId2, false /*fail*/);
DestroyBufferAndSetTerminateExpectation(gfx::kNullAcceleratedWidget,
@@ -408,7 +413,7 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) {
TEST_P(WaylandBufferManagerTest, CommitBufferNonExistingBufferId) {
EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, 1u);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, 1u);
// Can't commit for non-existing buffer id.
SetTerminateCallbackExpectationAndDestroyChannel(&callback_, true /*fail*/);
@@ -421,7 +426,7 @@ TEST_P(WaylandBufferManagerTest, CommitBufferNonExistingBufferId) {
TEST_P(WaylandBufferManagerTest, CommitBufferNullWidget) {
constexpr uint32_t kBufferId = 1;
EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId);
// Can't commit for non-existing widget.
SetTerminateCallbackExpectationAndDestroyChannel(&callback_, true /*fail*/);
@@ -443,8 +448,8 @@ TEST_P(WaylandBufferManagerTest, EnsureCorrectOrderOfCallbacks) {
auto* linux_dmabuf = server_.zwp_linux_dmabuf_v1();
EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(2);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId2);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId1);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId2);
Sync();
@@ -551,9 +556,9 @@ TEST_P(WaylandBufferManagerTest,
auto* linux_dmabuf = server_.zwp_linux_dmabuf_v1();
EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(3);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId2);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId3);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId1);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId2);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId3);
Sync();
@@ -650,7 +655,149 @@ TEST_P(WaylandBufferManagerTest,
DestroyBufferAndSetTerminateExpectation(widget, kBufferId3, false /*fail*/);
}
-TEST_P(WaylandBufferManagerTest, MultiplePendingPresentationsForSameBuffer) {}
+// This test ensures that a discarded presentation feedback sent prior receiving
+// results for the previous presentation feedback does not make them
+// automatically failed.
+TEST_P(WaylandBufferManagerTest,
+ EnsureDiscardedPresentationDoesNotMakePreviousFeedbacksFailed) {
+ constexpr uint32_t kBufferId1 = 1;
+ constexpr uint32_t kBufferId2 = 2;
+ constexpr uint32_t kBufferId3 = 3;
+
+ // Enable wp_presentation support.
+ auto* mock_wp_presentation = server_.EnsureWpPresentation();
+ ASSERT_TRUE(mock_wp_presentation);
+
+ const gfx::AcceleratedWidget widget = window_->GetWidget();
+ const gfx::Rect bounds = gfx::Rect({0, 0}, kDefaultSize);
+ window_->SetBounds(bounds);
+
+ MockSurfaceGpu mock_surface_gpu(buffer_manager_gpu_.get(), widget_);
+
+ auto* linux_dmabuf = server_.zwp_linux_dmabuf_v1();
+ EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(3);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId1);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId2);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId3);
+
+ Sync();
+
+ ProcessCreatedBufferResourcesWithExpectation(3u /* expected size */,
+ false /* fail */);
+
+ auto* mock_surface = server_.GetObject<wl::MockSurface>(widget);
+
+ constexpr uint32_t kNumberOfCommits = 3;
+ EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(kNumberOfCommits);
+ EXPECT_CALL(*mock_surface, Frame(_)).Times(kNumberOfCommits);
+ EXPECT_CALL(*mock_surface, Commit()).Times(kNumberOfCommits);
+
+ // All the other expectations must come in order.
+ ::testing::InSequence sequence;
+ EXPECT_CALL(mock_surface_gpu,
+ OnSubmission(kBufferId1, gfx::SwapResult::SWAP_ACK))
+ .Times(1);
+ EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
+
+ // Commit first buffer
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+
+ Sync();
+
+ // Will be sent later.
+ auto* presentation_callback1 =
+ mock_wp_presentation->ReleasePresentationCallback();
+
+ mock_surface->SendFrameCallback();
+
+ Sync();
+
+ EXPECT_CALL(mock_surface_gpu,
+ OnSubmission(kBufferId2, gfx::SwapResult::SWAP_ACK))
+ .Times(1);
+ EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
+
+ // Commit second buffer
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+
+ Sync();
+
+ // Will be sent later.
+ auto* presentation_callback2 =
+ mock_wp_presentation->ReleasePresentationCallback();
+
+ // Release previous buffer and commit third buffer.
+ mock_surface->ReleasePrevAttachedBuffer();
+ mock_surface->SendFrameCallback();
+
+ Sync();
+
+ EXPECT_CALL(mock_surface_gpu,
+ OnSubmission(kBufferId3, gfx::SwapResult::SWAP_ACK))
+ .Times(1);
+ EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
+
+ // Commit third buffer
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds);
+
+ Sync();
+
+ mock_surface->ReleasePrevAttachedBuffer();
+
+ Sync();
+
+ // Even though WaylandBufferManagerHost stores the previous stores
+ // presentation feedbacks and waits for their value, the current last one
+ // mustn't result in the previous marked as failed. Thus, no feedback must be
+ // actually sent to the MockSurfaceGpu as it's required to send feedbacks in
+ // order.
+ EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
+
+ mock_wp_presentation->SendPresentationCallbackDiscarded();
+
+ Sync();
+
+ // Now, start to send all the previous callbacks.
+ EXPECT_CALL(mock_surface_gpu,
+ OnPresentation(
+ kBufferId1,
+ ::testing::Field(
+ &gfx::PresentationFeedback::flags,
+ ::testing::Eq(gfx::PresentationFeedback::Flags::kVSync))))
+ .Times(1);
+
+ mock_wp_presentation->set_presentation_callback(presentation_callback1);
+ mock_wp_presentation->SendPresentationCallback();
+
+ Sync();
+
+ // Now, send the second presentation feedback. It will send both second and
+ // third feedback that was discarded.
+ EXPECT_CALL(mock_surface_gpu,
+ OnPresentation(
+ kBufferId2,
+ ::testing::Field(
+ &gfx::PresentationFeedback::flags,
+ ::testing::Eq(gfx::PresentationFeedback::Flags::kVSync))))
+ .Times(1);
+ EXPECT_CALL(
+ mock_surface_gpu,
+ OnPresentation(
+ kBufferId3,
+ ::testing::Field(
+ &gfx::PresentationFeedback::flags,
+ ::testing::Eq(gfx::PresentationFeedback::Flags::kFailure))))
+ .Times(1);
+
+ mock_wp_presentation->set_presentation_callback(presentation_callback2);
+ mock_wp_presentation->SendPresentationCallback();
+
+ Sync();
+
+ DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/);
+ DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, false /*fail*/);
+ DestroyBufferAndSetTerminateExpectation(widget, kBufferId3, false /*fail*/);
+}
TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) {
constexpr uint32_t kDmabufBufferId = 1;
@@ -662,8 +809,8 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) {
auto* linux_dmabuf = server_.zwp_linux_dmabuf_v1();
EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/,
- kDmabufBufferId);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
+ kDmabufBufferId);
// Part 1: the surface mustn't have a buffer attached until
// zwp_linux_buffer_params_v1_send_created is called. Instead, the buffer must
@@ -694,8 +841,8 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) {
// sent by the server.
EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/,
- kDmabufBufferId2);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
+ kDmabufBufferId2);
ProcessCreatedBufferResourcesWithExpectation(1u /* expected size */,
false /* fail */);
@@ -726,6 +873,77 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) {
false /*fail*/);
}
+// Tests the surface does not have buffers attached until it's configured at
+// least once.
+TEST_P(WaylandBufferManagerTest, TestCommitBufferConditionsAckConfigured) {
+ constexpr uint32_t kDmabufBufferId = 1;
+
+ // Exercise three window types that create different windows - toplevel, popup
+ // and subsurface.
+ std::vector<PlatformWindowType> window_types{PlatformWindowType::kWindow,
+ PlatformWindowType::kPopup,
+ PlatformWindowType::kTooltip};
+
+ for (const auto& type : window_types) {
+ // If the type is not kWindow, provide default created window as parent of
+ // the newly created window.
+ auto temp_window = CreateWindow(type, type != PlatformWindowType::kWindow
+ ? widget_
+ : gfx::kNullAcceleratedWidget);
+ auto widget = temp_window->GetWidget();
+
+ // Subsurface doesn't have an interface for sending configure events.
+ // Thus, WaylandSubsurface notifies the manager that the window is
+ // activated upon creation of the subsurface. Skip calling Show() and call
+ // later then.
+ if (type != PlatformWindowType::kTooltip)
+ temp_window->Show(false);
+
+ Sync();
+
+ auto* mock_surface = server_.GetObject<wl::MockSurface>(widget);
+
+ auto* linux_dmabuf = server_.zwp_linux_dmabuf_v1();
+ EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(1);
+
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
+ kDmabufBufferId);
+
+ Sync();
+
+ ProcessCreatedBufferResourcesWithExpectation(1u /* expected size */,
+ false /* fail */);
+
+ EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(0);
+ EXPECT_CALL(*mock_surface, Frame(_)).Times(0);
+ EXPECT_CALL(*mock_surface, Commit()).Times(0);
+
+ buffer_manager_gpu_->CommitBuffer(widget, kDmabufBufferId,
+ window_->GetBounds());
+ Sync();
+
+ if (type != PlatformWindowType::kTooltip) {
+ DCHECK(mock_surface->xdg_surface());
+ ActivateSurface(mock_surface->xdg_surface());
+ } else {
+ // See the comment near Show() call above.
+ temp_window->Show(false);
+ }
+
+ EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
+ EXPECT_CALL(*mock_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*mock_surface, Commit()).Times(1);
+
+ Sync();
+
+ temp_window.reset();
+ DestroyBufferAndSetTerminateExpectation(widget, kDmabufBufferId,
+ false /*fail*/);
+
+ Sync();
+ }
+}
+
// The buffer that is not originally attached to any of the surfaces,
// must be attached when a commit request comes. Also, it must setup a buffer
// release listener and OnSubmission must be called for that buffer if it is
@@ -743,7 +961,7 @@ TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) {
auto* linux_dmabuf = server_.zwp_linux_dmabuf_v1();
EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId1);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId1);
Sync();
@@ -776,7 +994,7 @@ TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) {
// Now synchronously create a second buffer and commit it. The release
// callback must be setup and OnSubmission must be called.
EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId2);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId2);
Sync();
@@ -804,7 +1022,7 @@ TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) {
// released once the buffer is committed and processed (that is, it must be
// able to setup a buffer release callback).
EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId3);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId3);
Sync();
@@ -845,7 +1063,7 @@ TEST_P(WaylandBufferManagerTest, DestroyBufferForDestroyedWindow) {
auto widget = temp_window->GetWidget();
EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId);
Sync();
@@ -866,7 +1084,7 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionSingleBuffer) {
auto bounds = temp_window->GetBounds();
EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId);
ProcessCreatedBufferResourcesWithExpectation(1u /* expected size */,
false /* fail */);
@@ -894,11 +1112,22 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionMultipleBuffers) {
constexpr uint32_t kBufferId2 = 2;
auto temp_window = CreateWindow();
+ temp_window->Show(false);
+
+ Sync();
+
auto widget = temp_window->GetWidget();
auto bounds = temp_window->GetBounds();
+ auto* mock_surface = server_.GetObject<wl::MockSurface>(widget);
+ ASSERT_TRUE(mock_surface);
+
+ ActivateSurface(mock_surface->xdg_surface());
+
+ Sync();
+
EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId1);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId1);
ProcessCreatedBufferResourcesWithExpectation(1u /* expected size */,
false /* fail */);
@@ -915,13 +1144,12 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionMultipleBuffers) {
Sync();
- auto* mock_surface = server_.GetObject<wl::MockSurface>(widget);
mock_surface->SendFrameCallback();
Sync();
EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId2);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId2);
ProcessCreatedBufferResourcesWithExpectation(1u /* expected size */,
false /* fail */);
@@ -966,8 +1194,8 @@ TEST_P(WaylandBufferManagerTest, SubmitSameBufferMultipleTimes) {
auto* linux_dmabuf = server_.zwp_linux_dmabuf_v1();
EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(2);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId1);
- CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId2);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId1);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId2);
Sync();
diff --git a/chromium/ui/ozone/platform/windows/BUILD.gn b/chromium/ui/ozone/platform/windows/BUILD.gn
index 766c32795be..72fb3aae39a 100644
--- a/chromium/ui/ozone/platform/windows/BUILD.gn
+++ b/chromium/ui/ozone/platform/windows/BUILD.gn
@@ -24,6 +24,8 @@ source_set("windows") {
"//base",
"//skia",
"//ui/base",
+ "//ui/base/cursor",
+ "//ui/base/cursor:cursor_base",
"//ui/display/fake",
"//ui/events",
"//ui/events/ozone/layout",
diff --git a/chromium/ui/ozone/platform/windows/ozone_platform_windows.cc b/chromium/ui/ozone/platform/windows/ozone_platform_windows.cc
index d6dee8a511c..5a686f01622 100644
--- a/chromium/ui/ozone/platform/windows/ozone_platform_windows.cc
+++ b/chromium/ui/ozone/platform/windows/ozone_platform_windows.cc
@@ -10,6 +10,7 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "ui/base/cursor/cursor_factory.h"
#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
#include "ui/display/fake/fake_display_delegate.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
@@ -20,7 +21,6 @@
#include "ui/ozone/platform/windows/windows_surface_factory.h"
#include "ui/ozone/platform/windows/windows_window.h"
#include "ui/ozone/platform/windows/windows_window_manager.h"
-#include "ui/ozone/public/cursor_factory_ozone.h"
#include "ui/ozone/public/gpu_platform_support_host.h"
#include "ui/ozone/public/input_controller.h"
#include "ui/ozone/public/ozone_platform.h"
@@ -56,9 +56,7 @@ class OzonePlatformWindows : public OzonePlatform {
OverlayManagerOzone* GetOverlayManager() override {
return overlay_manager_.get();
}
- CursorFactoryOzone* GetCursorFactoryOzone() override {
- return cursor_factory_ozone_.get();
- }
+ CursorFactory* GetCursorFactory() override { return cursor_factory_.get(); }
InputController* GetInputController() override {
return input_controller_.get();
}
@@ -96,7 +94,7 @@ class OzonePlatformWindows : public OzonePlatform {
overlay_manager_ = std::make_unique<StubOverlayManager>();
input_controller_ = CreateStubInputController();
- cursor_factory_ozone_ = std::make_unique<BitmapCursorFactoryOzone>();
+ cursor_factory_ = std::make_unique<BitmapCursorFactory>();
gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
}
@@ -110,7 +108,7 @@ class OzonePlatformWindows : public OzonePlatform {
std::unique_ptr<WindowsWindowManager> window_manager_;
std::unique_ptr<WindowsSurfaceFactory> surface_factory_;
std::unique_ptr<PlatformEventSource> platform_event_source_;
- std::unique_ptr<CursorFactoryOzone> cursor_factory_ozone_;
+ std::unique_ptr<CursorFactory> cursor_factory_;
std::unique_ptr<InputController> input_controller_;
std::unique_ptr<GpuPlatformSupportHost> gpu_platform_support_host_;
std::unique_ptr<OverlayManagerOzone> overlay_manager_;
diff --git a/chromium/ui/ozone/platform/x11/BUILD.gn b/chromium/ui/ozone/platform/x11/BUILD.gn
index fcdb99cdf60..35b64eb2caa 100644
--- a/chromium/ui/ozone/platform/x11/BUILD.gn
+++ b/chromium/ui/ozone/platform/x11/BUILD.gn
@@ -24,18 +24,12 @@ source_set("x11") {
"x11_canvas_surface.h",
"x11_clipboard_ozone.cc",
"x11_clipboard_ozone.h",
- "x11_cursor_factory_ozone.cc",
- "x11_cursor_factory_ozone.h",
- "x11_cursor_ozone.cc",
- "x11_cursor_ozone.h",
"x11_screen_ozone.cc",
"x11_screen_ozone.h",
"x11_surface_factory.cc",
"x11_surface_factory.h",
]
- public_deps = [ "//ui/base/cursor/mojom:cursor_type" ]
-
deps = [
"//base",
"//build:chromecast_buildflags",
@@ -45,6 +39,7 @@ source_set("x11") {
"//ui/base:buildflags",
"//ui/base:data_exchange",
"//ui/base/clipboard:clipboard_types",
+ "//ui/base/cursor:cursor_base",
"//ui/base/ime",
"//ui/base/x",
"//ui/base/x:gl",
@@ -68,17 +63,11 @@ source_set("x11") {
]
if (is_chromeos) {
- sources += [
- "x11_window_ozone_chromeos.cc",
- "x11_window_ozone_chromeos.h",
- ]
deps += [ "//ui/base/ime/chromeos" ]
} else {
sources += [
"x11_os_exchange_data_provider_ozone.cc",
"x11_os_exchange_data_provider_ozone.h",
- "x11_window_ozone.cc",
- "x11_window_ozone.h",
]
deps += [ "//ui/base/ime/linux" ]
}
@@ -101,7 +90,6 @@ source_set("x11") {
source_set("x11_unittests") {
testonly = true
sources = [
- "x11_cursor_factory_ozone_unittest.cc",
"x11_screen_ozone_unittest.cc",
"x11_window_ozone_unittest.cc",
]
diff --git a/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc b/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
index 2d26ced5587..394ef374c81 100644
--- a/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
+++ b/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
@@ -11,9 +11,11 @@
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "ui/base/buildflags.h"
+#include "ui/base/cursor/cursor_factory.h"
#include "ui/base/dragdrop/os_exchange_data_provider_factory.h"
#include "ui/base/dragdrop/os_exchange_data_provider_factory_ozone.h"
-#include "ui/base/ime/linux/linux_input_method_context_factory.h"
+#include "ui/base/x/x11_cursor_factory.h"
+#include "ui/base/x/x11_error_handler.h"
#include "ui/base/x/x11_util.h"
#include "ui/display/fake/fake_display_delegate.h"
#include "ui/events/devices/x11/touch_factory_x11.h"
@@ -25,22 +27,22 @@
#include "ui/ozone/common/stub_overlay_manager.h"
#include "ui/ozone/platform/x11/gl_egl_utility_x11.h"
#include "ui/ozone/platform/x11/x11_clipboard_ozone.h"
-#include "ui/ozone/platform/x11/x11_cursor_factory_ozone.h"
#include "ui/ozone/platform/x11/x11_screen_ozone.h"
#include "ui/ozone/platform/x11/x11_surface_factory.h"
-#include "ui/ozone/platform/x11/x11_window_ozone.h"
#include "ui/ozone/public/gpu_platform_support_host.h"
#include "ui/ozone/public/input_controller.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/system_input_injector.h"
#include "ui/platform_window/platform_window.h"
#include "ui/platform_window/platform_window_init_properties.h"
+#include "ui/platform_window/x11/x11_window.h"
#if defined(OS_CHROMEOS)
-#include "ui/base/dragdrop/os_exchange_data_provider_aura.h"
+#include "ui/base/dragdrop/os_exchange_data_provider_non_backed.h"
#include "ui/base/ime/chromeos/input_method_chromeos.h"
#else
-#include "ui/base/ime/linux/input_method_auralinux.h"
+#include "ui/base/ime/linux/input_method_auralinux.h" // nogncheck
+#include "ui/base/ime/linux/linux_input_method_context_factory.h" // nogncheck
#include "ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h"
#endif
@@ -88,9 +90,7 @@ class OzonePlatformX11 : public OzonePlatform,
return overlay_manager_.get();
}
- CursorFactoryOzone* GetCursorFactoryOzone() override {
- return cursor_factory_ozone_.get();
- }
+ CursorFactory* GetCursorFactory() override { return cursor_factory_.get(); }
std::unique_ptr<SystemInputInjector> CreateSystemInputInjector() override {
return nullptr;
@@ -107,8 +107,7 @@ class OzonePlatformX11 : public OzonePlatform,
std::unique_ptr<PlatformWindow> CreatePlatformWindow(
PlatformWindowDelegate* delegate,
PlatformWindowInitProperties properties) override {
- std::unique_ptr<X11WindowOzone> window =
- std::make_unique<X11WindowOzone>(delegate);
+ auto window = std::make_unique<X11Window>(delegate);
window->Initialize(std::move(properties));
window->SetTitle(base::ASCIIToUTF16("Ozone X11"));
return std::move(window);
@@ -151,7 +150,7 @@ class OzonePlatformX11 : public OzonePlatform,
std::unique_ptr<OSExchangeDataProvider> CreateProvider() override {
#if defined(OS_CHROMEOS)
- return std::make_unique<OSExchangeDataProviderAura>();
+ return std::make_unique<OSExchangeDataProviderNonBacked>();
#else
return std::make_unique<X11OSExchangeDataProviderOzone>();
#endif
@@ -167,7 +166,7 @@ class OzonePlatformX11 : public OzonePlatform,
overlay_manager_ = std::make_unique<StubOverlayManager>();
input_controller_ = CreateStubInputController();
clipboard_ = std::make_unique<X11ClipboardOzone>();
- cursor_factory_ozone_ = std::make_unique<X11CursorFactoryOzone>();
+ cursor_factory_ = std::make_unique<X11CursorFactory>();
gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
#if BUILDFLAG(USE_XKBCOMMON)
@@ -202,6 +201,28 @@ class OzonePlatformX11 : public OzonePlatform,
gl_egl_utility_ = std::make_unique<GLEGLUtilityX11>();
}
+ void PostMainMessageLoopStart(
+ base::OnceCallback<void()> shutdown_cb) override {
+ // Installs the X11 error handlers for the UI process after the
+ // main message loop has started. This will allow us to exit cleanly
+ // if X exits before we do.
+ SetErrorHandlers(std::move(shutdown_cb));
+ }
+
+ void PostMainMessageLoopRun() override {
+ // Unset the X11 error handlers. The X11 error handlers log the errors using
+ // a |PostTask()| on the message-loop. But since the message-loop is in the
+ // process of terminating, this can cause errors.
+ SetEmptyErrorHandlers();
+ }
+
+ void PreEarlyInitialize() override {
+ // Installs the X11 error handlers for the browser process used during
+ // startup. They simply print error messages and exit because
+ // we can't shutdown properly while creating and initializing services.
+ SetNullErrorHandlers();
+ }
+
private:
// Performs initialization steps need by both UI and GPU.
void InitializeCommon(const InitParams& params) {
@@ -238,7 +259,7 @@ class OzonePlatformX11 : public OzonePlatform,
std::unique_ptr<OverlayManagerOzone> overlay_manager_;
std::unique_ptr<InputController> input_controller_;
std::unique_ptr<X11ClipboardOzone> clipboard_;
- std::unique_ptr<X11CursorFactoryOzone> cursor_factory_ozone_;
+ std::unique_ptr<CursorFactory> cursor_factory_;
std::unique_ptr<GpuPlatformSupportHost> gpu_platform_support_host_;
// Objects in the GPU process.
diff --git a/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc b/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc
index 0f8b04c4f59..bea9cffe465 100644
--- a/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc
+++ b/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc
@@ -8,10 +8,14 @@
#include <vector>
#include "base/containers/span.h"
+#include "base/logging.h"
#include "base/stl_util.h"
#include "ui/base/clipboard/clipboard_constants.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/gfx/x/extension_manager.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_types.h"
+#include "ui/gfx/x/xproto.h"
using base::Contains;
@@ -42,13 +46,6 @@ void ExpandTypes(std::vector<std::string>* list) {
list->push_back(kMimeTypeTextUtf8);
}
-XID FindXEventTarget(const XEvent& xev) {
- XID target = xev.xany.window;
- if (xev.type == GenericEvent)
- target = static_cast<XIDeviceEvent*>(xev.xcookie.data)->event;
- return target;
-}
-
} // namespace
// Maintains state of a single selection (aka system clipboard buffer).
@@ -79,7 +76,7 @@ struct X11ClipboardOzone::SelectionState {
PlatformClipboard::RequestDataClosure request_clipboard_data_callback;
// The time that this instance took ownership of the clipboard.
- Time acquired_selection_timestamp;
+ x11::Time acquired_selection_timestamp;
};
X11ClipboardOzone::X11ClipboardOzone()
@@ -87,32 +84,21 @@ X11ClipboardOzone::X11ClipboardOzone()
atom_targets_(gfx::GetAtom(kTargets)),
atom_timestamp_(gfx::GetAtom(kTimestamp)),
x_property_(gfx::GetAtom(kChromeSelection)),
- x_display_(gfx::GetXDisplay()),
- x_window_(XCreateSimpleWindow(x_display_,
- DefaultRootWindow(x_display_),
- /*x=*/-100,
- /*y=*/-100,
- /*width=*/10,
- /*height=*/10,
- /*border_width=*/0,
- /*border=*/0,
- /*background=*/0)) {
- int ignored; // xfixes_error_base.
- if (!XFixesQueryExtension(x_display_, &xfixes_event_base_, &ignored)) {
- LOG(ERROR) << "X server does not support XFixes.";
+ connection_(x11::Connection::Get()),
+ x_window_(CreateDummyWindow("Chromium Clipboard Window")) {
+ if (!connection_->xfixes().present())
return;
- }
using_xfixes_ = true;
// Register to receive standard X11 events.
X11EventSource::GetInstance()->AddXEventDispatcher(this);
- for (auto atom : {atom_clipboard_, XA_PRIMARY}) {
+ for (auto atom : {atom_clipboard_, x11::Atom::PRIMARY}) {
// Register the selection state.
selection_state_.emplace(atom, std::make_unique<SelectionState>());
// Register to receive XFixes notification when selection owner changes.
- XFixesSelectSelectionInput(x_display_, x_window_, atom,
- XFixesSetSelectionOwnerNotifyMask);
+ connection_->xfixes().SelectSelectionInput(
+ {x_window_, atom, x11::XFixes::SelectionEventMask::SetSelectionOwner});
// Prefetch the current remote clipboard contents.
QueryTargets(atom);
}
@@ -122,21 +108,13 @@ X11ClipboardOzone::~X11ClipboardOzone() {
X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
}
-bool X11ClipboardOzone::DispatchXEvent(XEvent* xev) {
- if (FindXEventTarget(*xev) != x_window_)
- return false;
-
- switch (xev->type) {
- case SelectionRequest:
- return OnSelectionRequest(xev->xselectionrequest);
- case SelectionNotify:
- return OnSelectionNotify(xev->xselection);
- }
-
- if (using_xfixes_ &&
- xev->type == xfixes_event_base_ + XFixesSetSelectionOwnerNotify) {
- return OnSetSelectionOwnerNotify(xev);
- }
+bool X11ClipboardOzone::DispatchXEvent(x11::Event* xev) {
+ if (auto* request = xev->As<x11::SelectionRequestEvent>())
+ return request->owner == x_window_ && OnSelectionRequest(*request);
+ if (auto* notify = xev->As<x11::SelectionNotifyEvent>())
+ return notify->requestor == x_window_ && OnSelectionNotify(*notify);
+ if (auto* notify = xev->As<x11::XFixes::SelectionNotifyEvent>())
+ return notify->owner == x_window_ && OnSetSelectionOwnerNotify(*notify);
return false;
}
@@ -146,15 +124,17 @@ bool X11ClipboardOzone::DispatchXEvent(XEvent* xev) {
// TIMESTAMP: Time when we took ownership of the clipboard.
// <mime-type>: Mime type to receive clipboard as.
bool X11ClipboardOzone::OnSelectionRequest(
- const XSelectionRequestEvent& event) {
+ const x11::SelectionRequestEvent& event) {
// The property must be set.
- if (event.property == x11::None)
+ if (event.property == x11::Atom::None)
return false;
// target=TARGETS.
- auto& selection_state = GetSelectionState(event.selection);
+ auto& selection_state =
+ GetSelectionState(static_cast<x11::Atom>(event.selection));
+ auto target = static_cast<x11::Atom>(event.target);
PlatformClipboard::DataMap& offer_data_map = selection_state.offer_data_map;
- if (event.target == atom_targets_) {
+ if (target == atom_targets_) {
std::vector<std::string> targets;
// Add TIMESTAMP.
targets.push_back(kTimestamp);
@@ -163,26 +143,21 @@ bool X11ClipboardOzone::OnSelectionRequest(
}
// Expand types, then convert from string to atom.
ExpandTypes(&targets);
- std::vector<XAtom> atoms;
- for (auto& entry : targets) {
+ std::vector<x11::Atom> atoms;
+ for (auto& entry : targets)
atoms.push_back(gfx::GetAtom(entry.c_str()));
- }
- XChangeProperty(x_display_, event.requestor, event.property, XA_ATOM,
- /*format=*/32, PropModeReplace,
- reinterpret_cast<unsigned char*>(atoms.data()),
- atoms.size());
+ ui::SetArrayProperty(event.requestor, event.property, x11::Atom::ATOM,
+ atoms);
- } else if (event.target == atom_timestamp_) {
+ } else if (target == atom_timestamp_) {
// target=TIMESTAMP.
- XChangeProperty(x_display_, event.requestor, event.property, XA_INTEGER,
- /*format=*/32, PropModeReplace,
- reinterpret_cast<unsigned char*>(
- &selection_state.acquired_selection_timestamp),
- 1);
-
+ ui::SetProperty(event.requestor, event.property, x11::Atom::INTEGER,
+ selection_state.acquired_selection_timestamp);
} else {
// Send clipboard data.
- char* target_name = XGetAtomName(x_display_, event.target);
+ std::string target_name;
+ if (auto reply = connection_->GetAtomName({event.target}).Sync())
+ target_name = std::move(reply->name);
std::string key = target_name;
// Allow conversions for text/plain[;charset=utf-8] <=> [UTF8_]STRING.
@@ -193,58 +168,41 @@ bool X11ClipboardOzone::OnSelectionRequest(
}
auto it = offer_data_map.find(key);
if (it != offer_data_map.end()) {
- XChangeProperty(x_display_, event.requestor, event.property, event.target,
- /*format=*/8, PropModeReplace,
- const_cast<unsigned char*>(it->second.data()),
- it->second.size());
+ ui::SetArrayProperty(event.requestor, event.property, event.target,
+ it->second);
}
- XFree(target_name);
}
// Notify remote peer that clipboard has been sent.
- XSelectionEvent selection_event;
- selection_event.type = SelectionNotify;
- selection_event.display = event.display;
- selection_event.requestor = event.requestor;
- selection_event.selection = event.selection;
- selection_event.target = event.target;
- selection_event.property = event.property;
- selection_event.time = event.time;
- XSendEvent(x_display_, selection_event.requestor, /*propagate=*/x11::False,
- /*event_mask=*/0, reinterpret_cast<XEvent*>(&selection_event));
+ x11::SelectionNotifyEvent selection_event{
+ .time = event.time,
+ .requestor = event.requestor,
+ .selection = event.selection,
+ .target = event.target,
+ .property = event.property,
+ };
+ SendEvent(selection_event, selection_event.requestor,
+ x11::EventMask::NoEvent);
return true;
}
// A remote peer owns the clipboard. This event is received in response to
// our request for TARGETS (GetAvailableMimeTypes), or a specific mime type
// (RequestClipboardData).
-bool X11ClipboardOzone::OnSelectionNotify(const XSelectionEvent& event) {
+bool X11ClipboardOzone::OnSelectionNotify(
+ const x11::SelectionNotifyEvent& event) {
// GetAvailableMimeTypes.
- auto& selection_state = GetSelectionState(event.selection);
- if (event.target == atom_targets_) {
- XAtom type;
- int format;
- unsigned long item_count, after;
- unsigned char* data = nullptr;
-
- if (XGetWindowProperty(x_display_, x_window_, x_property_,
- /*long_offset=*/0,
- /*long_length=*/256 * sizeof(XAtom),
- /*delete=*/x11::False, XA_ATOM, &type, &format,
- &item_count, &after, &data) != x11::Success) {
- return false;
- }
+ auto selection = static_cast<x11::Atom>(event.selection);
+ auto& selection_state = GetSelectionState(selection);
+ if (static_cast<x11::Atom>(event.target) == atom_targets_) {
+ std::vector<x11::Atom> targets;
+ ui::GetArrayProperty(x_window_, x_property_, &targets);
selection_state.mime_types.clear();
- base::span<XAtom> targets(reinterpret_cast<XAtom*>(data), item_count);
for (auto target : targets) {
- char* atom_name = XGetAtomName(x_display_, target);
- if (atom_name) {
- selection_state.mime_types.push_back(atom_name);
- XFree(atom_name);
- }
+ if (auto reply = connection_->GetAtomName({target}).Sync())
+ selection_state.mime_types.push_back(std::move(reply->name));
}
- XFree(data);
// If we have a saved callback, invoke it now with expanded types, otherwise
// guess that we will want 'text/plain' and fetch it now.
@@ -255,27 +213,20 @@ bool X11ClipboardOzone::OnSelectionNotify(const XSelectionEvent& event) {
.Run(std::move(result));
} else {
selection_state.data_mime_type = kMimeTypeText;
- ReadRemoteClipboard(event.selection);
+ ReadRemoteClipboard(selection);
}
return true;
}
// RequestClipboardData.
- if (event.property == x_property_) {
- XAtom type;
- int format;
- unsigned long item_count, after;
- unsigned char* data;
- XGetWindowProperty(x_display_, x_window_, x_property_,
- /*long_offset=*/0, /*long_length=*/~0L,
- /*delete=*/x11::True, AnyPropertyType, &type, &format,
- &item_count, &after, &data);
- if (type != x11::None && format == 8) {
- std::vector<unsigned char> tmp(data, data + item_count);
- selection_state.data = tmp;
- }
- XFree(data);
+ if (static_cast<x11::Atom>(event.property) == x_property_) {
+ x11::Atom type;
+ std::vector<uint8_t> data;
+ ui::GetArrayProperty(x_window_, x_property_, &data, &type);
+ ui::DeleteProperty(x_window_, x_property_);
+ if (type != x11::Atom::None)
+ selection_state.data = std::move(data);
// If we have a saved callback, invoke it now, otherwise this was a prefetch
// and we have already saved |data_| for the next call to
@@ -292,41 +243,41 @@ bool X11ClipboardOzone::OnSelectionNotify(const XSelectionEvent& event) {
return false;
}
-bool X11ClipboardOzone::OnSetSelectionOwnerNotify(XEvent* xev) {
- XFixesSelectionNotifyEvent* event =
- reinterpret_cast<XFixesSelectionNotifyEvent*>(xev);
-
+bool X11ClipboardOzone::OnSetSelectionOwnerNotify(
+ const x11::XFixes::SelectionNotifyEvent& event) {
// Reset state and fetch remote clipboard if there is a new remote owner.
- if (!IsSelectionOwner(BufferForSelectionAtom(event->selection))) {
- auto& selection_state = GetSelectionState(event->selection);
+ x11::Atom selection = event.selection;
+ if (!IsSelectionOwner(BufferForSelectionAtom(selection))) {
+ auto& selection_state = GetSelectionState(selection);
selection_state.mime_types.clear();
selection_state.data_mime_type.clear();
selection_state.data.clear();
- QueryTargets(event->selection);
+ QueryTargets(selection);
}
// Increase the sequence number if the callback is set.
if (update_sequence_cb_)
- update_sequence_cb_.Run(BufferForSelectionAtom(event->selection));
+ update_sequence_cb_.Run(BufferForSelectionAtom(selection));
return true;
}
-XAtom X11ClipboardOzone::SelectionAtomForBuffer(ClipboardBuffer buffer) const {
+x11::Atom X11ClipboardOzone::SelectionAtomForBuffer(
+ ClipboardBuffer buffer) const {
switch (buffer) {
case ClipboardBuffer::kCopyPaste:
return atom_clipboard_;
case ClipboardBuffer::kSelection:
- return XA_PRIMARY;
+ return x11::Atom::PRIMARY;
default:
NOTREACHED();
- return x11::None;
+ return x11::Atom::None;
}
}
ClipboardBuffer X11ClipboardOzone::BufferForSelectionAtom(
- XAtom selection) const {
- if (selection == XA_PRIMARY)
+ x11::Atom selection) const {
+ if (selection == x11::Atom::PRIMARY)
return ClipboardBuffer::kSelection;
if (selection == atom_clipboard_)
return ClipboardBuffer::kCopyPaste;
@@ -335,18 +286,18 @@ ClipboardBuffer X11ClipboardOzone::BufferForSelectionAtom(
}
X11ClipboardOzone::SelectionState& X11ClipboardOzone::GetSelectionState(
- XAtom selection) {
+ x11::Atom selection) {
DCHECK(Contains(selection_state_, selection));
return *selection_state_[selection];
}
-void X11ClipboardOzone::QueryTargets(XAtom selection) {
+void X11ClipboardOzone::QueryTargets(x11::Atom selection) {
GetSelectionState(selection).mime_types.clear();
- XConvertSelection(x_display_, selection, atom_targets_, x_property_,
- x_window_, x11::CurrentTime);
+ connection_->ConvertSelection({x_window_, selection, atom_targets_,
+ x_property_, x11::Time::CurrentTime});
}
-void X11ClipboardOzone::ReadRemoteClipboard(XAtom selection) {
+void X11ClipboardOzone::ReadRemoteClipboard(x11::Atom selection) {
auto& selection_state = GetSelectionState(selection);
selection_state.data.clear();
// Allow conversions for text/plain[;charset=utf-8] <=> [UTF8_]STRING.
@@ -359,23 +310,24 @@ void X11ClipboardOzone::ReadRemoteClipboard(XAtom selection) {
}
}
- XConvertSelection(x_display_, selection, gfx::GetAtom(target.c_str()),
- x_property_, x_window_, x11::CurrentTime);
+ connection_->ConvertSelection({x_window_, selection, gfx::GetAtom(target),
+ x_property_, x11::Time::CurrentTime});
}
void X11ClipboardOzone::OfferClipboardData(
ClipboardBuffer buffer,
const PlatformClipboard::DataMap& data_map,
PlatformClipboard::OfferDataClosure callback) {
- const XAtom selection = SelectionAtomForBuffer(buffer);
+ const x11::Atom selection = SelectionAtomForBuffer(buffer);
auto& selection_state = GetSelectionState(selection);
- const auto timestamp = X11EventSource::GetInstance()->GetTimestamp();
+ const auto timestamp =
+ static_cast<x11::Time>(X11EventSource::GetInstance()->GetTimestamp());
selection_state.acquired_selection_timestamp = timestamp;
selection_state.offer_data_map = data_map;
// Only take ownership if we are using xfixes.
// TODO(joelhockey): Make clipboard work without xfixes.
if (using_xfixes_) {
- XSetSelectionOwner(x_display_, selection, x_window_, timestamp);
+ connection_->SetSelectionOwner({x_window_, selection, timestamp});
}
std::move(callback).Run();
}
@@ -385,7 +337,7 @@ void X11ClipboardOzone::RequestClipboardData(
const std::string& mime_type,
PlatformClipboard::DataMap* data_map,
PlatformClipboard::RequestDataClosure callback) {
- const XAtom selection = SelectionAtomForBuffer(buffer);
+ const x11::Atom selection = SelectionAtomForBuffer(buffer);
auto& selection_state = GetSelectionState(selection);
// If we are not using xfixes, return empty data.
// TODO(joelhockey): Make clipboard work without xfixes.
@@ -408,7 +360,7 @@ void X11ClipboardOzone::RequestClipboardData(
void X11ClipboardOzone::GetAvailableMimeTypes(
ClipboardBuffer buffer,
PlatformClipboard::GetMimeTypesClosure callback) {
- const XAtom selection = SelectionAtomForBuffer(buffer);
+ const x11::Atom selection = SelectionAtomForBuffer(buffer);
auto& selection_state = GetSelectionState(selection);
// If we are not using xfixes, return empty data.
// TODO(joelhockey): Make clipboard work without xfixes.
@@ -432,8 +384,9 @@ bool X11ClipboardOzone::IsSelectionOwner(ClipboardBuffer buffer) {
if (!using_xfixes_)
return true;
- return XGetSelectionOwner(x_display_, SelectionAtomForBuffer(buffer)) ==
- x_window_;
+ auto reply =
+ connection_->GetSelectionOwner({SelectionAtomForBuffer(buffer)}).Sync();
+ return reply && reply->owner == x_window_;
}
void X11ClipboardOzone::SetSequenceNumberUpdateCb(
diff --git a/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.h b/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.h
index 8743c6cc53a..478205cd472 100644
--- a/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.h
+++ b/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.h
@@ -11,8 +11,11 @@
#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/x/event.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_types.h"
+#include "ui/gfx/x/xfixes.h"
+#include "ui/gfx/x/xproto.h"
#include "ui/ozone/public/platform_clipboard.h"
namespace ui {
@@ -51,61 +54,59 @@ class X11ClipboardOzone : public PlatformClipboard, public XEventDispatcher {
struct SelectionState;
// XEventDispatcher:
- bool DispatchXEvent(XEvent* xev) override;
+ bool DispatchXEvent(x11::Event* xev) override;
- bool OnSelectionRequest(const XSelectionRequestEvent& event);
- bool OnSelectionNotify(const XSelectionEvent& event);
- bool OnSetSelectionOwnerNotify(XEvent* xev);
+ bool OnSelectionRequest(const x11::SelectionRequestEvent& event);
+ bool OnSelectionNotify(const x11::SelectionNotifyEvent& event);
+ bool OnSetSelectionOwnerNotify(
+ const x11::XFixes::SelectionNotifyEvent& event);
// Returns an X atom for a clipboard buffer type.
- XAtom SelectionAtomForBuffer(ClipboardBuffer buffer) const;
+ x11::Atom SelectionAtomForBuffer(ClipboardBuffer buffer) const;
// Returns a clipboard buffer type for an X atom for a selection name of the
// system clipboard buffer.
- ClipboardBuffer BufferForSelectionAtom(XAtom selection) const;
+ ClipboardBuffer BufferForSelectionAtom(x11::Atom selection) const;
// Returns the state for the given selection;
- SelectionState& GetSelectionState(XAtom selection);
+ SelectionState& GetSelectionState(x11::Atom selection);
// Queries the current clipboard owner for what mime types are available by
// sending XConvertSelection with target=TARGETS. After sending this, we
// will receive a SelectionNotify event with xselection.target=TARGETS which
// is processed in |OnSelectionNotify|.
- void QueryTargets(XAtom selection);
+ void QueryTargets(x11::Atom selection);
// Reads the contents of the remote clipboard by sending XConvertSelection
// with target=<mime-type>. After sending this, we will receive a
// SelectionNotify event with xselection.target=<mime-type> which is processed
// in |OnSelectionNotify|.
- void ReadRemoteClipboard(XAtom selection);
+ void ReadRemoteClipboard(x11::Atom selection);
// Local cache of atoms.
- const XAtom atom_clipboard_;
- const XAtom atom_targets_;
- const XAtom atom_timestamp_;
+ const x11::Atom atom_clipboard_;
+ const x11::Atom atom_targets_;
+ const x11::Atom atom_timestamp_;
// The property on |x_window_| which will receive remote clipboard contents.
- const XAtom x_property_;
+ const x11::Atom x_property_;
// Our X11 state.
- Display* const x_display_;
+ x11::Connection* connection_;
// Input-only window used as a selection owner.
- const XID x_window_;
+ const x11::Window x_window_;
// If XFixes is unavailable, this clipboard window will not register to
// receive events and no processing will take place.
// TODO(joelhockey): Make clipboard work without xfixes.
bool using_xfixes_ = false;
- // The event base returned by XFixesQueryExtension().
- int xfixes_event_base_;
-
// Notifies whenever clipboard sequence number is changed.
PlatformClipboard::SequenceNumberUpdateCb update_sequence_cb_;
// State of selections served by this instance.
- base::flat_map<XAtom, std::unique_ptr<SelectionState>> selection_state_;
+ base::flat_map<x11::Atom, std::unique_ptr<SelectionState>> selection_state_;
DISALLOW_COPY_AND_ASSIGN(X11ClipboardOzone);
};
diff --git a/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.cc b/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.cc
deleted file mode 100644
index 1b9b47ff5f9..00000000000
--- a/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/ozone/platform/x11/x11_cursor_factory_ozone.h"
-
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/cursor/cursor_lookup.h"
-#include "ui/base/cursor/cursors_aura.h"
-#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
-#include "ui/gfx/geometry/point.h"
-
-namespace ui {
-
-namespace {
-
-X11CursorOzone* ToX11CursorOzone(PlatformCursor cursor) {
- return static_cast<X11CursorOzone*>(cursor);
-}
-
-PlatformCursor ToPlatformCursor(X11CursorOzone* cursor) {
- return static_cast<PlatformCursor>(cursor);
-}
-
-// Gets default aura cursor bitmap/hotspot and creates a X11CursorOzone with it.
-scoped_refptr<X11CursorOzone> CreateAuraX11Cursor(mojom::CursorType type) {
- Cursor cursor(type);
- cursor.set_image_scale_factor(1);
- SkBitmap bitmap = GetCursorBitmap(cursor);
- gfx::Point hotspot = GetCursorHotspot(cursor);
- if (!bitmap.isNull())
- return new X11CursorOzone(bitmap, hotspot);
- return nullptr;
-}
-
-} // namespace
-
-X11CursorFactoryOzone::X11CursorFactoryOzone()
- : invisible_cursor_(X11CursorOzone::CreateInvisible()) {}
-
-X11CursorFactoryOzone::~X11CursorFactoryOzone() {}
-
-PlatformCursor X11CursorFactoryOzone::GetDefaultCursor(mojom::CursorType type) {
- return ToPlatformCursor(GetDefaultCursorInternal(type).get());
-}
-
-PlatformCursor X11CursorFactoryOzone::CreateImageCursor(
- const SkBitmap& bitmap,
- const gfx::Point& hotspot,
- float bitmap_dpi) {
- // There is a problem with custom cursors that have no custom data. The
- // resulting SkBitmap is empty and X crashes when creating a zero size cursor
- // image. Return invisible cursor here instead.
- if (bitmap.drawsNothing()) {
- // The result of |invisible_cursor_| is owned by the caller, and will be
- // Unref()ed by code far away. (Usually in web_cursor.cc in content, among
- // others.) If we don't manually add another reference before we cast this
- // to a void*, we can end up with |invisible_cursor_| being freed out from
- // under us.
- invisible_cursor_->AddRef();
- return ToPlatformCursor(invisible_cursor_.get());
- }
-
- X11CursorOzone* cursor = new X11CursorOzone(bitmap, hotspot);
- cursor->AddRef();
- return ToPlatformCursor(cursor);
-}
-
-PlatformCursor X11CursorFactoryOzone::CreateAnimatedCursor(
- const std::vector<SkBitmap>& bitmaps,
- const gfx::Point& hotspot,
- int frame_delay_ms,
- float bitmap_dpi) {
- X11CursorOzone* cursor = new X11CursorOzone(bitmaps, hotspot, frame_delay_ms);
- cursor->AddRef();
- return ToPlatformCursor(cursor);
-}
-
-void X11CursorFactoryOzone::RefImageCursor(PlatformCursor cursor) {
- ToX11CursorOzone(cursor)->AddRef();
-}
-
-void X11CursorFactoryOzone::UnrefImageCursor(PlatformCursor cursor) {
- ToX11CursorOzone(cursor)->Release();
-}
-
-scoped_refptr<X11CursorOzone> X11CursorFactoryOzone::GetDefaultCursorInternal(
- mojom::CursorType type) {
- if (type == mojom::CursorType::kNone)
- return invisible_cursor_;
-
- if (!default_cursors_.count(type)) {
- // First try to load a predefined X11 cursor.
- auto cursor =
- base::MakeRefCounted<X11CursorOzone>(CursorCssNameFromId(type));
- if (cursor->xcursor() != x11::None) {
- default_cursors_[type] = cursor;
- return cursor;
- }
-
- // Loads the default aura cursor bitmap for cursor type. Falls back on
- // pointer cursor then invisible cursor if this fails.
- cursor = CreateAuraX11Cursor(type);
- if (!cursor.get()) {
- if (type != mojom::CursorType::kPointer) {
- cursor = GetDefaultCursorInternal(mojom::CursorType::kPointer);
- } else {
- NOTREACHED() << "Failed to load default cursor bitmap";
- }
- }
- default_cursors_[type] = cursor;
- }
-
- // Returns owned default cursor for this type.
- return default_cursors_[type];
-}
-
-} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.h b/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.h
deleted file mode 100644
index 76efeeb526d..00000000000
--- a/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OZONE_PLATFORM_X11_X11_CURSOR_FACTORY_OZONE_H_
-#define UI_OZONE_PLATFORM_X11_X11_CURSOR_FACTORY_OZONE_H_
-
-#include <map>
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "ui/base/cursor/cursor.h"
-#include "ui/base/cursor/mojom/cursor_type.mojom-forward.h"
-#include "ui/gfx/x/x11.h"
-#include "ui/ozone/platform/x11/x11_cursor_ozone.h"
-#include "ui/ozone/public/cursor_factory_ozone.h"
-
-namespace ui {
-
-// CursorFactoryOzone implementation for X11 cursors.
-class X11CursorFactoryOzone : public CursorFactoryOzone {
- public:
- X11CursorFactoryOzone();
- ~X11CursorFactoryOzone() override;
-
- // CursorFactoryOzone:
- PlatformCursor GetDefaultCursor(mojom::CursorType type) override;
- PlatformCursor CreateImageCursor(const SkBitmap& bitmap,
- const gfx::Point& hotspot,
- float bitmap_dpi) override;
- PlatformCursor CreateAnimatedCursor(const std::vector<SkBitmap>& bitmaps,
- const gfx::Point& hotspot,
- int frame_delay_ms,
- float bitmap_dpi) override;
- void RefImageCursor(PlatformCursor cursor) override;
- void UnrefImageCursor(PlatformCursor cursor) override;
-
- private:
- // Loads/caches default cursor or returns cached version.
- scoped_refptr<X11CursorOzone> GetDefaultCursorInternal(
- mojom::CursorType type);
-
- // Holds a single instance of the invisible cursor. X11 has no way to hide
- // the cursor so an invisible cursor mimics that.
- scoped_refptr<X11CursorOzone> invisible_cursor_;
-
- std::map<mojom::CursorType, scoped_refptr<X11CursorOzone>> default_cursors_;
-
- DISALLOW_COPY_AND_ASSIGN(X11CursorFactoryOzone);
-};
-
-} // namespace ui
-
-#endif // UI_OZONE_PLATFORM_X11_X11_CURSOR_FACTORY_OZONE_H_
diff --git a/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone_unittest.cc b/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone_unittest.cc
deleted file mode 100644
index 8b065eb100b..00000000000
--- a/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone_unittest.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/ozone/platform/x11/x11_cursor_factory_ozone.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/geometry/point.h"
-
-namespace ui {
-
-TEST(X11CursorFactoryOzoneTest, InvisibleRefcount) {
- X11CursorFactoryOzone factory;
-
- // Building an image cursor with an invalid SkBitmap should return the
- // invisible cursor in X11. The invisible cursor instance should have more
- // than a single reference since the factory should hold a reference and
- // CreateImageCursor should return an incremented refcount.
- X11CursorOzone* invisible_cursor = static_cast<X11CursorOzone*>(
- factory.CreateImageCursor(SkBitmap(), gfx::Point(), 1.0f));
- ASSERT_FALSE(invisible_cursor->HasOneRef());
-
- // Release our refcount on the cursor
- factory.UnrefImageCursor(invisible_cursor);
-
- // The invisible cursor should still exist.
- EXPECT_TRUE(invisible_cursor->HasOneRef());
-}
-
-} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/x11_cursor_ozone.cc b/chromium/ui/ozone/platform/x11/x11_cursor_ozone.cc
deleted file mode 100644
index 64eb043d301..00000000000
--- a/chromium/ui/ozone/platform/x11/x11_cursor_ozone.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/ozone/platform/x11/x11_cursor_ozone.h"
-
-#include "base/check_op.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/x/x11_util.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/x/x11.h"
-
-namespace ui {
-
-X11CursorOzone::X11CursorOzone(const SkBitmap& bitmap,
- const gfx::Point& hotspot) {
- XcursorImage* image = SkBitmapToXcursorImage(bitmap, hotspot);
- xcursor_ = XcursorImageLoadCursor(gfx::GetXDisplay(), image);
- XcursorImageDestroy(image);
-}
-
-X11CursorOzone::X11CursorOzone(const std::vector<SkBitmap>& bitmaps,
- const gfx::Point& hotspot,
- int frame_delay_ms) {
- // Initialize an XCursorImage for each frame, store all of them in
- // XCursorImages and load the cursor from that.
- XcursorImages* images = XcursorImagesCreate(bitmaps.size());
- images->nimage = bitmaps.size();
- for (size_t frame = 0; frame < bitmaps.size(); ++frame) {
- XcursorImage* x_image = SkBitmapToXcursorImage(bitmaps[frame], hotspot);
- x_image->delay = frame_delay_ms;
- images->images[frame] = x_image;
- }
-
- xcursor_ = XcursorImagesLoadCursor(gfx::GetXDisplay(), images);
- XcursorImagesDestroy(images);
-}
-
-X11CursorOzone::X11CursorOzone(const char* name) {
- xcursor_ = XcursorLibraryLoadCursor(gfx::GetXDisplay(), name);
-}
-
-// static
-scoped_refptr<X11CursorOzone> X11CursorOzone::CreateInvisible() {
- scoped_refptr<X11CursorOzone> invisible_ = new X11CursorOzone();
- invisible_->xcursor_ = CreateInvisibleCursor();
- return invisible_;
-}
-
-X11CursorOzone::X11CursorOzone() {}
-
-X11CursorOzone::~X11CursorOzone() {
- XFreeCursor(gfx::GetXDisplay(), xcursor_);
-}
-
-} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/x11_cursor_ozone.h b/chromium/ui/ozone/platform/x11/x11_cursor_ozone.h
deleted file mode 100644
index 6718abae17d..00000000000
--- a/chromium/ui/ozone/platform/x11/x11_cursor_ozone.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OZONE_PLATFORM_X11_X11_CURSOR_OZONE_H_
-#define UI_OZONE_PLATFORM_X11_X11_CURSOR_OZONE_H_
-
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "ui/base/cursor/cursor.h"
-#include "ui/gfx/x/x11.h"
-
-class SkBitmap;
-
-namespace gfx {
-class Point;
-}
-
-namespace ui {
-
-// Ref counted class to hold an X11 cursor resource. Clears the X11 resources
-// on destruction
-class X11CursorOzone : public base::RefCounted<X11CursorOzone> {
- public:
- // Handles creating X11 cursor resources from SkBitmap/hotspot.
- X11CursorOzone(const SkBitmap& bitmap, const gfx::Point& hotspot);
- X11CursorOzone(const std::vector<SkBitmap>& bitmaps,
- const gfx::Point& hotspot,
- int frame_delay_ms);
- // Loads an X11 cursor named |name| by calling XcursorLibraryLoadCursor().
- // May end up wrapping an x11::None so validity must be checked after using
- // this constructor.
- explicit X11CursorOzone(const char* name);
-
- // Creates a new cursor that is invisible.
- static scoped_refptr<X11CursorOzone> CreateInvisible();
-
- XID xcursor() const { return xcursor_; }
-
- private:
- friend class base::RefCounted<X11CursorOzone>;
-
- X11CursorOzone();
- ~X11CursorOzone();
-
- XID xcursor_ = x11::None;
-
- DISALLOW_COPY_AND_ASSIGN(X11CursorOzone);
-};
-
-} // namespace ui
-
-#endif // UI_OZONE_PLATFORM_X11_X11_CURSOR_OZONE_H_
diff --git a/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.cc b/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.cc
index 7a31cb62ec9..7ede65f0e9c 100644
--- a/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.cc
+++ b/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.cc
@@ -6,13 +6,14 @@
#include <utility>
-#include "base/logging.h"
+#include "base/check.h"
+#include "base/notreached.h"
#include "ui/base/x/selection_utils.h"
namespace ui {
X11OSExchangeDataProviderOzone::X11OSExchangeDataProviderOzone(
- XID x_window,
+ x11::Window x_window,
const SelectionFormatMap& selection)
: XOSExchangeDataProvider(x_window, selection) {}
@@ -34,13 +35,14 @@ std::unique_ptr<OSExchangeDataProvider> X11OSExchangeDataProviderOzone::Clone()
return std::move(ret);
}
-bool X11OSExchangeDataProviderOzone::DispatchXEvent(XEvent* xev) {
- if (xev->xany.window != x_window())
+bool X11OSExchangeDataProviderOzone::DispatchXEvent(x11::Event* x11_event) {
+ XEvent* xev = &x11_event->xlib_event();
+ if (xev->xany.window != static_cast<uint32_t>(x_window()))
return false;
switch (xev->type) {
- case SelectionRequest:
- selection_owner().OnSelectionRequest(*xev);
+ case x11::SelectionRequestEvent::opcode:
+ selection_owner().OnSelectionRequest(*x11_event);
return true;
default:
NOTIMPLEMENTED();
diff --git a/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h b/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h
index 7a0637318fc..65542ea14d3 100644
--- a/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h
+++ b/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h
@@ -7,6 +7,7 @@
#include "ui/base/x/x11_os_exchange_data_provider.h"
#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/x/event.h"
namespace ui {
@@ -14,7 +15,7 @@ namespace ui {
class X11OSExchangeDataProviderOzone : public XOSExchangeDataProvider,
public XEventDispatcher {
public:
- X11OSExchangeDataProviderOzone(XID x_window,
+ X11OSExchangeDataProviderOzone(x11::Window x_window,
const SelectionFormatMap& selection);
X11OSExchangeDataProviderOzone();
~X11OSExchangeDataProviderOzone() override;
@@ -27,7 +28,7 @@ class X11OSExchangeDataProviderOzone : public XOSExchangeDataProvider,
std::unique_ptr<OSExchangeDataProvider> Clone() const override;
// XEventDispatcher:
- bool DispatchXEvent(XEvent* xev) override;
+ bool DispatchXEvent(x11::Event* xev) override;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc b/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc
index 5e9cf05b0a3..76aeb9e1c14 100644
--- a/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc
+++ b/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc
@@ -10,8 +10,9 @@
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/font_render_params.h"
#include "ui/gfx/geometry/dip_util.h"
-#include "ui/ozone/platform/x11/x11_window_ozone.h"
+#include "ui/gfx/native_widget_types.h"
#include "ui/platform_window/x11/x11_topmost_window_finder.h"
+#include "ui/platform_window/x11/x11_window.h"
#include "ui/platform_window/x11/x11_window_manager.h"
namespace ui {
@@ -86,14 +87,15 @@ gfx::Point X11ScreenOzone::GetCursorScreenPoint() const {
gfx::AcceleratedWidget X11ScreenOzone::GetAcceleratedWidgetAtScreenPoint(
const gfx::Point& point) const {
X11TopmostWindowFinder finder;
- return finder.FindWindowAt(point);
+ return static_cast<gfx::AcceleratedWidget>(finder.FindWindowAt(point));
}
gfx::AcceleratedWidget X11ScreenOzone::GetLocalProcessWidgetAtPoint(
const gfx::Point& point,
const std::set<gfx::AcceleratedWidget>& ignore) const {
X11TopmostWindowFinder finder;
- return finder.FindLocalProcessWindowAt(point, ignore);
+ return static_cast<gfx::AcceleratedWidget>(
+ finder.FindLocalProcessWindowAt(point, ignore));
}
display::Display X11ScreenOzone::GetDisplayNearestPoint(
@@ -125,7 +127,7 @@ std::string X11ScreenOzone::GetCurrentWorkspace() {
return x11_display_manager_->GetCurrentWorkspace();
}
-bool X11ScreenOzone::DispatchXEvent(XEvent* xev) {
+bool X11ScreenOzone::DispatchXEvent(x11::Event* xev) {
return x11_display_manager_->ProcessEvent(xev);
}
diff --git a/chromium/ui/ozone/platform/x11/x11_screen_ozone.h b/chromium/ui/ozone/platform/x11/x11_screen_ozone.h
index 02806ba53fc..de7d392d17b 100644
--- a/chromium/ui/ozone/platform/x11/x11_screen_ozone.h
+++ b/chromium/ui/ozone/platform/x11/x11_screen_ozone.h
@@ -14,6 +14,7 @@
#include "ui/base/x/x11_display_manager.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/x/event.h"
#include "ui/ozone/public/platform_screen.h"
namespace ui {
@@ -51,7 +52,7 @@ class X11ScreenOzone : public PlatformScreen,
std::string GetCurrentWorkspace() override;
// Overridden from ui::XEventDispatcher:
- bool DispatchXEvent(XEvent* event) override;
+ bool DispatchXEvent(x11::Event* event) override;
private:
friend class X11ScreenOzoneTest;
diff --git a/chromium/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc b/chromium/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc
index 121a6ccc77c..5b2ac245341 100644
--- a/chromium/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc
+++ b/chromium/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc
@@ -13,10 +13,10 @@
#include "ui/display/display.h"
#include "ui/display/display_observer.h"
#include "ui/events/platform/x11/x11_event_source.h"
-#include "ui/ozone/platform/x11/x11_window_ozone.h"
#include "ui/ozone/test/mock_platform_window_delegate.h"
#include "ui/platform_window/platform_window_delegate.h"
#include "ui/platform_window/platform_window_init_properties.h"
+#include "ui/platform_window/x11/x11_window.h"
#include "ui/platform_window/x11/x11_window_manager.h"
using ::testing::_;
@@ -95,14 +95,14 @@ class X11ScreenOzoneTest : public testing::Test {
manager->displays_);
}
- std::unique_ptr<X11WindowOzone> CreatePlatformWindow(
+ std::unique_ptr<X11Window> CreatePlatformWindow(
MockPlatformWindowDelegate* delegate,
const gfx::Rect& bounds,
gfx::AcceleratedWidget* widget = nullptr) {
EXPECT_CALL(*delegate, OnAcceleratedWidgetAvailable(_))
.WillOnce(StoreWidget(widget));
PlatformWindowInitProperties init_params(bounds);
- auto window = std::make_unique<X11WindowOzone>(delegate);
+ auto window = std::make_unique<X11Window>(delegate);
window->Initialize(std::move(init_params));
return window;
}
diff --git a/chromium/ui/ozone/platform/x11/x11_surface_factory.cc b/chromium/ui/ozone/platform/x11/x11_surface_factory.cc
index a0daef0e754..d747464e40f 100644
--- a/chromium/ui/ozone/platform/x11/x11_surface_factory.cc
+++ b/chromium/ui/ozone/platform/x11/x11_surface_factory.cc
@@ -43,7 +43,8 @@ class GLOzoneEGLX11 : public GLOzoneEGL {
base::MakeRefCounted<GLSurfaceEglReadbackX11>(window));
} else {
return gl::InitializeGLSurface(
- base::MakeRefCounted<gl::NativeViewGLSurfaceEGLX11GLES2>(window));
+ base::MakeRefCounted<gl::NativeViewGLSurfaceEGLX11GLES2>(
+ static_cast<x11::Window>(window)));
}
}
diff --git a/chromium/ui/ozone/platform/x11/x11_window_ozone.cc b/chromium/ui/ozone/platform/x11/x11_window_ozone.cc
deleted file mode 100644
index 66658dc1d92..00000000000
--- a/chromium/ui/ozone/platform/x11/x11_window_ozone.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/ozone/platform/x11/x11_window_ozone.h"
-
-#include "ui/base/dragdrop/os_exchange_data.h"
-#include "ui/base/x/x11_os_exchange_data_provider.h"
-#include "ui/base/x/x11_pointer_grab.h"
-#include "ui/base/x/x11_topmost_window_finder.h"
-#include "ui/events/event.h"
-#include "ui/events/platform/scoped_event_dispatcher.h"
-#include "ui/events/platform/x11/x11_event_source.h"
-#include "ui/events/x/x11_window_event_manager.h"
-#include "ui/ozone/platform/x11/x11_cursor_ozone.h"
-#include "ui/platform_window/platform_window_delegate.h"
-#include "ui/platform_window/platform_window_handler/wm_drop_handler.h"
-#include "ui/platform_window/x11/x11_topmost_window_finder.h"
-#include "ui/platform_window/x11/x11_window_manager.h"
-
-namespace ui {
-
-X11WindowOzone::X11WindowOzone(PlatformWindowDelegate* delegate)
- : X11Window(delegate) {}
-
-X11WindowOzone::~X11WindowOzone() = default;
-
-void X11WindowOzone::SetCursor(PlatformCursor cursor) {
- X11CursorOzone* cursor_ozone = static_cast<X11CursorOzone*>(cursor);
- XWindow::SetCursor(cursor_ozone->xcursor());
-}
-
-void X11WindowOzone::Initialize(PlatformWindowInitProperties properties) {
- X11Window::Initialize(std::move(properties));
- // Set a class property key that allows |this| to be used for drag action.
- SetWmDragHandler(this, this);
-
- drag_drop_client_ =
- std::make_unique<XDragDropClient>(this, display(), window());
-}
-
-void X11WindowOzone::StartDrag(const ui::OSExchangeData& data,
- int operation,
- gfx::NativeCursor cursor,
- base::OnceCallback<void(int)> callback) {
- DCHECK(drag_drop_client_);
-
- end_drag_callback_ = std::move(callback);
- drag_drop_client_->InitDrag(operation, &data);
-
- SetCapture();
-
- dragging_ = true;
-}
-
-std::unique_ptr<ui::XTopmostWindowFinder> X11WindowOzone::CreateWindowFinder() {
- return std::make_unique<X11TopmostWindowFinder>();
-}
-
-int X11WindowOzone::UpdateDrag(const gfx::Point& screen_point) {
- WmDropHandler* drop_handler = GetWmDropHandler(*this);
- if (!drop_handler)
- return ui::DragDropTypes::DRAG_NONE;
- // TODO: calculate the appropriate drag operation here.
- return drop_handler->OnDragMotion(gfx::PointF(screen_point),
- ui::DragDropTypes::DRAG_COPY);
-}
-
-void X11WindowOzone::UpdateCursor(
- ui::DragDropTypes::DragOperation negotiated_operation) {
- NOTIMPLEMENTED_LOG_ONCE();
-}
-
-void X11WindowOzone::OnBeginForeignDrag(XID window) {
- NOTIMPLEMENTED_LOG_ONCE();
-}
-
-void X11WindowOzone::OnEndForeignDrag() {
- NOTIMPLEMENTED_LOG_ONCE();
-}
-
-void X11WindowOzone::OnBeforeDragLeave() {
- NOTIMPLEMENTED_LOG_ONCE();
-}
-
-int X11WindowOzone::PerformDrop() {
- WmDropHandler* drop_handler = GetWmDropHandler(*this);
- if (!drop_handler)
- return ui::DragDropTypes::DRAG_NONE;
-
- DCHECK(drag_drop_client_);
- auto* target_current_context = drag_drop_client_->target_current_context();
- DCHECK(target_current_context);
-
- int drag_operation = ui::DragDropTypes::DRAG_NONE;
-
- drop_handler->OnDragDrop(std::make_unique<ui::OSExchangeData>(
- std::make_unique<ui::XOSExchangeDataProvider>(
- drag_drop_client_->xwindow(),
- target_current_context->fetched_targets())));
- return drag_operation;
-}
-
-void X11WindowOzone::EndMoveLoop() {
- std::move(end_drag_callback_).Run(0);
-}
-
-bool X11WindowOzone::DispatchDraggingUiEvent(ui::Event* event) {
- // Drag and drop have a priority over other processing.
- if (dragging_) {
- DCHECK(drag_drop_client_);
-
- switch (event->type()) {
- case ui::ET_MOUSE_MOVED:
- case ui::ET_MOUSE_DRAGGED: {
- drag_drop_client_->HandleMouseMovement(
- event->AsLocatedEvent()->root_location(),
- event->AsMouseEvent()->flags(),
- event->AsMouseEvent()->time_stamp());
- return true;
- }
- case ui::ET_MOUSE_RELEASED:
- if (!event->AsMouseEvent()->IsLeftMouseButton())
- break;
- // Assume that drags are being done with the left mouse button. Only
- // break the drag if the left mouse button was released.
- drag_drop_client_->HandleMouseReleased();
- dragging_ = false;
- ReleaseCapture();
- return true;
- case ui::ET_KEY_PRESSED:
- if (event->AsKeyEvent()->key_code() != ui::VKEY_ESCAPE)
- break;
- EndMoveLoop();
- drag_drop_client_->HandleMoveLoopEnded();
- dragging_ = false;
- ReleaseCapture();
- return true;
- default:
- break;
- }
- }
- return false;
-}
-
-void X11WindowOzone::OnXWindowSelectionEvent(XEvent* xev) {
- X11Window::OnXWindowSelectionEvent(xev);
- DCHECK(drag_drop_client_);
- drag_drop_client_->OnSelectionNotify(xev->xselection);
-}
-
-void X11WindowOzone::OnXWindowDragDropEvent(XEvent* xev) {
- X11Window::OnXWindowDragDropEvent(xev);
- DCHECK(drag_drop_client_);
- drag_drop_client_->HandleXdndEvent(xev->xclient);
-}
-
-} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/x11_window_ozone.h b/chromium/ui/ozone/platform/x11/x11_window_ozone.h
deleted file mode 100644
index 3e2a83fe42d..00000000000
--- a/chromium/ui/ozone/platform/x11/x11_window_ozone.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OZONE_PLATFORM_X11_X11_WINDOW_OZONE_H_
-#define UI_OZONE_PLATFORM_X11_X11_WINDOW_OZONE_H_
-
-#include "ui/base/x/x11_drag_drop_client.h"
-#include "ui/platform_window/platform_window_handler/wm_drag_handler.h"
-#include "ui/platform_window/x11/x11_window.h"
-
-namespace ui {
-
-class PlatformWindowDelegate;
-
-// PlatformWindow implementation for non-ChromeOS X11 Ozone.
-// PlatformEvents are ui::Events.
-class X11WindowOzone : public X11Window,
- public WmDragHandler,
- public XDragDropClient::Delegate {
- public:
- explicit X11WindowOzone(PlatformWindowDelegate* delegate);
- ~X11WindowOzone() override;
-
- X11WindowOzone(const X11WindowOzone&) = delete;
- X11WindowOzone& operator=(const X11WindowOzone&) = delete;
-
- // Overridden from PlatformWindow:
- void SetCursor(PlatformCursor cursor) override;
-
- // Overridden from X11Window:
- void Initialize(PlatformWindowInitProperties properties) override;
-
- private:
- // WmDragHandler
- void StartDrag(const ui::OSExchangeData& data,
- int operation,
- gfx::NativeCursor cursor,
- base::OnceCallback<void(int)> callback) override;
-
- // ui::XDragDropClient::Delegate
- std::unique_ptr<ui::XTopmostWindowFinder> CreateWindowFinder() override;
- int UpdateDrag(const gfx::Point& screen_point) override;
- void UpdateCursor(
- ui::DragDropTypes::DragOperation negotiated_operation) override;
- void OnBeginForeignDrag(XID window) override;
- void OnEndForeignDrag() override;
- void OnBeforeDragLeave() override;
- int PerformDrop() override;
- void EndMoveLoop() override;
-
- // X11Window:
- bool DispatchDraggingUiEvent(ui::Event* event) override;
- void OnXWindowSelectionEvent(XEvent* xev) override;
- void OnXWindowDragDropEvent(XEvent* xev) override;
-
- // True while the drag initiated in this window is in progress.
- bool dragging_ = false;
-
- std::unique_ptr<XDragDropClient> drag_drop_client_;
- base::OnceCallback<void(int)> end_drag_callback_;
-};
-
-} // namespace ui
-
-#endif // UI_OZONE_PLATFORM_X11_X11_WINDOW_OZONE_H_
diff --git a/chromium/ui/ozone/platform/x11/x11_window_ozone_chromeos.cc b/chromium/ui/ozone/platform/x11/x11_window_ozone_chromeos.cc
deleted file mode 100644
index d4f22451189..00000000000
--- a/chromium/ui/ozone/platform/x11/x11_window_ozone_chromeos.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/ozone/platform/x11/x11_window_ozone_chromeos.h"
-
-#include "ui/events/event.h"
-#include "ui/ozone/platform/x11/x11_cursor_ozone.h"
-#include "ui/platform_window/platform_window_delegate.h"
-#include "ui/platform_window/x11/x11_window_manager.h"
-
-namespace ui {
-
-X11WindowOzone::X11WindowOzone(PlatformWindowDelegate* delegate)
- : X11Window(delegate) {}
-
-X11WindowOzone::~X11WindowOzone() = default;
-
-void X11WindowOzone::SetCursor(PlatformCursor cursor) {
- X11CursorOzone* cursor_ozone = static_cast<X11CursorOzone*>(cursor);
- XWindow::SetCursor(cursor_ozone->xcursor());
-}
-
-void X11WindowOzone::Initialize(PlatformWindowInitProperties properties) {
- X11Window::Initialize(std::move(properties));
-}
-
-} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/x11_window_ozone_chromeos.h b/chromium/ui/ozone/platform/x11/x11_window_ozone_chromeos.h
deleted file mode 100644
index 3bcdec53c3c..00000000000
--- a/chromium/ui/ozone/platform/x11/x11_window_ozone_chromeos.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OZONE_PLATFORM_X11_X11_WINDOW_OZONE_CHROMEOS_H_
-#define UI_OZONE_PLATFORM_X11_X11_WINDOW_OZONE_CHROMEOS_H_
-
-#include "base/macros.h"
-#include "ui/platform_window/x11/x11_window.h"
-
-namespace ui {
-
-class PlatformWindowDelegate;
-
-// PlatformWindow implementation for ChromeOS X11 Ozone.
-// PlatformEvents are ui::Events.
-class X11WindowOzone : public X11Window {
- public:
- explicit X11WindowOzone(PlatformWindowDelegate* delegate);
- ~X11WindowOzone() override;
-
- // Overridden from PlatformWindow:
- void SetCursor(PlatformCursor cursor) override;
-
- // Overridden from X11Window:
- void Initialize(PlatformWindowInitProperties properties) override;
-
- DISALLOW_COPY_AND_ASSIGN(X11WindowOzone);
-};
-
-} // namespace ui
-
-#endif // UI_OZONE_PLATFORM_X11_X11_WINDOW_OZONE_CHROMEOS_H_
diff --git a/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc b/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
index e2c5fb1f609..ddf6448c669 100644
--- a/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
+++ b/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/ozone/platform/x11/x11_window_ozone.h"
+#include "ui/platform_window/x11/x11_window.h"
#include <memory>
#include <utility>
@@ -16,6 +16,7 @@
#include "ui/events/event.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/events/test/events_test_utils_x11.h"
+#include "ui/gfx/x/event.h"
#include "ui/ozone/test/mock_platform_window_delegate.h"
#include "ui/platform_window/platform_window_delegate.h"
#include "ui/platform_window/platform_window_init_properties.h"
@@ -45,9 +46,7 @@ ACTION_P(CloneEvent, event_ptr) {
// is more than enough.
class TestScreen : public display::ScreenBase {
public:
- TestScreen() {
- ProcessDisplayChanged({}, true);
- }
+ TestScreen() { ProcessDisplayChanged({}, true); }
~TestScreen() override = default;
TestScreen(const TestScreen& screen) = delete;
TestScreen& operator=(const TestScreen& screen) = delete;
@@ -88,16 +87,18 @@ class X11WindowOzoneTest : public testing::Test {
EXPECT_CALL(*delegate, OnAcceleratedWidgetAvailable(_))
.WillOnce(StoreWidget(widget));
PlatformWindowInitProperties init_params(bounds);
- auto window = std::make_unique<X11WindowOzone>(delegate);
+ auto window = std::make_unique<X11Window>(delegate);
window->Initialize(std::move(init_params));
return std::move(window);
}
- void DispatchXEvent(XEvent* event, gfx::AcceleratedWidget widget) {
- DCHECK_EQ(GenericEvent, event->type);
+ void DispatchXEvent(x11::Event* event, gfx::AcceleratedWidget widget) {
+ DCHECK_EQ(x11::GeGenericEvent::opcode, event->xlib_event().type);
XIDeviceEvent* device_event =
- static_cast<XIDeviceEvent*>(event->xcookie.data);
+ static_cast<XIDeviceEvent*>(event->xlib_event().xcookie.data);
device_event->event = widget;
+ event->As<x11::Input::DeviceEvent>()->event =
+ static_cast<x11::Window>(widget);
event_source_->ProcessXEvent(event);
}
@@ -186,8 +187,8 @@ TEST_F(X11WindowOzoneTest, SendPlatformEventToCapturedWindow) {
EXPECT_EQ(gfx::Point(-277, 215), event->AsLocatedEvent()->location());
}
-// This test case ensures window_manager properly provides X11WindowOzone
-// instances as they are created/destroyed.
+// This test case ensures window_manager properly provides X11Window instances
+// as they are created/destroyed.
TEST_F(X11WindowOzoneTest, GetWindowFromAcceleratedWigets) {
MockPlatformWindowDelegate delegate;
gfx::Rect bounds(0, 0, 100, 100);
@@ -225,12 +226,12 @@ TEST_F(X11WindowOzoneTest, MouseEnterAndDelete) {
auto window_2 = CreatePlatformWindow(&delegate_2, bounds_2, &widget_2);
EXPECT_CALL(delegate_1, OnMouseEnter()).Times(1);
- window_manager()->MouseOnWindow(static_cast<X11WindowOzone*>(window_1.get()));
+ window_manager()->MouseOnWindow(static_cast<X11Window*>(window_1.get()));
// The mouse is already on window_1, and this should not call OnMouseEnter.
- window_manager()->MouseOnWindow(static_cast<X11WindowOzone*>(window_1.get()));
+ window_manager()->MouseOnWindow(static_cast<X11Window*>(window_1.get()));
EXPECT_CALL(delegate_2, OnMouseEnter()).Times(1);
- window_manager()->MouseOnWindow(static_cast<X11WindowOzone*>(window_2.get()));
+ window_manager()->MouseOnWindow(static_cast<X11Window*>(window_2.get()));
EXPECT_EQ(window_2.get(),
window_manager()->window_mouse_currently_on_for_test());
diff --git a/chromium/ui/ozone/public/cursor_factory_ozone.cc b/chromium/ui/ozone/public/cursor_factory_ozone.cc
deleted file mode 100644
index 95caf2a8a0b..00000000000
--- a/chromium/ui/ozone/public/cursor_factory_ozone.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/ozone/public/cursor_factory_ozone.h"
-
-#include "base/check_op.h"
-#include "base/notreached.h"
-
-namespace ui {
-
-namespace {
-
-CursorFactoryOzone* g_instance = nullptr;
-
-} // namespace
-
-CursorFactoryOzone::CursorFactoryOzone() {
- DCHECK(!g_instance)
- << "There should only be a single CursorFactoryOzone per thread.";
- g_instance = this;
-}
-
-CursorFactoryOzone::~CursorFactoryOzone() {
- DCHECK_EQ(g_instance, this);
- g_instance = nullptr;
-}
-
-CursorFactoryOzone* CursorFactoryOzone::GetInstance() {
- DCHECK(g_instance);
- return g_instance;
-}
-
-PlatformCursor CursorFactoryOzone::GetDefaultCursor(mojom::CursorType type) {
- NOTIMPLEMENTED();
- return NULL;
-}
-
-PlatformCursor CursorFactoryOzone::CreateImageCursor(const SkBitmap& bitmap,
- const gfx::Point& hotspot,
- float bitmap_dpi) {
- NOTIMPLEMENTED();
- return NULL;
-}
-
-PlatformCursor CursorFactoryOzone::CreateAnimatedCursor(
- const std::vector<SkBitmap>& bitmaps,
- const gfx::Point& hotspot,
- int frame_delay_ms,
- float bitmap_dpi) {
- NOTIMPLEMENTED();
- return NULL;
-}
-
-void CursorFactoryOzone::RefImageCursor(PlatformCursor cursor) {
- NOTIMPLEMENTED();
-}
-
-void CursorFactoryOzone::UnrefImageCursor(PlatformCursor cursor) {
- NOTIMPLEMENTED();
-}
-
-} // namespace ui
diff --git a/chromium/ui/ozone/public/cursor_factory_ozone.h b/chromium/ui/ozone/public/cursor_factory_ozone.h
deleted file mode 100644
index a179bf08e73..00000000000
--- a/chromium/ui/ozone/public/cursor_factory_ozone.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OZONE_PUBLIC_CURSOR_FACTORY_OZONE_H_
-#define UI_OZONE_PUBLIC_CURSOR_FACTORY_OZONE_H_
-
-#include <vector>
-
-#include "base/component_export.h"
-#include "ui/base/cursor/mojom/cursor_type.mojom-forward.h"
-#include "ui/gfx/native_widget_types.h"
-
-namespace gfx {
-class Point;
-}
-
-namespace ui {
-
-typedef void* PlatformCursor;
-
-class COMPONENT_EXPORT(OZONE_BASE) CursorFactoryOzone {
- public:
- CursorFactoryOzone();
- virtual ~CursorFactoryOzone();
-
- // Returns the thread-local instance.
- static CursorFactoryOzone* GetInstance();
-
- // Return the default cursor of the specified type. The types are listed in
- // ui/base/cursor/cursor.h. Default cursors are managed by the implementation
- // and must live indefinitely; there's no way to know when to free them.
- virtual PlatformCursor GetDefaultCursor(mojom::CursorType type);
-
- // Return a image cursor from the specified image & hotspot. Image cursors
- // are referenced counted and have an initial refcount of 1. Therefore, each
- // CreateImageCursor call must be matched with a call to UnrefImageCursor.
- virtual PlatformCursor CreateImageCursor(const SkBitmap& bitmap,
- const gfx::Point& hotspot,
- float bitmap_dpi);
-
- // Return a animated cursor from the specified image & hotspot. Animated
- // cursors are referenced counted and have an initial refcount of 1.
- // Therefore, each CreateAnimatedCursor call must be matched with a call to
- // UnrefImageCursor.
- virtual PlatformCursor CreateAnimatedCursor(
- const std::vector<SkBitmap>& bitmaps,
- const gfx::Point& hotspot,
- int frame_delay_ms,
- float bitmap_dpi);
-
- // Increment platform image cursor refcount.
- virtual void RefImageCursor(PlatformCursor cursor);
-
- // Decrement platform image cursor refcount.
- virtual void UnrefImageCursor(PlatformCursor cursor);
-};
-
-} // namespace ui
-
-#endif // UI_OZONE_PUBLIC_CURSOR_FACTORY_OZONE_H_
diff --git a/chromium/ui/ozone/public/input_controller.cc b/chromium/ui/ozone/public/input_controller.cc
index 2f2bd8688a3..6b12bb5dff6 100644
--- a/chromium/ui/ozone/public/input_controller.cc
+++ b/chromium/ui/ozone/public/input_controller.cc
@@ -46,6 +46,8 @@ class StubInputController : public InputController {
void SetPrimaryButtonRight(bool right) override {}
void SetMouseReverseScroll(bool enabled) override {}
void SetMouseAcceleration(bool enabled) override {}
+ void SuspendMouseAcceleration() override {}
+ void EndMouseAccelerationSuspension() override {}
void SetMouseScrollAcceleration(bool enabled) override {}
void SetTouchpadAcceleration(bool enabled) override {}
void SetTouchpadScrollAcceleration(bool enabled) override {}
diff --git a/chromium/ui/ozone/public/input_controller.h b/chromium/ui/ozone/public/input_controller.h
index cc7c323f683..6de884cb29f 100644
--- a/chromium/ui/ozone/public/input_controller.h
+++ b/chromium/ui/ozone/public/input_controller.h
@@ -73,6 +73,8 @@ class COMPONENT_EXPORT(OZONE_BASE) InputController {
virtual void SetPrimaryButtonRight(bool right) = 0;
virtual void SetMouseReverseScroll(bool enabled) = 0;
virtual void SetMouseAcceleration(bool enabled) = 0;
+ virtual void SuspendMouseAcceleration() = 0;
+ virtual void EndMouseAccelerationSuspension() = 0;
virtual void SetMouseScrollAcceleration(bool enabled) = 0;
// Touch log collection.
diff --git a/chromium/ui/ozone/public/mojom/drm_device.mojom b/chromium/ui/ozone/public/mojom/drm_device.mojom
index c9b31a6c68c..9f67565431c 100644
--- a/chromium/ui/ozone/public/mojom/drm_device.mojom
+++ b/chromium/ui/ozone/public/mojom/drm_device.mojom
@@ -6,6 +6,7 @@ module ui.ozone.mojom;
import "mojo/public/mojom/base/file.mojom";
import "mojo/public/mojom/base/file_path.mojom";
+import "ui/display/mojom/display_configuration_params.mojom";
import "ui/display/mojom/display_constants.mojom";
import "ui/display/mojom/display_mode.mojom";
import "ui/display/mojom/display_snapshot.mojom";
@@ -50,13 +51,9 @@ interface DrmDevice {
// Instructs the GPU to abandon a DRM device.
RemoveGraphicsDevice(mojo_base.mojom.FilePath path);
- // Instructs the GPU to disable a DRM device.
- DisableNativeDisplay(int64 display_id) => (int64 display_id, bool success);
-
- // Configures a DRM display returning true on success.
- ConfigureNativeDisplay(int64 display_id,
- display.mojom.DisplayMode display_mode,
- gfx.mojom.Point point) =>
+ // Configures (Enables/Disables) a DRM display, returning true on success.
+ ConfigureNativeDisplay(
+ display.mojom.DisplayConfigurationParams display_config_params) =>
(int64 display_id, bool success);
// Gets or sets high-definition content protection (HDCP) (DRM as in
diff --git a/chromium/ui/ozone/public/ozone_platform.cc b/chromium/ui/ozone/public/ozone_platform.cc
index 0309fc67128..f08c81e9fc3 100644
--- a/chromium/ui/ozone/public/ozone_platform.cc
+++ b/chromium/ui/ozone/public/ozone_platform.cc
@@ -18,7 +18,6 @@
namespace ui {
namespace {
-
OzonePlatform* g_instance = nullptr;
void EnsureInstance() {
@@ -45,6 +44,15 @@ OzonePlatform::OzonePlatform() {
OzonePlatform::~OzonePlatform() = default;
// static
+void OzonePlatform::PreEarlyInitialization() {
+ EnsureInstance();
+ if (g_instance->prearly_initialized_)
+ return;
+ g_instance->prearly_initialized_ = true;
+ g_instance->PreEarlyInitialize();
+}
+
+// static
void OzonePlatform::InitializeForUI(const InitParams& args) {
EnsureInstance();
if (g_instance->initialized_ui_)
@@ -115,4 +123,11 @@ void OzonePlatform::AfterSandboxEntry() {
DCHECK(!single_process_);
}
+void OzonePlatform::PostMainMessageLoopStart(
+ base::OnceCallback<void()> shutdown_cb) {}
+
+void OzonePlatform::PostMainMessageLoopRun() {}
+
+void OzonePlatform::PreEarlyInitialize() {}
+
} // namespace ui
diff --git a/chromium/ui/ozone/public/ozone_platform.h b/chromium/ui/ozone/public/ozone_platform.h
index afb9099af3b..f1bbc12cf0c 100644
--- a/chromium/ui/ozone/public/ozone_platform.h
+++ b/chromium/ui/ozone/public/ozone_platform.h
@@ -23,8 +23,7 @@ class NativeDisplayDelegate;
}
namespace ui {
-
-class CursorFactoryOzone;
+class CursorFactory;
class InputController;
class GpuPlatformSupportHost;
class OverlayManagerOzone;
@@ -104,6 +103,30 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform {
bool supports_overlays = false;
};
+ // Corresponds to chrome_browser_main_extra_parts.h.
+ //
+ // The browser process' initialization involves several steps -
+ // PreEarlyInitialization, PostMainMessageLoopStart, PostMainMessageLoopRun,
+ // etc. In order to be consistent with that and allow platform specific
+ // initialization steps, the OzonePlatform has three methods - one static
+ // PreEarlyInitialization that is expected to do some early non-ui
+ // initialization (like error handlers that X11 sets), and two non-static
+ // methods - PostMainmessageLoopStart and PostMainMessageLoopRun. The latter
+ // two are supposed to be called on a post start and a post-run of the
+ // MessageLoop. Please note that this methods must be run on the browser' UI
+ // thread.
+ //
+ // Creates OzonePlatform and does pre-early initialization (internally, sets
+ // error handlers if supported so that we can print errors during the browser
+ // process' start up).
+ static void PreEarlyInitialization();
+ // Sets error handlers if supported for the browser process after the message
+ // loop started. It's required to call this so that we can exit cleanly if the
+ // server can exit before we do.
+ virtual void PostMainMessageLoopStart(base::OnceCallback<void()> shutdown_cb);
+ // Resets the error handlers if set.
+ virtual void PostMainMessageLoopRun();
+
// Initializes the subsystems/resources necessary for the UI process (e.g.
// events) with additional properties to customize the ozone platform
// implementation. Ozone will not retain InitParams after returning from
@@ -129,7 +152,7 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform {
// inject these objects themselves. Ownership is retained by OzonePlatform.
virtual ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() = 0;
virtual ui::OverlayManagerOzone* GetOverlayManager() = 0;
- virtual ui::CursorFactoryOzone* GetCursorFactoryOzone() = 0;
+ virtual ui::CursorFactory* GetCursorFactory() = 0;
virtual ui::InputController* GetInputController() = 0;
virtual ui::GpuPlatformSupportHost* GetGpuPlatformSupportHost() = 0;
virtual std::unique_ptr<SystemInputInjector> CreateSystemInputInjector() = 0;
@@ -189,11 +212,16 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform {
bool single_process() const { return single_process_; }
private:
+ // Optional method for pre-early initialization. In case of X11, sets X11
+ // error handlers so that errors can be caught if early initialization fails.
+ virtual void PreEarlyInitialize();
+
virtual void InitializeUI(const InitParams& params) = 0;
virtual void InitializeGPU(const InitParams& params) = 0;
bool initialized_ui_ = false;
bool initialized_gpu_ = false;
+ bool prearly_initialized_ = false;
bool single_process_ = false;
diff --git a/chromium/ui/ozone/public/platform_clipboard.h b/chromium/ui/ozone/public/platform_clipboard.h
index 0962bc9fd78..5ef3fb3d939 100644
--- a/chromium/ui/ozone/public/platform_clipboard.h
+++ b/chromium/ui/ozone/public/platform_clipboard.h
@@ -9,6 +9,7 @@
#include <unordered_map>
#include <vector>
+#include "base/callback_forward.h"
#include "base/component_export.h"
#include "base/macros.h"
#include "base/optional.h"
diff --git a/chromium/ui/ozone/public/platform_screen.cc b/chromium/ui/ozone/public/platform_screen.cc
index a95cfae1322..c2440a5b237 100644
--- a/chromium/ui/ozone/public/platform_screen.cc
+++ b/chromium/ui/ozone/public/platform_screen.cc
@@ -4,7 +4,7 @@
#include "ui/ozone/public/platform_screen.h"
-#include "base/logging.h"
+#include "base/notreached.h"
namespace ui {
diff --git a/chromium/ui/ozone/public/platform_window_surface.h b/chromium/ui/ozone/public/platform_window_surface.h
index f804dd1f795..b316e3ecbdb 100644
--- a/chromium/ui/ozone/public/platform_window_surface.h
+++ b/chromium/ui/ozone/public/platform_window_surface.h
@@ -6,6 +6,11 @@
#define UI_OZONE_PUBLIC_PLATFORM_WINDOW_SURFACE_H_
#include "base/component_export.h"
+#include "build/build_config.h"
+
+#if defined(OS_FUCHSIA)
+#include <fuchsia/images/cpp/fidl.h>
+#endif // defined(OS_FUCHSIA)
namespace ui {
@@ -28,9 +33,14 @@ class COMPONENT_EXPORT(OZONE_BASE) PlatformWindowSurface {
public:
virtual ~PlatformWindowSurface() {}
- // Note: GL & Vulkan surface are created through the GLOzone &
- // VulkanImplementation interfaces, respectively.
- //
+#if defined(OS_FUCHSIA)
+ // Sets the texture of the surface to a new image pipe.
+ virtual bool SetTextureToNewImagePipe(
+ fidl::InterfaceRequest<fuchsia::images::ImagePipe2>
+ image_pipe_request) = 0;
+#endif // defined(OS_FUCHSIA)
+
+ // Note: GL surface may be created through the GLOzone interface.
// However, you must still create a PlatformWindowSurface and keep it alive in
// order to present.
};