summaryrefslogtreecommitdiff
path: root/chromium/ui/ozone/platform/wayland/host
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-29 10:46:47 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-11-02 12:02:10 +0000
commit99677208ff3b216fdfec551fbe548da5520cd6fb (patch)
tree476a4865c10320249360e859d8fdd3e01833b03a /chromium/ui/ozone/platform/wayland/host
parentc30a6232df03e1efbd9f3b226777b07e087a1122 (diff)
downloadqtwebengine-chromium-99677208ff3b216fdfec551fbe548da5520cd6fb.tar.gz
BASELINE: Update Chromium to 86.0.4240.124
Change-Id: Ide0ff151e94cd665ae6521a446995d34a9d1d644 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/ui/ozone/platform/wayland/host')
-rw-r--r--chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc4
-rw-r--r--chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h1
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc115
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.h39
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc448
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h43
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc15
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h4
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_connection.cc51
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_connection.h5
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc10
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_cursor.h2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc30
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device.h6
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc5
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc61
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc25
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h4
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc186
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_offer_base.cc13
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc10
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_event_source.h6
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc4
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc8
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc5
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_output.cc9
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_output.h12
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_output_manager.cc50
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_output_manager.h3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_pointer.h4
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc4
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_popup.cc28
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_screen.cc56
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_screen.h13
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc175
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc176
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h68
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_surface.cc128
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_surface.h53
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc67
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h31
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_touch.cc3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window.cc255
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window.h89
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc131
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h36
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc118
-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.cc22
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_manager.h12
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc26
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_observer.cc7
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_observer.h9
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc220
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc4
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc19
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h1
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc2
59 files changed, 2011 insertions, 929 deletions
diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc
index fef56d4fcc8..e5017840921 100644
--- a/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc
@@ -43,6 +43,10 @@ bool GtkUiDelegateWayland::SetGdkWindowTransientFor(
return false;
}
+void GtkUiDelegateWayland::ClearTransientFor(gfx::AcceleratedWidget parent) {
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
void GtkUiDelegateWayland::ShowGtkWindow(GtkWindow* window) {
// TODO(crbug.com/1008755): Check if gtk_window_present_with_time is needed
// here as well, similarly to what is done in X11 impl.
diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h
index dd7baf93bf7..4f3f606c5ac 100644
--- a/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h
+++ b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h
@@ -25,6 +25,7 @@ class GtkUiDelegateWayland : public GtkUiDelegate {
GdkWindow* GetGdkWindow(gfx::AcceleratedWidget window_id) override;
bool SetGdkWindowTransientFor(GdkWindow* window,
gfx::AcceleratedWidget parent) override;
+ void ClearTransientFor(gfx::AcceleratedWidget parent) override;
void ShowGtkWindow(GtkWindow* window) override;
private:
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc b/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc
new file mode 100644
index 00000000000..c5e31fd5b9d
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc
@@ -0,0 +1,115 @@
+// 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_auxiliary_window.h"
+
+#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 {
+
+WaylandAuxiliaryWindow::WaylandAuxiliaryWindow(PlatformWindowDelegate* delegate,
+ WaylandConnection* connection)
+ : WaylandWindow(delegate, connection) {}
+
+WaylandAuxiliaryWindow::~WaylandAuxiliaryWindow() = default;
+
+void WaylandAuxiliaryWindow::Show(bool inactive) {
+ if (subsurface_)
+ return;
+
+ CreateSubsurface();
+ UpdateBufferScale(false);
+}
+
+void WaylandAuxiliaryWindow::Hide() {
+ if (!subsurface_)
+ return;
+
+ subsurface_.reset();
+
+ // Detach buffer from surface in order to completely shutdown menus and
+ // tooltips, and release resources.
+ connection()->buffer_manager_host()->ResetSurfaceContents(root_surface());
+}
+
+bool WaylandAuxiliaryWindow::IsVisible() const {
+ return !!subsurface_;
+}
+
+void WaylandAuxiliaryWindow::SetBounds(const gfx::Rect& bounds) {
+ auto old_bounds = GetBounds();
+ WaylandWindow::SetBounds(bounds);
+
+ if (old_bounds == bounds || !parent_window())
+ return;
+
+ auto subsurface_bounds_dip =
+ wl::TranslateWindowBoundsToParentDIP(this, parent_window());
+ wl_subsurface_set_position(subsurface_.get(), subsurface_bounds_dip.x(),
+ subsurface_bounds_dip.y());
+ root_surface()->Commit();
+ connection()->ScheduleFlush();
+}
+
+void WaylandAuxiliaryWindow::CreateSubsurface() {
+ auto* parent = parent_window();
+ if (!parent) {
+ // wl_subsurface can be used for several purposes: tooltips and drag arrow
+ // windows. If we are in a drag process, use the entered window. Otherwise,
+ // it must be a tooltip.
+ if (connection()->IsDragInProgress()) {
+ parent = connection()->data_drag_controller()->entered_window();
+ set_parent_window(parent);
+ } else {
+ // If Aura does not not provide a reference parent window, needed by
+ // Wayland, we get the current focused window to place and show the
+ // tooltips.
+ parent =
+ connection()->wayland_window_manager()->GetCurrentFocusedWindow();
+ }
+ }
+
+ // Tooltip and drag arrow creation is an async operation. By the time Aura
+ // actually creates them, it is possible that the user has already moved the
+ // mouse/pointer out of the window that triggered the tooltip, or user is no
+ // longer in a drag/drop process. In this case, parent is nullptr.
+ if (!parent)
+ return;
+
+ subsurface_ = root_surface()->CreateSubsurface(parent->root_surface());
+
+ auto subsurface_bounds_dip =
+ wl::TranslateWindowBoundsToParentDIP(this, parent);
+
+ DCHECK(subsurface_);
+ // Convert position to DIP.
+ wl_subsurface_set_position(subsurface_.get(), subsurface_bounds_dip.x(),
+ subsurface_bounds_dip.y());
+ wl_subsurface_set_desync(subsurface_.get());
+ parent->root_surface()->Commit();
+ 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 WaylandAuxiliaryWindow::OnInitialize(
+ PlatformWindowInitProperties properties) {
+ // If we do not have parent window provided, we must always use a focused
+ // window or a window that entered drag whenever the subsurface is created.
+ if (properties.parent_widget == gfx::kNullAcceleratedWidget) {
+ DCHECK(!parent_window());
+ return true;
+ }
+ set_parent_window(GetParentWindow(properties.parent_widget));
+ return true;
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.h b/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.h
new file mode 100644
index 00000000000..0db19755696
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.h
@@ -0,0 +1,39 @@
+// 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_AUXILIARY_WINDOW_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_AUXILIARY_WINDOW_H_
+
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+
+namespace ui {
+
+// A WaylandWindow implementation to show tooltips and arrow windows.
+class WaylandAuxiliaryWindow : public WaylandWindow {
+ public:
+ WaylandAuxiliaryWindow(PlatformWindowDelegate* delegate,
+ WaylandConnection* connection);
+ WaylandAuxiliaryWindow(const WaylandAuxiliaryWindow&) = delete;
+ WaylandAuxiliaryWindow& operator=(const WaylandAuxiliaryWindow&) = delete;
+ ~WaylandAuxiliaryWindow() override;
+
+ // PlatformWindow overrides:
+ void Show(bool inactive) override;
+ void Hide() override;
+ bool IsVisible() const override;
+ void SetBounds(const gfx::Rect& bounds) override;
+
+ private:
+ // WaylandWindow overrides:
+ bool OnInitialize(PlatformWindowInitProperties properties) override;
+
+ // Creates (if necessary) and shows a subsurface window.
+ void CreateSubsurface();
+
+ wl::Object<wl_subsurface> subsurface_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_AUXILIARY_WINDOW_H_
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 8320574a540..c60c35e4ab4 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
@@ -8,14 +8,15 @@
#include <memory>
#include "base/i18n/number_formatting.h"
-#include "base/message_loop/message_loop_current.h"
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/task/current_thread.h"
#include "base/trace_event/trace_event.h"
#include "ui/gfx/linux/drm_util_linux.h"
#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_subsurface.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"
@@ -65,8 +66,6 @@ class WaylandBufferManagerHost::Surface {
~Surface() = default;
bool CommitBuffer(uint32_t buffer_id, const gfx::Rect& damage_region) {
- DCHECK(!pending_buffer_);
-
// The window has already been destroyed.
if (!wayland_surface_)
return true;
@@ -96,7 +95,7 @@ class WaylandBufferManagerHost::Surface {
if (buffer->attached && !buffer->wl_buffer)
return false;
- pending_buffer_ = buffer;
+ pending_buffers_.push_back(buffer);
MaybeProcessPendingBuffer();
return true;
}
@@ -109,35 +108,16 @@ class WaylandBufferManagerHost::Surface {
size_t DestroyBuffer(uint32_t buffer_id) {
auto* buffer = GetBuffer(buffer_id);
- // We ack the submission of a front buffer whenever a previous front back
- // becomes the back one and receives a buffer release callback. But the
- // following can happen:
- //
- // Imagine the order:
- // the front buffer is buffer 2, then
- // Commit[1]
- // Destroy[2]
- // Commit[3]
- // Release[1]
- // Ack[3] <= this results in a wrong order of the callbacks. In reality,
- // the buffer [1] must have been acked, because the buffer 2 was
- // released.
- // But if the buffer 2 is destroyed, the buffer release callback never
- // comes for that buffer. Thus, if there is a submitted buffer, notify
- // the client about successful swap.
- // If the window has already been destroyed, no need to complete the
- // submission.
- if (buffer && !buffer->released && submitted_buffer_ && wayland_surface_)
- CompleteSubmission();
-
- if (prev_submitted_buffer_ == buffer)
- prev_submitted_buffer_ = nullptr;
-
- if (pending_buffer_ == buffer)
- pending_buffer_ = nullptr;
-
- auto result = buffers_.erase(buffer_id);
- return result;
+
+ // Treat destroying a buffer as a release, and make sure to call any
+ // OnSubmission callbacks that would be sent as a result of that.
+ if (buffer) {
+ buffer->released = true;
+ MaybeProcessSubmittedBuffers();
+ base::Erase(pending_buffers_, buffer);
+ }
+
+ return buffers_.erase(buffer_id);
}
void AttachWlBuffer(uint32_t buffer_id, wl::Object<wl_buffer> new_buffer) {
@@ -154,8 +134,7 @@ class WaylandBufferManagerHost::Surface {
if (buffer->wl_buffer)
SetupBufferReleaseListener(buffer);
- if (pending_buffer_ == buffer)
- MaybeProcessPendingBuffer();
+ MaybeProcessPendingBuffer();
}
void ClearState() {
@@ -165,9 +144,8 @@ class WaylandBufferManagerHost::Surface {
ResetSurfaceContents();
- prev_submitted_buffer_ = nullptr;
- submitted_buffer_ = nullptr;
- pending_buffer_ = nullptr;
+ submitted_buffers_.clear();
+ pending_buffers_.clear();
connection_->ScheduleFlush();
}
@@ -176,16 +154,11 @@ class WaylandBufferManagerHost::Surface {
if (!wayland_surface_)
return;
- 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;
+ wayland_surface_->AttachBuffer(nullptr);
+ wayland_surface_->Commit();
// ResetSurfaceContents happens upon WaylandWindow::Hide call, which
- // destroyes xdg_surface, xdg_popup, etc. They are going to be reinitialized
+ // destroys 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;
@@ -200,10 +173,10 @@ class WaylandBufferManagerHost::Surface {
bool HasBuffers() const { return !buffers_.empty(); }
- void OnWindowRemoved() { wayland_surface_ = nullptr; }
- bool HasWindow() const { return !!wayland_surface_; }
+ void OnSurfaceRemoved() { wayland_surface_ = nullptr; }
+ bool HasSurface() const { return !!wayland_surface_; }
- void OnWindowConfigured() {
+ void OnSurfaceConfigured() {
if (configured_)
return;
@@ -226,50 +199,44 @@ class WaylandBufferManagerHost::Surface {
using PresentationFeedbackQueue = std::vector<FeedbackInfo>;
+ // Holds information about a submitted buffer.
+ struct SubmissionInfo {
+ // ID of the submitted buffer. Buffers may be destroyed after they have been
+ // submitted but before we send OnSubmission for them, e.g. if the same
+ // buffer is submitted twice in a row. Keep the ID so we send OnSubmission
+ // even if a buffer is destroyed.
+ uint32_t buffer_id;
+ // Whether this buffer has had OnSubmission sent for it.
+ bool acked;
+ };
+
bool CommitBufferInternal(WaylandBuffer* buffer) {
DCHECK(buffer && wayland_surface_);
- DCHECK(!pending_buffer_);
- DCHECK(!submitted_buffer_);
- submitted_buffer_ = buffer;
-
- // if the same buffer has been submitted again right after the client
+ // If the same buffer has been submitted again right after the client
// received OnSubmission for that buffer, just damage the buffer and
// commit the surface again.
- if (prev_submitted_buffer_ != submitted_buffer_) {
+ if (submitted_buffers_.empty() ||
+ submitted_buffers_.back().buffer_id != buffer->buffer_id) {
// Once the BufferRelease is called, the buffer will be released.
DCHECK(buffer->released);
buffer->released = false;
AttachBuffer(buffer);
}
+ // If the client submits the same buffer twice, we need to store it twice,
+ // because the client will expect two acks for it.
+ submitted_buffers_.push_back(
+ SubmissionInfo{buffer->buffer_id, /*acked=*/false});
+
DamageBuffer(buffer);
SetupFrameCallback();
SetupPresentationFeedback(buffer->buffer_id);
CommitSurface();
-
connection_->ScheduleFlush();
-
- // If the contents were reset, there is no buffer attached. It means we have
- // to behave the same way as if it was the very first frame. Check the
- // comment below where the |contents_reset_| is declared.
- if (contents_reset_) {
- prev_submitted_buffer_ = nullptr;
- contents_reset_ = false;
- }
-
- // If it was the very first frame, the surface has not had a back buffer
- // before, and Wayland won't release the front buffer until next buffer is
- // attached. Thus, notify about successful submission immediately.
- //
- // As said above, if the client submits the same buffer again, we must
- // notify the client about the submission immediately as Wayland compositor
- // is not going to send a release callback for a buffer committed more than
- // once.
- if (!prev_submitted_buffer_ || prev_submitted_buffer_ == submitted_buffer_)
- CompleteSubmission();
+ MaybeProcessSubmittedBuffers();
return true;
}
@@ -277,7 +244,7 @@ class WaylandBufferManagerHost::Surface {
void DamageBuffer(WaylandBuffer* buffer) {
DCHECK(wayland_surface_);
- gfx::Rect pending_damage_region = std::move(buffer->damage_region);
+ gfx::Rect pending_damage_region = buffer->damage_region;
// If the size of the damage region is empty, wl_surface_damage must be
// supplied with the actual size of the buffer, which is going to be
// committed.
@@ -285,48 +252,17 @@ class WaylandBufferManagerHost::Surface {
pending_damage_region.set_size(buffer->size);
DCHECK(!pending_damage_region.size().IsEmpty());
- if (connection_->compositor_version() >=
- WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) {
- // wl_surface_damage_buffer relies on compositor API version 4. See
- // 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(
- 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)
- // 2) The API wl_surface::set_buffer_transform is not used.
- // It's possible to write logic that accounts for both cases above, but
- // it's currently unnecessary.
- //
- // 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 = 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);
- }
+ wayland_surface_->Damage(pending_damage_region);
}
void AttachBuffer(WaylandBuffer* buffer) {
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(wayland_surface_->surface(), buffer->wl_buffer.get(), 0,
- 0);
+ wayland_surface_->AttachBuffer(buffer->wl_buffer.get());
}
void CommitSurface() {
DCHECK(wayland_surface_);
- wl_surface_commit(wayland_surface_->surface());
+ wayland_surface_->Commit();
}
void SetupFrameCallback() {
@@ -390,42 +326,23 @@ class WaylandBufferManagerHost::Surface {
void OnRelease(struct wl_buffer* wl_buffer) {
DCHECK(wl_buffer);
+ // Releases may not necessarily come in order, so search the submitted
+ // buffers.
WaylandBuffer* buffer = nullptr;
- // The Wayland compositor may release the buffer immediately after it has
- // been submitted. Thus, check that wl_buffer belongs to either the
- // submitted buffer or the previously submitted buffer.
- if (submitted_buffer_ && submitted_buffer_->wl_buffer.get() == wl_buffer) {
- buffer = submitted_buffer_;
- DCHECK(buffer->wl_buffer.get() == wl_buffer);
- } else {
- buffer = prev_submitted_buffer_;
- DCHECK(buffer && buffer->wl_buffer.get() == wl_buffer);
+ for (const auto& b : submitted_buffers_) {
+ auto* submitted_buffer = GetBuffer(b.buffer_id);
+ if (submitted_buffer && wl_buffer == submitted_buffer->wl_buffer.get()) {
+ buffer = submitted_buffer;
+ break;
+ }
}
-
+ DCHECK(buffer);
DCHECK(!buffer->released);
buffer->released = true;
- // It may happen that the client has attached only one buffer and then
- // destroyed the window. That means that we manually called OnRelease on
- // that very first buffer attach as long as the surface has not had any
- // buffers attached before. However, the |submitted_buffer_| can be null in
- // the OnRelease and hit the DCHECK when the client does not continue
- // attaching new buffers (only one has been attached) and destroyes the
- // surface. In this case, the Wayland compositor releases the buffer and the
- // DCHECK is hit, because we have already run the OnRelease call manually.
- // Please note that the |prev_submitted_buffer_| is the buffer we have
- // released manually, and when the Wayland compositor sends OnRelease, the
- // validation of the wl_buffers succeeds because of that previous manual
- // OnRelease call.
- if (!submitted_buffer_)
- return;
-
- // Although, the Wayland compositor has just released the previously
- // attached buffer, which became a back buffer, we have to notify the client
- // that next buffer has been attach and become the front one. Thus, mark the
- // back buffer as released to ensure the DCHECK is not hit, and notify about
- // successful submission of the front buffer.
- CompleteSubmission();
+ // A release means we may be able to send OnSubmission for previously
+ // submitted buffers.
+ MaybeProcessSubmittedBuffers();
}
// wl_buffer_listener
@@ -435,19 +352,49 @@ class WaylandBufferManagerHost::Surface {
self->OnRelease(wl_buffer);
}
- void CompleteSubmission() {
- DCHECK(submitted_buffer_);
- auto id = submitted_buffer_->buffer_id;
- prev_submitted_buffer_ = submitted_buffer_;
- submitted_buffer_ = nullptr;
-
+ void MaybeProcessSubmittedBuffers() {
if (!wayland_surface_)
return;
+ // We force an OnSubmission call for the very first buffer submitted,
+ // otherwise buffers are not acked in a quiescent state. We keep track of
+ // whether it has already been acked. A buffer may have already been acked
+ // if it is the first buffer submitted and it is destroyed before being
+ // explicitly released. In that case, don't send an OnSubmission.
+ if (submitted_buffers_.size() == 1u && !submitted_buffers_[0].acked)
+ ProcessOldestSubmittedBuffer();
+
+ // Buffers may be released out of order, but we need to provide the
+ // guarantee that OnSubmission will be called in order of buffer submission.
+ while (submitted_buffers_.size() >= 2) {
+ auto* buffer0 = GetBuffer(submitted_buffers_[0].buffer_id);
+ // Treat a buffer as released if it has been explicitly released or
+ // destroyed.
+ bool buffer0_released = !buffer0 || buffer0->released;
+ // We can send OnSubmission for the 2nd oldest buffer if the oldest buffer
+ // is released, or it's the same buffer.
+ if (!buffer0_released &&
+ submitted_buffers_[0].buffer_id != submitted_buffers_[1].buffer_id)
+ break;
+
+ DCHECK(submitted_buffers_[0].acked);
+ DCHECK(!submitted_buffers_[1].acked);
+ submitted_buffers_.erase(submitted_buffers_.begin());
+ ProcessOldestSubmittedBuffer();
+ }
+ }
+
+ void ProcessOldestSubmittedBuffer() {
+ DCHECK(wayland_surface_);
+ DCHECK(!submitted_buffers_.empty());
+
+ submitted_buffers_.front().acked = true;
+ auto buffer_id = submitted_buffers_.front().buffer_id;
+
// 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(wayland_surface_->GetRootWidget(), id,
+ buffer_manager_->OnSubmission(wayland_surface_->GetWidget(), buffer_id,
gfx::SwapResult::SWAP_ACK);
// If presentation feedback is not supported, use a fake feedback. This
@@ -455,18 +402,19 @@ class WaylandBufferManagerHost::Surface {
if (!connection_->presentation()) {
DCHECK(feedback_queue_.empty());
buffer_manager_->OnPresentation(
- wayland_surface_->GetWidget(), id,
+ wayland_surface_->GetWidget(), buffer_id,
gfx::PresentationFeedback(base::TimeTicks::Now(), base::TimeDelta(),
GetPresentationKindFlags(0)));
} else {
for (auto& info : feedback_queue_) {
- if (info.buffer_id == id && !info.submission_completed) {
+ if (info.buffer_id == buffer_id && !info.submission_completed) {
info.submission_completed = true;
ProcessPresentationFeedbacks();
return;
}
}
- NOTREACHED() << "Did not find matching feedback for buffer_id=" << id;
+ NOTREACHED() << "Did not find matching feedback for buffer_id="
+ << buffer_id;
}
}
@@ -561,9 +509,10 @@ class WaylandBufferManagerHost::Surface {
}
void MaybeProcessPendingBuffer() {
+ DCHECK_LE(pending_buffers_.size(), 6u);
// There is nothing to process if there is no pending buffer or the window
// has been destroyed.
- if (!pending_buffer_ || !wayland_surface_)
+ if (pending_buffers_.empty() || !wayland_surface_)
return;
// This request may come earlier than the Wayland compositor has imported a
@@ -580,19 +529,19 @@ class WaylandBufferManagerHost::Surface {
//
// 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_)
+ auto* pending_buffer = pending_buffers_.front();
+ if (!pending_buffer->wl_buffer || wl_frame_callback_ || !configured_)
return;
- auto* buffer = pending_buffer_;
- pending_buffer_ = nullptr;
- CommitBufferInternal(buffer);
+ pending_buffers_.erase(pending_buffers_.begin());
+ CommitBufferInternal(pending_buffer);
}
// Widget this helper surface backs and has 1:1 relationship with the
// WaylandWindow.
- // Non-owned. The window this helper surface stores and submits buffers for.
- const WaylandSurface* wayland_surface_;
+ // Non-owned. The surface this helper stores and submits buffers for.
+ WaylandSurface* wayland_surface_;
// Non-owned pointer to the connection.
WaylandConnection* const connection_;
@@ -608,25 +557,17 @@ class WaylandBufferManagerHost::Surface {
// operation.
wl::Object<wl_callback> wl_frame_callback_;
- // A presentation feedback provided by the Wayland server once frame is
- // shown.
- PresentationFeedbackQueue feedback_queue_;
+ // Queue of buffers which are pending to be submitted (look the comment
+ // in the CommitBuffer method).
+ std::vector<WaylandBuffer*> pending_buffers_;
+
+ // Queue of buffers which have been submitted and are waiting to be
+ // acked (send OnSubmission)
+ std::vector<SubmissionInfo> submitted_buffers_;
- // A buffer, which is pending to be submitted (look the comment in the
- // CommitBuffer method).
- WaylandBuffer* pending_buffer_ = nullptr;
- // Current submitted buffer.
- WaylandBuffer* submitted_buffer_ = nullptr;
- // Previous submitted buffer.
- WaylandBuffer* prev_submitted_buffer_ = nullptr;
-
- // If WaylandWindow becomes hidden, it may need to attach a null buffer to the
- // surface it backed to avoid its contents shown on screen. However, it
- // means that the Wayland compositor no longer sends new buffer release events
- // as long as there has not been buffer attached and no submission callback is
- // sent. To avoid this, |contents_reset_| can be used as an identification of
- // a need to call submission callback manually.
- bool contents_reset_ = false;
+ // Queue of buffers which have been acked and are waiting to have
+ // OnPresentation sent.
+ PresentationFeedbackQueue feedback_queue_;
// If WaylandWindow has never been configured, do not try to attach
// buffers to its surface. Otherwise, Wayland server will drop the connection
@@ -653,25 +594,49 @@ WaylandBufferManagerHost::~WaylandBufferManagerHost() {
void WaylandBufferManagerHost::OnWindowAdded(WaylandWindow* window) {
DCHECK(window);
- surfaces_[window->GetWidget()] =
- std::make_unique<Surface>(window->wayland_surface(), connection_, this);
+ surfaces_[window->root_surface()] =
+ std::make_unique<Surface>(window->root_surface(), connection_, this);
}
void WaylandBufferManagerHost::OnWindowRemoved(WaylandWindow* window) {
DCHECK(window);
- auto it = surfaces_.find(window->GetWidget());
+ auto it = surfaces_.find(window->root_surface());
DCHECK(it != surfaces_.end());
- if (it->second->HasBuffers())
- it->second->OnWindowRemoved();
- else
- surfaces_.erase(it);
+ if (it->second->HasBuffers()) {
+ it->second->OnSurfaceRemoved();
+ surface_graveyard_.emplace_back(std::move(it->second));
+ }
+ surfaces_.erase(it);
}
void WaylandBufferManagerHost::OnWindowConfigured(WaylandWindow* window) {
DCHECK(window);
- auto it = surfaces_.find(window->GetWidget());
+ auto it = surfaces_.find(window->root_surface());
+ DCHECK(it != surfaces_.end());
+ it->second->OnSurfaceConfigured();
+}
+
+void WaylandBufferManagerHost::OnSubsurfaceAdded(
+ WaylandWindow* window,
+ WaylandSubsurface* subsurface) {
+ DCHECK(subsurface);
+ surfaces_[subsurface->wayland_surface()] = std::make_unique<Surface>(
+ subsurface->wayland_surface(), connection_, this);
+ // WaylandSubsurface is always configured.
+ surfaces_[subsurface->wayland_surface()]->OnSurfaceConfigured();
+}
+
+void WaylandBufferManagerHost::OnSubsurfaceRemoved(
+ WaylandWindow* window,
+ WaylandSubsurface* subsurface) {
+ DCHECK(subsurface);
+ auto it = surfaces_.find(subsurface->wayland_surface());
DCHECK(it != surfaces_.end());
- it->second->OnWindowConfigured();
+ if (it->second->HasBuffers()) {
+ it->second->OnSurfaceRemoved();
+ surface_graveyard_.emplace_back(std::move(it->second));
+ }
+ surfaces_.erase(it);
}
void WaylandBufferManagerHost::SetTerminateGpuCallback(
@@ -731,7 +696,7 @@ void WaylandBufferManagerHost::CreateDmabufBasedBuffer(
uint32_t format,
uint32_t planes_count,
uint32_t buffer_id) {
- DCHECK(base::MessageLoopCurrentForUI::IsSet());
+ DCHECK(base::CurrentUIThread::IsSet());
DCHECK(error_message_.empty());
TRACE_EVENT2("wayland", "WaylandBufferManagerHost::CreateDmabufBasedBuffer",
@@ -771,7 +736,7 @@ void WaylandBufferManagerHost::CreateShmBasedBuffer(mojo::PlatformHandle shm_fd,
uint64_t length,
const gfx::Size& size,
uint32_t buffer_id) {
- DCHECK(base::MessageLoopCurrentForUI::IsSet());
+ DCHECK(base::CurrentUIThread::IsSet());
DCHECK(error_message_.empty());
TRACE_EVENT1("wayland", "WaylandBufferManagerHost::CreateShmBasedBuffer",
@@ -792,10 +757,31 @@ void WaylandBufferManagerHost::CreateShmBasedBuffer(mojo::PlatformHandle shm_fd,
connection_->ScheduleFlush();
}
+bool WaylandBufferManagerHost::CommitBufferInternal(
+ WaylandSurface* wayland_surface,
+ uint32_t buffer_id,
+ const gfx::Rect& damage_region) {
+ DCHECK(base::CurrentUIThread::IsSet());
+
+ Surface* surface = GetSurface(wayland_surface);
+ if (!surface || !ValidateBufferIdFromGpu(buffer_id))
+ return false;
+
+ if (!surface->CommitBuffer(buffer_id, damage_region)) {
+ error_message_ =
+ base::StrCat({"Buffer with ", NumberToString(buffer_id),
+ " id does not exist or failed to be created."});
+ }
+
+ if (!error_message_.empty())
+ TerminateGpuProcess();
+ return true;
+}
+
void WaylandBufferManagerHost::CommitBuffer(gfx::AcceleratedWidget widget,
uint32_t buffer_id,
const gfx::Rect& damage_region) {
- DCHECK(base::MessageLoopCurrentForUI::IsSet());
+ DCHECK(base::CurrentUIThread::IsSet());
TRACE_EVENT1("wayland", "WaylandBufferManagerHost::CommitBuffer", "Buffer id",
buffer_id);
@@ -804,25 +790,42 @@ void WaylandBufferManagerHost::CommitBuffer(gfx::AcceleratedWidget widget,
if (widget == gfx::kNullAcceleratedWidget) {
error_message_ = "Invalid widget.";
- } else if (ValidateBufferIdFromGpu(buffer_id)) {
- Surface* surface = GetSurface(widget);
- if (!surface)
+ TerminateGpuProcess();
+ } else {
+ auto* window = connection_->wayland_window_manager()->GetWindow(widget);
+ if (!window)
return;
-
- if (!surface->CommitBuffer(buffer_id, damage_region)) {
- error_message_ =
- base::StrCat({"Buffer with ", NumberToString(buffer_id),
- " id does not exist or failed to be created."});
- }
+ CommitBufferInternal(window->root_surface(), buffer_id, damage_region);
}
+}
- if (!error_message_.empty())
+void WaylandBufferManagerHost::CommitOverlays(
+ gfx::AcceleratedWidget widget,
+ std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlays) {
+ DCHECK(base::CurrentUIThread::IsSet());
+
+ TRACE_EVENT0("wayland", "WaylandBufferManagerHost::CommitOverlays");
+
+ DCHECK(error_message_.empty());
+
+ if (widget == gfx::kNullAcceleratedWidget) {
+ error_message_ = "Invalid widget.";
TerminateGpuProcess();
+ }
+ WaylandWindow* window =
+ connection_->wayland_window_manager()->GetWindow(widget);
+ // In tab dragging, window may have been destroyed when buffers reach here. We
+ // omit buffer commits and OnSubmission, because the corresponding buffer
+ // queue in gpu process should be destroyed soon.
+ if (!window)
+ return;
+
+ window->CommitOverlays(overlays);
}
void WaylandBufferManagerHost::DestroyBuffer(gfx::AcceleratedWidget widget,
uint32_t buffer_id) {
- DCHECK(base::MessageLoopCurrentForUI::IsSet());
+ DCHECK(base::CurrentUIThread::IsSet());
TRACE_EVENT1("wayland", "WaylandBufferManagerHost::DestroyBuffer",
"Buffer id", buffer_id);
@@ -841,20 +844,45 @@ void WaylandBufferManagerHost::DestroyBuffer(gfx::AcceleratedWidget widget,
// has been stored in the |anonymous_buffers_|.
// 2) if the |widget| is null, always search a buffer with the |buffer_id| in
// the |anonymous_buffers_|.
+ // 3) if the |widget| hints at a non-existing window, it's likely that the
+ // window has been destroyed. In that case, the surface containing the buffer
+ // is in the graveyard.
uint32_t destroyed_count = 0u;
- Surface* surface = GetSurface(widget);
- if (surface) {
- destroyed_count = surface->DestroyBuffer(buffer_id);
- if (!surface->HasBuffers() && !surface->HasWindow())
- surfaces_.erase(widget);
+ auto* window = connection_->wayland_window_manager()->GetWindow(widget);
+ if (window) {
+ // Case 1).
+ Surface* surface = GetSurface(window->root_surface());
+ if (surface) {
+ destroyed_count = surface->DestroyBuffer(buffer_id);
+ if (!surface->HasBuffers() && !surface->HasSurface())
+ surfaces_.erase(window->root_surface());
+ }
+ const auto& subsurfaces = window->wayland_subsurfaces();
+ for (const auto& it : subsurfaces) {
+ Surface* subsurface = GetSurface((*it).wayland_surface());
+ if (subsurface)
+ destroyed_count += subsurface->DestroyBuffer(buffer_id);
+ }
+ } else {
+ // Case 3)
+ auto it = surface_graveyard_.begin();
+ while (it != surface_graveyard_.end()) {
+ destroyed_count += (*it)->DestroyBuffer(buffer_id);
+ if (!(*it)->HasBuffers() && !(*it)->HasSurface()) {
+ surface_graveyard_.erase(it++);
+ } else {
+ ++it;
+ }
+ }
}
// Ensure that we can't destroy more than 1 buffer. This can be 0 as well
// if no buffers are destroyed.
DCHECK_LE(destroyed_count, 1u);
+ // Case 2)
if (destroyed_count == 1u || DestroyAnonymousBuffer(buffer_id))
return;
@@ -864,8 +892,8 @@ void WaylandBufferManagerHost::DestroyBuffer(gfx::AcceleratedWidget widget,
}
void WaylandBufferManagerHost::ResetSurfaceContents(
- gfx::AcceleratedWidget widget) {
- auto* surface = GetSurface(widget);
+ WaylandSurface* wayland_surface) {
+ auto* surface = GetSurface(wayland_surface);
DCHECK(surface);
surface->ResetSurfaceContents();
}
@@ -901,8 +929,8 @@ bool WaylandBufferManagerHost::CreateBuffer(const gfx::Size& size,
}
WaylandBufferManagerHost::Surface* WaylandBufferManagerHost::GetSurface(
- gfx::AcceleratedWidget widget) const {
- auto it = surfaces_.find(widget);
+ WaylandSurface* wayland_surface) const {
+ auto it = surfaces_.find(wayland_surface);
return it != surfaces_.end() ? it->second.get() : nullptr;
}
@@ -1013,7 +1041,7 @@ void WaylandBufferManagerHost::OnSubmission(
gfx::AcceleratedWidget widget,
uint32_t buffer_id,
const gfx::SwapResult& swap_result) {
- DCHECK(base::MessageLoopCurrentForUI::IsSet());
+ DCHECK(base::CurrentUIThread::IsSet());
DCHECK(buffer_manager_gpu_associated_);
buffer_manager_gpu_associated_->OnSubmission(widget, buffer_id, swap_result);
@@ -1023,7 +1051,7 @@ void WaylandBufferManagerHost::OnPresentation(
gfx::AcceleratedWidget widget,
uint32_t buffer_id,
const gfx::PresentationFeedback& feedback) {
- DCHECK(base::MessageLoopCurrentForUI::IsSet());
+ DCHECK(base::CurrentUIThread::IsSet());
DCHECK(buffer_manager_gpu_associated_);
buffer_manager_gpu_associated_->OnPresentation(widget, buffer_id, feedback);
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 b467835f726..20a974e1a5c 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
@@ -29,7 +29,9 @@
namespace ui {
class WaylandConnection;
+class WaylandSubsurface;
class WaylandWindow;
+class WaylandSurface;
// This is an internal helper representation of a wayland buffer object, which
// the GPU process creates when CreateBuffer is called. It's used for
@@ -82,6 +84,10 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
void OnWindowAdded(WaylandWindow* window) override;
void OnWindowRemoved(WaylandWindow* window) override;
void OnWindowConfigured(WaylandWindow* window) override;
+ void OnSubsurfaceAdded(WaylandWindow* window,
+ WaylandSubsurface* subsurface) override;
+ void OnSubsurfaceRemoved(WaylandWindow* window,
+ WaylandSubsurface* subsurface) override;
void SetTerminateGpuCallback(
base::OnceCallback<void(std::string)> terminate_gpu_cb);
@@ -137,25 +143,39 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
void CommitBuffer(gfx::AcceleratedWidget widget,
uint32_t buffer_id,
const gfx::Rect& damage_region) override;
+ // Called by the GPU and asks to configure the surface/subsurfaces and attach
+ // wl_buffers to WaylandWindow with the specified |widget|. Calls OnSubmission
+ // and OnPresentation on successful swap and pixels presented.
+ void CommitOverlays(
+ gfx::AcceleratedWidget widget,
+ std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlays) override;
+
+ // Called by the WaylandWindow and asks to attach a wl_buffer with a
+ // |buffer_id| to a WaylandSurface.
+ // Calls OnSubmission and OnPresentation on successful swap and pixels
+ // presented.
+ bool CommitBufferInternal(WaylandSurface* wayland_surface,
+ uint32_t buffer_id,
+ const gfx::Rect& damage_region);
// When a surface is hidden, the client may want to detach the buffer attached
- // to the surface backed by |widget| to ensure Wayland does not present those
- // contents and do not composite in a wrong way. Otherwise, users may see the
- // contents of a hidden surface on their screens.
- void ResetSurfaceContents(gfx::AcceleratedWidget widget);
+ // to the surface to ensure Wayland does not present those contents and do not
+ // composite in a wrong way. Otherwise, users may see the contents of a hidden
+ // surface on their screens.
+ void ResetSurfaceContents(WaylandSurface* wayland_surface);
// Returns the anonymously created WaylandBuffer.
std::unique_ptr<WaylandBuffer> PassAnonymousWlBuffer(uint32_t buffer_id);
private:
// This is an internal representation of a real surface, which holds a pointer
- // to WaylandWindow. Also, this object holds buffers, frame callbacks and
- // presentation callbacks for that window's surface.
+ // to WaylandSurface. Also, this object holds buffers, frame callbacks and
+ // presentation callbacks for that surface.
class Surface;
bool CreateBuffer(const gfx::Size& size, uint32_t buffer_id);
- Surface* GetSurface(gfx::AcceleratedWidget widget) const;
+ Surface* GetSurface(WaylandSurface* wayland_surface) const;
// Validates data sent from GPU. If invalid, returns false and sets an error
// message to |error_message_|.
@@ -192,7 +212,14 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
bool DestroyAnonymousBuffer(uint32_t buffer_id);
- base::flat_map<gfx::AcceleratedWidget, std::unique_ptr<Surface>> surfaces_;
+ base::flat_map<WaylandSurface*, std::unique_ptr<Surface>> surfaces_;
+
+ // When a WaylandWindow/WaylandSubsurface is removed, its corresponding
+ // Surface may still have an un-released buffer and un-acked presentation.
+ // Thus, we keep removed surfaces in the graveyard. It's safe to delete them
+ // when all of the Surface's buffers are destroyed because buffer destruction
+ // is deferred till after buffers are released and presentations are acked.
+ std::list<std::unique_ptr<Surface>> surface_graveyard_;
// Set when invalid data is received from the GPU process.
std::string error_message_;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc
index a0e848a216d..7e1cdf1aee4 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc
@@ -109,7 +109,7 @@ class ClipboardImpl final : public Clipboard, public DataSource::Delegate {
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());
+ contents->assign(it->second->data().begin(), it->second->data().end());
}
// The device manager used to access data device and create data sources.
@@ -157,8 +157,10 @@ void WaylandClipboard::RequestClipboardData(
data_map_ = data_map;
read_clipboard_closure_ = std::move(callback);
auto* clipboard = GetClipboard(buffer);
- if (!clipboard || !clipboard->Read(mime_type))
- SetData({}, mime_type);
+ if (!clipboard || !clipboard->Read(mime_type)) {
+ SetData(scoped_refptr<base::RefCountedBytes>(new base::RefCountedBytes()),
+ mime_type);
+ }
}
bool WaylandClipboard::IsSelectionOwner(ClipboardBuffer buffer) {
@@ -183,11 +185,16 @@ void WaylandClipboard::GetAvailableMimeTypes(
std::move(callback).Run(mime_types);
}
-void WaylandClipboard::SetData(const std::vector<uint8_t>& contents,
+bool WaylandClipboard::IsSelectionBufferAvailable() const {
+ return (connection_->primary_selection_device_manager() != nullptr);
+}
+
+void WaylandClipboard::SetData(PlatformClipboard::Data contents,
const std::string& mime_type) {
if (!data_map_)
return;
+ DCHECK(contents);
(*data_map_)[mime_type] = contents;
if (!read_clipboard_closure_.is_null()) {
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h
index d4641406e0c..515c85ca6c3 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h
@@ -53,11 +53,11 @@ class WaylandClipboard : public PlatformClipboard {
bool IsSelectionOwner(ClipboardBuffer buffer) override;
void SetSequenceNumberUpdateCb(
PlatformClipboard::SequenceNumberUpdateCb cb) override;
+ bool IsSelectionBufferAvailable() const override;
// 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 SetData(PlatformClipboard::Data contents, const std::string& mime_type);
void UpdateSequenceNumber(ClipboardBuffer buffer);
private:
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc b/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc
index 0246bc58695..febebefad2c 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc
@@ -14,8 +14,8 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop_current.h"
#include "base/strings/string_util.h"
+#include "base/task/current_thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include "ui/gfx/geometry/point.h"
@@ -52,6 +52,7 @@ constexpr uint32_t kMaxXdgShellVersion = 1;
constexpr uint32_t kMaxDeviceManagerVersion = 3;
constexpr uint32_t kMaxWpPresentationVersion = 1;
constexpr uint32_t kMaxTextInputManagerVersion = 1;
+constexpr uint32_t kMinAuraShellVersion = 10;
constexpr uint32_t kMinWlDrmVersion = 2;
constexpr uint32_t kMinWlOutputVersion = 2;
} // namespace
@@ -117,7 +118,7 @@ void WaylandConnection::ScheduleFlush() {
// When we are in tests, the message loop is set later when the
// initialization of the OzonePlatform complete. Thus, just
// flush directly. This doesn't happen in normal run.
- if (!base::MessageLoopCurrentForUI::IsSet()) {
+ if (!base::CurrentUIThread::IsSet()) {
Flush();
} else if (!scheduled_flush_) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -140,6 +141,12 @@ bool WaylandConnection::IsDragInProgress() const {
WaylandDataDragController::State::kIdle;
}
+wl::Object<wl_surface> WaylandConnection::CreateSurface() {
+ DCHECK(compositor_);
+ return wl::Object<wl_surface>(
+ wl_compositor_create_surface(compositor_.get()));
+}
+
void WaylandConnection::Flush() {
wl_display_flush(display_.get());
scheduled_flush_ = false;
@@ -157,26 +164,33 @@ void WaylandConnection::UpdateInputDevices(wl_seat* seat,
pointer_.reset();
cursor_.reset();
wayland_cursor_position_.reset();
- } else if (wl_pointer* pointer = wl_seat_get_pointer(seat)) {
- pointer_ = std::make_unique<WaylandPointer>(pointer, this, event_source());
- cursor_ = std::make_unique<WaylandCursor>(pointer_.get(), this);
- wayland_cursor_position_ = std::make_unique<WaylandCursorPosition>();
- } else {
- LOG(ERROR) << "Failed to get wl_pointer from seat";
+ } else if (!pointer_) {
+ if (wl_pointer* pointer = wl_seat_get_pointer(seat)) {
+ pointer_ =
+ std::make_unique<WaylandPointer>(pointer, this, event_source());
+ cursor_ = std::make_unique<WaylandCursor>(pointer_.get(), this);
+ wayland_cursor_position_ = std::make_unique<WaylandCursorPosition>();
+ } else {
+ LOG(ERROR) << "Failed to get wl_pointer from seat";
+ }
}
if (!has_keyboard) {
keyboard_.reset();
- } else if (!CreateKeyboard()) {
- LOG(ERROR) << "Failed to create WaylandKeyboard";
+ } else if (!keyboard_) {
+ if (!CreateKeyboard()) {
+ LOG(ERROR) << "Failed to create WaylandKeyboard";
+ }
}
if (!has_touch) {
touch_.reset();
- } else if (wl_touch* touch = wl_seat_get_touch(seat)) {
- touch_ = std::make_unique<WaylandTouch>(touch, this, event_source());
- } else {
- LOG(ERROR) << "Failed to get wl_touch from seat";
+ } else if (!touch_) {
+ if (wl_touch* touch = wl_seat_get_touch(seat)) {
+ touch_ = std::make_unique<WaylandTouch>(touch, this, event_source());
+ } else {
+ LOG(ERROR) << "Failed to get wl_touch from seat";
+ }
}
}
@@ -352,6 +366,15 @@ void WaylandConnection::Global(void* data,
auto wayland_drm = wl::Bind<struct wl_drm>(registry, name, version);
connection->drm_ =
std::make_unique<WaylandDrm>(wayland_drm.release(), connection);
+ } else if (!connection->aura_shell_ &&
+ (strcmp(interface, "zaura_shell") == 0) &&
+ version >= kMinAuraShellVersion) {
+ connection->aura_shell_ =
+ wl::Bind<struct zaura_shell>(registry, name, version);
+ if (!connection->aura_shell_) {
+ LOG(ERROR) << "Failed to bind zaura_shell";
+ return;
+ }
}
connection->ScheduleFlush();
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection.h b/chromium/ui/ozone/platform/wayland/host/wayland_connection.h
index 5c5754dd2fa..6dfc5b7a560 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_connection.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection.h
@@ -54,6 +54,7 @@ class WaylandConnection {
wl_subcompositor* subcompositor() const { return subcompositor_.get(); }
xdg_wm_base* shell() const { return shell_.get(); }
zxdg_shell_v6* shell_v6() const { return shell_v6_.get(); }
+ zaura_shell* aura_shell() const { return aura_shell_.get(); }
wl_seat* seat() const { return seat_.get(); }
wp_presentation* presentation() const { return presentation_.get(); }
zwp_text_input_manager_v1* text_input_manager_v1() const {
@@ -121,6 +122,9 @@ class WaylandConnection {
// Returns true when dragging is entered or started.
bool IsDragInProgress() const;
+ // Creates a new wl_surface.
+ wl::Object<wl_surface> CreateSurface();
+
private:
void Flush();
void UpdateInputDevices(wl_seat* seat, uint32_t capabilities);
@@ -162,6 +166,7 @@ class WaylandConnection {
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_;
+ wl::Object<zaura_shell> aura_shell_;
// Event source instance. Must be declared before input objects so it
// outlives them so thus being able to properly handle their destruction.
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc
index 7ffd900fcae..fa12bbb1e31 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc
@@ -19,13 +19,9 @@ namespace ui {
WaylandCursor::WaylandCursor(WaylandPointer* pointer,
WaylandConnection* connection)
- : pointer_(pointer), connection_(connection) {
- DCHECK(connection);
- DCHECK(connection->compositor());
-
- pointer_surface_.reset(
- wl_compositor_create_surface(connection->compositor()));
-}
+ : pointer_(pointer),
+ connection_(connection),
+ pointer_surface_(connection->CreateSurface()) {}
WaylandCursor::~WaylandCursor() = default;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h
index 5f8b6364bd4..1f73050be9b 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h
@@ -56,7 +56,7 @@ class WaylandCursor {
// Holds the buffers and their memory until the compositor releases them.
base::flat_map<wl_buffer*, WaylandShmBuffer> buffers_;
- wl::Object<wl_surface> pointer_surface_;
+ const wl::Object<wl_surface> pointer_surface_;
DISALLOW_COPY_AND_ASSIGN(WaylandCursor);
};
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 1edd356006b..f80738e5e34 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc
@@ -43,8 +43,8 @@ void WaylandDataDevice::StartDrag(const WaylandDataSource& data_source,
drag_delegate_ = delegate;
wl_data_device_start_drag(data_device_.get(), data_source.data_source(),
- origin_window.surface(), icon_surface,
- connection()->serial());
+ origin_window.root_surface()->surface(),
+ icon_surface, connection()->serial());
drag_delegate_->DrawIcon();
connection()->ScheduleFlush();
}
@@ -81,12 +81,12 @@ void WaylandDataDevice::SetSelectionSource(WaylandDataSource* source) {
connection()->ScheduleFlush();
}
-void WaylandDataDevice::ReadDragDataFromFD(
- base::ScopedFD fd,
- base::OnceCallback<void(const PlatformClipboard::Data&)> callback) {
- PlatformClipboard::Data contents;
+void WaylandDataDevice::ReadDragDataFromFD(base::ScopedFD fd,
+ RequestDataCallback callback) {
+ std::vector<uint8_t> contents;
wl::ReadDataFromFD(std::move(fd), &contents);
- std::move(callback).Run(contents);
+ std::move(callback).Run(scoped_refptr<base::RefCountedBytes>(
+ base::RefCountedBytes::TakeVector(&contents)));
}
// static
@@ -109,7 +109,7 @@ void WaylandDataDevice::OnEnter(void* data,
wl_fixed_t x,
wl_fixed_t y,
wl_data_offer* offer) {
- WaylandWindow* window = WaylandWindow::FromSurface(surface);
+ WaylandWindow* window = wl::RootWindowFromWlSurface(surface);
if (!window) {
LOG(ERROR) << "Failed to get window.";
return;
@@ -149,15 +149,15 @@ void WaylandDataDevice::OnDrop(void* data, wl_data_device* data_device) {
void WaylandDataDevice::OnLeave(void* data, wl_data_device* data_device) {
auto* self = static_cast<WaylandDataDevice*>(data);
- if (self->drag_delegate_) {
+ if (self->drag_delegate_)
self->drag_delegate_->OnDragLeave();
- // 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;
- }
+ // 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. Above call to OnDragLeave() may result in
+ // |drag_delegate_| being reset, so it must be checked here as well.
+ if (self->drag_delegate_ && !self->drag_delegate_->IsDragSource())
+ self->drag_delegate_ = nullptr;
}
void WaylandDataDevice::OnSelection(void* data,
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 5512f4c4480..12b84cf9cb1 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h
@@ -13,6 +13,7 @@
#include "base/callback.h"
#include "base/files/scoped_file.h"
+#include "base/gtest_prod_util.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"
@@ -32,8 +33,7 @@ class WaylandWindow;
// such as copy-and-paste and drag-and-drop mechanisms.
class WaylandDataDevice : public WaylandDataDeviceBase {
public:
- using RequestDataCallback =
- base::OnceCallback<void(const PlatformClipboard::Data&)>;
+ using RequestDataCallback = base::OnceCallback<void(PlatformClipboard::Data)>;
// DragDelegate is responsible for handling drag and drop sessions.
class DragDelegate {
@@ -79,6 +79,8 @@ class WaylandDataDevice : public WaylandDataDeviceBase {
void SetSelectionSource(WaylandDataSource* source);
private:
+ FRIEND_TEST_ALL_PREFIXES(WaylandDataDragControllerTest, StartDrag);
+
void ReadDragDataFromFD(base::ScopedFD fd, RequestDataCallback callback);
// wl_data_device_listener callbacks
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 3e020a31134..7df5d9ec709 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
@@ -56,7 +56,10 @@ void WaylandDataDeviceBase::ReadClipboardDataFromFD(
const std::string& mime_type) {
std::vector<uint8_t> contents;
wl::ReadDataFromFD(std::move(fd), &contents);
- connection_->clipboard()->SetData(contents, mime_type);
+ connection_->clipboard()->SetData(
+ scoped_refptr<base::RefCountedBytes>(
+ base::RefCountedBytes::TakeVector(&contents)),
+ mime_type);
}
void WaylandDataDeviceBase::RegisterDeferredReadCallback() {
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 b4bedb59ac9..855982cf567 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
@@ -15,7 +15,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/clipboard/clipboard_constants.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"
#include "ui/ozone/platform/wayland/test/test_data_device.h"
#include "ui/ozone/platform/wayland/test/test_data_device_manager.h"
@@ -32,15 +31,14 @@ namespace ui {
namespace {
+constexpr char kSampleClipboardText[] = "This is a sample text for clipboard.";
+
template <typename StringType>
ui::PlatformClipboard::Data ToClipboardData(const StringType& data_string) {
- ui::PlatformClipboard::Data result;
- auto* begin =
- reinterpret_cast<typename ui::PlatformClipboard::Data::const_pointer>(
- data_string.data());
- result.assign(begin, begin + (data_string.size() *
- sizeof(typename StringType::value_type)));
- return result;
+ std::vector<uint8_t> data_vector;
+ data_vector.assign(data_string.begin(), data_string.end());
+ return scoped_refptr<base::RefCountedBytes>(
+ base::RefCountedBytes::TakeVector(&data_vector));
}
} // namespace
@@ -64,7 +62,7 @@ class MockClipboardClient {
~MockClipboardClient() = default;
// Fill the clipboard backing store with sample data.
- void SetData(const PlatformClipboard::Data& data,
+ void SetData(PlatformClipboard::Data data,
const std::string& mime_type,
PlatformClipboard::OfferDataClosure callback) {
data_types_[mime_type] = data;
@@ -115,23 +113,25 @@ class WaylandDataDeviceManagerTest : public WaylandTest {
TEST_P(WaylandDataDeviceManagerTest, WriteToClipboard) {
// The client writes data to the clipboard ...
- PlatformClipboard::Data data;
- data.assign(wl::kSampleClipboardText,
- wl::kSampleClipboardText + strlen(wl::kSampleClipboardText));
- clipboard_client_->SetData(data, wl::kTextMimeTypeUtf8,
- base::BindOnce([]() {}));
+ std::vector<uint8_t> data_vector(
+ kSampleClipboardText,
+ kSampleClipboardText + strlen(kSampleClipboardText));
+ clipboard_client_->SetData(
+ scoped_refptr<base::RefCountedBytes>(
+ base::RefCountedBytes::TakeVector(&data_vector)),
+ {kMimeTypeTextUtf8}, base::BindOnce([]() {}));
Sync();
// ... and the server reads it.
base::RunLoop run_loop;
auto callback = base::BindOnce(
- [](base::RunLoop* loop, PlatformClipboard::Data&& data) {
+ [](base::RunLoop* loop, std::vector<uint8_t>&& data) {
std::string string_data(data.begin(), data.end());
- EXPECT_EQ(wl::kSampleClipboardText, string_data);
+ EXPECT_EQ(kSampleClipboardText, string_data);
loop->Quit();
},
&run_loop);
- data_device_manager_->data_source()->ReadData(wl::kTextMimeTypeUtf8,
+ data_device_manager_->data_source()->ReadData(kMimeTypeTextUtf8,
std::move(callback));
run_loop.Run();
}
@@ -140,8 +140,8 @@ TEST_P(WaylandDataDeviceManagerTest, ReadFromClipboard) {
// TODO(nickdiego): implement this in terms of an actual wl_surface that
// gets focused and compositor sends data_device data to it.
auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
- data_offer->OnOffer(wl::kTextMimeTypeUtf8,
- ToClipboardData(std::string(wl::kSampleClipboardText)));
+ data_offer->OnOffer(kMimeTypeTextUtf8,
+ ToClipboardData(std::string(kSampleClipboardText)));
data_device_manager_->data_device()->OnSelection(data_offer);
Sync();
@@ -150,10 +150,11 @@ TEST_P(WaylandDataDeviceManagerTest, ReadFromClipboard) {
// expectation.
auto callback =
base::BindOnce([](const base::Optional<PlatformClipboard::Data>& data) {
- std::string string_data = std::string(data->begin(), data->end());
- EXPECT_EQ(wl::kSampleClipboardText, string_data);
+ auto& bytes = data->get()->data();
+ std::string string_data = std::string(bytes.begin(), bytes.end());
+ EXPECT_EQ(kSampleClipboardText, string_data);
});
- clipboard_client_->ReadData(wl::kTextMimeTypeUtf8, std::move(callback));
+ clipboard_client_->ReadData(kMimeTypeTextUtf8, std::move(callback));
Sync();
}
@@ -163,18 +164,22 @@ TEST_P(WaylandDataDeviceManagerTest, ReadFromClipboardWithoutOffer) {
// an empty string.
auto callback =
base::BindOnce([](const base::Optional<PlatformClipboard::Data>& data) {
- std::string string_data = std::string(data->begin(), data->end());
+ auto& bytes = data->get()->data();
+ std::string string_data = std::string(bytes.begin(), bytes.end());
EXPECT_EQ("", string_data);
});
- clipboard_client_->ReadData(wl::kTextMimeTypeUtf8, std::move(callback));
+ clipboard_client_->ReadData(kMimeTypeTextUtf8, std::move(callback));
}
TEST_P(WaylandDataDeviceManagerTest, IsSelectionOwner) {
auto callback = base::BindOnce([]() {});
- PlatformClipboard::Data data;
- data.assign(wl::kSampleClipboardText,
- wl::kSampleClipboardText + strlen(wl::kSampleClipboardText));
- clipboard_client_->SetData(data, wl::kTextMimeTypeUtf8, std::move(callback));
+ std::vector<uint8_t> data_vector(
+ kSampleClipboardText,
+ kSampleClipboardText + strlen(kSampleClipboardText));
+ clipboard_client_->SetData(
+ scoped_refptr<base::RefCountedBytes>(
+ base::RefCountedBytes::TakeVector(&data_vector)),
+ {kMimeTypeTextUtf8}, std::move(callback));
Sync();
ASSERT_TRUE(clipboard_client_->IsSelectionOwner());
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
index ec14c3e3b7f..e4337897d54 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
@@ -96,7 +96,7 @@ void WaylandDataDragController::StartSession(const OSExchangeData& data,
Offer(data, operation);
// Create drag icon surface (if any) and store the data to be exchanged.
- icon_surface_.reset(CreateIconSurfaceIfNeeded(data));
+ CreateIconSurfaceIfNeeded(data);
data_ = std::make_unique<OSExchangeData>(data.provider().Clone());
// Starts the wayland drag session setting |this| object as delegate.
@@ -216,13 +216,21 @@ void WaylandDataDragController::OnDragDrop() {
void WaylandDataDragController::OnDataSourceFinish(bool completed) {
DCHECK(data_source_);
- if (origin_window_)
- origin_window_->OnDragSessionClose(data_source_->dnd_action());
+ DCHECK(origin_window_);
+
+ origin_window_->OnDragSessionClose(data_source_->dnd_action());
+
+ // DnD handlers expect DragLeave to be sent for drag sessions that end up
+ // with no data transfer (wl_data_source::cancelled event).
+ if (!completed)
+ origin_window_->OnDragLeave();
origin_window_ = nullptr;
data_source_.reset();
data_offer_.reset();
data_.reset();
+ data_device_->ResetDragDelegate();
+
state_ = State::kIdle;
}
@@ -265,11 +273,11 @@ void WaylandDataDragController::Offer(const OSExchangeData& data,
data_source_->SetAction(operation);
}
-wl_surface* WaylandDataDragController::CreateIconSurfaceIfNeeded(
+void WaylandDataDragController::CreateIconSurfaceIfNeeded(
const OSExchangeData& data) {
icon_bitmap_ = GetDragImage(data);
- return icon_bitmap_ ? wl_compositor_create_surface(connection_->compositor())
- : nullptr;
+ if (icon_bitmap_)
+ icon_surface_ = connection_->CreateSurface();
}
// Asynchronously requests and reads data for every negotiated/supported mime
@@ -293,9 +301,10 @@ void WaylandDataDragController::HandleUnprocessedMimeTypes() {
}
void WaylandDataDragController::OnMimeTypeDataTransferred(
- const PlatformClipboard::Data& contents) {
+ PlatformClipboard::Data contents) {
DCHECK_EQ(state_, State::kTransferring);
- if (!contents.empty()) {
+ DCHECK(contents);
+ if (!contents->data().empty()) {
std::string mime_type = unprocessed_mime_types_.front();
wl::AddToOSExchangeData(contents, mime_type, received_data_.get());
}
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
index 2d1e1b09d6d..5e4c15dd08b 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
@@ -78,9 +78,9 @@ class WaylandDataDragController : public WaylandDataDevice::DragDelegate,
std::string* contents) override;
void Offer(const OSExchangeData& data, int operation);
- wl_surface* CreateIconSurfaceIfNeeded(const OSExchangeData& data);
+ void CreateIconSurfaceIfNeeded(const OSExchangeData& data);
void HandleUnprocessedMimeTypes();
- void OnMimeTypeDataTransferred(const PlatformClipboard::Data& contents);
+ void OnMimeTypeDataTransferred(PlatformClipboard::Data contents);
void OnDataTransferFinished(
std::unique_ptr<ui::OSExchangeData> received_data);
std::string GetNextUnprocessedMimeType();
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
index a320c70dd1d..8bd11603863 100644
--- 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
@@ -14,16 +14,18 @@
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/clipboard/clipboard_constants.h"
+#include "ui/base/cursor/cursor.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/gfx/geometry/point.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/host/wayland_toplevel_window.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"
@@ -32,7 +34,9 @@
#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 "ui/platform_window/platform_window_init_properties.h"
+#include "ui/platform_window/wm/wm_drag_handler.h"
+#include "ui/platform_window/wm/wm_drop_handler.h"
#include "url/gurl.h"
using testing::_;
@@ -42,32 +46,45 @@ namespace ui {
namespace {
+constexpr char kSampleTextForDragAndDrop[] =
+ "This is a sample text for drag-and-drop.";
+
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;
+ auto* begin = reinterpret_cast<typename std::vector<uint8_t>::const_pointer>(
+ data_string.data());
+ std::vector<uint8_t> result(
+ begin,
+ begin + (data_string.size() * sizeof(typename StringType::value_type)));
+ return scoped_refptr<base::RefCountedBytes>(
+ base::RefCountedBytes::TakeVector(&result));
}
} // namespace
+class MockDragHandlerDelegate : public WmDragHandler::Delegate {
+ public:
+ MOCK_METHOD1(OnDragLocationChanged, void(const gfx::Point& location));
+ MOCK_METHOD1(OnDragOperationChanged,
+ void(DragDropTypes::DragOperation operation));
+ MOCK_METHOD1(OnDragFinished, void(int operation));
+};
+
class MockDropHandler : public WmDropHandler {
public:
MockDropHandler() = default;
~MockDropHandler() override = default;
- MOCK_METHOD3(OnDragEnter,
+ MOCK_METHOD4(OnDragEnter,
void(const gfx::PointF& point,
std::unique_ptr<OSExchangeData> data,
- int operation));
- MOCK_METHOD2(OnDragMotion, int(const gfx::PointF& point, int operation));
+ int operation,
+ int modifiers));
+ MOCK_METHOD3(OnDragMotion,
+ int(const gfx::PointF& point, int operation, int modifiers));
MOCK_METHOD0(MockOnDragDrop, void());
MOCK_METHOD0(OnDragLeave, void());
@@ -78,7 +95,8 @@ class MockDropHandler : public WmDropHandler {
OSExchangeData* dropped_data() { return dropped_data_.get(); }
protected:
- void OnDragDrop(std::unique_ptr<OSExchangeData> data) override {
+ void OnDragDrop(std::unique_ptr<OSExchangeData> data,
+ int modifiers) override {
dropped_data_ = std::move(data);
MockOnDragDrop();
on_drop_closure_.Run();
@@ -103,6 +121,7 @@ class WaylandDataDragControllerTest : public WaylandTest {
data_device_manager_ = server_.data_device_manager();
DCHECK(data_device_manager_);
+ drag_handler_delegate_ = std::make_unique<MockDragHandlerDelegate>();
drop_handler_ = std::make_unique<MockDropHandler>();
SetWmDropHandler(window_.get(), drop_handler_.get());
}
@@ -116,38 +135,88 @@ class WaylandDataDragControllerTest : public WaylandTest {
}
base::string16 sample_text_for_dnd() const {
- static auto text = base::ASCIIToUTF16(wl::kSampleTextForDragAndDrop);
+ static auto text = base::ASCIIToUTF16(kSampleTextForDragAndDrop);
return text;
}
+ void ReadDataWhenSourceIsReady() {
+ Sync();
+
+ if (!data_device_manager_->data_source()) {
+ // The data source is created asynchronously via the window's data drag
+ // controller. If it is null now, it means that the task for that has not
+ // yet executed, and we have to come later.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &WaylandDataDragControllerTest::ReadDataWhenSourceIsReady,
+ base::Unretained(this)));
+ return;
+ }
+
+ // Now the server can read the data and give it to our callback.
+ base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+ auto callback = base::BindOnce(
+ [](base::RunLoop* loop, std::vector<uint8_t>&& data) {
+ std::string result(data.begin(), data.end());
+ EXPECT_EQ(kSampleTextForDragAndDrop, result);
+ loop->Quit();
+ },
+ &run_loop);
+ data_device_manager_->data_source()->ReadData(kMimeTypeTextUtf8,
+ std::move(callback));
+ run_loop.Run();
+
+ data_device_manager_->data_source()->OnCancelled();
+ Sync();
+ }
+
+ void ScheduleDragCancel() {
+ Sync();
+
+ if (!data_device_manager_->data_source()) {
+ // The data source is created asynchronously by the data drag controller.
+ // If it is null at this point, it means that the task for that has not
+ // yet executed, and we have to try again a bit later.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&WaylandDataDragControllerTest::ScheduleDragCancel,
+ base::Unretained(this)));
+ return;
+ }
+
+ data_device_manager_->data_source()->OnCancelled();
+ Sync();
+ }
+
protected:
wl::TestDataDeviceManager* data_device_manager_;
std::unique_ptr<MockDropHandler> drop_handler_;
+ std::unique_ptr<MockDragHandlerDelegate> drag_handler_delegate_;
};
TEST_P(WaylandDataDragControllerTest, StartDrag) {
- bool restored_focus = window_->has_pointer_focus();
+ const bool restored_focus = window_->has_pointer_focus();
window_->SetPointerFocus(true);
// The client starts dragging.
+ ASSERT_EQ(PlatformWindowType::kWindow, window_->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);
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&WaylandDataDragControllerTest::ReadDataWhenSourceIsReady,
+ base::Unretained(this)));
+
+ static_cast<WaylandToplevelWindow*>(window_.get())
+ ->StartDrag(os_exchange_data,
+ DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE, {}, true,
+ drag_handler_delegate_.get());
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();
+ EXPECT_FALSE(data_device()->drag_delegate_);
+
window_->SetPointerFocus(restored_focus);
}
@@ -166,7 +235,7 @@ TEST_P(WaylandDataDragControllerTest, StartDragWithWrongMimeType) {
// to read it with a different mime type.
base::RunLoop run_loop;
auto callback = base::BindOnce(
- [](base::RunLoop* loop, PlatformClipboard::Data&& data) {
+ [](base::RunLoop* loop, std::vector<uint8_t>&& data) {
std::string result(data.begin(), data.end());
EXPECT_TRUE(result.empty());
loop->Quit();
@@ -194,9 +263,9 @@ TEST_P(WaylandDataDragControllerTest, StartDragWithText) {
// |kTextMimeTypeUtf8|.
base::RunLoop run_loop;
auto callback = base::BindOnce(
- [](base::RunLoop* loop, PlatformClipboard::Data&& data) {
+ [](base::RunLoop* loop, std::vector<uint8_t>&& data) {
std::string result(data.begin(), data.end());
- EXPECT_EQ(wl::kSampleTextForDragAndDrop, result);
+ EXPECT_EQ(kSampleTextForDragAndDrop, result);
loop->Quit();
},
&run_loop);
@@ -208,9 +277,8 @@ TEST_P(WaylandDataDragControllerTest, StartDragWithText) {
TEST_P(WaylandDataDragControllerTest, ReceiveDrag) {
auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
- data_offer->OnOffer(
- kMimeTypeText,
- ToClipboardData(std::string(wl::kSampleTextForDragAndDrop)));
+ data_offer->OnOffer(kMimeTypeText,
+ ToClipboardData(std::string(kSampleTextForDragAndDrop)));
gfx::Point entered_point(10, 10);
// The server sends an enter event.
@@ -229,11 +297,11 @@ TEST_P(WaylandDataDragControllerTest, ReceiveDrag) {
Sync();
- auto callback = base::BindOnce([](const PlatformClipboard::Data& contents) {
+ auto callback = base::BindOnce([](PlatformClipboard::Data contents) {
std::string result;
- result.assign(reinterpret_cast<std::string::const_pointer>(&contents[0]),
- contents.size());
- EXPECT_EQ(wl::kSampleTextForDragAndDrop, result);
+ EXPECT_TRUE(contents);
+ result.assign(contents->front_as<char>(), contents->size());
+ EXPECT_EQ(kSampleTextForDragAndDrop, result);
});
// The client requests the data and gets callback with it.
@@ -246,9 +314,8 @@ TEST_P(WaylandDataDragControllerTest, ReceiveDrag) {
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(kMimeTypeText,
+ ToClipboardData(std::string(kSampleTextForDragAndDrop)));
data_offer->OnOffer(kMimeTypeMozillaURL, ToClipboardData(base::UTF8ToUTF16(
"https://sample.com/\r\n"
"Sample")));
@@ -256,7 +323,7 @@ TEST_P(WaylandDataDragControllerTest, DropSeveralMimeTypes) {
kMimeTypeURIList,
ToClipboardData(std::string("file:///home/user/file\r\n")));
- EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _)).Times(1);
+ 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()),
@@ -303,7 +370,7 @@ TEST_P(WaylandDataDragControllerTest, ValidateDroppedUriList) {
auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
data_offer->OnOffer(kMimeTypeURIList, ToClipboardData(kCase.content));
- EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _)).Times(1);
+ 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()),
@@ -358,7 +425,7 @@ TEST_P(WaylandDataDragControllerTest, ValidateDroppedXMozUrl) {
data_offer->OnOffer(kMimeTypeMozillaURL,
ToClipboardData(base::UTF8ToUTF16(kCase.content)));
- EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _)).Times(1);
+ 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()),
@@ -395,6 +462,35 @@ TEST_P(WaylandDataDragControllerTest, ValidateDroppedXMozUrl) {
}
}
+// Verifies the correct delegate functions are called when a drag session is
+// started and cancelled within the same surface.
+TEST_P(WaylandDataDragControllerTest, StartAndCancel) {
+ const bool restored_focus = window_->has_pointer_focus();
+ window_->SetPointerFocus(true);
+
+ ASSERT_EQ(PlatformWindowType::kWindow, window_->type());
+ OSExchangeData os_exchange_data;
+ os_exchange_data.SetString(sample_text_for_dnd());
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&WaylandDataDragControllerTest::ScheduleDragCancel,
+ base::Unretained(this)));
+
+ // DnD handlers expect DragLeave to be sent before DragFinished when drag
+ // sessions end up with no data transfer (cancelled). Otherwise, it might lead
+ // to issues like https://crbug.com/1109324.
+ EXPECT_CALL(*drop_handler_, OnDragLeave()).Times(1);
+ EXPECT_CALL(*drag_handler_delegate_, OnDragFinished(_)).Times(1);
+
+ static_cast<WaylandToplevelWindow*>(window_.get())
+ ->StartDrag(os_exchange_data, DragDropTypes::DRAG_COPY, {}, true,
+ drag_handler_delegate_.get());
+ Sync();
+
+ window_->SetPointerFocus(restored_focus);
+}
+
INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
WaylandDataDragControllerTest,
::testing::Values(kXdgShellStable));
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer_base.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer_base.cc
index 8656f41412c..cbdd82a25d0 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer_base.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer_base.cc
@@ -9,14 +9,6 @@
namespace ui {
-namespace {
-
-const char kString[] = "STRING";
-const char kText[] = "TEXT";
-const char kUtf8String[] = "UTF8_STRING";
-
-} // namespace
-
WaylandDataOfferBase::WaylandDataOfferBase() = default;
WaylandDataOfferBase::~WaylandDataOfferBase() = default;
@@ -26,9 +18,10 @@ void WaylandDataOfferBase::EnsureTextMimeTypeIfNeeded() {
if (std::any_of(mime_types_.begin(), mime_types_.end(),
[](const std::string& mime_type) {
- return mime_type == kString || mime_type == kText ||
+ return mime_type == kMimeTypeLinuxString ||
+ mime_type == kMimeTypeLinuxText ||
mime_type == kMimeTypeTextUtf8 ||
- mime_type == kUtf8String;
+ mime_type == kMimeTypeLinuxUtf8String;
})) {
mime_types_.push_back(kMimeTypeText);
text_plain_mime_type_inserted_ = true;
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 48d500ae5fb..41f186362f9 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc
@@ -161,13 +161,18 @@ void WaylandEventSource::OnPointerFocusChanged(WaylandWindow* window,
}
void WaylandEventSource::OnPointerButtonEvent(EventType type,
- int changed_button) {
+ int changed_button,
+ WaylandWindow* window) {
DCHECK(type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED);
DCHECK(HasAnyPointerButtonFlag(changed_button));
if (!pointer_)
return;
+ auto* prev_focused_window = window_with_pointer_focus_;
+ if (window)
+ HandlePointerFocusChange(window);
+
pointer_flags_ = type == ET_MOUSE_PRESSED
? (pointer_flags_ | changed_button)
: (pointer_flags_ & ~changed_button);
@@ -177,6 +182,9 @@ void WaylandEventSource::OnPointerButtonEvent(EventType type,
MouseEvent event(type, pointer_location_, pointer_location_,
EventTimeForNow(), flags, changed_button);
DispatchEvent(&event);
+
+ if (window)
+ HandlePointerFocusChange(prev_focused_window);
}
void WaylandEventSource::OnPointerMotionEvent(const gfx::PointF& location) {
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 7c9c409e702..e646df4fd4d 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h
@@ -59,6 +59,8 @@ class WaylandEventSource : public PlatformEventSource,
return last_pointer_button_pressed_;
}
+ int keyboard_modifiers() const { return keyboard_modifiers_; }
+
// 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.
@@ -92,7 +94,9 @@ class WaylandEventSource : public PlatformEventSource,
void OnPointerDestroyed(WaylandPointer* pointer) override;
void OnPointerFocusChanged(WaylandWindow* window,
const gfx::PointF& location) override;
- void OnPointerButtonEvent(EventType evtype, int changed_button) override;
+ void OnPointerButtonEvent(EventType evtype,
+ int changed_button,
+ WaylandWindow* window = nullptr) override;
void OnPointerMotionEvent(const gfx::PointF& location) override;
void OnPointerAxisEvent(const gfx::Vector2d& offset) override;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc
index 9cec9ccbd4b..34bf114fa03 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc
@@ -79,7 +79,9 @@ TEST_P(WaylandEventSourceTest, CheckPointerButtonHandling) {
uint32_t serial = 0;
uint32_t tstamp = 0;
wl_resource* surface_res =
- server_.GetObject<wl::MockSurface>(window1->GetWidget())->resource();
+ server_
+ .GetObject<wl::MockSurface>(window1->root_surface()->GetSurfaceId())
+ ->resource();
wl_resource* pointer_res = server_.seat()->pointer()->resource();
wl_pointer_send_enter(pointer_res, serial++, surface_res, 0, 0);
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc
index 30325c45884..52f5eb0e870 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc
@@ -9,7 +9,7 @@
#include "base/bind.h"
#include "base/check.h"
-#include "base/message_loop/message_loop_current.h"
+#include "base/task/current_thread.h"
#include "ui/events/event.h"
namespace ui {
@@ -38,7 +38,7 @@ bool WaylandEventWatcher::StopProcessingEvents() {
if (!watching_)
return false;
- DCHECK(base::MessageLoopCurrentForUI::IsSet());
+ DCHECK(base::CurrentUIThread::IsSet());
watching_ = false;
return controller_.StopWatchingFileDescriptor();
}
@@ -85,9 +85,9 @@ bool WaylandEventWatcher::StartWatchingFd(
DCHECK(!watching_);
}
- DCHECK(base::MessageLoopCurrentForUI::IsSet());
+ DCHECK(base::CurrentUIThread::IsSet());
int display_fd = wl_display_get_fd(display_);
- watching_ = base::MessageLoopCurrentForUI::Get()->WatchFileDescriptor(
+ watching_ = base::CurrentUIThread::Get()->WatchFileDescriptor(
display_fd, true, mode, &controller_, this);
return watching_;
}
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc
index 7de0fe694d7..a4c905b7895 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc
@@ -20,6 +20,7 @@
#include "ui/events/ozone/layout/keyboard_layout_engine.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include "ui/events/types/event_type.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_window.h"
@@ -101,7 +102,7 @@ void WaylandKeyboard::Enter(void* data,
wl_surface* surface,
wl_array* keys) {
// wl_surface might have been destroyed by this time.
- if (auto* window = WaylandWindow::FromSurface(surface)) {
+ if (auto* window = wl::RootWindowFromWlSurface(surface)) {
auto* self = static_cast<WaylandKeyboard*>(data);
self->delegate_->OnKeyboardFocusChanged(window, /*focused=*/true);
}
@@ -113,7 +114,7 @@ void WaylandKeyboard::Leave(void* data,
wl_surface* surface) {
// wl_surface might have been destroyed by this time.
auto* self = static_cast<WaylandKeyboard*>(data);
- if (auto* window = WaylandWindow::FromSurface(surface))
+ if (auto* window = wl::RootWindowFromWlSurface(surface))
self->delegate_->OnKeyboardFocusChanged(window, /*focused=*/false);
// Upon window focus lose, reset the key repeat timers.
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_output.cc b/chromium/ui/ozone/platform/wayland/host/wayland_output.cc
index 701f1678b19..7a4067df952 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_output.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_output.cc
@@ -11,7 +11,7 @@
namespace ui {
-WaylandOutput::WaylandOutput(const uint32_t output_id, wl_output* output)
+WaylandOutput::WaylandOutput(uint32_t output_id, wl_output* output)
: output_id_(output_id),
output_(output),
scale_factor_(kDefaultScaleFactor),
@@ -31,7 +31,7 @@ void WaylandOutput::Initialize(Delegate* delegate) {
wl_output_add_listener(output_.get(), &output_listener, this);
}
-void WaylandOutput::TriggerDelegateNotification() const {
+void WaylandOutput::TriggerDelegateNotifications() const {
DCHECK(!rect_in_physical_pixels_.IsEmpty());
delegate_->OnOutputHandleMetrics(output_id_, rect_in_physical_pixels_,
scale_factor_);
@@ -67,9 +67,8 @@ void WaylandOutput::OutputHandleMode(void* data,
// static
void WaylandOutput::OutputHandleDone(void* data, struct wl_output* wl_output) {
- WaylandOutput* wayland_output = static_cast<WaylandOutput*>(data);
- if (wayland_output)
- wayland_output->TriggerDelegateNotification();
+ if (auto* output = static_cast<WaylandOutput*>(data))
+ output->TriggerDelegateNotifications();
}
// static
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_output.h b/chromium/ui/ozone/platform/wayland/host/wayland_output.h
index 36f8c89fc1e..3bda676a179 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_output.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_output.h
@@ -20,23 +20,23 @@ class WaylandOutput {
public:
class Delegate {
public:
- virtual ~Delegate() {}
-
virtual void OnOutputHandleMetrics(uint32_t output_id,
const gfx::Rect& new_bounds,
int32_t scale_factor) = 0;
+
+ protected:
+ virtual ~Delegate() = default;
};
- WaylandOutput(const uint32_t output_id, wl_output* output);
+ WaylandOutput(uint32_t output_id, wl_output* output);
~WaylandOutput();
void Initialize(Delegate* delegate);
- void TriggerDelegateNotification() const;
-
uint32_t output_id() const { return output_id_; }
bool has_output(wl_output* output) const { return output_.get() == output; }
int32_t scale_factor() const { return scale_factor_; }
+ gfx::Rect bounds() const { return rect_in_physical_pixels_; }
// Tells if the output has already received physical screen dimensions in the
// global compositor space.
@@ -45,6 +45,8 @@ class WaylandOutput {
private:
static constexpr int32_t kDefaultScaleFactor = 1;
+ void TriggerDelegateNotifications() const;
+
// Callback functions used for setting geometric properties of the output
// and available modes.
static void OutputHandleGeometry(void* data,
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_output_manager.cc b/chromium/ui/ozone/platform/wayland/host/wayland_output_manager.cc
index 1f403f4928a..4d71d142fe7 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_output_manager.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_output_manager.cc
@@ -4,6 +4,8 @@
#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
+#include <algorithm>
+#include <cstdint>
#include <memory>
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
@@ -15,13 +17,16 @@ WaylandOutputManager::WaylandOutputManager() = default;
WaylandOutputManager::~WaylandOutputManager() = default;
+// Output is considered ready when at least one wl_output is fully configured
+// (i.e: wl_output::done received), so that WaylandOutputManager is able to
+// instantiate a valid WaylandScreen when requested by the upper layer.
bool WaylandOutputManager::IsOutputReady() const {
- if (output_list_.empty())
- return false;
- return output_list_.front()->is_ready();
+ return std::find_if(output_list_.begin(), output_list_.end(),
+ [](const auto& output) { return output->is_ready(); }) !=
+ output_list_.end();
}
-void WaylandOutputManager::AddWaylandOutput(const uint32_t output_id,
+void WaylandOutputManager::AddWaylandOutput(uint32_t output_id,
wl_output* output) {
// Make sure an output with |output_id| has not been added yet. It's very
// unlikely to happen, unless a compositor has a bug in the numeric names
@@ -29,26 +34,26 @@ void WaylandOutputManager::AddWaylandOutput(const uint32_t output_id,
auto output_it = GetOutputItById(output_id);
DCHECK(output_it == output_list_.end());
auto wayland_output = std::make_unique<WaylandOutput>(output_id, output);
- WaylandOutput* wayland_output_ptr = wayland_output.get();
- output_list_.push_back(std::move(wayland_output));
-
- OnWaylandOutputAdded(output_id);
// Even if WaylandScreen has not been created, the output still must be
// initialized, which results in setting up a wl_listener and getting the
// geometry and the scaling factor from the Wayland Compositor.
- wayland_output_ptr->Initialize(this);
+ wayland_output->Initialize(this);
+ DCHECK(!wayland_output->is_ready());
+
+ output_list_.push_back(std::move(wayland_output));
}
-void WaylandOutputManager::RemoveWaylandOutput(const uint32_t output_id) {
+void WaylandOutputManager::RemoveWaylandOutput(uint32_t output_id) {
auto output_it = GetOutputItById(output_id);
// Check the comment in the WaylandConnetion::GlobalRemove.
if (output_it == output_list_.end())
return;
+ if (wayland_screen_)
+ wayland_screen_->OnOutputRemoved(output_id);
output_list_.erase(output_it);
- OnWaylandOutputRemoved(output_id);
}
std::unique_ptr<WaylandScreen> WaylandOutputManager::CreateWaylandScreen(
@@ -64,10 +69,10 @@ std::unique_ptr<WaylandScreen> WaylandOutputManager::CreateWaylandScreen(
// OutOutputHandleScale. All the other hot geometry and scale changes are done
// automatically, and the |wayland_screen_| is notified immediately about the
// changes.
- if (!output_list_.empty()) {
- for (auto& output : output_list_) {
- OnWaylandOutputAdded(output->output_id());
- output->TriggerDelegateNotification();
+ for (const auto& output : output_list_) {
+ if (output->is_ready()) {
+ wayland_screen->OnOutputAddedOrUpdated(
+ output->output_id(), output->bounds(), output->scale_factor());
}
}
@@ -90,22 +95,13 @@ WaylandOutput* WaylandOutputManager::GetOutput(uint32_t id) const {
return output_it->get();
}
-void WaylandOutputManager::OnWaylandOutputAdded(uint32_t output_id) {
- if (wayland_screen_)
- wayland_screen_->OnOutputAdded(output_id);
-}
-
-void WaylandOutputManager::OnWaylandOutputRemoved(uint32_t output_id) {
- if (wayland_screen_)
- wayland_screen_->OnOutputRemoved(output_id);
-}
-
void WaylandOutputManager::OnOutputHandleMetrics(uint32_t output_id,
const gfx::Rect& new_bounds,
int32_t scale_factor) {
- if (wayland_screen_)
- wayland_screen_->OnOutputMetricsChanged(output_id, new_bounds,
+ if (wayland_screen_) {
+ wayland_screen_->OnOutputAddedOrUpdated(output_id, new_bounds,
scale_factor);
+ }
}
WaylandOutputManager::OutputList::const_iterator
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_output_manager.h b/chromium/ui/ozone/platform/wayland/host/wayland_output_manager.h
index f05828a6d90..e02f10974c5 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_output_manager.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_output_manager.h
@@ -44,9 +44,6 @@ class WaylandOutputManager : public WaylandOutput::Delegate {
WaylandScreen* wayland_screen() const { return wayland_screen_.get(); }
private:
- void OnWaylandOutputAdded(uint32_t output_id);
- void OnWaylandOutputRemoved(uint32_t output_id);
-
// WaylandOutput::Delegate:
void OnOutputHandleMetrics(uint32_t output_id,
const gfx::Rect& new_bounds,
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc
index 1658a68cc93..13cb8c0a3fc 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc
@@ -10,6 +10,7 @@
#include "ui/events/event.h"
#include "ui/events/types/event_type.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_window.h"
@@ -45,7 +46,7 @@ void WaylandPointer::Enter(void* data,
wl_fixed_t surface_y) {
DCHECK(data);
WaylandPointer* pointer = static_cast<WaylandPointer*>(data);
- WaylandWindow* window = WaylandWindow::FromSurface(surface);
+ WaylandWindow* window = wl::RootWindowFromWlSurface(surface);
gfx::PointF location{wl_fixed_to_double(surface_x),
wl_fixed_to_double(surface_y)};
pointer->delegate_->OnPointerFocusChanged(window, location);
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h
index b3f3a6ccbfa..c5cf9f7dccc 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h
@@ -74,7 +74,9 @@ class WaylandPointer::Delegate {
virtual void OnPointerDestroyed(WaylandPointer* pointer) = 0;
virtual void OnPointerFocusChanged(WaylandWindow* window,
const gfx::PointF& location) = 0;
- virtual void OnPointerButtonEvent(EventType evtype, int changed_button) = 0;
+ virtual void OnPointerButtonEvent(EventType evtype,
+ int changed_button,
+ WaylandWindow* window = nullptr) = 0;
virtual void OnPointerMotionEvent(const gfx::PointF& location) = 0;
virtual void OnPointerAxisEvent(const gfx::Vector2d& offset) = 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 cf12f91f1b7..41dfb730784 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
@@ -85,8 +85,8 @@ TEST_P(WaylandPointerTest, Leave) {
Sync();
- wl::MockSurface* other_surface =
- server_.GetObject<wl::MockSurface>(other_widget);
+ wl::MockSurface* other_surface = server_.GetObject<wl::MockSurface>(
+ other_window->root_surface()->GetSurfaceId());
ASSERT_TRUE(other_surface);
wl_pointer_send_enter(pointer_->resource(), 1, surface_->resource(), 0, 0);
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc b/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc
index ba52979990a..f1f7c8d43e5 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc
@@ -24,10 +24,12 @@ bool WaylandPopup::CreateShellPopup() {
DCHECK(parent_window() && !shell_popup_);
- auto bounds_px = AdjustPopupWindowPosition();
+ auto subsurface_bounds_dip =
+ wl::TranslateWindowBoundsToParentDIP(this, parent_window());
ShellObjectFactory factory;
- shell_popup_ = factory.CreateShellPopupWrapper(connection(), this, bounds_px);
+ shell_popup_ = factory.CreateShellPopupWrapper(connection(), this,
+ subsurface_bounds_dip);
if (!shell_popup_) {
LOG(ERROR) << "Failed to create Wayland shell popup";
return false;
@@ -64,7 +66,7 @@ void WaylandPopup::Hide() {
// Detach buffer from surface in order to completely shutdown popups and
// tooltips, and release resources.
- connection()->buffer_manager_host()->ResetSurfaceContents(GetWidget());
+ connection()->buffer_manager_host()->ResetSurfaceContents(root_surface());
}
bool WaylandPopup::IsVisible() const {
@@ -75,7 +77,7 @@ void WaylandPopup::HandlePopupConfigure(const gfx::Rect& bounds_dip) {
DCHECK(shell_popup());
DCHECK(parent_window());
- SetBufferScale(parent_window()->buffer_scale(), true);
+ root_surface()->SetBufferScale(parent_window()->buffer_scale(), true);
gfx::Rect new_bounds_dip = bounds_dip;
@@ -138,25 +140,9 @@ bool WaylandPopup::OnInitialize(PlatformWindowInitProperties properties) {
return false;
}
// If parent window is known in advanced, we may set the scale early.
- SetBufferScale(parent_window()->buffer_scale(), false);
+ root_surface()->SetBufferScale(parent_window()->buffer_scale(), false);
set_ui_scale(parent_window()->ui_scale());
return true;
}
-gfx::Rect WaylandPopup::AdjustPopupWindowPosition() {
- 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());
-
- // Chromium positions windows in screen coordinates, but Wayland requires them
- // to be in local surface coordinates a.k.a relative to parent window.
- const gfx::Rect parent_bounds_dip =
- gfx::ScaleToRoundedRect(parent_window()->GetBounds(), 1.0 / ui_scale());
- gfx::Rect new_bounds_dip = wl::TranslateBoundsToParentCoordinates(
- gfx::ScaleToRoundedRect(GetBounds(), 1.0 / ui_scale()),
- parent_bounds_dip);
- return gfx::ScaleToRoundedRect(new_bounds_dip, ui_scale() / buffer_scale());
-}
-
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc b/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc
index 81af6275b27..fc4d4fac5ca 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc
@@ -10,8 +10,10 @@
#include "base/stl_util.h"
#include "ui/display/display.h"
#include "ui/display/display_finder.h"
+#include "ui/display/display_list.h"
#include "ui/display/display_observer.h"
#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_cursor_position.h"
@@ -26,9 +28,10 @@ WaylandScreen::WaylandScreen(WaylandConnection* connection)
WaylandScreen::~WaylandScreen() = default;
-void WaylandScreen::OnOutputAdded(uint32_t output_id) {
- display_list_.AddDisplay(display::Display(output_id),
- display::DisplayList::Type::NOT_PRIMARY);
+void WaylandScreen::OnOutputAddedOrUpdated(uint32_t output_id,
+ const gfx::Rect& bounds,
+ int32_t scale) {
+ AddOrUpdateDisplay(output_id, bounds, scale);
}
void WaylandScreen::OnOutputRemoved(uint32_t output_id) {
@@ -49,41 +52,32 @@ void WaylandScreen::OnOutputRemoved(uint32_t output_id) {
display_list_.RemoveDisplay(output_id);
}
-void WaylandScreen::OnOutputMetricsChanged(uint32_t output_id,
- const gfx::Rect& new_bounds,
- int32_t device_pixel_ratio) {
+void WaylandScreen::AddOrUpdateDisplay(uint32_t output_id,
+ const gfx::Rect& new_bounds,
+ int32_t scale_factor) {
display::Display changed_display(output_id);
if (!display::Display::HasForceDeviceScaleFactor())
- changed_display.set_device_scale_factor(device_pixel_ratio);
+ changed_display.set_device_scale_factor(scale_factor);
changed_display.set_bounds(new_bounds);
changed_display.set_work_area(new_bounds);
- bool is_primary = false;
- display::Display display_nearest_origin =
- GetDisplayNearestPoint(gfx::Point(0, 0));
- // If bounds of the nearest to origin display are empty, it must have been the
- // very first and the same display added before.
- if (display_nearest_origin.bounds().IsEmpty()) {
- DCHECK_EQ(display_nearest_origin.id(), changed_display.id());
- is_primary = true;
- } else if (changed_display.bounds().origin() <
- display_nearest_origin.bounds().origin()) {
- // If changed display is nearer to the origin than the previous display,
- // that one must become a primary display.
- is_primary = true;
- } else if (changed_display.bounds().OffsetFromOrigin() ==
- display_nearest_origin.bounds().OffsetFromOrigin()) {
- // If changed display has the same origin as the nearest to origin display,
- // |changed_display| must become a primary one or it has already been the
- // primary one. If a user changed positions of two displays (the second at
- // x,x was set to 0,0), the second change will modify geometry of the
- // display, which used to be the one nearest to the origin.
- is_primary = true;
+ // There are 2 cases where |changed_display| must be set as primary:
+ // 1. When it is the first one being added to the |display_list_|. Or
+ // 2. If it is nearest the origin than the previous primary or has the same
+ // origin as it. When an user, for example, swaps two side-by-side displays,
+ // at some point, as the notification come in, both will have the same
+ // origin.
+ auto type = display::DisplayList::Type::NOT_PRIMARY;
+ if (display_list_.displays().empty()) {
+ type = display::DisplayList::Type::PRIMARY;
+ } else {
+ auto nearest_origin = GetDisplayNearestPoint({0, 0}).bounds().origin();
+ auto changed_origin = changed_display.bounds().origin();
+ if (changed_origin < nearest_origin || changed_origin == nearest_origin)
+ type = display::DisplayList::Type::PRIMARY;
}
- display_list_.UpdateDisplay(
- changed_display, is_primary ? display::DisplayList::Type::PRIMARY
- : display::DisplayList::Type::NOT_PRIMARY);
+ display_list_.AddOrUpdateDisplay(changed_display, type);
auto* wayland_window_manager = connection_->wayland_window_manager();
for (auto* window : wayland_window_manager->GetWindowsOnOutput(output_id))
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_screen.h b/chromium/ui/ozone/platform/wayland/host/wayland_screen.h
index 8d65dd8130e..55993fc2a1a 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_screen.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_screen.h
@@ -14,6 +14,10 @@
#include "ui/gfx/geometry/point.h"
#include "ui/ozone/public/platform_screen.h"
+namespace gfx {
+class Rect;
+}
+
namespace ui {
class WaylandConnection;
@@ -26,11 +30,10 @@ class WaylandScreen : public PlatformScreen {
WaylandScreen& operator=(const WaylandScreen&) = delete;
~WaylandScreen() override;
- void OnOutputAdded(uint32_t output_id);
- void OnOutputRemoved(uint32_t output_id);
- void OnOutputMetricsChanged(uint32_t output_id,
+ void OnOutputAddedOrUpdated(uint32_t output_id,
const gfx::Rect& bounds,
int32_t output_scale);
+ void OnOutputRemoved(uint32_t output_id);
base::WeakPtr<WaylandScreen> GetWeakPtr();
@@ -53,6 +56,10 @@ class WaylandScreen : public PlatformScreen {
void RemoveObserver(display::DisplayObserver* observer) override;
private:
+ void AddOrUpdateDisplay(uint32_t output_id,
+ const gfx::Rect& bounds,
+ int32_t scale);
+
WaylandConnection* connection_ = nullptr;
display::DisplayList display_list_;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
index 899fff6445a..46b30f43b54 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
@@ -10,12 +10,15 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/display_observer.h"
#include "ui/display/display_switches.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_output.h"
#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_pointer.h"
#include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/test_output.h"
#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
#include "ui/ozone/platform/wayland/test/wayland_test.h"
#include "ui/platform_window/platform_window_init_properties.h"
@@ -68,15 +71,19 @@ class TestDisplayObserver : public display::DisplayObserver {
class WaylandScreenTest : public WaylandTest {
public:
- WaylandScreenTest() {}
- ~WaylandScreenTest() override {}
+ WaylandScreenTest() = default;
+ ~WaylandScreenTest() override = default;
void SetUp() override {
output_ = server_.output();
- output_->SetRect(gfx::Rect(0, 0, kOutputWidth, kOutputHeight));
WaylandTest::SetUp();
+ output_->SetRect({kOutputWidth, kOutputHeight});
+ output_->SetScale(1);
+ output_->Flush();
+ Sync();
+
output_manager_ = connection_->wayland_output_manager();
ASSERT_TRUE(output_manager_);
@@ -98,17 +105,6 @@ class WaylandScreenTest : public WaylandTest {
std::move(properties));
}
- void UpdateOutputGeometry(wl_resource* output_resource,
- const gfx::Rect& new_rect) {
- wl_output_send_geometry(output_resource, new_rect.x(), new_rect.y(),
- 0 /* physical_width */, 0 /* physical_height */,
- 0 /* subpixel */, "unknown_make", "unknown_model",
- 0 /* transform */);
- wl_output_send_mode(output_resource, WL_OUTPUT_MODE_CURRENT,
- new_rect.width(), new_rect.height(), 0 /* refresh */);
- wl_output_send_done(output_resource);
- }
-
void ValidateTheDisplayForWidget(gfx::AcceleratedWidget widget,
int64_t expected_display_id) {
display::Display display_for_widget =
@@ -146,18 +142,18 @@ TEST_P(WaylandScreenTest, MultipleOutputsAddedAndRemoved) {
const int64_t old_primary_display_id =
platform_screen_->GetPrimaryDisplay().id();
+ gfx::Rect output1_rect = server_.output()->GetRect();
// Add a second display.
wl::TestOutput* output2 = server_.CreateAndInitializeOutput();
Sync();
- // Update rect of that display.
- gfx::Rect output1_rect = server_.output()->GetRect();
- gfx::Rect output2_rect(output1_rect.width(), 0, 800, 600);
// The second display is located to the right of first display like
// | || |.
- UpdateOutputGeometry(output2->resource(), output2_rect);
+ gfx::Rect output2_rect(output1_rect.width(), 0, 800, 600);
+ output2->SetRect(output2_rect);
+ output2->Flush();
Sync();
@@ -179,7 +175,8 @@ TEST_P(WaylandScreenTest, MultipleOutputsAddedAndRemoved) {
Sync();
// Updates rect again.
- UpdateOutputGeometry(output2->resource(), output2_rect);
+ output2->SetRect(output2_rect);
+ output2->Flush();
Sync();
@@ -187,11 +184,14 @@ TEST_P(WaylandScreenTest, MultipleOutputsAddedAndRemoved) {
added_display_id = observer.GetDisplay().id();
EXPECT_NE(platform_screen_->GetPrimaryDisplay().id(), added_display_id);
- // Now, rearrange displays so that second display becomes a primary one.
+ // Now, rearrange displays so that second display becomes the primary one.
output1_rect = gfx::Rect(1024, 0, 1024, 768);
+ output_->SetRect(output1_rect);
+ output_->Flush();
+
output2_rect = gfx::Rect(0, 0, 1024, 768);
- UpdateOutputGeometry(server_.output()->resource(), output1_rect);
- UpdateOutputGeometry(output2->resource(), output2_rect);
+ output2->SetRect(output2_rect);
+ output2->Flush();
Sync();
@@ -215,25 +215,24 @@ TEST_P(WaylandScreenTest, OutputPropertyChanges) {
TestDisplayObserver observer;
platform_screen_->AddObserver(&observer);
- const gfx::Rect new_rect(0, 0, 800, 600);
- UpdateOutputGeometry(output_->resource(), new_rect);
+ gfx::Rect new_rect{100, 100};
+ output_->SetRect(new_rect);
+ output_->Flush();
Sync();
- uint32_t changed_values = 0;
- changed_values |= display::DisplayObserver::DISPLAY_METRIC_BOUNDS;
- changed_values |= display::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
+ uint32_t changed_values = display::DisplayObserver::DISPLAY_METRIC_BOUNDS |
+ display::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values);
EXPECT_EQ(observer.GetDisplay().bounds(), new_rect);
const int32_t new_scale_value = 2;
output_->SetScale(new_scale_value);
+ output_->Flush();
Sync();
- changed_values = 0;
- changed_values |=
- display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
+ changed_values = display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values);
EXPECT_EQ(observer.GetDisplay().device_scale_factor(), new_scale_value);
@@ -329,7 +328,8 @@ TEST_P(WaylandScreenTest, GetDisplayMatching) {
// Place it on the right side of the primary display.
const gfx::Rect output2_rect =
gfx::Rect(primary_display.bounds().width(), 0, 1024, 768);
- UpdateOutputGeometry(output2->resource(), output2_rect);
+ output2->SetRect(output2_rect);
+ output2->Flush();
Sync();
@@ -360,10 +360,10 @@ TEST_P(WaylandScreenTest, GetDisplayMatching) {
platform_screen_->GetDisplayMatching(gfx::Rect(1019, 0, 10, 10)).id());
// Place second display 700 pixels below along y axis (1024:700,1024x768)
- UpdateOutputGeometry(
- output2->resource(),
+ output2->SetRect(
gfx::Rect(gfx::Point(output2_rect.x(), output2_rect.y() + 700),
output2_rect.size()));
+ output2->Flush();
Sync();
@@ -388,6 +388,8 @@ TEST_P(WaylandScreenTest, GetDisplayMatching) {
platform_screen_->GetDisplayMatching(gfx::Rect(0, 0, 0, 0)).id());
platform_screen_->RemoveObserver(&observer);
+ output2->DestroyGlobal();
+ Sync();
}
TEST_P(WaylandScreenTest, GetDisplayForAcceleratedWidget) {
@@ -406,7 +408,8 @@ TEST_P(WaylandScreenTest, GetDisplayForAcceleratedWidget) {
// display.
const gfx::Rect output2_rect =
gfx::Rect(primary_display.bounds().width(), 0, 1024, 768);
- UpdateOutputGeometry(output2->resource(), output2_rect);
+ output2->SetRect(output2_rect);
+ output2->Flush();
Sync();
@@ -419,7 +422,8 @@ TEST_P(WaylandScreenTest, GetDisplayForAcceleratedWidget) {
ValidateTheDisplayForWidget(widget, primary_display.id());
// Now, send enter event for the surface, which was created before.
- wl::MockSurface* surface = server_.GetObject<wl::MockSurface>(widget);
+ wl::MockSurface* surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
ASSERT_TRUE(surface);
wl_surface_send_enter(surface->resource(), output_->resource());
@@ -454,6 +458,9 @@ TEST_P(WaylandScreenTest, GetDisplayForAcceleratedWidget) {
// The id of the entered display must correspond to the second output.
ValidateTheDisplayForWidget(widget, secondary_display.id());
+
+ output2->DestroyGlobal();
+ Sync();
}
TEST_P(WaylandScreenTest, GetCursorScreenPoint) {
@@ -463,7 +470,8 @@ TEST_P(WaylandScreenTest, GetCursorScreenPoint) {
PlatformWindowType::kWindow,
gfx::kNullAcceleratedWidget, &delegate);
- auto* surface = server_.GetObject<wl::MockSurface>(window_->GetWidget());
+ auto* surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
ASSERT_TRUE(surface);
// Announce pointer capability so that WaylandPointer is created on the client
@@ -488,8 +496,8 @@ TEST_P(WaylandScreenTest, GetCursorScreenPoint) {
// WaylandScreen must return the last pointer location.
EXPECT_EQ(gfx::Point(10, 20), platform_screen_->GetCursorScreenPoint());
- auto* second_surface =
- server_.GetObject<wl::MockSurface>(second_window->GetWidget());
+ auto* second_surface = server_.GetObject<wl::MockSurface>(
+ second_window->root_surface()->GetSurfaceId());
ASSERT_TRUE(second_surface);
// Now, leave the first surface and enter second one.
wl_pointer_send_leave(pointer->resource(), ++serial, surface->resource());
@@ -530,8 +538,8 @@ TEST_P(WaylandScreenTest, GetCursorScreenPoint) {
Sync();
- auto* menu_surface =
- server_.GetObject<wl::MockSurface>(menu_window->GetWidget());
+ auto* menu_surface = server_.GetObject<wl::MockSurface>(
+ menu_window->root_surface()->GetSurfaceId());
ASSERT_TRUE(menu_surface);
wl_pointer_send_enter(pointer->resource(), ++serial, menu_surface->resource(),
@@ -577,8 +585,8 @@ TEST_P(WaylandScreenTest, GetCursorScreenPoint) {
Sync();
- auto* nested_menu_surface =
- server_.GetObject<wl::MockSurface>(nested_menu_window->GetWidget());
+ auto* nested_menu_surface = server_.GetObject<wl::MockSurface>(
+ nested_menu_window->root_surface()->GetSurfaceId());
ASSERT_TRUE(nested_menu_surface);
wl_pointer_send_enter(pointer->resource(), ++serial,
@@ -616,6 +624,7 @@ TEST_P(WaylandScreenTest, SetBufferScale) {
const int32_t kTripleScale = 3;
EXPECT_CALL(*surface_, SetBufferScale(kTripleScale));
output_->SetScale(kTripleScale);
+ output_->Flush();
Sync();
@@ -637,6 +646,7 @@ TEST_P(WaylandScreenTest, SetBufferScale) {
EXPECT_NE(kForcedUIScale, kDoubleScale);
EXPECT_CALL(*surface_, SetBufferScale(kDoubleScale));
output_->SetScale(kDoubleScale);
+ output_->Flush();
Sync();
@@ -646,11 +656,92 @@ TEST_P(WaylandScreenTest, SetBufferScale) {
display::Display::ResetForceDeviceScaleFactorForTesting();
}
+namespace {
+
+class LazilyConfiguredScreenTest
+ : public WaylandTest,
+ public wl::TestWaylandServerThread::OutputDelegate {
+ public:
+ LazilyConfiguredScreenTest() = default;
+ LazilyConfiguredScreenTest(const LazilyConfiguredScreenTest&) = delete;
+ LazilyConfiguredScreenTest& operator=(const LazilyConfiguredScreenTest&) =
+ delete;
+ ~LazilyConfiguredScreenTest() override = default;
+
+ void SetUp() override {
+ // Being the server's output delegate allows LazilyConfiguredScreenTest to
+ // manipulate wl_outputs during the server's global objects initialization
+ // phase. See SetupOutputs() function below.
+ server_.set_output_delegate(this);
+
+ WaylandTest::SetUp();
+
+ output_manager_ = connection_->wayland_output_manager();
+ ASSERT_TRUE(output_manager_);
+ }
+
+ void TearDown() override {
+ WaylandTest::TearDown();
+ server_.set_output_delegate(nullptr);
+ }
+
+ protected:
+ // wl::TestWaylandServerThread::OutputDelegate:
+ void SetupOutputs(wl::TestOutput* primary) override {
+ // Keep the first wl_output announced "unconfigured" and just caches it for
+ // now, so we can exercise WaylandOutputManager::IsOutputReady() function
+ // when wl_output events come in unordered.
+ primary_output_ = primary;
+
+ // Create/announce a second wl_output object and makes it the first one to
+ // get configuration events (eg: geometry, done, etc). This is achieved by
+ // setting its bounds here.
+ aux_output_ = server_.CreateAndInitializeOutput();
+ aux_output_->SetRect({0, 0, 800, 600});
+ }
+
+ wl::TestOutput* primary_output_ = nullptr;
+ wl::TestOutput* aux_output_ = nullptr;
+ WaylandOutputManager* output_manager_ = nullptr;
+ bool auto_configure;
+};
+
+} // namespace
+
+// Ensures WaylandOutputManager and WaylandScreen properly handle scenarios
+// where multiple wl_output objects are announced but not "configured" (ie:
+// size, position, mode, etc sent to client) at bind time.
+TEST_P(LazilyConfiguredScreenTest, DualOutput) {
+ // Ensure WaylandScreen got properly created and fed with a single display
+ // object, ie: |aux_output_| at server side.
+ EXPECT_TRUE(output_manager_->IsOutputReady());
+ EXPECT_TRUE(screen_);
+ EXPECT_EQ(1u, screen_->GetAllDisplays().size());
+ Sync();
+
+ // Send wl_output configuration events for the first advertised wl_output
+ // object. ie: |primary_output_| at server side.
+ primary_output_->SetRect({800, 0, kOutputWidth, kOutputHeight});
+ primary_output_->SetScale(1);
+ primary_output_->Flush();
+ Sync();
+
+ // And make sure it makes its way into the WaylandScreen's display list at
+ // client side.
+ EXPECT_EQ(2u, screen_->GetAllDisplays().size());
+}
+
INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
WaylandScreenTest,
::testing::Values(kXdgShellStable));
INSTANTIATE_TEST_SUITE_P(XdgVersionV6Test,
WaylandScreenTest,
::testing::Values(kXdgShellV6));
+INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
+ LazilyConfiguredScreenTest,
+ ::testing::Values(kXdgShellStable));
+INSTANTIATE_TEST_SUITE_P(XdgVersionV6Test,
+ LazilyConfiguredScreenTest,
+ ::testing::Values(kXdgShellV6));
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc
index e76aa6376dd..11d37ab75e1 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc
@@ -1,44 +1,60 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// 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_subsurface.h"
+#include <wayland-client.h>
+#include <cstdint>
+
#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 {
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
namespace {
gfx::Rect AdjustSubsurfaceBounds(const gfx::Rect& bounds_px,
const gfx::Rect& parent_bounds_px,
float ui_scale,
- int32_t buffer_scale) {
+ int32_t parent_buffer_scale) {
+ // TODO(fangzhoug): Verify the correctness of using ui_scale here, and in
+ // other ozone wayland files.
const auto parent_bounds_dip =
gfx::ScaleToRoundedRect(parent_bounds_px, 1.0 / ui_scale);
+ const auto bounds_dip = gfx::ScaleToRoundedRect(bounds_px, 1.0 / ui_scale);
auto new_bounds_dip =
- wl::TranslateBoundsToParentCoordinates(bounds_px, parent_bounds_dip);
- return gfx::ScaleToRoundedRect(new_bounds_dip, ui_scale / buffer_scale);
+ wl::TranslateBoundsToParentCoordinates(bounds_dip, parent_bounds_dip);
+ return gfx::ScaleToRoundedRect(new_bounds_dip,
+ ui_scale / parent_buffer_scale);
}
} // namespace
-WaylandSubsurface::WaylandSubsurface(PlatformWindowDelegate* delegate,
- WaylandConnection* connection)
- : WaylandWindow(delegate, connection) {}
+namespace ui {
+
+WaylandSubsurface::WaylandSubsurface(WaylandConnection* connection,
+ WaylandWindow* parent)
+ : wayland_surface_(connection, parent),
+ connection_(connection),
+ parent_(parent) {
+ DCHECK(parent_);
+ DCHECK(connection_);
+ if (!surface()) {
+ LOG(ERROR) << "Failed to create wl_surface";
+ return;
+ }
+}
WaylandSubsurface::~WaylandSubsurface() = default;
-void WaylandSubsurface::Show(bool inactive) {
- if (subsurface_)
- return;
+gfx::AcceleratedWidget WaylandSubsurface::GetWidget() const {
+ return wayland_surface_.GetWidget();
+}
- CreateSubsurface();
- UpdateBufferScale(false);
+void WaylandSubsurface::Show() {
+ if (!subsurface_)
+ CreateSubsurface();
}
void WaylandSubsurface::Hide() {
@@ -46,91 +62,89 @@ void WaylandSubsurface::Hide() {
return;
subsurface_.reset();
-
- // Detach buffer from surface in order to completely shutdown menus and
- // tooltips, and release resources.
- connection()->buffer_manager_host()->ResetSurfaceContents(GetWidget());
+ connection_->buffer_manager_host()->ResetSurfaceContents(wayland_surface());
}
bool WaylandSubsurface::IsVisible() const {
return !!subsurface_;
}
-void WaylandSubsurface::SetBounds(const gfx::Rect& bounds) {
- auto old_bounds = GetBounds();
- WaylandWindow::SetBounds(bounds);
+void WaylandSubsurface::UpdateOpaqueRegion() {
+ gfx::Size region_size = enable_blend_ ? gfx::Size() : bounds_px_.size();
+ wl::Object<wl_region> region(
+ wl_compositor_create_region(connection_->compositor()));
+ wl_region_add(region.get(), 0, 0, region_size.width(), region_size.height());
+ wl_surface_set_opaque_region(surface(), region.get());
+}
- if (old_bounds == bounds || !parent_window())
+void WaylandSubsurface::SetBounds(const gfx::Rect& bounds) {
+ if (bounds_px_ == bounds)
return;
- // Translate location from screen to surface coordinates.
- auto bounds_px = AdjustSubsurfaceBounds(
- GetBounds(), parent_window()->GetBounds(), ui_scale(), buffer_scale());
- wl_subsurface_set_position(subsurface_.get(), bounds_px.x() / buffer_scale(),
- bounds_px.y() / buffer_scale());
- wl_surface_commit(surface());
- connection()->ScheduleFlush();
+ bounds_px_ = bounds;
+ if (IsVisible()) {
+ // Translate location from screen to surface coordinates.
+ auto bounds_px =
+ AdjustSubsurfaceBounds(bounds_px_, parent_->GetBounds(),
+ parent_->ui_scale(), parent_->buffer_scale());
+ wl_subsurface_set_position(subsurface_.get(), bounds_px.x(), bounds_px.y());
+ }
}
void WaylandSubsurface::CreateSubsurface() {
- auto* parent = parent_window();
- if (!parent) {
- // wl_subsurface can be used for several purposes: tooltips and drag arrow
- // windows. If we are in a drag process, use the entered window. Otherwise,
- // it must be a tooltip.
- if (connection()->IsDragInProgress()) {
- parent = connection()->data_drag_controller()->entered_window();
- set_parent_window(parent);
- } else {
- // If Aura does not not provide a reference parent window, needed by
- // Wayland, we get the current focused window to place and show the
- // tooltips.
- parent =
- connection()->wayland_window_manager()->GetCurrentFocusedWindow();
- }
- }
+ DCHECK(parent_);
- // Tooltip and drag arrow creation is an async operation. By the time Aura
- // actually creates them, it is possible that the user has already moved the
- // mouse/pointer out of the window that triggered the tooltip, or user is no
- // longer in a drag/drop process. In this case, parent is NULL.
- if (!parent)
- return;
-
- wl_subcompositor* subcompositor = connection()->subcompositor();
+ wl_subcompositor* subcompositor = connection_->subcompositor();
DCHECK(subcompositor);
- subsurface_.reset(wl_subcompositor_get_subsurface(subcompositor, surface(),
- parent->surface()));
+ subsurface_ = wayland_surface()->CreateSubsurface(parent_->root_surface());
- // Chromium positions tooltip windows in screen coordinates, but Wayland
- // requires them to be in local surface coordinates a.k.a relative to parent
- // window.
- auto bounds_px = AdjustSubsurfaceBounds(GetBounds(), parent->GetBounds(),
- ui_scale(), buffer_scale());
+ // Chromium positions quads in display::Display coordinates in physical
+ // pixels, but Wayland requires them to be in local surface coordinates a.k.a
+ // relative to parent window.
+ auto bounds_px =
+ AdjustSubsurfaceBounds(bounds_px_, parent_->GetBounds(),
+ parent_->ui_scale(), parent_->buffer_scale());
DCHECK(subsurface_);
- // Convert position to DIP.
- wl_subsurface_set_position(subsurface_.get(), bounds_px.x() / buffer_scale(),
- bounds_px.y() / buffer_scale());
- 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);
+ wl_subsurface_set_position(subsurface_.get(), bounds_px.x(), bounds_px.y());
+ wl_subsurface_set_sync(subsurface_.get());
+
+ // Subsurfaces don't need to trap input events. Its display rect is fully
+ // contained in |parent_|'s. Setting input_region to empty allows |parent_| to
+ // dispatch all of the input to platform window.
+ wl::Object<wl_region> region(
+ wl_compositor_create_region(connection_->compositor()));
+ wl_region_add(region.get(), 0, 0, 0, 0);
+ wl_surface_set_input_region(surface(), region.get());
}
-bool WaylandSubsurface::OnInitialize(PlatformWindowInitProperties properties) {
- // If we do not have parent window provided, we must always use a focused
- // window or a window that entered drag whenever the subsurface is created.
- if (properties.parent_widget == gfx::kNullAcceleratedWidget) {
- DCHECK(!parent_window());
- return true;
+void WaylandSubsurface::ConfigureAndShowSurface(
+ gfx::OverlayTransform transform,
+ const gfx::Rect& bounds_rect,
+ bool enable_blend,
+ const WaylandSurface* reference_below,
+ const WaylandSurface* reference_above) {
+ wayland_surface()->SetBufferScale(parent_->buffer_scale(), false);
+
+ gfx::Rect bounds_px{
+ bounds_rect.origin() + parent_->GetBounds().origin().OffsetFromOrigin(),
+ bounds_rect.size()};
+ auto old_bounds = bounds_px_;
+ SetBounds(bounds_px);
+
+ if (old_bounds != bounds_px_ || enable_blend_ != enable_blend) {
+ enable_blend_ = enable_blend;
+ UpdateOpaqueRegion();
+ }
+
+ Show();
+
+ DCHECK(!reference_above || !reference_below);
+ if (reference_below) {
+ wl_subsurface_place_above(subsurface_.get(), reference_below->surface());
+ } else if (reference_above) {
+ wl_subsurface_place_below(subsurface_.get(), reference_above->surface());
}
- set_parent_window(GetParentWindow(properties.parent_widget));
- return true;
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h
index e5c8bed26f8..50098b21715 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h
@@ -1,36 +1,72 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// 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_SUBSURFACE_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SUBSURFACE_H_
-#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/overlay_transform.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/wayland_surface.h"
namespace ui {
+class WaylandConnection;
+class WaylandWindow;
-class WaylandSubsurface : public WaylandWindow {
+// Wraps a wl_surface with a wl_subsurface role assigned. It is used to submit a
+// buffer as a sub region of WaylandWindow.
+class WaylandSubsurface {
public:
- WaylandSubsurface(PlatformWindowDelegate* delegate,
- WaylandConnection* connection);
- ~WaylandSubsurface() override;
+ WaylandSubsurface(WaylandConnection* connection, WaylandWindow* parent);
+ WaylandSubsurface(const WaylandSubsurface&) = delete;
+ WaylandSubsurface& operator=(const WaylandSubsurface&) = delete;
+ ~WaylandSubsurface();
- // PlatformWindow overrides:
- void Show(bool inactive) override;
- void Hide() override;
- bool IsVisible() const override;
- void SetBounds(const gfx::Rect& bounds) override;
+ wl_surface* surface() const { return wayland_surface_.surface(); }
+ int32_t buffer_scale() const { return wayland_surface_.buffer_scale(); }
+ WaylandSurface* wayland_surface() { return &wayland_surface_; }
+ gfx::Rect bounds_px() { return bounds_px_; }
+ bool IsOpaque() const { return !enable_blend_; }
- private:
- // WaylandWindow overrides:
- bool OnInitialize(PlatformWindowInitProperties properties) override;
+ gfx::AcceleratedWidget GetWidget() const;
+
+ // Sets up wl_surface and wl_subsurface. Allows an overlay to be shown
+ // correctly once a wl_buffer is attached.
+ void ConfigureAndShowSurface(gfx::OverlayTransform transform,
+ const gfx::Rect& bounds_rect,
+ bool enable_blend,
+ const WaylandSurface* reference_below,
+ const WaylandSurface* reference_above);
+
+ // Assigns wl_subsurface role to the wl_surface so it is visible when a
+ // wl_buffer is attached.
+ void Show();
+ // Remove wl_subsurface role to make this invisible.
+ void Hide();
+ bool IsVisible() const;
- // Creates (if necessary) and shows a subsurface window.
+ private:
+ // Helper of Show(). It does the role-assigning to wl_surface.
void CreateSubsurface();
+ void SetBounds(const gfx::Rect& bounds);
+
+ // Tells wayland compositor to update the opaque region according to
+ // |enable_blend_| and |bounds_px_|.
+ void UpdateOpaqueRegion();
+ WaylandSurface wayland_surface_;
wl::Object<wl_subsurface> subsurface_;
- DISALLOW_COPY_AND_ASSIGN(WaylandSubsurface);
+ WaylandConnection* const connection_;
+ // |parent_| refers to the WaylandWindow whose wl_surface is the parent to
+ // this subsurface.
+ WaylandWindow* const parent_;
+
+ // Pixel bounds within the display to position this subsurface.
+ gfx::Rect bounds_px_;
+ bool enable_blend_ = true;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc b/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc
index c2cf21baf62..0300a7bcacc 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc
@@ -4,21 +4,139 @@
#include "ui/ozone/platform/wayland/host/wayland_surface.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
namespace ui {
-WaylandSurface::WaylandSurface() = default;
-WaylandSurface::~WaylandSurface() = default;
+WaylandSurface::WaylandSurface(WaylandConnection* connection,
+ WaylandWindow* root_window)
+ : connection_(connection),
+ root_window_(root_window),
+ surface_(connection->CreateSurface()) {}
-gfx::AcceleratedWidget WaylandSurface::GetWidget() const {
+WaylandSurface::~WaylandSurface() {
+ if (surface_) {
+ wl_surface_add_listener(surface_.get(), nullptr, nullptr);
+ wl_surface_set_user_data(surface_.get(), nullptr);
+ }
+}
+
+uint32_t WaylandSurface::GetSurfaceId() const {
if (!surface_)
- return gfx::kNullAcceleratedWidget;
+ return 0u;
return surface_.id();
}
-gfx::AcceleratedWidget WaylandSurface::GetRootWidget() const {
+gfx::AcceleratedWidget WaylandSurface::GetWidget() const {
return root_window_->GetWidget();
}
+bool WaylandSurface::Initialize() {
+ if (!surface_)
+ return false;
+
+ wl_surface_set_user_data(surface_.get(), this);
+
+ static struct wl_surface_listener surface_listener = {
+ &WaylandSurface::Enter,
+ &WaylandSurface::Leave,
+ };
+ wl_surface_add_listener(surface_.get(), &surface_listener, this);
+
+ return true;
+}
+
+void WaylandSurface::AttachBuffer(wl_buffer* buffer) {
+ // 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(surface_.get(), buffer, 0, 0);
+ connection_->ScheduleFlush();
+}
+
+void WaylandSurface::Damage(const gfx::Rect& pending_damage_region) {
+ if (connection_->compositor_version() >=
+ WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) {
+ // wl_surface_damage_buffer relies on compositor API version 4. See
+ // 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(
+ surface_.get(), 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)
+ // 2) The API wl_surface::set_buffer_transform is not used.
+ // It's possible to write logic that accounts for both cases above, but
+ // it's currently unnecessary.
+ //
+ // 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.
+ wl_surface_damage(surface_.get(), pending_damage_region.x() / buffer_scale_,
+ pending_damage_region.y() / buffer_scale_,
+ pending_damage_region.width() / buffer_scale_ + 1,
+ pending_damage_region.height() / buffer_scale_ + 1);
+ }
+ connection_->ScheduleFlush();
+}
+
+void WaylandSurface::Commit() {
+ wl_surface_commit(surface_.get());
+ connection_->ScheduleFlush();
+}
+
+void WaylandSurface::SetBufferScale(int32_t new_scale, bool update_bounds) {
+ DCHECK_GT(new_scale, 0);
+
+ if (new_scale == buffer_scale_)
+ return;
+
+ buffer_scale_ = new_scale;
+ wl_surface_set_buffer_scale(surface_.get(), buffer_scale_);
+ connection_->ScheduleFlush();
+}
+
+void WaylandSurface::SetBounds(const gfx::Rect& bounds_px) {
+ // It's important to set opaque region for opaque windows (provides
+ // optimization hint for the Wayland compositor).
+ if (!root_window_->IsOpaqueWindow())
+ return;
+
+ wl::Object<wl_region> region(
+ wl_compositor_create_region(connection_->compositor()));
+ wl_region_add(region.get(), 0, 0, bounds_px.width(), bounds_px.height());
+
+ wl_surface_set_opaque_region(surface_.get(), region.get());
+
+ connection_->ScheduleFlush();
+}
+
+wl::Object<wl_subsurface> WaylandSurface::CreateSubsurface(
+ WaylandSurface* parent) {
+ DCHECK(parent);
+ wl_subcompositor* subcompositor = connection_->subcompositor();
+ DCHECK(subcompositor);
+ wl::Object<wl_subsurface> subsurface(wl_subcompositor_get_subsurface(
+ subcompositor, surface_.get(), parent->surface_.get()));
+ return subsurface;
+}
+
+// static
+void WaylandSurface::Enter(void* data,
+ struct wl_surface* wl_surface,
+ struct wl_output* output) {
+ static_cast<WaylandSurface*>(data)->root_window_->AddEnteredOutputId(output);
+}
+
+// static
+void WaylandSurface::Leave(void* data,
+ struct wl_surface* wl_surface,
+ struct wl_output* output) {
+ static_cast<WaylandSurface*>(data)->root_window_->RemoveEnteredOutputId(
+ output);
+}
+
} // 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 e432ceb7e7d..37755f9ac3d 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_surface.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_surface.h
@@ -5,17 +5,21 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SURFACE_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SURFACE_H_
+#include <cstdint>
+
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
namespace ui {
+class WaylandConnection;
class WaylandWindow;
// Wrapper of a wl_surface, owned by a WaylandWindow or a WlSubsurface.
class WaylandSurface {
public:
- WaylandSurface();
+ WaylandSurface(WaylandConnection* connection, WaylandWindow* root_window);
WaylandSurface(const WaylandSurface&) = delete;
WaylandSurface& operator=(const WaylandSurface&) = delete;
~WaylandSurface();
@@ -23,20 +27,55 @@ class WaylandSurface {
WaylandWindow* root_window() const { return root_window_; }
wl_surface* surface() const { return surface_.get(); }
int32_t buffer_scale() const { return buffer_scale_; }
+ void set_buffer_scale(int32_t scale) { buffer_scale_ = scale; }
- // gfx::AcceleratedWidget identifies a wl_surface or a ui::WaylandWindow. Note
- // that GetWidget() and GetRootWidget() do not necessarily return the same
- // result.
+ // Returns an id that identifies the |wl_surface_|.
+ uint32_t GetSurfaceId() const;
+ // Returns a gfx::AcceleratedWidget that identifies the WaylandWindow that
+ // this WaylandSurface belongs to.
gfx::AcceleratedWidget GetWidget() const;
- gfx::AcceleratedWidget GetRootWidget() const;
+
+ // Initializes the WaylandSurface and returns true iff success.
+ // This may return false if a wl_surface could not be created, for example.
+ bool Initialize();
+
+ // Attaches the given wl_buffer to the underlying wl_surface at (0, 0).
+ void AttachBuffer(wl_buffer* buffer);
+
+ // Damages the surface according to |pending_damage_region|, which should be
+ // in surface coordinates (dp).
+ void Damage(const gfx::Rect& pending_damage_region);
+
+ // Commits the underlying wl_surface.
+ void Commit();
+
+ // Sets the buffer scale for this surface.
+ void SetBufferScale(int32_t scale, bool update_bounds);
+
+ // Sets the bounds on this surface. This is used for determining the opaque
+ // region.
+ void SetBounds(const gfx::Rect& bounds_px);
+
+ // Creates a wl_subsurface relating this surface and a parent surface,
+ // |parent|. Callers take ownership of the wl_subsurface.
+ wl::Object<wl_subsurface> CreateSubsurface(WaylandSurface* parent);
private:
- WaylandWindow* root_window_ = nullptr;
+ WaylandConnection* const connection_;
+ WaylandWindow* const root_window_;
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;
+
+ // wl_surface_listener
+ static void Enter(void* data,
+ struct wl_surface* wl_surface,
+ struct wl_output* output);
+ static void Leave(void* data,
+ struct wl_surface* wl_surface,
+ struct wl_output* output);
};
} // 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
index 10ecbcf7b47..86bab661269 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
@@ -4,6 +4,9 @@
#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
+#include "base/run_loop.h"
+#include "base/unguessable_token.h"
+#include "build/lacros_buildflags.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/hit_test.h"
@@ -14,8 +17,10 @@
#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.h"
#include "ui/ozone/platform/wayland/host/wayland_window_drag_controller.h"
-#include "ui/platform_window/platform_window_handler/wm_drop_handler.h"
+#include "ui/platform_window/extensions/wayland_extension.h"
+#include "ui/platform_window/wm/wm_drop_handler.h"
namespace ui {
@@ -36,6 +41,7 @@ WaylandToplevelWindow::~WaylandToplevelWindow() {
drag_handler_delegate_->OnDragFinished(
DragDropTypes::DragOperation::DRAG_NONE);
}
+ CancelDrag();
}
bool WaylandToplevelWindow::CreateShellSurface() {
@@ -46,7 +52,11 @@ bool WaylandToplevelWindow::CreateShellSurface() {
return false;
}
- shell_surface_->SetAppId(app_id_);
+#if BUILDFLAG(IS_LACROS)
+ shell_surface_->SetAppId(window_unique_id_);
+#else
+ shell_surface_->SetAppId(wm_class_class_);
+#endif
shell_surface_->SetTitle(window_title_);
SetSizeConstraints();
TriggerStateChanges();
@@ -78,13 +88,29 @@ void WaylandToplevelWindow::DispatchHostWindowDragMovement(
connection()->ScheduleFlush();
}
-void WaylandToplevelWindow::StartDrag(const ui::OSExchangeData& data,
+bool WaylandToplevelWindow::StartDrag(const ui::OSExchangeData& data,
int operation,
gfx::NativeCursor cursor,
+ bool can_grab_pointer,
WmDragHandler::Delegate* delegate) {
DCHECK(!drag_handler_delegate_);
drag_handler_delegate_ = delegate;
connection()->data_drag_controller()->StartSession(data, operation);
+
+ base::RunLoop drag_loop(base::RunLoop::Type::kNestableTasksAllowed);
+ drag_loop_quit_closure_ = drag_loop.QuitClosure();
+
+ auto alive = weak_ptr_factory_.GetWeakPtr();
+ drag_loop.Run();
+ if (!alive)
+ return false;
+ return true;
+}
+
+void WaylandToplevelWindow::CancelDrag() {
+ if (drag_loop_quit_closure_.is_null())
+ return;
+ std::move(drag_loop_quit_closure_).Run();
}
void WaylandToplevelWindow::Show(bool inactive) {
@@ -113,7 +139,7 @@ void WaylandToplevelWindow::Hide() {
// Detach buffer from surface in order to completely shutdown menus and
// tooltips, and release resources.
- connection()->buffer_manager_host()->ResetSurfaceContents(GetWidget());
+ connection()->buffer_manager_host()->ResetSurfaceContents(root_surface());
}
bool WaylandToplevelWindow::IsVisible() const {
@@ -182,6 +208,14 @@ void WaylandToplevelWindow::SizeConstraintsChanged() {
SetSizeConstraints();
}
+std::string WaylandToplevelWindow::GetWindowUniqueId() const {
+#if BUILDFLAG(IS_LACROS)
+ return window_unique_id_;
+#else
+ return std::string();
+#endif
+}
+
void WaylandToplevelWindow::HandleSurfaceConfigure(int32_t width,
int32_t height,
bool is_maximized,
@@ -254,9 +288,11 @@ void WaylandToplevelWindow::OnDragEnter(const gfx::PointF& point,
// Wayland sends locations in DIP so they need to be translated to
// physical pixels.
+ // TODO(crbug.com/1102857): get the real event modifier here.
drop_handler->OnDragEnter(
gfx::ScalePoint(point, buffer_scale(), buffer_scale()), std::move(data),
- operation);
+ operation,
+ /*modifiers=*/0);
}
int WaylandToplevelWindow::OnDragMotion(const gfx::PointF& point,
@@ -267,15 +303,18 @@ int WaylandToplevelWindow::OnDragMotion(const gfx::PointF& point,
// Wayland sends locations in DIP so they need to be translated to
// physical pixels.
+ // TODO(crbug.com/1102857): get the real event modifier here.
return drop_handler->OnDragMotion(
- gfx::ScalePoint(point, buffer_scale(), buffer_scale()), operation);
+ gfx::ScalePoint(point, buffer_scale(), buffer_scale()), operation,
+ /*modifiers=*/0);
}
void WaylandToplevelWindow::OnDragDrop(std::unique_ptr<OSExchangeData> data) {
WmDropHandler* drop_handler = GetWmDropHandler(*this);
if (!drop_handler)
return;
- drop_handler->OnDragDrop(std::move(data));
+ // TODO(crbug.com/1102857): get the real event modifier here.
+ drop_handler->OnDragDrop(std::move(data), /*modifiers=*/0);
}
void WaylandToplevelWindow::OnDragLeave() {
@@ -290,11 +329,18 @@ void WaylandToplevelWindow::OnDragSessionClose(uint32_t dnd_action) {
drag_handler_delegate_->OnDragFinished(dnd_action);
drag_handler_delegate_ = nullptr;
connection()->event_source()->ResetPointerFlags();
+ std::move(drag_loop_quit_closure_).Run();
}
bool WaylandToplevelWindow::OnInitialize(
PlatformWindowInitProperties properties) {
- app_id_ = properties.wm_class_class;
+#if BUILDFLAG(IS_LACROS)
+ auto token = base::UnguessableToken::Create();
+ window_unique_id_ = "org.chromium.lacros." + token.ToString();
+#else
+ wm_class_class_ = properties.wm_class_class;
+#endif
+ SetWaylandExtension(this, static_cast<WaylandExtension*>(this));
SetWmMoveLoopHandler(this, static_cast<WmMoveLoopHandler*>(this));
return true;
}
@@ -309,6 +355,11 @@ void WaylandToplevelWindow::EndMoveLoop() {
connection()->window_drag_controller()->StopDragging();
}
+void WaylandToplevelWindow::StartWindowDraggingSessionIfNeeded() {
+ DCHECK(connection()->window_drag_controller());
+ connection()->window_drag_controller()->StartDragSession();
+}
+
void WaylandToplevelWindow::TriggerStateChanges() {
if (!shell_surface_)
return;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
index 0455078ee38..4c0a6a7d013 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
@@ -5,11 +5,13 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_TOPLEVEL_WINDOW_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_TOPLEVEL_WINDOW_H_
+#include "build/lacros_buildflags.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"
+#include "ui/platform_window/extensions/wayland_extension.h"
+#include "ui/platform_window/wm/wm_drag_handler.h"
+#include "ui/platform_window/wm/wm_move_loop_handler.h"
+#include "ui/platform_window/wm/wm_move_resize_handler.h"
namespace ui {
@@ -18,7 +20,8 @@ class ShellSurfaceWrapper;
class WaylandToplevelWindow : public WaylandWindow,
public WmMoveResizeHandler,
public WmDragHandler,
- public WmMoveLoopHandler {
+ public WmMoveLoopHandler,
+ public WaylandExtension {
public:
WaylandToplevelWindow(PlatformWindowDelegate* delegate,
WaylandConnection* connection);
@@ -38,10 +41,12 @@ class WaylandToplevelWindow : public WaylandWindow,
const gfx::Point& pointer_location_in_px) override;
// WmDragHandler
- void StartDrag(const ui::OSExchangeData& data,
+ bool StartDrag(const ui::OSExchangeData& data,
int operation,
gfx::NativeCursor cursor,
+ bool can_grab_pointer,
WmDragHandler::Delegate* delegate) override;
+ void CancelDrag() override;
// PlatformWindow
void Show(bool inactive) override;
@@ -54,6 +59,7 @@ class WaylandToplevelWindow : public WaylandWindow,
void Restore() override;
PlatformWindowState GetPlatformWindowState() const override;
void SizeConstraintsChanged() override;
+ std::string GetWindowUniqueId() const override;
private:
// WaylandWindow overrides:
@@ -75,6 +81,9 @@ class WaylandToplevelWindow : public WaylandWindow,
bool RunMoveLoop(const gfx::Vector2d& drag_offset) override;
void EndMoveLoop() override;
+ // WaylandExtension:
+ void StartWindowDraggingSessionIfNeeded() override;
+
void TriggerStateChanges();
void SetWindowState(PlatformWindowState state);
@@ -112,11 +121,17 @@ class WaylandToplevelWindow : public WaylandWindow,
bool is_active_ = false;
+#if BUILDFLAG(IS_LACROS)
+ // Unique ID for this window. May be shared over non-Wayland IPC transports
+ // (e.g. mojo) to identify the window.
+ std::string window_unique_id_;
+#else
// 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_;
+ std::string wm_class_class_;
+#endif
// Title of the ShellSurface.
base::string16 window_title_;
@@ -124,6 +139,10 @@ class WaylandToplevelWindow : public WaylandWindow,
// Max and min sizes of the WaylandToplevelWindow window.
base::Optional<gfx::Size> min_size_;
base::Optional<gfx::Size> max_size_;
+
+ base::OnceClosure drag_loop_quit_closure_;
+
+ base::WeakPtrFactory<WaylandToplevelWindow> weak_ptr_factory_{this};
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc b/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc
index aff5c24befa..9298a43d67d 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc
@@ -8,6 +8,7 @@
#include "base/time/time.h"
#include "ui/gfx/geometry/point_f.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_window.h"
@@ -47,7 +48,7 @@ void WaylandTouch::Down(void* data,
DCHECK(touch);
touch->connection_->set_serial(serial);
- WaylandWindow* window = WaylandWindow::FromSurface(surface);
+ WaylandWindow* window = wl::RootWindowFromWlSurface(surface);
gfx::PointF location(wl_fixed_to_double(x), wl_fixed_to_double(y));
base::TimeTicks timestamp =
base::TimeTicks() + base::TimeDelta::FromMilliseconds(time);
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window.cc
index 21ebb192e5a..2e436462afb 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -6,6 +6,7 @@
#include <wayland-client.h>
+#include <algorithm>
#include <memory>
#include "base/bind.h"
@@ -21,30 +22,44 @@
#include "ui/ozone/platform/wayland/host/wayland_cursor_position.h"
#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
+#include "ui/ozone/platform/wayland/host/wayland_subsurface.h"
+#include "ui/ozone/public/mojom/wayland/wayland_overlay_config.mojom.h"
+
+namespace {
+
+bool OverlayStackOrderCompare(
+ const ui::ozone::mojom::WaylandOverlayConfigPtr& i,
+ const ui::ozone::mojom::WaylandOverlayConfigPtr& j) {
+ return i->z_order < j->z_order;
+}
+
+} // namespace
namespace ui {
WaylandWindow::WaylandWindow(PlatformWindowDelegate* delegate,
WaylandConnection* connection)
- : delegate_(delegate), connection_(connection) {}
+ : delegate_(delegate),
+ connection_(connection),
+ accelerated_widget_(
+ connection->wayland_window_manager()->AllocateAcceleratedWidget()) {}
WaylandWindow::~WaylandWindow() {
+ shutting_down_ = true;
+
PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
- if (surface())
+
+ for (const auto& widget_subsurface : wayland_subsurfaces()) {
+ connection_->wayland_window_manager()->RemoveSubsurface(
+ GetWidget(), widget_subsurface.get());
+ }
+ if (root_surface_)
connection_->wayland_window_manager()->RemoveWindow(GetWidget());
if (parent_window_)
parent_window_->set_child_window(nullptr);
}
-// static
-WaylandWindow* WaylandWindow::FromSurface(wl_surface* surface) {
- if (!surface)
- return nullptr;
- return static_cast<WaylandWindow*>(
- wl_proxy_get_user_data(reinterpret_cast<wl_proxy*>(surface)));
-}
-
void WaylandWindow::OnWindowLostCapture() {
delegate_->OnLostCapture();
}
@@ -76,12 +91,17 @@ void WaylandWindow::UpdateBufferScale(bool update_bounds) {
else
ui_scale_ = display.device_scale_factor();
}
- SetBufferScale(new_scale, update_bounds);
+ // At this point, buffer_scale() still returns the old scale.
+ if (update_bounds)
+ SetBoundsDip(gfx::ScaleToRoundedRect(bounds_px_, 1.0 / buffer_scale()));
+
+ root_surface_->SetBufferScale(new_scale, update_bounds);
}
gfx::AcceleratedWidget WaylandWindow::GetWidget() const {
- return wayland_surface_.GetWidget();
+ return accelerated_widget_;
}
+
void WaylandWindow::SetPointerFocus(bool focus) {
has_pointer_focus_ = focus;
@@ -116,10 +136,7 @@ void WaylandWindow::SetBounds(const gfx::Rect& bounds_px) {
return;
bounds_px_ = bounds_px;
- // Opaque region is based on the size of the window. Thus, update the region
- // on each update.
- MaybeUpdateOpaqueRegion();
-
+ root_surface_->SetBounds(bounds_px);
delegate_->OnBoundsChanged(bounds_px_);
}
@@ -316,24 +333,19 @@ void WaylandWindow::SetBoundsDip(const gfx::Rect& bounds_dip) {
}
bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
+ root_surface_ = std::make_unique<WaylandSurface>(connection_, this);
+ if (!root_surface_->Initialize()) {
+ LOG(ERROR) << "Failed to create wl_surface";
+ return false;
+ }
+
// 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);
bounds_px_ = properties.bounds;
opacity_ = properties.opacity;
type_ = properties.type;
- 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(), this);
- AddSurfaceListener();
-
connection_->wayland_window_manager()->AddWindow(GetWidget(), this);
if (!OnInitialize(std::move(properties)))
@@ -346,27 +358,11 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
// Will do nothing for menus because they have got their scale above.
UpdateBufferScale(false);
+ root_surface_->SetBounds(bounds_px_);
- MaybeUpdateOpaqueRegion();
return true;
}
-void WaylandWindow::SetBufferScale(int32_t new_scale, bool update_bounds) {
- DCHECK_GT(new_scale, 0);
-
- if (new_scale == buffer_scale())
- return;
-
- 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());
- connection_->ScheduleFlush();
-}
-
WaylandWindow* WaylandWindow::GetParentWindow(
gfx::AcceleratedWidget parent_widget) {
auto* parent_window =
@@ -393,14 +389,6 @@ WaylandWindow* WaylandWindow::GetRootParentWindow() {
return parent_window_ ? parent_window_->GetRootParentWindow() : this;
}
-void WaylandWindow::AddSurfaceListener() {
- static struct wl_surface_listener surface_listener = {
- &WaylandWindow::Enter,
- &WaylandWindow::Leave,
- };
- wl_surface_add_listener(surface(), &surface_listener, this);
-}
-
void WaylandWindow::AddEnteredOutputId(struct wl_output* output) {
// Wayland does weird things for menus so instead of tracking outputs that
// we entered or left, we take that from the parent window and ignore this
@@ -477,18 +465,6 @@ WaylandWindow* WaylandWindow::GetTopMostChildWindow() {
return child_window_ ? child_window_->GetTopMostChildWindow() : this;
}
-void WaylandWindow::MaybeUpdateOpaqueRegion() {
- if (!IsOpaqueWindow())
- return;
-
- wl::Object<wl_region> region(
- wl_compositor_create_region(connection_->compositor()));
- wl_region_add(region.get(), 0, 0, bounds_px_.width(), bounds_px_.height());
- wl_surface_set_opaque_region(surface(), region.get());
-
- connection_->ScheduleFlush();
-}
-
bool WaylandWindow::IsOpaqueWindow() const {
return opacity_ == ui::PlatformWindowOpacity::kOpaqueWindow;
}
@@ -505,26 +481,145 @@ uint32_t WaylandWindow::DispatchEventToDelegate(
return handled ? POST_DISPATCH_STOP_PROPAGATION : POST_DISPATCH_NONE;
}
-// static
-void WaylandWindow::Enter(void* data,
- struct wl_surface* wl_surface,
- struct wl_output* output) {
- auto* window = static_cast<WaylandWindow*>(data);
- if (window) {
- DCHECK(window->surface() == wl_surface);
- window->AddEnteredOutputId(output);
+std::unique_ptr<WaylandSurface> WaylandWindow::TakeWaylandSurface() {
+ DCHECK(shutting_down_);
+ DCHECK(root_surface_);
+ return std::move(root_surface_);
+}
+
+bool WaylandWindow::RequestSubsurface() {
+ auto subsurface = std::make_unique<WaylandSubsurface>(connection_, this);
+ if (!subsurface->surface())
+ return false;
+ connection_->wayland_window_manager()->AddSubsurface(GetWidget(),
+ subsurface.get());
+ subsurface_stack_above_.push_back(subsurface.get());
+ auto result = wayland_subsurfaces_.emplace(std::move(subsurface));
+ DCHECK(result.second);
+ return true;
+}
+
+bool WaylandWindow::ArrangeSubsurfaceStack(size_t above, size_t below) {
+ while (wayland_subsurfaces_.size() < above + below) {
+ if (!RequestSubsurface())
+ return false;
}
+
+ DCHECK(subsurface_stack_below_.size() + subsurface_stack_above_.size() >=
+ above + below);
+
+ if (subsurface_stack_above_.size() < above) {
+ auto splice_start = subsurface_stack_below_.begin();
+ for (size_t i = 0; i < below; ++i)
+ ++splice_start;
+ subsurface_stack_above_.splice(subsurface_stack_above_.end(),
+ subsurface_stack_below_, splice_start,
+ subsurface_stack_below_.end());
+
+ } else if (subsurface_stack_below_.size() < below) {
+ auto splice_start = subsurface_stack_above_.end();
+ for (size_t i = 0; i < below - subsurface_stack_below_.size(); ++i)
+ --splice_start;
+ subsurface_stack_below_.splice(subsurface_stack_below_.end(),
+ subsurface_stack_above_, splice_start,
+ subsurface_stack_above_.end());
+ }
+
+ DCHECK(subsurface_stack_below_.size() >= below);
+ DCHECK(subsurface_stack_above_.size() >= above);
+ return true;
}
-// static
-void WaylandWindow::Leave(void* data,
- struct wl_surface* wl_surface,
- struct wl_output* output) {
- auto* window = static_cast<WaylandWindow*>(data);
- if (window) {
- DCHECK(window->surface() == wl_surface);
- window->RemoveEnteredOutputId(output);
+bool WaylandWindow::CommitOverlays(
+ std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr>& overlays) {
+ // |overlays| is sorted from bottom to top.
+ std::sort(overlays.begin(), overlays.end(), OverlayStackOrderCompare);
+
+ // Find the location where z_oder becomes non-negative.
+ ozone::mojom::WaylandOverlayConfigPtr value =
+ ozone::mojom::WaylandOverlayConfig::New();
+ auto split = std::lower_bound(overlays.begin(), overlays.end(), value,
+ OverlayStackOrderCompare);
+ CHECK((*split)->z_order >= 0);
+ size_t num_primary_planes = (*split)->z_order == 0 ? 1 : 0;
+
+ size_t above = (overlays.end() - split) - num_primary_planes;
+ size_t below = split - overlays.begin();
+ // Re-arrange the list of subsurfaces to fit the |overlays|. Request extra
+ // subsurfaces if needed.
+ if (!ArrangeSubsurfaceStack(above, below))
+ return false;
+
+ {
+ // Iterate through |subsurface_stack_below_|, setup subsurfaces and place
+ // them in corresponding order. Commit wl_buffers once a subsurface is
+ // configured.
+ auto overlay_iter = split - 1;
+ for (auto iter = subsurface_stack_below_.begin();
+ iter != subsurface_stack_below_.end(); ++iter, --overlay_iter) {
+ if (overlay_iter >= overlays.begin()) {
+ WaylandSurface* reference_above = nullptr;
+ if (overlay_iter == split - 1) {
+ // It's possible that |overlays| does not contain primary plane, we
+ // still want to place relative to the surface with z_order=0.
+ reference_above = root_surface();
+ } else {
+ reference_above = (*std::next(iter))->wayland_surface();
+ }
+ (*iter)->ConfigureAndShowSurface(
+ (*overlay_iter)->transform, (*overlay_iter)->bounds_rect,
+ (*overlay_iter)->enable_blend, nullptr, reference_above);
+ connection_->buffer_manager_host()->CommitBufferInternal(
+ (*iter)->wayland_surface(), (*overlay_iter)->buffer_id,
+ gfx::Rect());
+ } else {
+ // If there're more subsurfaces requested that we don't need at the
+ // moment, hide them.
+ (*iter)->Hide();
+ }
+ }
+
+ // Iterate through |subsurface_stack_above_|, setup subsurfaces and place
+ // them in corresponding order. Commit wl_buffers once a subsurface is
+ // configured.
+ overlay_iter = split + num_primary_planes;
+ for (auto iter = subsurface_stack_above_.begin();
+ iter != subsurface_stack_above_.end(); ++iter, ++overlay_iter) {
+ if (overlay_iter < overlays.end()) {
+ WaylandSurface* reference_below = nullptr;
+ if (overlay_iter == split + num_primary_planes) {
+ // It's possible that |overlays| does not contain primary plane, we
+ // still want to place relative to the surface with z_order=0.
+ reference_below = root_surface();
+ } else {
+ reference_below = (*std::prev(iter))->wayland_surface();
+ }
+ (*iter)->ConfigureAndShowSurface(
+ (*overlay_iter)->transform, (*overlay_iter)->bounds_rect,
+ (*overlay_iter)->enable_blend, reference_below, nullptr);
+ connection_->buffer_manager_host()->CommitBufferInternal(
+ (*iter)->wayland_surface(), (*overlay_iter)->buffer_id,
+ gfx::Rect());
+ } else {
+ // If there're more subsurfaces requested that we don't need at the
+ // moment, hide them.
+ (*iter)->Hide();
+ }
+ }
}
+
+ if (num_primary_planes) {
+ // TODO: forward fence.
+ connection_->buffer_manager_host()->CommitBufferInternal(
+ root_surface(), (*split)->buffer_id, (*split)->damage_region);
+ } else {
+ // Subsurfaces are set to desync, above operations will only take effects
+ // when root_surface is committed.
+ root_surface()->Commit();
+ }
+
+ // commit all;
+ return true;
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window.h b/chromium/ui/ozone/platform/wayland/host/wayland_window.h
index 9c42eb59c80..cd9f1e9fb35 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window.h
@@ -5,6 +5,7 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_WINDOW_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_WINDOW_H_
+#include <list>
#include <memory>
#include <set>
#include <vector>
@@ -18,6 +19,7 @@
#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/ozone/public/mojom/wayland/wayland_overlay_config.mojom-forward.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"
@@ -31,20 +33,22 @@ namespace ui {
class BitmapCursorOzone;
class OSExchangeData;
class WaylandConnection;
+class WaylandSubsurface;
+class WaylandWindowDragController;
+
+using WidgetSubsurfaceSet = base::flat_set<std::unique_ptr<WaylandSubsurface>>;
class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
public:
~WaylandWindow() override;
// A factory method that can create any of the derived types of WaylandWindow
- // (WaylandToplevelWindow, WaylandPopup and WaylandSubsurface).
+ // (WaylandToplevelWindow, WaylandPopup and WaylandAuxiliaryWindow).
static std::unique_ptr<WaylandWindow> Create(
PlatformWindowDelegate* delegate,
WaylandConnection* connection,
PlatformWindowInitProperties properties);
- static WaylandWindow* FromSurface(wl_surface* surface);
-
void OnWindowLostCapture();
// Updates the surface buffer scale of the window. Top level windows take
@@ -54,8 +58,10 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// to do so (this is not needed upon window initialization).
void UpdateBufferScale(bool update_bounds);
- WaylandSurface* wayland_surface() { return &wayland_surface_; }
- wl_surface* surface() const { return wayland_surface_.surface(); }
+ WaylandSurface* root_surface() const { return root_surface_.get(); }
+ const WidgetSubsurfaceSet& wayland_subsurfaces() const {
+ return wayland_subsurfaces_;
+ }
void set_parent_window(WaylandWindow* parent_window) {
parent_window_ = parent_window;
@@ -64,6 +70,16 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
gfx::AcceleratedWidget GetWidget() const;
+ // Creates a WaylandSubsurface to put into |wayland_subsurfaces_|. Called if
+ // more subsurfaces are needed when a frame arrives.
+ bool RequestSubsurface();
+ // Re-arrange the |subsurface_stack_above_| and |subsurface_stack_below_| s.t.
+ // subsurface_stack_above_.size() >= above and
+ // subsurface_stack_below_.size() >= below.
+ bool ArrangeSubsurfaceStack(size_t above, size_t below);
+ bool CommitOverlays(
+ std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr>& overlays);
+
// Set whether this window has pointer focus and should dispatch mouse events.
void SetPointerFocus(bool focus);
bool has_pointer_focus() const { return has_pointer_focus_; }
@@ -82,7 +98,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 wayland_surface_.buffer_scale(); }
+ int32_t buffer_scale() const { return root_surface_->buffer_scale(); }
int32_t ui_scale() const { return ui_scale_; }
const base::flat_set<uint32_t>& entered_outputs_ids() const {
@@ -145,8 +161,7 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
virtual void OnDragEnter(const gfx::PointF& point,
std::unique_ptr<OSExchangeData> data,
int operation);
- virtual int OnDragMotion(const gfx::PointF& point,
- int operation);
+ virtual int OnDragMotion(const gfx::PointF& point, int operation);
virtual void OnDragDrop(std::unique_ptr<OSExchangeData> data);
virtual void OnDragLeave();
virtual void OnDragSessionClose(uint32_t dnd_action);
@@ -157,6 +172,17 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// Returns a top most child window within the same hierarchy.
WaylandWindow* GetTopMostChildWindow();
+ // This should be called when a WaylandSurface part of this window becomes
+ // partially or fully within the scanout region of |output|.
+ void AddEnteredOutputId(struct wl_output* output);
+
+ // This should be called when a WaylandSurface part of this window becomes
+ // fully outside of the scanout region of |output|.
+ void RemoveEnteredOutputId(struct wl_output* output);
+
+ // Returns true iff this window is opaque.
+ bool IsOpaqueWindow() const;
+
protected:
WaylandWindow(PlatformWindowDelegate* delegate,
WaylandConnection* connection);
@@ -170,10 +196,6 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// Gets a parent window for this window.
WaylandWindow* GetParentWindow(gfx::AcceleratedWidget parent_widget);
- // Sets the buffer scale.
- void SetBufferScale(int32_t scale, bool update_bounds);
-
- // Sets the ui scale.
void set_ui_scale(int32_t ui_scale) { ui_scale_ = ui_scale; }
private:
@@ -182,41 +204,38 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// Initializes the WaylandWindow with supplied properties.
bool Initialize(PlatformWindowInitProperties properties);
- // Install a surface listener and start getting wl_output enter/leave events.
- void AddSurfaceListener();
-
- void AddEnteredOutputId(struct wl_output* output);
- void RemoveEnteredOutputId(struct wl_output* output);
-
void UpdateCursorPositionFromEvent(std::unique_ptr<Event> event);
WaylandWindow* GetTopLevelWindow();
- // It's important to set opaque region for opaque windows (provides
- // optimization hint for the Wayland compositor).
- void MaybeUpdateOpaqueRegion();
-
- bool IsOpaqueWindow() const;
-
uint32_t DispatchEventToDelegate(const PlatformEvent& native_event);
// Additional initialization of derived classes.
virtual bool OnInitialize(PlatformWindowInitProperties properties) = 0;
- // wl_surface_listener
- static void Enter(void* data,
- struct wl_surface* wl_surface,
- struct wl_output* output);
- static void Leave(void* data,
- struct wl_surface* wl_surface,
- struct wl_output* output);
+ // WaylandWindowDragController might need to take ownership of the wayland
+ // surface whether the window that originated the DND session gets destroyed
+ // in the middle of that session (e.g: when it is snapped into a tab strip).
+ // Surface ownership is allowed to be taken only when the window is under
+ // destruction, i.e: |shutting_down_| is set. This can be done, for example,
+ // by implementing |WaylandWindowObserver::OnWindowRemoved|.
+ friend WaylandWindowDragController;
+ std::unique_ptr<WaylandSurface> TakeWaylandSurface();
PlatformWindowDelegate* delegate_;
WaylandConnection* connection_;
WaylandWindow* parent_window_ = nullptr;
WaylandWindow* child_window_ = nullptr;
- WaylandSurface wayland_surface_;
+ std::unique_ptr<WaylandSurface> root_surface_;
+ WidgetSubsurfaceSet wayland_subsurfaces_;
+
+ // The stack of sub-surfaces to take effect when Commit() is called.
+ // |subsurface_stack_above_| refers to subsurfaces that are stacked above the
+ // parent.
+ // Subsurface at the front of the list is the closest to the parent.
+ std::list<WaylandSubsurface*> subsurface_stack_above_;
+ std::list<WaylandSubsurface*> subsurface_stack_below_;
// The current cursor bitmap (immutable).
scoped_refptr<BitmapCursorOzone> bitmap_;
@@ -250,6 +269,12 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// The type of the current WaylandWindow object.
ui::PlatformWindowType type_ = ui::PlatformWindowType::kWindow;
+ // Set when the window enters in shutdown process.
+ bool shutting_down_ = false;
+
+ // AcceleratedWidget for this window. This will be unique even over time.
+ gfx::AcceleratedWidget accelerated_widget_;
+
DISALLOW_COPY_AND_ASSIGN(WaylandWindow);
};
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
index 08d5cb633ca..64ffd8b4845 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
@@ -12,9 +12,9 @@
#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 "base/task/current_thread.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
@@ -64,19 +64,48 @@ WaylandWindowDragController::WaylandWindowDragController(
WaylandWindowDragController::~WaylandWindowDragController() = default;
-bool WaylandWindowDragController::Drag(WaylandToplevelWindow* window,
- const gfx::Vector2d& offset) {
- DCHECK_LE(state_, State::kAttached);
- DCHECK(window);
+bool WaylandWindowDragController::StartDragSession() {
+ if (state_ != State::kIdle)
+ return true;
- if (!OfferWindow())
+ origin_window_ = window_manager_->GetCurrentFocusedWindow();
+ if (!origin_window_) {
+ LOG(ERROR) << "Failed to get origin window.";
return false;
+ }
+
+ VLOG(1) << "Starting DND session.";
+ state_ = State::kAttached;
+
+ DCHECK(!data_source_);
+ data_source_ = data_device_manager_->CreateSource(this);
+ data_source_->Offer({kMimeTypeChromiumWindow});
+ data_source_->SetAction(DragDropTypes::DRAG_MOVE);
+
+ // TODO(crbug.com/1099418): Use dragged window's surface as icon surface
+ // once "immediate drag" protocol extensions are available.
+ data_device_->StartDrag(*data_source_, *origin_window_,
+ /*icon_surface=*/nullptr, this);
+
+ pointer_grab_owner_ = origin_window_;
+
+ // Observe window so we can take ownership of the origin surface in case it
+ // is destroyed during the DND session.
+ window_manager_->AddObserver(this);
+ return true;
+}
+bool WaylandWindowDragController::Drag(WaylandToplevelWindow* window,
+ const gfx::Vector2d& offset) {
DCHECK_EQ(state_, State::kAttached);
+ DCHECK(window);
dragged_window_ = window;
drag_offset_ = offset;
+
RunLoop();
+ dragged_window_ = nullptr;
+
DCHECK(state_ == State::kAttached || state_ == State::kDropped);
bool dropped = state_ == State::kDropped;
if (dropped)
@@ -91,9 +120,11 @@ void WaylandWindowDragController::StopDragging() {
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.
+ // snapped into a tab strip. So switch to |kAttached| state, store the focused
+ // window as the pointer grabber and ask to quit the nested loop.
state_ = State::kAttached;
+ pointer_grab_owner_ = window_manager_->GetCurrentFocusedWindow();
+ DCHECK(pointer_grab_owner_);
QuitLoop();
}
@@ -118,6 +149,8 @@ void WaylandWindowDragController::OnDragEnter(WaylandWindow* window,
uint32_t serial) {
DCHECK_GE(state_, State::kAttached);
DCHECK(window);
+ DCHECK(data_source_);
+ DCHECK(data_offer_);
// Forward focus change event to the input delegate, so other components, such
// as WaylandScreen, are able to properly retrieve focus related info during
@@ -126,8 +159,13 @@ void WaylandWindowDragController::OnDragEnter(WaylandWindow* window,
VLOG(1) << "OnEnter. widget=" << window->GetWidget();
+ // TODO(crbug.com/1102946): Exo does not support custom mime types. In this
+ // case, |data_offer_| will hold an empty mime_types list and, at this point,
+ // it's safe just to skip the offer checks and requests here.
+ if (data_offer_->mime_types().empty())
+ return;
+
// 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);
@@ -161,16 +199,39 @@ void WaylandWindowDragController::OnDragLeave() {
// which would require hacky workarounds in HandleDropAndResetState function
// to properly detect and handle such cases.
- VLOG(1) << "OnLeave";
+ if (!data_offer_)
+ return;
+ VLOG(1) << "OnLeave";
data_offer_.reset();
+
+ // As Wayland clients are only aware of surface-local coordinates and there is
+ // no implicit grab during DND sessions, a fake motion event with negative
+ // coordinates must be used here to make it possible for higher level UI
+ // components to detect when a window should be detached. E.g: On Chrome,
+ // dragging a tab all the way up to the top edge of the window won't work
+ // without this fake motion event upon wl_data_device::leave events.
+ if (state_ == State::kAttached)
+ pointer_delegate_->OnPointerMotionEvent({-1, -1});
}
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}.
+ DCHECK_GE(state_, State::kAttached);
+ VLOG(1) << "Dropped. state=" << state_;
+
+ // Some compositors, e.g: Exo, may delay the wl_data_source::cancelled event
+ // delivery for some seconds, when the drop happens within a toplevel surface.
+ // Such event is handled by OnDataSourceFinish() function below, which is the
+ // single entry point for the drop event in window drag controller. In order
+ // to prevent such delay, the current data offer must be destroyed here.
+ DCHECK(data_offer_);
+ data_offer_.reset();
}
+// This function is called when either 'cancelled' or 'finished' data source
+// events is received during a window dragging session. It is used to detect
+// when drop happens, since it is the only event sent by the server regardless
+// where it happens, inside or outside toplevel surfaces.
void WaylandWindowDragController::OnDataSourceFinish(bool completed) {
DCHECK_GE(state_, State::kAttached);
DCHECK(data_source_);
@@ -180,7 +241,8 @@ void WaylandWindowDragController::OnDataSourceFinish(bool completed) {
// Release DND objects.
data_offer_.reset();
data_source_.reset();
- icon_surface_.reset();
+ origin_surface_.reset();
+ origin_window_ = nullptr;
dragged_window_ = nullptr;
// Transition to |kDropped| state and determine the next action to take. If
@@ -193,6 +255,7 @@ void WaylandWindowDragController::OnDataSourceFinish(bool completed) {
HandleDropAndResetState();
data_device_->ResetDragDelegate();
+ window_manager_->RemoveObserver(this);
}
void WaylandWindowDragController::OnDataSourceSend(const std::string& mime_type,
@@ -208,7 +271,7 @@ bool WaylandWindowDragController::CanDispatchEvent(const PlatformEvent& event) {
uint32_t WaylandWindowDragController::DispatchEvent(
const PlatformEvent& event) {
DCHECK_EQ(state_, State::kDetached);
- DCHECK(base::MessageLoopCurrentForUI::IsSet());
+ DCHECK(base::CurrentUIThread::IsSet());
VLOG(2) << "Dispatch. event=" << event->GetName();
@@ -219,30 +282,10 @@ uint32_t WaylandWindowDragController::DispatchEvent(
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::OnWindowRemoved(WaylandWindow* window) {
+ DCHECK_NE(state_, State::kIdle);
+ if (window == origin_window_)
+ origin_surface_ = origin_window_->TakeWaylandSurface();
}
void WaylandWindowDragController::HandleMotionEvent(MouseEvent* event) {
@@ -273,14 +316,15 @@ void WaylandWindowDragController::HandleMotionEvent(MouseEvent* event) {
// about to finish.
void WaylandWindowDragController::HandleDropAndResetState() {
DCHECK_EQ(state_, State::kDropped);
- DCHECK(window_manager_->GetCurrentFocusedWindow());
- VLOG(1) << "Notifying drop. window="
- << window_manager_->GetCurrentFocusedWindow();
+ DCHECK(pointer_grab_owner_);
+ VLOG(1) << "Notifying drop. window=" << pointer_grab_owner_;
EventFlags pointer_button = EF_LEFT_MOUSE_BUTTON;
DCHECK(connection_->event_source()->IsPointerButtonPressed(pointer_button));
- pointer_delegate_->OnPointerButtonEvent(ET_MOUSE_RELEASED, pointer_button);
+ pointer_delegate_->OnPointerButtonEvent(ET_MOUSE_RELEASED, pointer_button,
+ pointer_grab_owner_);
+ pointer_grab_owner_ = nullptr;
state_ = State::kIdle;
}
@@ -288,7 +332,8 @@ void WaylandWindowDragController::RunLoop() {
DCHECK_EQ(state_, State::kAttached);
DCHECK(dragged_window_);
- VLOG(1) << "Starting drag loop. widget=" << dragged_window_->GetWidget();
+ VLOG(1) << "Starting drag loop. widget=" << dragged_window_->GetWidget()
+ << " offset=" << drag_offset_.ToString();
// TODO(crbug.com/896640): Handle cursor
auto old_dispatcher = std::move(nested_dispatcher_);
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
index 071cc9672bc..fa3ed531119 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h
@@ -21,6 +21,7 @@
#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"
+#include "ui/ozone/platform/wayland/host/wayland_window_observer.h"
namespace ui {
@@ -29,6 +30,7 @@ class WaylandDataDeviceManager;
class WaylandDataOffer;
class WaylandWindow;
class WaylandWindowManager;
+class WaylandSurface;
// Drag controller implementation that drives window moving sessions (aka: tab
// dragging). Wayland Drag and Drop protocol is used, under the hood, to keep
@@ -37,7 +39,8 @@ class WaylandWindowManager;
// TODO(crbug.com/896640): Use drag icon to emulate window moving.
class WaylandWindowDragController : public WaylandDataDevice::DragDelegate,
public WaylandDataSource::Delegate,
- public PlatformEventDispatcher {
+ public PlatformEventDispatcher,
+ public WaylandWindowObserver {
public:
// Constants used to keep track of the drag controller state.
enum class State {
@@ -55,7 +58,12 @@ class WaylandWindowDragController : public WaylandDataDevice::DragDelegate,
delete;
~WaylandWindowDragController() override;
- bool Drag(WaylandToplevelWindow* surface, const gfx::Vector2d& offset);
+ // Starts a new Wayland DND session for window dragging, if not done yet. A
+ // new data source is setup and the focused window is used as the origin
+ // surface.
+ bool StartDragSession();
+
+ bool Drag(WaylandToplevelWindow* window, const gfx::Vector2d& offset);
void StopDragging();
State state() const { return state_; }
@@ -81,9 +89,9 @@ class WaylandWindowDragController : public WaylandDataDevice::DragDelegate,
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();
+ // WaylandWindowObserver:
+ void OnWindowRemoved(WaylandWindow* window) override;
+
// 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);
@@ -103,12 +111,26 @@ class WaylandWindowDragController : public WaylandDataDevice::DragDelegate,
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_;
+
+ // The current toplevel window being dragged, when in detached mode.
+ WaylandToplevelWindow* dragged_window_ = nullptr;
+
+ // Keeps track of the window that holds the pointer grab. i.e: the owner of
+ // the surface that must receive the mouse release event upon drop.
+ WaylandWindow* pointer_grab_owner_ = nullptr;
+
+ // The window where the DND session originated from. i.e: which had the
+ // pointer focus when the session was initiated.
+ WaylandWindow* origin_window_ = nullptr;
+
+ // The |origin_window_| can be destroyed during the DND session. If this
+ // happens, |origin_surface_| takes ownership of its surface and ensure it
+ // is kept alive until the end of the session.
+ std::unique_ptr<WaylandSurface> origin_surface_;
std::unique_ptr<ScopedEventDispatcher> nested_dispatcher_;
base::OnceClosure quit_loop_closure_;
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
index 56a13b46e48..4f24aadffb4 100644
--- 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
@@ -21,7 +21,6 @@
#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"
@@ -31,8 +30,9 @@
#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/extensions/wayland_extension.h"
#include "ui/platform_window/platform_window_delegate.h"
-#include "ui/platform_window/platform_window_handler/wm_move_loop_handler.h"
+#include "ui/platform_window/wm/wm_move_loop_handler.h"
using testing::_;
using testing::Mock;
@@ -109,7 +109,8 @@ class WaylandWindowDragControllerTest : public WaylandTest,
void SendDndEnter(WaylandWindow* window) {
EXPECT_TRUE(window);
- OfferAndEnter(server_.GetObject<wl::MockSurface>(window->GetWidget()));
+ OfferAndEnter(server_.GetObject<wl::MockSurface>(
+ window->root_surface()->GetSurfaceId()));
}
void SendDndLeave() {
@@ -124,7 +125,8 @@ class WaylandWindowDragControllerTest : public WaylandTest,
void SendPointerEnter(WaylandWindow* window,
MockPlatformWindowDelegate* delegate) {
- auto* surface = server_.GetObject<wl::MockSurface>(window->GetWidget());
+ auto* surface = server_.GetObject<wl::MockSurface>(
+ window->root_surface()->GetSurfaceId());
wl_pointer_send_enter(pointer_->resource(), NextSerial(),
surface->resource(), 0, 0);
EXPECT_CALL(*delegate, DispatchEvent(_)).Times(1);
@@ -133,6 +135,18 @@ class WaylandWindowDragControllerTest : public WaylandTest,
EXPECT_EQ(window, window_manager()->GetCurrentFocusedWindow());
}
+ void SendPointerLeave(WaylandWindow* window,
+ MockPlatformWindowDelegate* delegate) {
+ auto* surface = server_.GetObject<wl::MockSurface>(
+ window->root_surface()->GetSurfaceId());
+ wl_pointer_send_leave(pointer_->resource(), NextSerial(),
+ surface->resource());
+ EXPECT_CALL(*delegate, DispatchEvent(_)).Times(1);
+ Sync();
+
+ EXPECT_EQ(nullptr, window_manager()->GetCurrentFocusedWindow());
+ }
+
void SendPointerPress(WaylandWindow* window,
MockPlatformWindowDelegate* delegate,
int button) {
@@ -195,10 +209,14 @@ TEST_P(WaylandWindowDragControllerTest, DragInsideWindowAndDrop) {
SendPointerPress(window_.get(), &delegate_, BTN_LEFT);
SendPointerMotion(window_.get(), &delegate_, {10, 10});
- // Set up an "interaction flow" and RunMoveLoop:
+ // Set up an "interaction flow", start the drag session and run move loop:
// - 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* wayland_extension = GetWaylandExtension(*window_);
+ wayland_extension->StartWindowDraggingSessionIfNeeded();
+ EXPECT_EQ(State::kAttached, drag_controller()->state());
+
auto* move_loop_handler = GetWmMoveLoopHandler(*window_);
DCHECK(move_loop_handler);
@@ -281,21 +299,20 @@ TEST_P(WaylandWindowDragControllerTest, DragExitWindowAndDrop) {
SendPointerEnter(window_.get(), &delegate_);
SendPointerPress(window_.get(), &delegate_, BTN_LEFT);
SendPointerMotion(window_.get(), &delegate_, {10, 10});
+ Sync();
- // Sets up an "interaction flow" and RunMoveLoop:
+ // Sets up an "interaction flow", start the drag session and run move loop:
// - 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* wayland_extension = GetWaylandExtension(*window_);
+ wayland_extension->StartWindowDraggingSessionIfNeeded();
+ EXPECT_EQ(State::kAttached, drag_controller()->state());
+
auto* move_loop_handler = GetWmMoveLoopHandler(*window_);
DCHECK(move_loop_handler);
- enum {
- kStarted,
- kDragging,
- kExitedWindow,
- kDropping,
- kDone
- } test_step = kStarted;
+ enum { kStarted, kDragging, kExitedDropping, kDone } test_step = kStarted;
EXPECT_CALL(delegate_, DispatchEvent(_)).WillRepeatedly([&](Event* event) {
EXPECT_TRUE(event->IsMouseEvent());
@@ -310,13 +327,7 @@ TEST_P(WaylandWindowDragControllerTest, DragExitWindowAndDrop) {
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:
+ case kExitedDropping:
EXPECT_EQ(ET_MOUSE_RELEASED, event->type());
EXPECT_EQ(State::kDropped, drag_controller()->state());
// Ensure PlatformScreen keeps consistent.
@@ -343,8 +354,9 @@ TEST_P(WaylandWindowDragControllerTest, DragExitWindowAndDrop) {
EXPECT_EQ(kDragging, test_step);
EXPECT_EQ(gfx::Point(20, 20), bounds.origin());
+ SendDndLeave();
SendDndDrop();
- test_step = kDropping;
+ test_step = kExitedDropping;
});
// RunMoveLoop() blocks until the dragging sessions ends, so resume test
@@ -394,10 +406,14 @@ TEST_P(WaylandWindowDragControllerTest, DragToOtherWindowSnapDragDrop) {
SendPointerPress(source_window, &delegate_, BTN_LEFT);
SendPointerMotion(source_window, &delegate_, {10, 10});
- // Sets up an "interaction flow" and RunMoveLoop:
+ // Sets up an "interaction flow", start the drag session and run move loop:
// - 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* wayland_extension = GetWaylandExtension(*window_);
+ wayland_extension->StartWindowDraggingSessionIfNeeded();
+ EXPECT_EQ(State::kAttached, drag_controller()->state());
+
auto* move_loop_handler = GetWmMoveLoopHandler(*window_);
DCHECK(move_loop_handler);
@@ -479,20 +495,22 @@ TEST_P(WaylandWindowDragControllerTest, DragToOtherWindowSnapDragDrop) {
EXPECT_EQ(target_window->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({50, 50}, {}));
+ // Emulates a pointer::leave event being sent before data_source::cancelled,
+ // what happens with some compositors, e.g: Exosphere. Even in these cases,
+ // WaylandWindowDragController must guarantee the mouse button release event
+ // (aka: drop) is delivered to the upper layer listeners.
+ SendPointerLeave(target_window, &delegate_);
+
SendDndDrop();
- EXPECT_CALL(delegate_, DispatchEvent(_)).WillRepeatedly([&](Event* event) {
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce([&](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());
+ EXPECT_EQ(target_window, window_manager()->GetCurrentFocusedWindow());
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()
@@ -508,6 +526,50 @@ TEST_P(WaylandWindowDragControllerTest, DragToOtherWindowSnapDragDrop) {
screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
}
+// Verifies wl_data_device::leave events are properly handled and propagated
+// while in window dragging "attached" mode.
+TEST_P(WaylandWindowDragControllerTest, DragExitAttached) {
+ // 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});
+ Sync();
+ EXPECT_EQ(window_->GetWidget(),
+ screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
+
+ auto* wayland_extension = GetWaylandExtension(*window_);
+ wayland_extension->StartWindowDraggingSessionIfNeeded();
+ EXPECT_CALL(delegate_, DispatchEvent(_)).Times(1);
+ Sync();
+ Sync();
+ EXPECT_EQ(State::kAttached, drag_controller()->state());
+
+ // Emulate a wl_data_device::leave and make sure a motion event is dispatched
+ // in response.
+ SendDndLeave();
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce([&](Event* event) {
+ EXPECT_EQ(ET_MOUSE_DRAGGED, event->type());
+ EXPECT_EQ(gfx::Point(-1, -1).ToString(),
+ event->AsMouseEvent()->location().ToString());
+ });
+ Sync();
+
+ SendDndDrop();
+ EXPECT_CALL(delegate_, DispatchEvent(_)).Times(1);
+ Sync();
+
+ SendPointerEnter(window_.get(), &delegate_);
+ Sync();
+
+ EXPECT_EQ(window_.get(), window_manager()->GetCurrentFocusedWindow());
+ EXPECT_EQ(window_->GetWidget(),
+ screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
+}
+
INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
WaylandWindowDragControllerTest,
::testing::Values(kXdgShellStable));
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 29d70dbdc39..7854b05b999 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc
@@ -5,9 +5,9 @@
#include <memory>
#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/wayland/host/wayland_auxiliary_window.h"
#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_toplevel_window.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
@@ -30,13 +30,13 @@ std::unique_ptr<WaylandWindow> WaylandWindow::Create(
} else if (connection->IsDragInProgress()) {
// We are in the process of drag and requested a popup. Most probably,
// it is an arrow window.
- window.reset(new WaylandSubsurface(delegate, connection));
+ window.reset(new WaylandAuxiliaryWindow(delegate, connection));
} else {
window.reset(new WaylandPopup(delegate, connection));
}
break;
case PlatformWindowType::kTooltip:
- window.reset(new WaylandSubsurface(delegate, connection));
+ window.reset(new WaylandAuxiliaryWindow(delegate, connection));
break;
case PlatformWindowType::kWindow:
case PlatformWindowType::kBubble:
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 51f07bbc27a..0c9b86e81fc 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc
@@ -110,6 +110,28 @@ void WaylandWindowManager::RemoveWindow(gfx::AcceleratedWidget widget) {
observer.OnWindowRemoved(window);
}
+void WaylandWindowManager::AddSubsurface(gfx::AcceleratedWidget widget,
+ WaylandSubsurface* subsurface) {
+ auto* window = window_map_[widget];
+ DCHECK(window);
+
+ for (WaylandWindowObserver& observer : observers_)
+ observer.OnSubsurfaceAdded(window, subsurface);
+}
+
+void WaylandWindowManager::RemoveSubsurface(gfx::AcceleratedWidget widget,
+ WaylandSubsurface* subsurface) {
+ auto* window = window_map_[widget];
+ DCHECK(window);
+
+ for (WaylandWindowObserver& observer : observers_)
+ observer.OnSubsurfaceRemoved(window, subsurface);
+}
+
+gfx::AcceleratedWidget WaylandWindowManager::AllocateAcceleratedWidget() {
+ return ++last_accelerated_widget_;
+}
+
std::vector<WaylandWindow*> WaylandWindowManager::GetAllWindows() const {
std::vector<WaylandWindow*> result;
for (auto entry : window_map_)
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 1f4cad045ca..ca32c24833f 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.h
@@ -16,6 +16,7 @@
namespace ui {
class WaylandWindow;
+class WaylandSubsurface;
// Stores and returns WaylandWindows. Clients that are interested in knowing
// when a new window is added or removed, but set self as an observer.
@@ -63,6 +64,13 @@ class WaylandWindowManager {
void AddWindow(gfx::AcceleratedWidget widget, WaylandWindow* window);
void RemoveWindow(gfx::AcceleratedWidget widget);
+ void AddSubsurface(gfx::AcceleratedWidget widget,
+ WaylandSubsurface* subsurface);
+ void RemoveSubsurface(gfx::AcceleratedWidget widget,
+ WaylandSubsurface* subsurface);
+
+ // Creates a new unique gfx::AcceleratedWidget.
+ gfx::AcceleratedWidget AllocateAcceleratedWidget();
private:
base::ObserverList<WaylandWindowObserver> observers_;
@@ -71,6 +79,10 @@ class WaylandWindowManager {
WaylandWindow* located_events_grabber_ = nullptr;
+ // Stores strictly monotonically increasing counter for allocating unique
+ // AccelerateWidgets.
+ gfx::AcceleratedWidget last_accelerated_widget_ = gfx::kNullAcceleratedWidget;
+
DISALLOW_COPY_AND_ASSIGN(WaylandWindowManager);
};
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc
index 73b6d2c187e..8237298cde9 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc
@@ -100,8 +100,8 @@ TEST_P(WaylandWindowManagerTest, GetCurrentFocusedWindow) {
auto* pointer = server_.seat()->pointer();
ASSERT_TRUE(pointer);
- wl::MockSurface* surface =
- server_.GetObject<wl::MockSurface>(window1->GetWidget());
+ wl::MockSurface* surface = server_.GetObject<wl::MockSurface>(
+ window1->root_surface()->GetSurfaceId());
wl_pointer_send_enter(pointer->resource(), 1, surface->resource(), 0, 0);
Sync();
@@ -137,8 +137,8 @@ TEST_P(WaylandWindowManagerTest, GetCurrentKeyboardFocusedWindow) {
auto* keyboard = server_.seat()->keyboard();
ASSERT_TRUE(keyboard);
- wl::MockSurface* surface =
- server_.GetObject<wl::MockSurface>(window1->GetWidget());
+ wl::MockSurface* surface = server_.GetObject<wl::MockSurface>(
+ window1->root_surface()->GetSurfaceId());
struct wl_array empty;
wl_array_init(&empty);
@@ -159,7 +159,15 @@ TEST_P(WaylandWindowManagerTest, GetCurrentKeyboardFocusedWindow) {
TEST_P(WaylandWindowManagerTest, GetWindowsOnOutput) {
MockPlatformWindowDelegate delegate;
+ // Create a second wl_output.
wl::TestOutput* output = server_.CreateAndInitializeOutput();
+ Sync();
+
+ // Place it at the right of the first output.
+ int x = server_.output()->GetRect().x();
+ output->SetRect({x, 0, 800, 600});
+ output->Flush();
+ Sync();
auto window1 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow,
kDefaultBounds, &delegate);
@@ -169,8 +177,8 @@ TEST_P(WaylandWindowManagerTest, GetWindowsOnOutput) {
Sync();
- wl::MockSurface* surface =
- server_.GetObject<wl::MockSurface>(window1->GetWidget());
+ wl::MockSurface* surface = server_.GetObject<wl::MockSurface>(
+ window1->root_surface()->GetSurfaceId());
ASSERT_TRUE(surface);
wl_surface_send_enter(surface->resource(), output->resource());
@@ -186,7 +194,8 @@ TEST_P(WaylandWindowManagerTest, GetWindowsOnOutput) {
EXPECT_TRUE(window1.get() == *windows_on_output.begin());
- surface = server_.GetObject<wl::MockSurface>(window2->GetWidget());
+ surface = server_.GetObject<wl::MockSurface>(
+ window2->root_surface()->GetSurfaceId());
ASSERT_TRUE(surface);
wl_surface_send_enter(surface->resource(), output->resource());
@@ -194,6 +203,9 @@ TEST_P(WaylandWindowManagerTest, GetWindowsOnOutput) {
windows_on_output = manager_->GetWindowsOnOutput(output_id);
EXPECT_EQ(2u, windows_on_output.size());
+
+ output->DestroyGlobal();
+ Sync();
}
TEST_P(WaylandWindowManagerTest, GetAllWindows) {
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 e289ea88e3d..5ce43f062f3 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.cc
@@ -14,4 +14,11 @@ void WaylandWindowObserver::OnWindowRemoved(WaylandWindow* window) {}
void WaylandWindowObserver::OnWindowConfigured(WaylandWindow* window) {}
+void WaylandWindowObserver::OnSubsurfaceAdded(WaylandWindow* window,
+ WaylandSubsurface* subsurface) {}
+
+void WaylandWindowObserver::OnSubsurfaceRemoved(WaylandWindow* window,
+ WaylandSubsurface* subsurface) {
+}
+
} // 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 c461b03114e..2434eb779a4 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.h
@@ -10,6 +10,7 @@
namespace ui {
class WaylandWindow;
+class WaylandSubsurface;
// Observers for window management notifications.
class WaylandWindowObserver : public base::CheckedObserver {
@@ -23,6 +24,14 @@ class WaylandWindowObserver : public base::CheckedObserver {
// Called when |window| has been ack configured.
virtual void OnWindowConfigured(WaylandWindow* window);
+ // Called when |window| adds |subsurface|.
+ virtual void OnSubsurfaceAdded(WaylandWindow* window,
+ WaylandSubsurface* subsurface);
+
+ // Called when |window| removes |subsurface|.
+ virtual void OnSubsurfaceRemoved(WaylandWindow* window,
+ WaylandSubsurface* subsurface);
+
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 d7c533edc09..2626222a427 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
@@ -19,7 +19,9 @@
#include "ui/base/hit_test.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"
+#include "ui/gfx/overlay_transform.h"
#include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_subsurface.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_keyboard.h"
@@ -28,8 +30,8 @@
#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_handler/wm_move_resize_handler.h"
#include "ui/platform_window/platform_window_init_properties.h"
+#include "ui/platform_window/wm/wm_move_resize_handler.h"
using ::testing::_;
using ::testing::Eq;
@@ -98,9 +100,9 @@ class WaylandWindowTest : public WaylandTest {
}
protected:
- void SendConfigureEventPopup(gfx::AcceleratedWidget menu_widget,
+ void SendConfigureEventPopup(WaylandWindow* menu_window,
const gfx::Rect bounds) {
- auto* popup = GetPopupByWidget(menu_widget);
+ auto* popup = GetPopupByWindow(menu_window);
ASSERT_TRUE(popup);
if (GetParam() == kXdgShellV6) {
zxdg_popup_v6_send_configure(popup->resource(), bounds.x(), bounds.y(),
@@ -164,9 +166,9 @@ class WaylandWindowTest : public WaylandTest {
Mock::VerifyAndClearExpectations(&delegate_);
}
- void VerifyXdgPopupPosition(gfx::AcceleratedWidget menu_widget,
+ void VerifyXdgPopupPosition(WaylandWindow* menu_window,
const PopupPosition& position) {
- auto* popup = GetPopupByWidget(menu_widget);
+ auto* popup = GetPopupByWindow(menu_window);
ASSERT_TRUE(popup);
EXPECT_EQ(popup->anchor_rect(), position.anchor_rect);
@@ -207,8 +209,9 @@ class WaylandWindowTest : public WaylandTest {
EXPECT_FALSE(window->CanDispatchEvent(&test_key_event));
}
- wl::TestXdgPopup* GetPopupByWidget(gfx::AcceleratedWidget widget) {
- wl::MockSurface* mock_surface = server_.GetObject<wl::MockSurface>(widget);
+ wl::TestXdgPopup* GetPopupByWindow(WaylandWindow* window) {
+ wl::MockSurface* mock_surface = server_.GetObject<wl::MockSurface>(
+ window->root_surface()->GetSurfaceId());
if (mock_surface) {
auto* mock_xdg_surface = mock_surface->xdg_surface();
if (mock_xdg_surface)
@@ -384,7 +387,8 @@ TEST_P(WaylandWindowTest, StartWithFullscreen) {
// The state must not be changed to the fullscreen before the surface is
// activated.
- auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget());
+ auto* mock_surface = server_.GetObject<wl::MockSurface>(
+ window->root_surface()->GetSurfaceId());
EXPECT_FALSE(mock_surface->xdg_surface());
EXPECT_CALL(delegate, OnWindowStateChanged(_)).Times(0);
window->ToggleFullscreen();
@@ -428,7 +432,8 @@ TEST_P(WaylandWindowTest, StartMaximized) {
// The state must not be changed to the fullscreen before the surface is
// activated.
- auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget());
+ auto* mock_surface = server_.GetObject<wl::MockSurface>(
+ window->root_surface()->GetSurfaceId());
EXPECT_FALSE(mock_surface->xdg_surface());
EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
@@ -1196,8 +1201,8 @@ TEST_P(WaylandWindowTest, CanDispatchEvent) {
uint32_t serial = 0;
// Test that CanDispatchEvent is set correctly.
- wl::MockSurface* toplevel_surface =
- server_.GetObject<wl::MockSurface>(widget_);
+ wl::MockSurface* toplevel_surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
wl_pointer_send_enter(server_.seat()->pointer()->resource(), ++serial,
toplevel_surface->resource(), 0, 0);
@@ -1240,8 +1245,8 @@ TEST_P(WaylandWindowTest, CanDispatchEvent) {
VerifyCanDispatchKeyEvents({window_.get()},
{menu_window.get(), nested_menu_window.get()});
- wl::MockSurface* menu_window_surface =
- server_.GetObject<wl::MockSurface>(menu_window->GetWidget());
+ wl::MockSurface* menu_window_surface = server_.GetObject<wl::MockSurface>(
+ menu_window->root_surface()->GetSurfaceId());
wl_pointer_send_leave(server_.seat()->pointer()->resource(), ++serial,
toplevel_surface->resource());
@@ -1263,7 +1268,8 @@ TEST_P(WaylandWindowTest, CanDispatchEvent) {
{}, {window_.get(), menu_window.get(), nested_menu_window.get()});
wl::MockSurface* nested_menu_window_surface =
- server_.GetObject<wl::MockSurface>(nested_menu_window->GetWidget());
+ server_.GetObject<wl::MockSurface>(
+ nested_menu_window->root_surface()->GetSurfaceId());
wl_pointer_send_leave(server_.seat()->pointer()->resource(), ++serial,
menu_window_surface->resource());
@@ -1351,11 +1357,10 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) {
Sync();
- gfx::AcceleratedWidget menu_window_widget = menu_window->GetWidget();
- VerifyXdgPopupPosition(menu_window_widget, menu_window_positioner);
+ VerifyXdgPopupPosition(menu_window.get(), menu_window_positioner);
EXPECT_CALL(menu_window_delegate, OnBoundsChanged(_)).Times(0);
- SendConfigureEventPopup(menu_window_widget, menu_window_bounds);
+ SendConfigureEventPopup(menu_window.get(), menu_window_bounds);
Sync();
@@ -1367,15 +1372,13 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) {
nested_menu_window_positioner.size);
std::unique_ptr<WaylandWindow> nested_menu_window =
CreateWaylandWindowWithParams(
- PlatformWindowType::kMenu, menu_window_widget,
+ PlatformWindowType::kMenu, menu_window->GetWidget(),
nested_menu_window_bounds, &nested_menu_window_delegate);
EXPECT_TRUE(nested_menu_window);
Sync();
- gfx::AcceleratedWidget nested_menu_window_widget =
- nested_menu_window->GetWidget();
- VerifyXdgPopupPosition(nested_menu_window_widget,
+ VerifyXdgPopupPosition(nested_menu_window.get(),
nested_menu_window_positioner);
EXPECT_CALL(nested_menu_window_delegate, OnBoundsChanged(_)).Times(0);
@@ -1384,7 +1387,7 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) {
nested_menu_window_positioner.anchor_rect.y());
gfx::Rect calculated_nested_bounds = nested_menu_window_bounds;
calculated_nested_bounds.set_origin(origin);
- SendConfigureEventPopup(nested_menu_window_widget, calculated_nested_bounds);
+ SendConfigureEventPopup(nested_menu_window.get(), calculated_nested_bounds);
Sync();
@@ -1402,7 +1405,7 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) {
nested_menu_window_delegate,
OnBoundsChanged(gfx::Rect({139, 156}, nested_menu_window_bounds.size())));
calculated_nested_bounds.set_origin({-301, 80});
- SendConfigureEventPopup(nested_menu_window_widget, calculated_nested_bounds);
+ SendConfigureEventPopup(nested_menu_window.get(), calculated_nested_bounds);
Sync();
@@ -1417,7 +1420,7 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) {
gfx::Rect({0, 363}, window_->GetBounds().size())));
EXPECT_CALL(menu_window_delegate,
OnBoundsChanged(gfx::Rect({440, 0}, menu_window_bounds.size())));
- SendConfigureEventPopup(menu_window_widget,
+ SendConfigureEventPopup(menu_window.get(),
gfx::Rect({440, -363}, menu_window_bounds.size()));
Sync();
@@ -1428,23 +1431,22 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) {
nested_menu_window.reset();
nested_menu_window_bounds.set_origin({723, 258});
nested_menu_window = CreateWaylandWindowWithParams(
- PlatformWindowType::kMenu, menu_window_widget, nested_menu_window_bounds,
- &nested_menu_window_delegate);
+ PlatformWindowType::kMenu, menu_window->GetWidget(),
+ nested_menu_window_bounds, &nested_menu_window_delegate);
EXPECT_TRUE(nested_menu_window);
Sync();
- nested_menu_window_widget = nested_menu_window->GetWidget();
// We must get the anchor on gfx::Point(4, 258).
nested_menu_window_positioner.anchor_rect.set_origin({4, 258});
- VerifyXdgPopupPosition(nested_menu_window_widget,
+ VerifyXdgPopupPosition(nested_menu_window.get(),
nested_menu_window_positioner);
Sync();
EXPECT_CALL(nested_menu_window_delegate, OnBoundsChanged(_)).Times(0);
calculated_nested_bounds.set_origin({283, 258});
- SendConfigureEventPopup(nested_menu_window_widget, calculated_nested_bounds);
+ SendConfigureEventPopup(nested_menu_window.get(), calculated_nested_bounds);
Sync();
@@ -1459,7 +1461,7 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) {
nested_menu_window_delegate,
OnBoundsChanged(gfx::Rect({149, 258}, nested_menu_window_bounds.size())));
calculated_nested_bounds.set_origin({-291, 258});
- SendConfigureEventPopup(nested_menu_window_widget, calculated_nested_bounds);
+ SendConfigureEventPopup(nested_menu_window.get(), calculated_nested_bounds);
Sync();
@@ -1472,7 +1474,7 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) {
OnBoundsChanged(gfx::Rect({0, 0}, window_->GetBounds().size())));
EXPECT_CALL(menu_window_delegate,
OnBoundsChanged(gfx::Rect({440, 76}, menu_window_bounds.size())));
- SendConfigureEventPopup(menu_window_widget,
+ SendConfigureEventPopup(menu_window.get(),
gfx::Rect({440, 76}, menu_window_bounds.size()));
Sync();
@@ -1486,8 +1488,8 @@ ACTION_P(VerifyRegion, ptr) {
}
TEST_P(WaylandWindowTest, SetOpaqueRegion) {
- wl::MockSurface* mock_surface =
- server_.GetObject<wl::MockSurface>(window_->GetWidget());
+ wl::MockSurface* mock_surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
gfx::Rect new_bounds(0, 0, 500, 600);
auto state_array = MakeStateArray({XDG_TOPLEVEL_STATE_ACTIVATED});
@@ -1525,7 +1527,7 @@ TEST_P(WaylandWindowTest, OnCloseRequest) {
Sync();
}
-TEST_P(WaylandWindowTest, SubsurfaceSimpleParent) {
+TEST_P(WaylandWindowTest, AuxiliaryWindowSimpleParent) {
VerifyAndClearExpectations();
std::unique_ptr<WaylandWindow> second_window = CreateWaylandWindowWithParams(
@@ -1536,60 +1538,64 @@ TEST_P(WaylandWindowTest, SubsurfaceSimpleParent) {
// Test case 1: if the subsurface is provided with a parent widget, it must
// always use that as a parent.
gfx::Rect subsurface_bounds(gfx::Point(15, 15), gfx::Size(10, 10));
- std::unique_ptr<WaylandWindow> subsuface_window =
+ std::unique_ptr<WaylandWindow> auxiliary_window =
CreateWaylandWindowWithParams(PlatformWindowType::kTooltip,
window_->GetWidget(), subsurface_bounds,
&delegate_);
- EXPECT_TRUE(subsuface_window);
+ EXPECT_TRUE(auxiliary_window);
// The subsurface mustn't take the focused window as a parent, but use the
// provided one.
second_window->SetPointerFocus(true);
- subsuface_window->Show(false);
+ auxiliary_window->Show(false);
Sync();
- auto* mock_surface_subsurface =
- server_.GetObject<wl::MockSurface>(subsuface_window->GetWidget());
+ auto* mock_surface_subsurface = server_.GetObject<wl::MockSurface>(
+ auxiliary_window->root_surface()->GetSurfaceId());
auto* test_subsurface = mock_surface_subsurface->sub_surface();
EXPECT_EQ(test_subsurface->position(), subsurface_bounds.origin());
EXPECT_FALSE(test_subsurface->sync());
auto* parent_resource =
- server_.GetObject<wl::MockSurface>(window_->GetWidget())->resource();
+ server_
+ .GetObject<wl::MockSurface>(window_->root_surface()->GetSurfaceId())
+ ->resource();
EXPECT_EQ(parent_resource, test_subsurface->parent_resource());
// Test case 2: the subsurface must use the focused window as its parent.
- subsuface_window = CreateWaylandWindowWithParams(
+ auxiliary_window = CreateWaylandWindowWithParams(
PlatformWindowType::kTooltip, gfx::kNullAcceleratedWidget,
subsurface_bounds, &delegate_);
- EXPECT_TRUE(subsuface_window);
+ EXPECT_TRUE(auxiliary_window);
// The tooltip must take the focused window.
second_window->SetPointerFocus(true);
- subsuface_window->Show(false);
+ auxiliary_window->Show(false);
Sync();
- // Get new surface after recreating the WaylandSubsurface.
- mock_surface_subsurface =
- server_.GetObject<wl::MockSurface>(subsuface_window->GetWidget());
+ // Get new surface after recreating the WaylandAuxiliaryWindow.
+ mock_surface_subsurface = server_.GetObject<wl::MockSurface>(
+ auxiliary_window->root_surface()->GetSurfaceId());
test_subsurface = mock_surface_subsurface->sub_surface();
auto* second_parent_resource =
- server_.GetObject<wl::MockSurface>(second_window->GetWidget())
+ server_
+ .GetObject<wl::MockSurface>(
+ second_window->root_surface()->GetSurfaceId())
->resource();
EXPECT_EQ(second_parent_resource, test_subsurface->parent_resource());
- subsuface_window->Hide();
+ auxiliary_window->Hide();
Sync();
// The subsurface must take the focused window.
second_window->SetPointerFocus(false);
window_->SetPointerFocus(true);
- subsuface_window->Show(false);
+ auxiliary_window->Show(false);
Sync();
@@ -1616,27 +1622,26 @@ TEST_P(WaylandWindowTest, NestedPopupMenu) {
VerifyAndClearExpectations();
gfx::Rect nestedPopup_bounds(gfx::Rect(10, 30, 40, 20));
- std::unique_ptr<WaylandWindow> nestedPopup_window =
+ std::unique_ptr<WaylandWindow> nested_popup_window =
CreateWaylandWindowWithParams(PlatformWindowType::kPopup,
menu_window->GetWidget(),
nestedPopup_bounds, &delegate_);
- EXPECT_TRUE(nestedPopup_window);
+ EXPECT_TRUE(nested_popup_window);
VerifyAndClearExpectations();
- nestedPopup_window->SetPointerFocus(true);
+ nested_popup_window->SetPointerFocus(true);
Sync();
- auto* mock_surface_nested_popup =
- GetPopupByWidget(nestedPopup_window->GetWidget());
+ auto* mock_surface_nested_popup = GetPopupByWindow(nested_popup_window.get());
ASSERT_TRUE(mock_surface_nested_popup);
auto anchor_width = (mock_surface_nested_popup->anchor_rect()).width();
EXPECT_EQ(4, anchor_width);
- nestedPopup_window->SetPointerFocus(false);
+ nested_popup_window->SetPointerFocus(false);
}
// Case 2: When the menu bounds are positive and there is a negative or
@@ -1653,27 +1658,26 @@ TEST_P(WaylandWindowTest, NestedPopupMenu1) {
VerifyAndClearExpectations();
gfx::Rect nestedPopup_bounds(gfx::Rect(10, 30, 10, 20));
- std::unique_ptr<WaylandWindow> nestedPopup_window =
+ std::unique_ptr<WaylandWindow> nested_popup_window =
CreateWaylandWindowWithParams(PlatformWindowType::kPopup,
menu_window->GetWidget(),
nestedPopup_bounds, &delegate_);
- EXPECT_TRUE(nestedPopup_window);
+ EXPECT_TRUE(nested_popup_window);
VerifyAndClearExpectations();
- nestedPopup_window->SetPointerFocus(true);
+ nested_popup_window->SetPointerFocus(true);
Sync();
- auto* mock_surface_nested_popup =
- GetPopupByWidget(nestedPopup_window->GetWidget());
+ auto* mock_surface_nested_popup = GetPopupByWindow(nested_popup_window.get());
ASSERT_TRUE(mock_surface_nested_popup);
auto anchor_width = (mock_surface_nested_popup->anchor_rect()).width();
EXPECT_EQ(1, anchor_width);
- nestedPopup_window->SetPointerFocus(false);
+ nested_popup_window->SetPointerFocus(false);
}
// Case 3: When the menu bounds are negative and there is a positive,
@@ -1690,27 +1694,26 @@ TEST_P(WaylandWindowTest, NestedPopupMenu2) {
VerifyAndClearExpectations();
gfx::Rect nestedPopup_bounds(gfx::Rect(5, 30, 21, 20));
- std::unique_ptr<WaylandWindow> nestedPopup_window =
+ std::unique_ptr<WaylandWindow> nested_popup_window =
CreateWaylandWindowWithParams(PlatformWindowType::kPopup,
menu_window->GetWidget(),
nestedPopup_bounds, &delegate_);
- EXPECT_TRUE(nestedPopup_window);
+ EXPECT_TRUE(nested_popup_window);
VerifyAndClearExpectations();
- nestedPopup_window->SetPointerFocus(true);
+ nested_popup_window->SetPointerFocus(true);
Sync();
- auto* mock_surface_nested_popup =
- GetPopupByWidget(nestedPopup_window->GetWidget());
+ auto* mock_surface_nested_popup = GetPopupByWindow(nested_popup_window.get());
ASSERT_TRUE(mock_surface_nested_popup);
auto anchor_width = (mock_surface_nested_popup->anchor_rect()).width();
EXPECT_EQ(8, anchor_width);
- nestedPopup_window->SetPointerFocus(false);
+ nested_popup_window->SetPointerFocus(false);
}
// Case 4: When the menu bounds are negative and there is a negative,
@@ -1727,20 +1730,19 @@ TEST_P(WaylandWindowTest, NestedPopupMenu3) {
VerifyAndClearExpectations();
gfx::Rect nestedPopup_bounds(gfx::Rect(5, 30, 21, 20));
- std::unique_ptr<WaylandWindow> nestedPopup_window =
+ std::unique_ptr<WaylandWindow> nested_popup_window =
CreateWaylandWindowWithParams(PlatformWindowType::kPopup,
menu_window->GetWidget(),
nestedPopup_bounds, &delegate_);
- EXPECT_TRUE(nestedPopup_window);
+ EXPECT_TRUE(nested_popup_window);
VerifyAndClearExpectations();
- nestedPopup_window->SetPointerFocus(true);
+ nested_popup_window->SetPointerFocus(true);
Sync();
- auto* mock_surface_nested_popup =
- GetPopupByWidget(nestedPopup_window->GetWidget());
+ auto* mock_surface_nested_popup = GetPopupByWindow(nested_popup_window.get());
ASSERT_TRUE(mock_surface_nested_popup);
@@ -1748,10 +1750,10 @@ TEST_P(WaylandWindowTest, NestedPopupMenu3) {
EXPECT_EQ(1, anchor_width);
- nestedPopup_window->SetPointerFocus(false);
+ nested_popup_window->SetPointerFocus(false);
}
-TEST_P(WaylandWindowTest, SubsurfaceNestedParent) {
+TEST_P(WaylandWindowTest, AuxiliaryWindowNestedParent) {
VerifyAndClearExpectations();
gfx::Rect menu_window_bounds(gfx::Point(10, 10), gfx::Size(100, 100));
@@ -1763,22 +1765,22 @@ TEST_P(WaylandWindowTest, SubsurfaceNestedParent) {
VerifyAndClearExpectations();
gfx::Rect subsurface_bounds(gfx::Point(15, 15), gfx::Size(10, 10));
- std::unique_ptr<WaylandWindow> subsuface_window =
+ std::unique_ptr<WaylandWindow> auxiliary_window =
CreateWaylandWindowWithParams(PlatformWindowType::kTooltip,
menu_window->GetWidget(), subsurface_bounds,
&delegate_);
- EXPECT_TRUE(subsuface_window);
+ EXPECT_TRUE(auxiliary_window);
VerifyAndClearExpectations();
menu_window->SetPointerFocus(true);
- subsuface_window->Show(false);
+ auxiliary_window->Show(false);
Sync();
- auto* mock_surface_subsurface =
- server_.GetObject<wl::MockSurface>(subsuface_window->GetWidget());
+ auto* mock_surface_subsurface = server_.GetObject<wl::MockSurface>(
+ auxiliary_window->root_surface()->GetSurfaceId());
auto* test_subsurface = mock_surface_subsurface->sub_surface();
auto new_origin = subsurface_bounds.origin() -
@@ -1825,7 +1827,8 @@ TEST_P(WaylandWindowTest, DestroysCreatesSurfaceOnHideShow) {
Sync();
- auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget());
+ auto* mock_surface = server_.GetObject<wl::MockSurface>(
+ window->root_surface()->GetSurfaceId());
EXPECT_TRUE(mock_surface->xdg_surface());
EXPECT_TRUE(mock_surface->xdg_surface()->xdg_toplevel());
@@ -1854,7 +1857,8 @@ TEST_P(WaylandWindowTest, DestroysCreatesPopupsOnHideShow) {
Sync();
- auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget());
+ auto* mock_surface = server_.GetObject<wl::MockSurface>(
+ window->root_surface()->GetSurfaceId());
EXPECT_TRUE(mock_surface->xdg_surface());
EXPECT_TRUE(mock_surface->xdg_surface()->xdg_popup());
@@ -1893,7 +1897,8 @@ TEST_P(WaylandWindowTest, SetsPropertiesOnShow) {
Sync();
- auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget());
+ auto* mock_surface = server_.GetObject<wl::MockSurface>(
+ window->root_surface()->GetSurfaceId());
auto* mock_xdg_toplevel = mock_surface->xdg_surface()->xdg_toplevel();
// Only app id must be set now.
@@ -1952,8 +1957,8 @@ TEST_P(WaylandWindowTest, CreatesPopupOnButtonPressSerial) {
constexpr uint32_t button_press_serial = 2;
constexpr uint32_t button_release_serial = 3;
- wl::MockSurface* toplevel_surface =
- server_.GetObject<wl::MockSurface>(window_->GetWidget());
+ wl::MockSurface* toplevel_surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
struct wl_array empty;
wl_array_init(&empty);
wl_keyboard_send_enter(server_.seat()->keyboard()->resource(), enter_serial,
@@ -1977,7 +1982,7 @@ TEST_P(WaylandWindowTest, CreatesPopupOnButtonPressSerial) {
Sync();
- auto* test_popup = GetPopupByWidget(popup->GetWidget());
+ auto* test_popup = GetPopupByWindow(popup.get());
ASSERT_TRUE(test_popup);
EXPECT_NE(test_popup->grab_serial(), button_release_serial);
EXPECT_EQ(test_popup->grab_serial(), button_press_serial);
@@ -1996,8 +2001,8 @@ TEST_P(WaylandWindowTest, CreatesPopupOnTouchDownSerial) {
constexpr uint32_t touch_down_serial = 2;
constexpr uint32_t touch_up_serial = 3;
- wl::MockSurface* toplevel_surface =
- server_.GetObject<wl::MockSurface>(window_->GetWidget());
+ wl::MockSurface* toplevel_surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
struct wl_array empty;
wl_array_init(&empty);
wl_keyboard_send_enter(server_.seat()->keyboard()->resource(), enter_serial,
@@ -2021,7 +2026,7 @@ TEST_P(WaylandWindowTest, CreatesPopupOnTouchDownSerial) {
Sync();
- auto* test_popup = GetPopupByWidget(popup->GetWidget());
+ auto* test_popup = GetPopupByWindow(popup.get());
ASSERT_TRUE(test_popup);
EXPECT_NE(test_popup->grab_serial(), touch_up_serial);
EXPECT_EQ(test_popup->grab_serial(), touch_down_serial);
@@ -2075,11 +2080,48 @@ TEST_P(WaylandWindowTest, DoesNotGrabPopupIfNoSeat) {
Sync();
- auto* test_popup = GetPopupByWidget(popup->GetWidget());
+ auto* test_popup = GetPopupByWindow(popup.get());
ASSERT_TRUE(test_popup);
EXPECT_EQ(test_popup->grab_serial(), 0u);
}
+TEST_P(WaylandWindowTest, OneWaylandSubsurface) {
+ VerifyAndClearExpectations();
+
+ std::unique_ptr<WaylandWindow> window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget,
+ gfx::Rect(0, 0, 640, 480), &delegate_);
+ EXPECT_TRUE(window);
+
+ gfx::Rect subsurface_bounds(gfx::Point(15, 15), gfx::Size(10, 10));
+ bool result = window->RequestSubsurface();
+ EXPECT_TRUE(result);
+
+ WaylandSubsurface* wayland_subsurface =
+ window->wayland_subsurfaces().begin()->get();
+
+ Sync();
+
+ auto* mock_surface_root_window = server_.GetObject<wl::MockSurface>(
+ window->root_surface()->GetSurfaceId());
+ auto* mock_surface_subsurface = server_.GetObject<wl::MockSurface>(
+ wayland_subsurface->wayland_surface()->GetSurfaceId());
+ EXPECT_TRUE(mock_surface_subsurface);
+ wayland_subsurface->ConfigureAndShowSurface(
+ gfx::OVERLAY_TRANSFORM_NONE, subsurface_bounds, true, nullptr, nullptr);
+ connection_->ScheduleFlush();
+
+ Sync();
+
+ auto* test_subsurface = mock_surface_subsurface->sub_surface();
+ EXPECT_TRUE(test_subsurface);
+ auto* parent_resource = mock_surface_root_window->resource();
+ EXPECT_EQ(parent_resource, test_subsurface->parent_resource());
+
+ EXPECT_EQ(test_subsurface->position(), subsurface_bounds.origin());
+ EXPECT_TRUE(test_subsurface->sync());
+}
+
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 758ae1f222e..99eb2e7012a 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
@@ -329,7 +329,7 @@ bool XDGPopupWrapperImpl::InitializeStable(
}
xdg_popup_add_listener(xdg_popup_.get(), &xdg_popup_listener, this);
- wl_surface_commit(wayland_window_->surface());
+ wayland_window_->root_surface()->Commit();
return true;
}
@@ -393,7 +393,7 @@ bool XDGPopupWrapperImpl::InitializeV6(
zxdg_popup_v6_add_listener(zxdg_popup_v6_.get(), &zxdg_popup_v6_listener,
this);
- wl_surface_commit(wayland_window_->surface());
+ wayland_window_->root_surface()->Commit();
return true;
}
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 ae1ca159fd4..f1a03831363 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
@@ -4,6 +4,7 @@
#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h"
+#include <aura-shell-client-protocol.h>
#include <xdg-shell-client-protocol.h>
#include <xdg-shell-unstable-v6-client-protocol.h>
@@ -267,8 +268,8 @@ bool XDGSurfaceWrapperImpl::InitializeStable(bool with_toplevel) {
// configuration acknowledgement on each configure event.
surface_for_popup_ = !with_toplevel;
- xdg_surface_.reset(xdg_wm_base_get_xdg_surface(connection_->shell(),
- wayland_window_->surface()));
+ xdg_surface_.reset(xdg_wm_base_get_xdg_surface(
+ connection_->shell(), wayland_window_->root_surface()->surface()));
if (!xdg_surface_) {
LOG(ERROR) << "Failed to create xdg_surface";
return false;
@@ -287,8 +288,7 @@ bool XDGSurfaceWrapperImpl::InitializeStable(bool with_toplevel) {
return false;
}
xdg_toplevel_add_listener(xdg_toplevel_.get(), &xdg_toplevel_listener, this);
- wl_surface_commit(wayland_window_->surface());
-
+ wayland_window_->root_surface()->Commit();
connection_->ScheduleFlush();
return true;
}
@@ -307,7 +307,7 @@ bool XDGSurfaceWrapperImpl::InitializeV6(bool with_toplevel) {
surface_for_popup_ = !with_toplevel;
zxdg_surface_v6_.reset(zxdg_shell_v6_get_xdg_surface(
- connection_->shell_v6(), wayland_window_->surface()));
+ connection_->shell_v6(), wayland_window_->root_surface()->surface()));
if (!zxdg_surface_v6_) {
LOG(ERROR) << "Failed to create zxdg_surface";
return false;
@@ -328,8 +328,15 @@ bool XDGSurfaceWrapperImpl::InitializeV6(bool with_toplevel) {
}
zxdg_toplevel_v6_add_listener(zxdg_toplevel_v6_.get(),
&zxdg_toplevel_v6_listener, this);
- wl_surface_commit(wayland_window_->surface());
+ if (connection_->aura_shell()) {
+ aura_surface_.reset(zaura_shell_get_aura_surface(
+ connection_->aura_shell(), wayland_window_->root_surface()->surface()));
+ zaura_surface_set_fullscreen_mode(aura_surface_.get(),
+ ZAURA_SURFACE_FULLSCREEN_MODE_IMMERSIVE);
+ }
+
+ wayland_window_->root_surface()->Commit();
connection_->ScheduleFlush();
return true;
}
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
index ea1e81b44dc..2381aecfd9c 100644
--- a/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
@@ -87,6 +87,7 @@ class XDGSurfaceWrapperImpl : public ShellSurfaceWrapper {
wl::Object<zxdg_toplevel_v6> zxdg_toplevel_v6_;
wl::Object<struct xdg_surface> xdg_surface_;
wl::Object<xdg_toplevel> xdg_toplevel_;
+ wl::Object<zaura_surface> aura_surface_;
bool surface_for_popup_ = false;
diff --git a/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc b/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
index 7b72165b4ff..b1c021ad330 100644
--- a/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
+++ b/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
@@ -57,7 +57,7 @@ void ZWPTextInputWrapperV1::Reset() {
void ZWPTextInputWrapperV1::Activate(WaylandWindow* window) {
zwp_text_input_v1_activate(obj_.get(), connection_->seat(),
- window->surface());
+ window->root_surface()->surface());
}
void ZWPTextInputWrapperV1::Deactivate() {