summaryrefslogtreecommitdiff
path: root/chromium/components/exo
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/components/exo')
-rw-r--r--chromium/components/exo/BUILD.gn8
-rw-r--r--chromium/components/exo/client_controlled_shell_surface.cc48
-rw-r--r--chromium/components/exo/client_controlled_shell_surface.h4
-rw-r--r--chromium/components/exo/client_controlled_shell_surface_unittest.cc2
-rw-r--r--chromium/components/exo/data_device.cc71
-rw-r--r--chromium/components/exo/data_device.h11
-rw-r--r--chromium/components/exo/data_device_unittest.cc40
-rw-r--r--chromium/components/exo/data_offer.cc10
-rw-r--r--chromium/components/exo/data_offer.h5
-rw-r--r--chromium/components/exo/drag_drop_operation.cc14
-rw-r--r--chromium/components/exo/drag_drop_operation.h2
-rw-r--r--chromium/components/exo/drag_drop_operation_unittest.cc127
-rw-r--r--chromium/components/exo/fullscreen_shell_surface.cc62
-rw-r--r--chromium/components/exo/fullscreen_shell_surface.h11
-rw-r--r--chromium/components/exo/gamepad_delegate.h10
-rw-r--r--chromium/components/exo/gaming_seat.cc8
-rw-r--r--chromium/components/exo/gaming_seat_unittest.cc80
-rw-r--r--chromium/components/exo/keyboard.cc16
-rw-r--r--chromium/components/exo/keyboard_unittest.cc155
-rw-r--r--chromium/components/exo/notification_surface_manager.h5
-rw-r--r--chromium/components/exo/pointer.cc19
-rw-r--r--chromium/components/exo/pointer.h2
-rw-r--r--chromium/components/exo/seat.cc8
-rw-r--r--chromium/components/exo/seat.h6
-rw-r--r--chromium/components/exo/server/BUILD.gn21
-rw-r--r--chromium/components/exo/server/OWNERS1
-rw-r--r--chromium/components/exo/server/wayland_server_controller.cc62
-rw-r--r--chromium/components/exo/server/wayland_server_controller.h61
-rw-r--r--chromium/components/exo/shell_surface_base.cc49
-rw-r--r--chromium/components/exo/shell_surface_base.h7
-rw-r--r--chromium/components/exo/shell_surface_unittest.cc142
-rw-r--r--chromium/components/exo/shell_surface_util.cc58
-rw-r--r--chromium/components/exo/shell_surface_util.h2
-rw-r--r--chromium/components/exo/sub_surface.cc6
-rw-r--r--chromium/components/exo/sub_surface.h2
-rw-r--r--chromium/components/exo/sub_surface_unittest.cc22
-rw-r--r--chromium/components/exo/surface.cc28
-rw-r--r--chromium/components/exo/surface.h6
-rw-r--r--chromium/components/exo/surface_unittest.cc67
-rw-r--r--chromium/components/exo/text_input.cc7
-rw-r--r--chromium/components/exo/text_input.h2
-rw-r--r--chromium/components/exo/touch.cc2
-rw-r--r--chromium/components/exo/wayland/BUILD.gn5
-rw-r--r--chromium/components/exo/wayland/DEPS1
-rw-r--r--chromium/components/exo/wayland/clients/blur.cc2
-rw-r--r--chromium/components/exo/wayland/clients/blur_main.cc1
-rw-r--r--chromium/components/exo/wayland/clients/client_base.cc2
-rw-r--r--chromium/components/exo/wayland/clients/color_space.cc1
-rw-r--r--chromium/components/exo/wayland/clients/explicit_synchronization.cc2
-rw-r--r--chromium/components/exo/wayland/clients/fullscreen_shell.cc2
-rw-r--r--chromium/components/exo/wayland/clients/rects.cc2
-rw-r--r--chromium/components/exo/wayland/clients/simple.cc2
-rw-r--r--chromium/components/exo/wayland/clients/subsurface.cc4
-rw-r--r--chromium/components/exo/wayland/clients/yuv.cc1
-rw-r--r--chromium/components/exo/wayland/server.cc35
-rw-r--r--chromium/components/exo/wayland/server.h2
-rw-r--r--chromium/components/exo/wayland/wayland_display_observer.cc13
-rw-r--r--chromium/components/exo/wayland/wayland_display_observer.h8
-rw-r--r--chromium/components/exo/wayland/wayland_display_output.cc29
-rw-r--r--chromium/components/exo/wayland/wayland_display_output.h13
-rw-r--r--chromium/components/exo/wayland/wayland_positioner.cc199
-rw-r--r--chromium/components/exo/wayland/wayland_positioner.h25
-rw-r--r--chromium/components/exo/wayland/wayland_positioner_unittest.cc182
-rw-r--r--chromium/components/exo/wayland/wl_compositor.cc7
-rw-r--r--chromium/components/exo/wayland/wl_data_device_manager.cc31
-rw-r--r--chromium/components/exo/wayland/wl_output.cc16
-rw-r--r--chromium/components/exo/wayland/xdg_shell.cc692
-rw-r--r--chromium/components/exo/wayland/xdg_shell.h41
-rw-r--r--chromium/components/exo/wayland/zaura_shell.cc4
-rw-r--r--chromium/components/exo/wayland/zaura_shell_unittest.cc34
-rw-r--r--chromium/components/exo/wayland/zcr_gaming_input.cc17
-rw-r--r--chromium/components/exo/wayland/zwp_text_input_manager.cc1
-rw-r--r--chromium/components/exo/wayland/zxdg_shell.cc13
-rw-r--r--chromium/components/exo/wayland/zxdg_shell.h14
-rw-r--r--chromium/components/exo/wm_helper_chromeos.cc7
-rw-r--r--chromium/components/exo/xdg_shell_surface.h1
76 files changed, 2317 insertions, 361 deletions
diff --git a/chromium/components/exo/BUILD.gn b/chromium/components/exo/BUILD.gn
index 3f3efb0587f..56e5f781552 100644
--- a/chromium/components/exo/BUILD.gn
+++ b/chromium/components/exo/BUILD.gn
@@ -6,7 +6,7 @@ import("//build/config/ui.gni")
import("//chrome/common/features.gni")
import("//testing/test.gni")
-source_set("exo") {
+static_library("exo") {
sources = [
"buffer.cc",
"buffer.h",
@@ -79,6 +79,7 @@ source_set("exo") {
"//skia",
"//third_party/blink/public/common",
"//ui/aura",
+ "//ui/base/cursor",
"//ui/base/ime",
"//ui/compositor",
"//ui/compositor_extra",
@@ -97,12 +98,13 @@ source_set("exo") {
]
public_deps = [
- "//ui/base/cursor",
+ "//ui/base/cursor:cursor_base",
"//ui/base/cursor/mojom:cursor_type",
]
if (is_chromeos) {
deps += [
+ "//ash",
"//ash/keyboard/ui",
"//ash/public/cpp",
"//chromeos/constants",
@@ -237,6 +239,7 @@ source_set("unit_tests") {
"data_offer_unittest.cc",
"data_source_unittest.cc",
"display_unittest.cc",
+ "drag_drop_operation_unittest.cc",
"gaming_seat_unittest.cc",
"input_method_surface_unittest.cc",
"keyboard_unittest.cc",
@@ -259,6 +262,7 @@ source_set("unit_tests") {
"//ash/keyboard/ui",
"//ash/public/cpp",
"//chromeos/constants",
+ "//ui/base:test_support",
"//ui/base/cursor/mojom:cursor_type",
]
}
diff --git a/chromium/components/exo/client_controlled_shell_surface.cc b/chromium/components/exo/client_controlled_shell_surface.cc
index 0e55b1931e4..56fa48f3fd7 100644
--- a/chromium/components/exo/client_controlled_shell_surface.cc
+++ b/chromium/components/exo/client_controlled_shell_surface.cc
@@ -690,28 +690,7 @@ bool ClientControlledShellSurface::IsInputEnabled(Surface* surface) const {
}
void ClientControlledShellSurface::OnSetFrame(SurfaceFrameType type) {
- if (container_ == ash::kShellWindowId_SystemModalContainer &&
- type != SurfaceFrameType::NONE) {
- LOG(WARNING)
- << "A surface in system modal container should not have a frame:"
- << static_cast<int>(type);
- return;
- }
-
- // TODO(oshima): We shouldn't send the synthesized motion event when just
- // changing the frame type. The better solution would be to keep the window
- // position regardless of the frame state, but that won't be available until
- // next arc version.
- // This is a stopgap solution not to generate the event until it is resolved.
- EventTargetingBlocker blocker;
- bool suppress_mouse_event = frame_type_ != type && widget_;
- if (suppress_mouse_event)
- blocker.Block(widget_->GetNativeWindow());
- ShellSurfaceBase::OnSetFrame(type);
- UpdateAutoHideFrame();
-
- if (suppress_mouse_event)
- UpdateSurfaceBounds();
+ pending_frame_type_ = type;
}
void ClientControlledShellSurface::OnSetFrameColors(SkColor active_color,
@@ -1254,6 +1233,31 @@ void ClientControlledShellSurface::UpdateFrameWidth() {
->SetWidthInPixels(width);
}
+void ClientControlledShellSurface::UpdateFrameType() {
+ if (container_ == ash::kShellWindowId_SystemModalContainer &&
+ pending_frame_type_ != SurfaceFrameType::NONE) {
+ LOG(WARNING)
+ << "A surface in system modal container should not have a frame:"
+ << static_cast<int>(pending_frame_type_);
+ return;
+ }
+
+ // TODO(oshima): We shouldn't send the synthesized motion event when just
+ // changing the frame type. The better solution would be to keep the window
+ // position regardless of the frame state, but that won't be available until
+ // next arc version.
+ // This is a stopgap solution not to generate the event until it is resolved.
+ EventTargetingBlocker blocker;
+ bool suppress_mouse_event = frame_type_ != pending_frame_type_ && widget_;
+ if (suppress_mouse_event)
+ blocker.Block(widget_->GetNativeWindow());
+ ShellSurfaceBase::OnSetFrame(pending_frame_type_);
+ UpdateAutoHideFrame();
+
+ if (suppress_mouse_event)
+ UpdateSurfaceBounds();
+}
+
void ClientControlledShellSurface::
EnsureCompositorIsLockedForOrientationChange() {
if (!orientation_compositor_lock_) {
diff --git a/chromium/components/exo/client_controlled_shell_surface.h b/chromium/components/exo/client_controlled_shell_surface.h
index 2d339f43983..20c5833a06d 100644
--- a/chromium/components/exo/client_controlled_shell_surface.h
+++ b/chromium/components/exo/client_controlled_shell_surface.h
@@ -285,6 +285,8 @@ class ClientControlledShellSurface : public ShellSurfaceBase,
void UpdateFrameWidth();
+ void UpdateFrameType() override;
+
void AttemptToStartDrag(int component, const gfx::PointF& location);
// Lock the compositor if it's not already locked, or extends the
@@ -325,6 +327,8 @@ class ClientControlledShellSurface : public ShellSurfaceBase,
bool pending_always_on_top_ = false;
+ SurfaceFrameType pending_frame_type_ = SurfaceFrameType::NONE;
+
ash::WindowPinType current_pin_;
bool can_maximize_ = true;
diff --git a/chromium/components/exo/client_controlled_shell_surface_unittest.cc b/chromium/components/exo/client_controlled_shell_surface_unittest.cc
index a99d492f2e9..924ef3dd608 100644
--- a/chromium/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/chromium/components/exo/client_controlled_shell_surface_unittest.cc
@@ -1586,6 +1586,7 @@ TEST_F(ClientControlledShellSurfaceTest, SetExtraTitle) {
// Setting the extra title/debug text won't change the window's title, but it
// will be drawn by the frame header.
shell_surface->SetExtraTitle(base::ASCIIToUTF16("extra"));
+ surface->Commit();
EXPECT_EQ(window_title, window->GetTitle());
EXPECT_TRUE(paint_does_draw_text());
EXPECT_FALSE(
@@ -1933,6 +1934,7 @@ TEST_F(ClientControlledShellSurfaceTest, SnappedInTabletMode) {
shell_surface->GetWidget()->non_client_view()->frame_view());
// Snapped window can also use auto hide.
surface->SetFrame(SurfaceFrameType::AUTOHIDE);
+ surface->Commit();
EXPECT_TRUE(frame_view->GetVisible());
EXPECT_TRUE(frame_view->GetHeaderView()->in_immersive_mode());
}
diff --git a/chromium/components/exo/data_device.cc b/chromium/components/exo/data_device.cc
index e93d7352196..4682130192f 100644
--- a/chromium/components/exo/data_device.cc
+++ b/chromium/components/exo/data_device.cc
@@ -4,6 +4,7 @@
#include "components/exo/data_device.h"
+#include "base/run_loop.h"
#include "components/exo/data_device_delegate.h"
#include "components/exo/data_offer.h"
#include "components/exo/data_source.h"
@@ -16,10 +17,34 @@
namespace exo {
+namespace {
+
+constexpr base::TimeDelta kDataOfferDestructionTimeout =
+ base::TimeDelta::FromMilliseconds(1000);
+
+ui::DragDropTypes::DragOperation DndActionToDragOperation(
+ DndAction dnd_action) {
+ switch (dnd_action) {
+ case DndAction::kMove:
+ return ui::DragDropTypes::DRAG_MOVE;
+ case DndAction::kCopy:
+ return ui::DragDropTypes::DRAG_COPY;
+ case DndAction::kAsk:
+ return ui::DragDropTypes::DRAG_LINK;
+ case DndAction::kNone:
+ return ui::DragDropTypes::DRAG_NONE;
+ }
+}
+
+} // namespace
+
DataDevice::DataDevice(DataDeviceDelegate* delegate,
Seat* seat,
FileHelper* file_helper)
- : delegate_(delegate), seat_(seat), file_helper_(file_helper) {
+ : delegate_(delegate),
+ seat_(seat),
+ file_helper_(file_helper),
+ drop_succeeded_(false) {
WMHelper::GetInstance()->AddDragDropObserver(this);
ui::ClipboardMonitor::GetInstance()->AddObserver(this);
@@ -44,8 +69,7 @@ void DataDevice::StartDrag(DataSource* source,
seat_->StartDrag(source, origin, icon, event_source);
}
-void DataDevice::SetSelection(DataSource* source, uint32_t serial) {
- // TODO(hirono): Check if serial is valid. crbug.com/746111
+void DataDevice::SetSelection(DataSource* source) {
seat_->SetSelection(source);
}
@@ -83,16 +107,7 @@ int DataDevice::OnDragUpdated(const ui::DropTargetEvent& event) {
// TODO(hirono): dnd_action() here may not be updated. Chrome needs to provide
// a way to update DND action asynchronously.
- switch (data_offer_->get()->dnd_action()) {
- case DndAction::kMove:
- return ui::DragDropTypes::DRAG_MOVE;
- case DndAction::kCopy:
- return ui::DragDropTypes::DRAG_COPY;
- case DndAction::kAsk:
- return ui::DragDropTypes::DRAG_LINK;
- case DndAction::kNone:
- return ui::DragDropTypes::DRAG_NONE;
- }
+ return DndActionToDragOperation(data_offer_->get()->dnd_action());
}
void DataDevice::OnDragExited() {
@@ -107,9 +122,29 @@ int DataDevice::OnPerformDrop(const ui::DropTargetEvent& event) {
if (!data_offer_)
return ui::DragDropTypes::DRAG_NONE;
+ DndAction dnd_action = data_offer_->get()->dnd_action();
+
delegate_->OnDrop();
- data_offer_.reset();
- return ui::DragDropTypes::DRAG_NONE;
+
+ // TODO(tetsui): Avoid using nested loop by adding asynchronous callback to
+ // aura::client::DragDropDelegate.
+ base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(), kDataOfferDestructionTimeout);
+ quit_closure_ = run_loop.QuitClosure();
+ run_loop.Run();
+
+ if (quit_closure_) {
+ // DataOffer not destroyed by the client until the timeout.
+ quit_closure_.Reset();
+ data_offer_.reset();
+ drop_succeeded_ = false;
+ }
+
+ if (!drop_succeeded_)
+ return ui::DragDropTypes::DRAG_NONE;
+
+ return DndActionToDragOperation(dnd_action);
}
void DataDevice::OnClipboardDataChanged() {
@@ -140,8 +175,12 @@ void DataDevice::OnSurfaceFocusing(Surface* surface) {
void DataDevice::OnSurfaceFocused(Surface* surface) {}
void DataDevice::OnDataOfferDestroying(DataOffer* data_offer) {
- if (data_offer_ && data_offer_->get() == data_offer)
+ if (data_offer_ && data_offer_->get() == data_offer) {
+ drop_succeeded_ = data_offer_->get()->finished();
+ if (quit_closure_)
+ std::move(quit_closure_).Run();
data_offer_.reset();
+ }
}
void DataDevice::OnSurfaceDestroying(Surface* surface) {
diff --git a/chromium/components/exo/data_device.h b/chromium/components/exo/data_device.h
index 9f110ef6dfb..8b0bb19b371 100644
--- a/chromium/components/exo/data_device.h
+++ b/chromium/components/exo/data_device.h
@@ -48,17 +48,15 @@ class DataDevice : public WMHelper::DragDropObserver,
// be null if the data will be transferred only in the client. |origin| is
// the surface which starts the drag and drop operation. |icon| is the
// nullable image which is rendered at the next to cursor while drag
- // operation. |serial| is the unique number comes from input events which
- // triggers the drag and drop operation.
+ // operation.
void StartDrag(DataSource* source,
Surface* origin,
Surface* icon,
ui::DragDropTypes::DragEventSource event_source);
// Sets selection data to the clipboard.
- // |source| represents data comes from the client. |serial| is the unique
- // number comes from input events which triggers the drag and drop operation.
- void SetSelection(DataSource* source, uint32_t serial);
+ // |source| represents data comes from the client.
+ void SetSelection(DataSource* source);
// Overridden from WMHelper::DragDropObserver:
void OnDragEntered(const ui::DropTargetEvent& event) override;
@@ -91,6 +89,9 @@ class DataDevice : public WMHelper::DragDropObserver,
std::unique_ptr<ScopedDataOffer> data_offer_;
std::unique_ptr<ScopedSurface> focused_surface_;
+ base::OnceClosure quit_closure_;
+ bool drop_succeeded_;
+
DISALLOW_COPY_AND_ASSIGN(DataDevice);
};
diff --git a/chromium/components/exo/data_device_unittest.cc b/chromium/components/exo/data_device_unittest.cc
index 8315408b871..189a6d9f6de 100644
--- a/chromium/components/exo/data_device_unittest.cc
+++ b/chromium/components/exo/data_device_unittest.cc
@@ -61,7 +61,11 @@ class TestDataDeviceDelegate : public DataDeviceDelegate {
return out->size();
}
Surface* entered_surface() const { return entered_surface_; }
- void DeleteDataOffer() { data_offer_.reset(); }
+ void DeleteDataOffer(bool finished) {
+ if (finished)
+ data_offer_->Finish();
+ data_offer_.reset();
+ }
void set_can_accept_data_events_for_surface(bool value) {
can_accept_data_events_for_surface_ = value;
}
@@ -186,7 +190,12 @@ TEST_F(DataDeviceTest, DataEventsDrop) {
ASSERT_EQ(1u, delegate_.PopEvents(&events));
EXPECT_EQ(DataEvent::kMotion, events[0]);
- device_->OnPerformDrop(event);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&TestDataDeviceDelegate::DeleteDataOffer,
+ base::Unretained(&delegate_), true));
+
+ int result = device_->OnPerformDrop(event);
+ EXPECT_EQ(ui::DragDropTypes::DRAG_LINK, result);
ASSERT_EQ(1u, delegate_.PopEvents(&events));
EXPECT_EQ(DataEvent::kDrop, events[0]);
}
@@ -222,7 +231,7 @@ TEST_F(DataDeviceTest, DeleteDataOfferDuringDrag) {
EXPECT_EQ(DataEvent::kOffer, events[0]);
EXPECT_EQ(DataEvent::kEnter, events[1]);
- delegate_.DeleteDataOffer();
+ delegate_.DeleteDataOffer(false);
EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, device_->OnDragUpdated(event));
EXPECT_EQ(0u, delegate_.PopEvents(&events));
@@ -231,6 +240,31 @@ TEST_F(DataDeviceTest, DeleteDataOfferDuringDrag) {
EXPECT_EQ(0u, delegate_.PopEvents(&events));
}
+TEST_F(DataDeviceTest, DataOfferNotFinished) {
+ ui::DropTargetEvent event(data_, gfx::PointF(), gfx::PointF(),
+ ui::DragDropTypes::DRAG_MOVE);
+ ui::Event::DispatcherApi(&event).set_target(surface_->window());
+
+ std::vector<DataEvent> events;
+ device_->OnDragEntered(event);
+ ASSERT_EQ(2u, delegate_.PopEvents(&events));
+ EXPECT_EQ(DataEvent::kOffer, events[0]);
+ EXPECT_EQ(DataEvent::kEnter, events[1]);
+
+ EXPECT_EQ(ui::DragDropTypes::DRAG_LINK, device_->OnDragUpdated(event));
+ ASSERT_EQ(1u, delegate_.PopEvents(&events));
+ EXPECT_EQ(DataEvent::kMotion, events[0]);
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&TestDataDeviceDelegate::DeleteDataOffer,
+ base::Unretained(&delegate_), false));
+
+ int result = device_->OnPerformDrop(event);
+ EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
+ ASSERT_EQ(1u, delegate_.PopEvents(&events));
+ EXPECT_EQ(DataEvent::kDrop, events[0]);
+}
+
TEST_F(DataDeviceTest, NotAcceptDataEventsForSurface) {
ui::DropTargetEvent event(data_, gfx::PointF(), gfx::PointF(),
ui::DragDropTypes::DRAG_MOVE);
diff --git a/chromium/components/exo/data_offer.cc b/chromium/components/exo/data_offer.cc
index eee7b8cbf2d..8ec119a950b 100644
--- a/chromium/components/exo/data_offer.cc
+++ b/chromium/components/exo/data_offer.cc
@@ -14,6 +14,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
+#include "components/exo/data_device.h"
#include "components/exo/data_offer_delegate.h"
#include "components/exo/data_offer_observer.h"
#include "components/exo/file_helper.h"
@@ -181,7 +182,10 @@ ScopedDataOffer::~ScopedDataOffer() {
}
DataOffer::DataOffer(DataOfferDelegate* delegate, Purpose purpose)
- : delegate_(delegate), purpose_(purpose) {}
+ : delegate_(delegate),
+ dnd_action_(DndAction::kNone),
+ purpose_(purpose),
+ finished_(false) {}
DataOffer::~DataOffer() {
delegate_->OnDataOfferDestroying(this);
@@ -226,7 +230,9 @@ void DataOffer::Receive(const std::string& mime_type, base::ScopedFD fd) {
}
}
-void DataOffer::Finish() {}
+void DataOffer::Finish() {
+ finished_ = true;
+}
void DataOffer::SetActions(const base::flat_set<DndAction>& dnd_actions,
DndAction preferred_action) {
diff --git a/chromium/components/exo/data_offer.h b/chromium/components/exo/data_offer.h
index 1086d53158c..3c540f35583 100644
--- a/chromium/components/exo/data_offer.h
+++ b/chromium/components/exo/data_offer.h
@@ -8,6 +8,7 @@
#include <cstdint>
#include <string>
+#include "base/callback_forward.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/files/scoped_file.h"
@@ -79,7 +80,8 @@ class DataOffer final : public ui::PropertyHandler {
// DataOffer object.
void SetSourceActions(const base::flat_set<DndAction>& source_actions);
- DndAction dnd_action() { return dnd_action_; }
+ DndAction dnd_action() const { return dnd_action_; }
+ bool finished() const { return finished_; }
private:
void OnPickledUrlsResolved(const std::string& uri_list_mime_type,
@@ -104,6 +106,7 @@ class DataOffer final : public ui::PropertyHandler {
DndAction dnd_action_;
base::ObserverList<DataOfferObserver>::Unchecked observers_;
Purpose purpose_;
+ bool finished_;
base::WeakPtrFactory<DataOffer> weak_ptr_factory_{this};
diff --git a/chromium/components/exo/drag_drop_operation.cc b/chromium/components/exo/drag_drop_operation.cc
index 1fee5aa1595..e7ad6b32e7d 100644
--- a/chromium/components/exo/drag_drop_operation.cc
+++ b/chromium/components/exo/drag_drop_operation.cc
@@ -78,8 +78,10 @@ base::WeakPtr<DragDropOperation> DragDropOperation::Create(
DataSource* source,
Surface* origin,
Surface* icon,
+ const gfx::Point& drag_start_point,
ui::DragDropTypes::DragEventSource event_source) {
- auto* dnd_op = new DragDropOperation(source, origin, icon, event_source);
+ auto* dnd_op = new DragDropOperation(source, origin, icon, drag_start_point,
+ event_source);
return dnd_op->weak_ptr_factory_.GetWeakPtr();
}
@@ -87,11 +89,12 @@ DragDropOperation::DragDropOperation(
DataSource* source,
Surface* origin,
Surface* icon,
+ const gfx::Point& drag_start_point,
ui::DragDropTypes::DragEventSource event_source)
: SurfaceTreeHost("ExoDragDropOperation"),
source_(std::make_unique<ScopedDataSource>(source, this)),
origin_(std::make_unique<ScopedSurface>(origin, this)),
- drag_start_point_(display::Screen::GetScreen()->GetCursorScreenPoint()),
+ drag_start_point_(drag_start_point),
os_exchange_data_(std::make_unique<ui::OSExchangeData>()),
event_source_(event_source),
weak_ptr_factory_(this) {
@@ -185,6 +188,7 @@ void DragDropOperation::CaptureDragIcon() {
viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP,
base::BindOnce(&DragDropOperation::OnDragIconCaptured,
weak_ptr_factory_.GetWeakPtr()));
+ request->set_result_task_runner(base::SequencedTaskRunnerHandle::Get());
host_window()->layer()->RequestCopyOfOutput(std::move(request));
}
@@ -235,6 +239,8 @@ void DragDropOperation::StartDragDropOperation() {
uint32_t dnd_operations =
DndActionsToDragOperations(source_->get()->GetActions());
+ base::WeakPtr<DragDropOperation> weak_ptr = weak_ptr_factory_.GetWeakPtr();
+
started_by_this_object_ = true;
// This triggers a nested run loop that terminates when the drag and drop
// operation is completed.
@@ -243,6 +249,10 @@ void DragDropOperation::StartDragDropOperation() {
origin_->get()->window(), drag_start_point_, dnd_operations,
event_source_);
+ // The instance deleted during StartDragAndDrop's nested RunLoop.
+ if (!weak_ptr)
+ return;
+
if (op) {
// Success
diff --git a/chromium/components/exo/drag_drop_operation.h b/chromium/components/exo/drag_drop_operation.h
index ae02f4494bb..823258c8198 100644
--- a/chromium/components/exo/drag_drop_operation.h
+++ b/chromium/components/exo/drag_drop_operation.h
@@ -50,6 +50,7 @@ class DragDropOperation : public DataSourceObserver,
DataSource* source,
Surface* origin,
Surface* icon,
+ const gfx::Point& drag_start_point,
ui::DragDropTypes::DragEventSource event_source);
// Abort the operation if it hasn't been started yet, otherwise do nothing.
@@ -77,6 +78,7 @@ class DragDropOperation : public DataSourceObserver,
DragDropOperation(DataSource* source,
Surface* origin,
Surface* icon,
+ const gfx::Point& drag_start_point,
ui::DragDropTypes::DragEventSource event_source);
~DragDropOperation() override;
diff --git a/chromium/components/exo/drag_drop_operation_unittest.cc b/chromium/components/exo/drag_drop_operation_unittest.cc
new file mode 100644
index 00000000000..9e02d45146c
--- /dev/null
+++ b/chromium/components/exo/drag_drop_operation_unittest.cc
@@ -0,0 +1,127 @@
+// 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 "components/exo/drag_drop_operation.h"
+
+#include <memory>
+
+#include "ash/shell.h"
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/run_loop.h"
+#include "components/exo/buffer.h"
+#include "components/exo/data_source.h"
+#include "components/exo/data_source_delegate.h"
+#include "components/exo/surface.h"
+#include "components/exo/test/exo_test_base.h"
+#include "ui/aura/client/drag_drop_client.h"
+
+namespace exo {
+namespace {
+
+constexpr char kText[] = "test";
+constexpr char kTextMimeType[] = "text/plain";
+
+} // namespace
+
+class TestDataSourceDelegate : public DataSourceDelegate {
+ public:
+ // DataSourceDelegate:
+ void OnDataSourceDestroying(DataSource* source) override {}
+
+ void OnTarget(const base::Optional<std::string>& mime_type) override {}
+
+ void OnSend(const std::string& mime_type, base::ScopedFD fd) override {
+ base::WriteFileDescriptor(fd.get(), kText, sizeof(kText));
+ }
+
+ void OnCancelled() override {}
+
+ void OnDndDropPerformed() override {}
+
+ void OnDndFinished() override {}
+
+ void OnAction(DndAction dnd_action) override {}
+
+ bool CanAcceptDataEventsForSurface(Surface* surface) const override {
+ return true;
+ }
+};
+
+class DragDropOperationTest : public test::ExoTestBase,
+ public aura::client::DragDropClientObserver {
+ public:
+ DragDropOperationTest() = default;
+ ~DragDropOperationTest() override = default;
+ DragDropOperationTest(const DragDropOperationTest&) = delete;
+ DragDropOperationTest& operator=(const DragDropOperationTest&) = delete;
+
+ void SetUp() override {
+ test::ExoTestBase::SetUp();
+ aura::client::GetDragDropClient(ash::Shell::GetPrimaryRootWindow())
+ ->AddObserver(this);
+ }
+
+ void TearDown() override {
+ aura::client::GetDragDropClient(ash::Shell::GetPrimaryRootWindow())
+ ->RemoveObserver(this);
+ test::ExoTestBase::TearDown();
+ }
+
+ // aura::client::DragDropClientObserver:
+ void OnDragStarted() override {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, std::move(drag_blocked_callback_));
+ }
+
+ void OnDragEnded() override {}
+
+ protected:
+ void set_drag_blocked_callback(base::OnceClosure callback) {
+ drag_blocked_callback_ = std::move(callback);
+ }
+
+ private:
+ // Callback running inside the nested RunLoop in StartDragAndDrop().
+ base::OnceClosure drag_blocked_callback_;
+};
+
+TEST_F(DragDropOperationTest, DeleteDuringDragging) {
+ auto delegate = std::make_unique<TestDataSourceDelegate>();
+ auto data_source = std::make_unique<DataSource>(delegate.get());
+ data_source->Offer(kTextMimeType);
+
+ auto origin_surface = std::make_unique<Surface>();
+ ash::Shell::GetPrimaryRootWindow()->AddChild(origin_surface->window());
+
+ gfx::Size buffer_size(100, 100);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ auto icon_surface = std::make_unique<Surface>();
+ icon_surface->Attach(buffer.get());
+
+ auto operation = DragDropOperation::Create(
+ data_source.get(), origin_surface.get(), icon_surface.get(), gfx::Point(),
+ ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
+ icon_surface->Commit();
+
+ base::RunLoop run_loop;
+ set_drag_blocked_callback(base::BindOnce(
+ [](std::unique_ptr<DataSource> data_source,
+ base::WeakPtr<DragDropOperation> operation,
+ base::OnceClosure quit_closure) {
+ // This function runs inside the nested RunLoop in
+ // ash::DragDropController::StartDragAndDrop().
+ EXPECT_TRUE(operation);
+ // Deleting DataSource causes DragDropOperation to be deleted as well.
+ data_source.reset();
+ EXPECT_FALSE(operation);
+ std::move(quit_closure).Run();
+ },
+ std::move(data_source), operation, run_loop.QuitClosure()));
+ run_loop.Run();
+ EXPECT_FALSE(operation);
+}
+
+} // namespace exo
diff --git a/chromium/components/exo/fullscreen_shell_surface.cc b/chromium/components/exo/fullscreen_shell_surface.cc
index b2bc0b7fbc8..ef253ea127b 100644
--- a/chromium/components/exo/fullscreen_shell_surface.cc
+++ b/chromium/components/exo/fullscreen_shell_surface.cc
@@ -15,14 +15,40 @@
#include "ui/aura/window_targeter.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/dip_util.h"
+#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/window_util.h"
namespace exo {
+class FullscreenShellSurface::FullscreenShellView : public views::View {
+ public:
+ FullscreenShellView() = default;
+ FullscreenShellView(const FullscreenShellView&) = delete;
+ FullscreenShellView& operator=(const FullscreenShellView&) = delete;
+ ~FullscreenShellView() override = default;
+
+ // views::View:
+ void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
+ node_data->role = ax::mojom::Role::kClient;
+
+ if (child_ax_tree_id_ == ui::AXTreeIDUnknown())
+ return;
+
+ node_data->AddStringAttribute(ax::mojom::StringAttribute::kChildTreeId,
+ child_ax_tree_id_.ToString());
+ }
+
+ void SetChildAxTreeId(ui::AXTreeID child_ax_tree_id) {
+ child_ax_tree_id_ = child_ax_tree_id;
+ }
+
+ private:
+ ui::AXTreeID child_ax_tree_id_ = ui::AXTreeIDUnknown();
+};
+
FullscreenShellSurface::FullscreenShellSurface()
: SurfaceTreeHost("FullscreenShellSurfaceHost") {
- set_owned_by_client();
CreateFullscreenShellSurfaceWidget(ui::SHOW_STATE_FULLSCREEN);
widget_->SetFullscreen(true);
}
@@ -69,7 +95,6 @@ void FullscreenShellSurface::SetSurface(Surface* surface) {
if (root_surface())
root_surface()->RemoveSurfaceObserver(this);
SetRootSurface(surface);
- set_owned_by_client();
SetShellMainSurface(widget_->GetNativeWindow(), root_surface());
if (surface) {
surface->AddSurfaceObserver(this);
@@ -167,7 +192,8 @@ bool FullscreenShellSurface::ShouldShowWindowTitle() const {
}
void FullscreenShellSurface::WindowClosing() {
- SetEnabled(false);
+ contents_view_->SetEnabled(false);
+ contents_view_ = nullptr;
widget_ = nullptr;
}
@@ -180,7 +206,9 @@ const views::Widget* FullscreenShellSurface::GetWidget() const {
}
views::View* FullscreenShellSurface::GetContentsView() {
- return this;
+ if (!contents_view_)
+ contents_view_ = new FullscreenShellView();
+ return contents_view_;
}
bool FullscreenShellSurface::WidgetHasHitTestMask() const {
@@ -210,18 +238,19 @@ void FullscreenShellSurface::OnWindowDestroying(aura::Window* window) {
window->RemoveObserver(this);
}
-void FullscreenShellSurface::GetAccessibleNodeData(ui::AXNodeData* node_data) {
- node_data->role = ax::mojom::Role::kClient;
-
- if (child_ax_tree_id_ == ui::AXTreeIDUnknown())
- return;
+void FullscreenShellSurface::SetChildAxTreeId(ui::AXTreeID child_ax_tree_id) {
+ DCHECK(contents_view_);
+ contents_view_->SetChildAxTreeId(child_ax_tree_id);
+}
- node_data->AddStringAttribute(ax::mojom::StringAttribute::kChildTreeId,
- child_ax_tree_id_.ToString());
+void FullscreenShellSurface::SetEnabled(bool enabled) {
+ DCHECK(contents_view_);
+ contents_view_->SetEnabled(enabled);
}
-void FullscreenShellSurface::SetChildAxTreeId(ui::AXTreeID child_ax_tree_id) {
- child_ax_tree_id_ = child_ax_tree_id;
+void FullscreenShellSurface::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+ DCHECK(contents_view_);
+ contents_view_->GetAccessibleNodeData(node_data);
}
void FullscreenShellSurface::UpdateHostWindowBounds() {
@@ -237,7 +266,6 @@ void FullscreenShellSurface::UpdateHostWindowBounds() {
void FullscreenShellSurface::CreateFullscreenShellSurfaceWidget(
ui::WindowShowState show_state) {
- DCHECK(GetEnabled());
DCHECK(!widget_);
views::Widget::InitParams params;
@@ -278,8 +306,12 @@ void FullscreenShellSurface::CommitWidget() {
}
bool FullscreenShellSurface::OnPreWidgetCommit() {
- if (!widget_ && GetEnabled() && host_window()->bounds().IsEmpty())
+ // If we have a |widget_|, then we must have a |contents_view_| as both are
+ // created together.
+ if (!widget_ && contents_view_->GetEnabled() &&
+ host_window()->bounds().IsEmpty()) {
return false;
+ }
return true;
}
diff --git a/chromium/components/exo/fullscreen_shell_surface.h b/chromium/components/exo/fullscreen_shell_surface.h
index c867a791cc4..15bedf9c384 100644
--- a/chromium/components/exo/fullscreen_shell_surface.h
+++ b/chromium/components/exo/fullscreen_shell_surface.h
@@ -20,8 +20,7 @@ class Surface;
class FullscreenShellSurface : public SurfaceTreeHost,
public SurfaceObserver,
public aura::WindowObserver,
- public views::WidgetDelegate,
- public views::View {
+ public views::WidgetDelegate {
public:
FullscreenShellSurface();
~FullscreenShellSurface() override;
@@ -78,12 +77,12 @@ class FullscreenShellSurface : public SurfaceTreeHost,
// aura::WindowObserver:
void OnWindowDestroying(aura::Window* window) override;
- // ui::View:
- void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
-
void SetChildAxTreeId(ui::AXTreeID child_ax_tree_id);
+ void SetEnabled(bool enabled);
+ void GetAccessibleNodeData(ui::AXNodeData* node_data);
private:
+ class FullscreenShellView;
// Keep the bounds in sync with the root surface bounds.
void UpdateHostWindowBounds() override;
@@ -97,7 +96,7 @@ class FullscreenShellSurface : public SurfaceTreeHost,
base::Optional<std::string> startup_id_;
base::RepeatingClosure close_callback_;
base::OnceClosure surface_destroyed_callback_;
- ui::AXTreeID child_ax_tree_id_ = ui::AXTreeIDUnknown();
+ FullscreenShellView* contents_view_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(FullscreenShellSurface);
};
diff --git a/chromium/components/exo/gamepad_delegate.h b/chromium/components/exo/gamepad_delegate.h
index 8ca47f8c625..bb698612c6f 100644
--- a/chromium/components/exo/gamepad_delegate.h
+++ b/chromium/components/exo/gamepad_delegate.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_EXO_GAMEPAD_DELEGATE_H_
#define COMPONENTS_EXO_GAMEPAD_DELEGATE_H_
+#include "base/time/time.h"
+
namespace exo {
// Handles events for a specific gamepad.
@@ -14,14 +16,16 @@ class GamepadDelegate {
virtual void OnRemoved() = 0;
// Called when the user moved an axis of the gamepad.
- virtual void OnAxis(int axis, double value) = 0;
+ virtual void OnAxis(int axis, double value, base::TimeTicks timestamp) = 0;
// Called when the user pressed or moved a button of the gamepad.
- virtual void OnButton(int button, bool pressed) = 0;
+ virtual void OnButton(int button,
+ bool pressed,
+ base::TimeTicks timestamp) = 0;
// Called after all gamepad information of this frame has been set and the
// client should evaluate the updated state.
- virtual void OnFrame() = 0;
+ virtual void OnFrame(base::TimeTicks timestamp) = 0;
protected:
virtual ~GamepadDelegate() {}
diff --git a/chromium/components/exo/gaming_seat.cc b/chromium/components/exo/gaming_seat.cc
index c578348c3d1..f63b2fac4dc 100644
--- a/chromium/components/exo/gaming_seat.cc
+++ b/chromium/components/exo/gaming_seat.cc
@@ -4,6 +4,8 @@
#include "components/exo/gaming_seat.h"
+#include <vector>
+
#include "components/exo/gamepad_delegate.h"
#include "components/exo/gaming_seat_delegate.h"
#include "components/exo/shell_surface_util.h"
@@ -97,13 +99,13 @@ void GamingSeat::OnGamepadEvent(const ui::GamepadEvent& event) {
switch (event.type()) {
case ui::GamepadEventType::BUTTON:
- it->second->OnButton(event.code(), event.value());
+ it->second->OnButton(event.code(), event.value(), event.timestamp());
break;
case ui::GamepadEventType::AXIS:
- it->second->OnAxis(event.code(), event.value());
+ it->second->OnAxis(event.code(), event.value(), event.timestamp());
break;
case ui::GamepadEventType::FRAME:
- it->second->OnFrame();
+ it->second->OnFrame(event.timestamp());
break;
}
}
diff --git a/chromium/components/exo/gaming_seat_unittest.cc b/chromium/components/exo/gaming_seat_unittest.cc
index 6a04350f0de..4d763b60c18 100644
--- a/chromium/components/exo/gaming_seat_unittest.cc
+++ b/chromium/components/exo/gaming_seat_unittest.cc
@@ -3,9 +3,13 @@
// found in the LICENSE file.
#include "components/exo/gaming_seat.h"
+
+#include <vector>
+
#include "ash/shell.h"
#include "base/command_line.h"
#include "base/run_loop.h"
+#include "base/time/time.h"
#include "components/exo/buffer.h"
#include "components/exo/gamepad_delegate.h"
#include "components/exo/gaming_seat_delegate.h"
@@ -37,9 +41,9 @@ class MockGamepadDelegate : public GamepadDelegate {
// Overridden from GamepadDelegate:
MOCK_METHOD0(OnRemoved, void());
- MOCK_METHOD2(OnAxis, void(int, double));
- MOCK_METHOD2(OnButton, void(int, bool));
- MOCK_METHOD0(OnFrame, void());
+ MOCK_METHOD3(OnAxis, void(int, double, base::TimeTicks));
+ MOCK_METHOD3(OnButton, void(int, bool, base::TimeTicks));
+ MOCK_METHOD1(OnFrame, void(base::TimeTicks));
};
class GamingSeatTest : public test::ExoTestBase {
@@ -73,6 +77,15 @@ class GamingSeatTest : public test::ExoTestBase {
}
}
+ void SendButtonToGamepads(const std::vector<int>& gamepad_device_ids,
+ base::TimeTicks timestamp) {
+ for (auto& id : gamepad_device_ids) {
+ ui::GamepadEvent event(id, ui::GamepadEventType::BUTTON, 310, 1,
+ timestamp);
+ ui::GamepadProviderOzone::GetInstance()->DispatchGamepadEvent(event);
+ }
+ }
+
protected:
std::unique_ptr<GamingSeat> gaming_seat_;
@@ -104,19 +117,19 @@ TEST_F(GamingSeatTest, ConnectionChange) {
.WillOnce(testing::Return(&gamepad_delegate[0]))
.WillOnce(testing::Return(&gamepad_delegate[1]));
// Send frame to connected gamepad.
- EXPECT_CALL(gamepad_delegate[0], OnFrame()).Times(1);
- EXPECT_CALL(gamepad_delegate[1], OnFrame()).Times(1);
+ EXPECT_CALL(gamepad_delegate[0], OnFrame(testing::_)).Times(1);
+ EXPECT_CALL(gamepad_delegate[1], OnFrame(testing::_)).Times(1);
// Connect 3 more.
EXPECT_CALL(*gaming_seat_delegate, GamepadAdded(testing::_))
.WillOnce(testing::Return(&gamepad_delegate[2]))
.WillOnce(testing::Return(&gamepad_delegate[3]))
.WillOnce(testing::Return(&gamepad_delegate[4]));
// Send frame to all gamepads.
- EXPECT_CALL(gamepad_delegate[0], OnFrame()).Times(1);
- EXPECT_CALL(gamepad_delegate[1], OnFrame()).Times(1);
- EXPECT_CALL(gamepad_delegate[2], OnFrame()).Times(1);
- EXPECT_CALL(gamepad_delegate[3], OnFrame()).Times(1);
- EXPECT_CALL(gamepad_delegate[4], OnFrame()).Times(1);
+ EXPECT_CALL(gamepad_delegate[0], OnFrame(testing::_)).Times(1);
+ EXPECT_CALL(gamepad_delegate[1], OnFrame(testing::_)).Times(1);
+ EXPECT_CALL(gamepad_delegate[2], OnFrame(testing::_)).Times(1);
+ EXPECT_CALL(gamepad_delegate[3], OnFrame(testing::_)).Times(1);
+ EXPECT_CALL(gamepad_delegate[4], OnFrame(testing::_)).Times(1);
// Disconnect gamepad 0 and gamepad 2 and connect a new gamepad.
EXPECT_CALL(gamepad_delegate[0], OnRemoved()).Times(1);
EXPECT_CALL(gamepad_delegate[2], OnRemoved()).Times(1);
@@ -124,9 +137,9 @@ TEST_F(GamingSeatTest, ConnectionChange) {
EXPECT_CALL(*gaming_seat_delegate, GamepadAdded(testing::_))
.WillOnce(testing::Return(&gamepad_delegate[5]));
// Send frame to all gamepads.
- EXPECT_CALL(gamepad_delegate[1], OnFrame()).Times(1);
- EXPECT_CALL(gamepad_delegate[3], OnFrame()).Times(1);
- EXPECT_CALL(gamepad_delegate[5], OnFrame()).Times(1);
+ EXPECT_CALL(gamepad_delegate[1], OnFrame(testing::_)).Times(1);
+ EXPECT_CALL(gamepad_delegate[3], OnFrame(testing::_)).Times(1);
+ EXPECT_CALL(gamepad_delegate[5], OnFrame(testing::_)).Times(1);
// disconnect other gamepads
EXPECT_CALL(gamepad_delegate[1], OnRemoved()).Times(1);
@@ -140,6 +153,47 @@ TEST_F(GamingSeatTest, ConnectionChange) {
SendFrameToGamepads({0, 1, 2, 3, 4});
UpdateGamepadDevice({1, 3, 5});
SendFrameToGamepads({1, 2, 3, 4, 5});
+ UpdateGamepadDevice({});
+ DestroyGamingSeat(gaming_seat_delegate);
+}
+
+TEST_F(GamingSeatTest, Timestamp) {
+ std::unique_ptr<Surface> surface(new Surface);
+ std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+ gfx::Size buffer_size(10, 10);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ surface->Attach(buffer.get());
+ surface->Commit();
+
+ testing::StrictMock<MockGamingSeatDelegate>* gaming_seat_delegate =
+ new testing::StrictMock<MockGamingSeatDelegate>();
+ EXPECT_CALL(*gaming_seat_delegate,
+ CanAcceptGamepadEventsForSurface(testing::_))
+ .WillOnce(testing::Return(true));
+
+ InitializeGamingSeat(gaming_seat_delegate);
+ testing::StrictMock<MockGamepadDelegate> gamepad_delegate;
+
+ base::TimeTicks expected_time = base::TimeTicks::Now();
+
+ { // Test sequence
+ testing::InSequence s;
+
+ // Connect gamepad.
+ EXPECT_CALL(*gaming_seat_delegate, GamepadAdded(testing::_))
+ .WillOnce(testing::Return(&gamepad_delegate));
+ // Send button to connected gamepad. Expect correct timestamp.
+ EXPECT_CALL(gamepad_delegate,
+ OnButton(testing::_, testing::_, testing::Eq(expected_time)))
+ .Times(1);
+ // Disconnect gamepad.
+ EXPECT_CALL(gamepad_delegate, OnRemoved()).Times(1);
+ }
+ // Gamepad connected.
+ UpdateGamepadDevice({1});
+ SendButtonToGamepads({1}, expected_time);
+ UpdateGamepadDevice({});
DestroyGamingSeat(gaming_seat_delegate);
}
diff --git a/chromium/components/exo/keyboard.cc b/chromium/components/exo/keyboard.cc
index 64aa296e8a9..554e57e3400 100644
--- a/chromium/components/exo/keyboard.cc
+++ b/chromium/components/exo/keyboard.cc
@@ -4,12 +4,10 @@
#include "components/exo/keyboard.h"
-#include "ash/accessibility/accessibility_controller_impl.h"
#include "ash/keyboard/ui/keyboard_ui_controller.h"
#include "ash/keyboard/ui/keyboard_util.h"
#include "ash/public/cpp/app_types.h"
#include "ash/public/cpp/keyboard/keyboard_controller.h"
-#include "ash/shell.h"
#include "base/bind.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/exo/input_trace.h"
@@ -224,12 +222,7 @@ bool Keyboard::AreKeyboardKeyAcksNeeded() const {
// While the spoken feedback is enabled, a key event is sent to both of a
// wayland client and Chrome to give a chance to work to Chrome OS's
// shortcuts.
- return are_keyboard_key_acks_needed_
- // TODO(yhanada): Remove this once ARC++ can send ack with a serial
- // correctly while ChromeVox is on.
- && !ash::Shell::Get()
- ->accessibility_controller()
- ->spoken_feedback_enabled();
+ return are_keyboard_key_acks_needed_;
}
void Keyboard::AckKeyboardKey(uint32_t serial, bool handled) {
@@ -279,7 +272,12 @@ void Keyboard::OnKeyEvent(ui::KeyEvent* event) {
// When IME ate a key event, we use the event only for tracking key states and
// ignore for further processing. Otherwise it is handled in two places (IME
// and client) and causes undesired behavior.
- bool consumed_by_ime = ConsumedByIme(focus_, event);
+ // If the window should receive a key event before IME, Exo should send any
+ // key events to a client. The client will send back the events to IME if
+ // needed.
+ const bool consumed_by_ime =
+ !focus_->window()->GetProperty(aura::client::kSkipImeProcessing) &&
+ ConsumedByIme(focus_, event);
// Always update modifiers.
int modifier_flags = event->flags() & kModifierMask;
diff --git a/chromium/components/exo/keyboard_unittest.cc b/chromium/components/exo/keyboard_unittest.cc
index 83e176ff0d4..50e037c21c8 100644
--- a/chromium/components/exo/keyboard_unittest.cc
+++ b/chromium/components/exo/keyboard_unittest.cc
@@ -23,7 +23,9 @@
#include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_helper.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/focus_client.h"
+#include "ui/base/ime/dummy_text_input_client.h"
#include "ui/events/devices/device_data_manager.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/dom/dom_code.h"
@@ -50,6 +52,7 @@ class MockKeyboardDelegate : public KeyboardDelegate {
MOCK_METHOD3(OnKeyRepeatSettingsChanged,
void(bool, base::TimeDelta, base::TimeDelta));
};
+using NiceMockKeyboardDelegate = ::testing::NiceMock<MockKeyboardDelegate>;
class MockKeyboardDeviceConfigurationDelegate
: public KeyboardDeviceConfigurationDelegate {
@@ -80,7 +83,7 @@ class TestShellSurface : public ShellSurface {
// key events. https://crbug.com/1008574.
TEST_F(KeyboardTest, CorrectSeatPressedKeysOnSwitchingDesks) {
Seat seat;
- MockKeyboardDelegate delegate;
+ NiceMockKeyboardDelegate delegate;
auto keyboard = std::make_unique<Keyboard>(&delegate, &seat);
// Create 2 desks.
@@ -155,7 +158,7 @@ TEST_F(KeyboardTest, OnKeyboardEnter) {
focus_client->FocusWindow(surface->window());
// Keyboard should try to set initial focus to surface.
- MockKeyboardDelegate delegate;
+ NiceMockKeyboardDelegate delegate;
EXPECT_CALL(delegate, CanAcceptKeyboardEventsForSurface(surface.get()))
.WillOnce(testing::Return(false));
auto keyboard = std::make_unique<Keyboard>(&delegate, &seat);
@@ -201,7 +204,7 @@ TEST_F(KeyboardTest, OnKeyboardLeave) {
aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
focus_client->FocusWindow(nullptr);
- MockKeyboardDelegate delegate;
+ NiceMockKeyboardDelegate delegate;
Seat seat;
auto keyboard = std::make_unique<Keyboard>(&delegate, &seat);
@@ -242,7 +245,7 @@ TEST_F(KeyboardTest, OnKeyboardKey) {
aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
focus_client->FocusWindow(nullptr);
- MockKeyboardDelegate delegate;
+ NiceMockKeyboardDelegate delegate;
Seat seat;
auto keyboard = std::make_unique<Keyboard>(&delegate, &seat);
@@ -328,6 +331,77 @@ TEST_F(KeyboardTest, OnKeyboardKey) {
keyboard.reset();
}
+TEST_F(KeyboardTest, OnKeyboardKey_NotSendKeyIfConsumedByIme) {
+ std::unique_ptr<Surface> surface(new Surface);
+ std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+ gfx::Size buffer_size(10, 10);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ surface->Attach(buffer.get());
+ surface->Commit();
+
+ aura::client::FocusClient* focus_client =
+ aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
+ focus_client->FocusWindow(nullptr);
+
+ NiceMockKeyboardDelegate delegate;
+ Seat seat;
+ auto keyboard = std::make_unique<Keyboard>(&delegate, &seat);
+
+ EXPECT_CALL(delegate, CanAcceptKeyboardEventsForSurface(surface.get()))
+ .WillOnce(testing::Return(true));
+ EXPECT_CALL(delegate, OnKeyboardModifiers(0));
+ EXPECT_CALL(delegate,
+ OnKeyboardEnter(surface.get(),
+ base::flat_map<ui::DomCode, ui::DomCode>()));
+ focus_client->FocusWindow(surface->window());
+
+ ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+ views::Widget* widget =
+ views::Widget::GetTopLevelWidgetForNativeView(surface->window());
+ ui::InputMethod* input_method = widget->GetInputMethod();
+ ui::DummyTextInputClient client{ui::TEXT_INPUT_TYPE_TEXT};
+ input_method->SetFocusedTextInputClient(&client);
+
+ // If a text field is focused, a pressed key event is not sent to a client
+ // because a key event should be consumed by the IME.
+ EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::US_A, true))
+ .Times(0);
+ seat.set_physical_code_for_currently_processing_event_for_testing(
+ ui::DomCode::US_A);
+ generator.PressKey(ui::VKEY_A, 0);
+ // TODO(yhanada): The below EXPECT_CALL fails because exo::Keyboard currently
+ // sends a key release event for the keys which exo::Keyboard sent a pressed
+ // event for. It might causes a never-ending key repeat in the client.
+ // EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::US_A, false));
+ generator.ReleaseKey(ui::VKEY_A, 0);
+
+ // Any key event should be sent to a client if the focused window is marked as
+ // ImeBlocking.
+ WMHelper::GetInstance()->SetImeBlocked(surface->window()->GetToplevelWindow(),
+ true);
+ EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::US_B, true));
+ seat.set_physical_code_for_currently_processing_event_for_testing(
+ ui::DomCode::US_B);
+ generator.PressKey(ui::VKEY_B, 0);
+ EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::US_B, false));
+ generator.ReleaseKey(ui::VKEY_B, 0);
+ WMHelper::GetInstance()->SetImeBlocked(surface->window()->GetToplevelWindow(),
+ false);
+
+ // Any key event should be sent to a client if a key event skips IME.
+ surface->window()->SetProperty(aura::client::kSkipImeProcessing, true);
+ EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::US_C, true));
+ seat.set_physical_code_for_currently_processing_event_for_testing(
+ ui::DomCode::US_C);
+ generator.PressKey(ui::VKEY_C, 0);
+ EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::US_C, false));
+ generator.ReleaseKey(ui::VKEY_C, 0);
+
+ input_method->SetFocusedTextInputClient(nullptr);
+ keyboard.reset();
+}
+
TEST_F(KeyboardTest, OnKeyboardModifiers) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
@@ -341,7 +415,7 @@ TEST_F(KeyboardTest, OnKeyboardModifiers) {
aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
focus_client->FocusWindow(nullptr);
- MockKeyboardDelegate delegate;
+ NiceMockKeyboardDelegate delegate;
Seat seat;
auto keyboard = std::make_unique<Keyboard>(&delegate, &seat);
@@ -407,7 +481,7 @@ TEST_F(KeyboardTest, OnKeyboardTypeChanged) {
ash::Shell::Get()->tablet_mode_controller();
tablet_mode_controller->SetEnabledForTest(true);
- MockKeyboardDelegate delegate;
+ NiceMockKeyboardDelegate delegate;
Seat seat;
auto keyboard = std::make_unique<Keyboard>(&delegate, &seat);
MockKeyboardDeviceConfigurationDelegate configuration_delegate;
@@ -452,7 +526,7 @@ TEST_F(KeyboardTest, OnKeyboardTypeChanged_AccessibilityKeyboard) {
ui::InputDevice(2, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard")};
device_data_manager->OnKeyboardDevicesUpdated(keyboards);
- MockKeyboardDelegate delegate;
+ NiceMockKeyboardDelegate delegate;
Seat seat;
auto keyboard = std::make_unique<Keyboard>(&delegate, &seat);
MockKeyboardDeviceConfigurationDelegate configuration_delegate;
@@ -586,7 +660,7 @@ TEST_F(KeyboardTest, KeyRepeatSettingsUpdateOnProfileChange) {
}
TEST_F(KeyboardTest, KeyboardObserver) {
- MockKeyboardDelegate delegate;
+ NiceMockKeyboardDelegate delegate;
Seat seat;
auto keyboard = std::make_unique<Keyboard>(&delegate, &seat);
MockKeyboardObserver observer1;
@@ -619,7 +693,7 @@ TEST_F(KeyboardTest, NeedKeyboardKeyAcks) {
aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
focus_client->FocusWindow(nullptr);
- MockKeyboardDelegate delegate;
+ NiceMockKeyboardDelegate delegate;
Seat seat;
auto keyboard = std::make_unique<Keyboard>(&delegate, &seat);
@@ -645,7 +719,7 @@ TEST_F(KeyboardTest, AckKeyboardKey) {
aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
focus_client->FocusWindow(nullptr);
- MockKeyboardDelegate delegate;
+ NiceMockKeyboardDelegate delegate;
Seat seat;
auto keyboard = std::make_unique<Keyboard>(&delegate, &seat);
@@ -743,7 +817,7 @@ TEST_F(KeyboardTest, AckKeyboardKeyMoveFocus) {
aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
focus_client->FocusWindow(nullptr);
- MockKeyboardDelegate delegate;
+ NiceMockKeyboardDelegate delegate;
Seat seat;
auto keyboard = std::make_unique<Keyboard>(&delegate, &seat);
@@ -789,7 +863,7 @@ TEST_F(KeyboardTest, AckKeyboardKeyExpired) {
aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
focus_client->FocusWindow(nullptr);
- MockKeyboardDelegate delegate;
+ NiceMockKeyboardDelegate delegate;
Seat seat;
auto keyboard = std::make_unique<Keyboard>(&delegate, &seat);
@@ -874,7 +948,7 @@ TEST_F(KeyboardTest, AckKeyboardKeyExpiredWithMovingFocusAccelerator) {
aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
focus_client->FocusWindow(nullptr);
- MockKeyboardDelegate delegate;
+ NiceMockKeyboardDelegate delegate;
Seat seat;
auto keyboard = std::make_unique<Keyboard>(&delegate, &seat);
@@ -913,60 +987,5 @@ TEST_F(KeyboardTest, AckKeyboardKeyExpiredWithMovingFocusAccelerator) {
keyboard.reset();
}
-
-// A test case for b/130312917. While spoken feedback is enabled, a key event is
-// sent to both of a wayland client and Chrome.
-TEST_F(KeyboardTest, AckKeyboardKeyWithSpokenFeedback) {
- std::unique_ptr<Surface> surface(new Surface);
- auto shell_surface = std::make_unique<TestShellSurface>(surface.get());
- gfx::Size buffer_size(10, 10);
- std::unique_ptr<Buffer> buffer(
- new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
- surface->Attach(buffer.get());
- surface->Commit();
-
- aura::client::FocusClient* focus_client =
- aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
- focus_client->FocusWindow(nullptr);
-
- MockKeyboardDelegate delegate;
- Seat seat;
- auto keyboard = std::make_unique<Keyboard>(&delegate, &seat);
-
- EXPECT_CALL(delegate, CanAcceptKeyboardEventsForSurface(surface.get()))
- .WillOnce(testing::Return(true));
- EXPECT_CALL(delegate, OnKeyboardModifiers(0));
- EXPECT_CALL(delegate,
- OnKeyboardEnter(surface.get(),
- base::flat_map<ui::DomCode, ui::DomCode>()));
- focus_client->FocusWindow(surface->window());
-
- // Enable spoken feedback.
- ash::Shell::Get()->accessibility_controller()->SetSpokenFeedbackEnabled(
- true, ash::A11Y_NOTIFICATION_NONE);
-
- ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
- // Press KEY_W with Ctrl.
- // Key event should be sent to both of AcceleratorPressed and OnKeyboardKey.
- EXPECT_CALL(delegate, OnKeyboardModifiers(4));
- EXPECT_CALL(*shell_surface.get(), AcceleratorPressed(ui::Accelerator(
- ui::VKEY_W, ui::EF_CONTROL_DOWN,
- ui::Accelerator::KeyState::PRESSED)));
- EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::US_W, true))
- .WillOnce(testing::Return(1));
- seat.set_physical_code_for_currently_processing_event_for_testing(
- ui::DomCode::US_W);
- generator.PressKey(ui::VKEY_W, ui::EF_CONTROL_DOWN);
-
- // Sending ack for the keypress doesn't cause anything.
- keyboard->AckKeyboardKey(1, false /* handled */);
-
- // Release the key and reset modifier_flags.
- EXPECT_CALL(delegate, OnKeyboardModifiers(0));
- EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::US_W, false));
- generator.ReleaseKey(ui::VKEY_W, 0);
-
- keyboard.reset();
-}
} // namespace
} // namespace exo
diff --git a/chromium/components/exo/notification_surface_manager.h b/chromium/components/exo/notification_surface_manager.h
index f5427b815fc..5840cfce000 100644
--- a/chromium/components/exo/notification_surface_manager.h
+++ b/chromium/components/exo/notification_surface_manager.h
@@ -13,6 +13,8 @@ class NotificationSurface;
class NotificationSurfaceManager {
public:
+ virtual ~NotificationSurfaceManager() = default;
+
// Gets the NotificationSurface associated with the given notification id.
// Returns nullptr if no NotificationSurface is associated with the id.
virtual NotificationSurface* GetSurface(
@@ -23,9 +25,6 @@ class NotificationSurfaceManager {
// Removes a NotificationSurface from the manager.
virtual void RemoveSurface(NotificationSurface* surface) = 0;
-
- protected:
- virtual ~NotificationSurfaceManager() {}
};
} // namespace exo
diff --git a/chromium/components/exo/pointer.cc b/chromium/components/exo/pointer.cc
index 9435a608c8a..cc5735f5eb9 100644
--- a/chromium/components/exo/pointer.cc
+++ b/chromium/components/exo/pointer.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/feature_list.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "components/exo/input_trace.h"
#include "components/exo/pointer_constraint_delegate.h"
#include "components/exo/pointer_delegate.h"
@@ -41,11 +42,7 @@
#endif
#if defined(USE_OZONE)
-#include "ui/ozone/public/cursor_factory_ozone.h"
-#endif
-
-#if defined(USE_X11)
-#include "ui/base/cursor/cursor_loader_x11.h"
+#include "ui/base/cursor/cursor_factory.h"
#endif
namespace exo {
@@ -343,6 +340,8 @@ void Pointer::OnSurfaceDestroying(Surface* surface) {
// ui::EventHandler overrides:
void Pointer::OnMouseEvent(ui::MouseEvent* event) {
+ seat_->SetLastLocation(event->root_location());
+
Surface* target = GetEffectiveTargetForEvent(event);
gfx::PointF location_in_target = event->location_f();
if (target) {
@@ -555,7 +554,8 @@ void Pointer::OnWindowFocused(aura::Window* gained_focus,
////////////////////////////////////////////////////////////////////////////////
// Pointer, private:
-Surface* Pointer::GetEffectiveTargetForEvent(ui::LocatedEvent* event) const {
+Surface* Pointer::GetEffectiveTargetForEvent(
+ const ui::LocatedEvent* event) const {
if (capture_window_)
return Surface::AsSurface(capture_window_);
@@ -637,6 +637,7 @@ void Pointer::CaptureCursor(const gfx::Point& hotspot) {
base::BindOnce(&Pointer::OnCursorCaptured,
cursor_capture_weak_ptr_factory_.GetWeakPtr(),
hotspot));
+ request->set_result_task_runner(base::SequencedTaskRunnerHandle::Get());
request->set_source(cursor_capture_source_id_);
host_window()->layer()->RequestCopyOfOutput(std::move(request));
@@ -688,8 +689,8 @@ void Pointer::UpdateCursor() {
// TODO(reveman): Add interface for creating cursors from GpuMemoryBuffers
// and use that here instead of the current bitmap API.
// https://crbug.com/686600
- platform_cursor = ui::CursorFactoryOzone::GetInstance()->CreateImageCursor(
- bitmap, hotspot, 0);
+ platform_cursor =
+ ui::CursorFactory::GetInstance()->CreateImageCursor(bitmap, hotspot);
#elif defined(USE_X11)
XcursorImage* image = ui::SkBitmapToXcursorImage(&bitmap, hotspot);
platform_cursor = ui::CreateReffedCustomXCursor(image);
@@ -698,7 +699,7 @@ void Pointer::UpdateCursor() {
cursor_.set_custom_bitmap(bitmap);
cursor_.set_custom_hotspot(hotspot);
#if defined(USE_OZONE)
- ui::CursorFactoryOzone::GetInstance()->UnrefImageCursor(platform_cursor);
+ ui::CursorFactory::GetInstance()->UnrefImageCursor(platform_cursor);
#elif defined(USE_X11)
ui::UnrefCustomXCursor(platform_cursor);
#endif
diff --git a/chromium/components/exo/pointer.h b/chromium/components/exo/pointer.h
index bc8f52e1076..d9f0cff3d81 100644
--- a/chromium/components/exo/pointer.h
+++ b/chromium/components/exo/pointer.h
@@ -115,7 +115,7 @@ class Pointer : public SurfaceTreeHost,
void DisablePointerCapture();
// Returns the effective target for |event|.
- Surface* GetEffectiveTargetForEvent(ui::LocatedEvent* event) const;
+ Surface* GetEffectiveTargetForEvent(const ui::LocatedEvent* event) const;
// Change pointer focus to |surface|.
void SetFocus(Surface* surface,
diff --git a/chromium/components/exo/seat.cc b/chromium/components/exo/seat.cc
index af1838fcc63..e4915ffdd24 100644
--- a/chromium/components/exo/seat.cc
+++ b/chromium/components/exo/seat.cc
@@ -83,8 +83,12 @@ void Seat::StartDrag(DataSource* source,
Surface* icon,
ui::DragDropTypes::DragEventSource event_source) {
// DragDropOperation manages its own lifetime.
- drag_drop_operation_ =
- DragDropOperation::Create(source, origin, icon, event_source);
+ drag_drop_operation_ = DragDropOperation::Create(
+ source, origin, icon, last_location_, event_source);
+}
+
+void Seat::SetLastLocation(const gfx::Point& last_location) {
+ last_location_ = last_location;
}
void Seat::AbortPendingDragOperation() {
diff --git a/chromium/components/exo/seat.h b/chromium/components/exo/seat.h
index e114c1eac77..d5730af5df0 100644
--- a/chromium/components/exo/seat.h
+++ b/chromium/components/exo/seat.h
@@ -72,6 +72,10 @@ class Seat : public aura::client::FocusChangeObserver,
Surface* icon,
ui::DragDropTypes::DragEventSource event_source);
+ // Sets the last location in screen coordinates, irrespective of mouse or
+ // touch.
+ void SetLastLocation(const gfx::Point& last_location);
+
// Abort any drag operations that haven't been started yet.
void AbortPendingDragOperation();
@@ -159,6 +163,8 @@ class Seat : public aura::client::FocusChangeObserver,
// True while Seat is updating clipboard data to selection source.
bool changing_clipboard_data_to_selection_source_;
+ gfx::Point last_location_;
+
base::WeakPtrFactory<Seat> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(Seat);
diff --git a/chromium/components/exo/server/BUILD.gn b/chromium/components/exo/server/BUILD.gn
new file mode 100644
index 00000000000..0dc6caef345
--- /dev/null
+++ b/chromium/components/exo/server/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+assert(is_chromeos)
+
+source_set("server") {
+ sources = [
+ "wayland_server_controller.cc",
+ "wayland_server_controller.h",
+ ]
+
+ deps = [
+ "//ash/public/cpp",
+ "//ash/public/cpp/external_arc",
+ "//base",
+ "//components/exo",
+ "//components/exo/wayland",
+ "//skia",
+ ]
+}
diff --git a/chromium/components/exo/server/OWNERS b/chromium/components/exo/server/OWNERS
new file mode 100644
index 00000000000..2285adf99b1
--- /dev/null
+++ b/chromium/components/exo/server/OWNERS
@@ -0,0 +1 @@
+penghuang@chromium.org
diff --git a/chromium/components/exo/server/wayland_server_controller.cc b/chromium/components/exo/server/wayland_server_controller.cc
new file mode 100644
index 00000000000..8f2823796be
--- /dev/null
+++ b/chromium/components/exo/server/wayland_server_controller.cc
@@ -0,0 +1,62 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/exo/server/wayland_server_controller.h"
+
+#include <memory>
+
+#include "base/command_line.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop_current.h"
+#include "components/exo/display.h"
+#include "components/exo/file_helper.h"
+#include "components/exo/input_method_surface_manager.h"
+#include "components/exo/notification_surface_manager.h"
+#include "components/exo/wayland/server.h"
+#include "components/exo/wayland/wayland_watcher.h"
+#include "components/exo/wm_helper.h"
+#include "components/exo/wm_helper_chromeos.h"
+
+namespace exo {
+
+// static
+std::unique_ptr<WaylandServerController>
+WaylandServerController::CreateIfNecessary(
+ std::unique_ptr<FileHelper> file_helper,
+ std::unique_ptr<NotificationSurfaceManager> notification_surface_manager,
+ std::unique_ptr<InputMethodSurfaceManager> input_method_surface_manager) {
+ return std::make_unique<WaylandServerController>(
+ std::move(file_helper), std::move(notification_surface_manager),
+ std::move(input_method_surface_manager));
+}
+
+WaylandServerController::~WaylandServerController() {
+ // Delete the instance in the reversed order they are created.
+ wayland_watcher_.reset();
+ wayland_server_.reset();
+ display_.reset();
+ WMHelper::SetInstance(nullptr);
+ wm_helper_.reset();
+}
+
+WaylandServerController::WaylandServerController(
+ std::unique_ptr<FileHelper> file_helper,
+ std::unique_ptr<NotificationSurfaceManager> notification_surface_manager,
+ std::unique_ptr<InputMethodSurfaceManager> input_method_surface_manager)
+ : wm_helper_(std::make_unique<WMHelperChromeOS>()),
+ notification_surface_manager_(std::move(notification_surface_manager)),
+ input_method_surface_manager_(std::move(input_method_surface_manager)) {
+ WMHelper::SetInstance(wm_helper_.get());
+ display_ = std::make_unique<Display>(notification_surface_manager_.get(),
+ input_method_surface_manager_.get(),
+ std::move(file_helper));
+ wayland_server_ = wayland::Server::Create(display_.get());
+ // Wayland server creation can fail if XDG_RUNTIME_DIR is not set correctly.
+ if (wayland_server_) {
+ wayland_watcher_ =
+ std::make_unique<wayland::WaylandWatcher>(wayland_server_.get());
+ }
+}
+
+} // namespace exo
diff --git a/chromium/components/exo/server/wayland_server_controller.h b/chromium/components/exo/server/wayland_server_controller.h
new file mode 100644
index 00000000000..9f448c6e9fd
--- /dev/null
+++ b/chromium/components/exo/server/wayland_server_controller.h
@@ -0,0 +1,61 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_EXO_SERVER_WAYLAND_SERVER_CONTROLLER_H_
+#define COMPONENTS_EXO_SERVER_WAYLAND_SERVER_CONTROLLER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+
+namespace exo {
+
+namespace wayland {
+class Server;
+class WaylandWatcher;
+} // namespace wayland
+
+class Display;
+class FileHelper;
+class WMHelper;
+class NotificationSurfaceManager;
+class InputMethodSurfaceManager;
+
+class WaylandServerController {
+ public:
+ static std::unique_ptr<WaylandServerController> CreateForArcIfNecessary(
+ std::unique_ptr<FileHelper> file_helper);
+
+ // Creates WaylandServerController. Returns null if controller should not be
+ // created.
+ static std::unique_ptr<WaylandServerController> CreateIfNecessary(
+ std::unique_ptr<FileHelper> file_helper,
+ std::unique_ptr<NotificationSurfaceManager> notification_surface_manager,
+ std::unique_ptr<InputMethodSurfaceManager> input_method_surface_manager);
+
+ ~WaylandServerController();
+
+ InputMethodSurfaceManager* input_method_surface_manager() {
+ return input_method_surface_manager_.get();
+ }
+
+ WaylandServerController(
+ std::unique_ptr<FileHelper> file_helper,
+ std::unique_ptr<NotificationSurfaceManager> notification_surface_manager,
+ std::unique_ptr<InputMethodSurfaceManager> input_method_surface_manager);
+
+ private:
+ std::unique_ptr<WMHelper> wm_helper_;
+ std::unique_ptr<Display> display_;
+ std::unique_ptr<wayland::Server> wayland_server_;
+ std::unique_ptr<wayland::WaylandWatcher> wayland_watcher_;
+ std::unique_ptr<NotificationSurfaceManager> notification_surface_manager_;
+ std::unique_ptr<InputMethodSurfaceManager> input_method_surface_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(WaylandServerController);
+};
+
+} // namespace exo
+
+#endif // COMPONENTS_EXO_SERVER_WAYLAND_SERVER_CONTROLLER_H_
diff --git a/chromium/components/exo/shell_surface_base.cc b/chromium/components/exo/shell_surface_base.cc
index 315948b4243..2a6951c2f02 100644
--- a/chromium/components/exo/shell_surface_base.cc
+++ b/chromium/components/exo/shell_surface_base.cc
@@ -58,6 +58,14 @@
namespace exo {
namespace {
+// Set aura::client::kSkipImeProcessing to all Surface descendants.
+void SetSkipImeProcessingToDescendentSurfaces(aura::Window* window) {
+ if (Surface::AsSurface(window))
+ window->SetProperty(aura::client::kSkipImeProcessing, true);
+ for (aura::Window* child : window->children())
+ SetSkipImeProcessingToDescendentSurfaces(child);
+}
+
// The accelerator keys used to close ShellSurfaces.
const struct {
ui::KeyboardCode keycode;
@@ -286,6 +294,8 @@ void CloseAllTransientChildren(aura::Window* window) {
}
}
+int shell_id = 0;
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -296,7 +306,7 @@ ShellSurfaceBase::ShellSurfaceBase(Surface* surface,
bool activatable,
bool can_minimize,
int container)
- : SurfaceTreeHost("ExoShellSurfaceHost"),
+ : SurfaceTreeHost(base::StringPrintf("ExoShellSurfaceHost-%d", shell_id)),
origin_(origin),
container_(container),
activatable_(activatable),
@@ -327,6 +337,7 @@ ShellSurfaceBase::~ShellSurfaceBase() {
root_surface()->RemoveSurfaceObserver(this);
if (has_grab_)
WMHelper::GetInstance()->GetCaptureClient()->RemoveObserver(this);
+ CHECK(!views::WidgetObserver::IsInObserverList());
}
void ShellSurfaceBase::Activate() {
@@ -556,7 +567,7 @@ void ShellSurfaceBase::OnSetFrame(SurfaceFrameType frame_type) {
}
bool frame_was_disabled = !frame_enabled();
- // TODO(b/141151475): Make frame_type a committable property.
+ bool frame_type_Changed = frame_type_ != frame_type;
frame_type_ = frame_type;
switch (frame_type) {
case SurfaceFrameType::NONE:
@@ -565,16 +576,15 @@ void ShellSurfaceBase::OnSetFrame(SurfaceFrameType frame_type) {
case SurfaceFrameType::NORMAL:
case SurfaceFrameType::AUTOHIDE:
case SurfaceFrameType::OVERLAY:
+ case SurfaceFrameType::SHADOW:
// Initialize the shadow if it didn't exist. Do not reset if
// the frame type just switched from another enabled type or
// there is a pending shadow_bounds_ change to avoid overriding
// a shadow bounds which have been changed and not yet committed.
- if (!shadow_bounds_ || (frame_was_disabled && !shadow_bounds_changed_))
+ if (frame_type_Changed &&
+ (!shadow_bounds_ || (frame_was_disabled && !shadow_bounds_changed_)))
shadow_bounds_ = gfx::Rect();
break;
- case SurfaceFrameType::SHADOW:
- shadow_bounds_ = gfx::Rect();
- break;
}
if (!widget_)
return;
@@ -832,6 +842,15 @@ void ShellSurfaceBase::OnWindowDestroying(aura::Window* window) {
window->RemoveObserver(this);
}
+void ShellSurfaceBase::OnWindowPropertyChanged(aura::Window* window,
+ const void* key,
+ intptr_t old_value) {
+ if (widget_ && window == widget_->GetNativeWindow() &&
+ key == aura::client::kSkipImeProcessing) {
+ SetSkipImeProcessingToDescendentSurfaces(window);
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// wm::ActivationChangeObserver overrides:
@@ -922,7 +941,7 @@ void ShellSurfaceBase::CreateShellSurfaceWidget(
widget_->AddObserver(this);
aura::Window* window = widget_->GetNativeWindow();
- window->SetName("ExoShellSurface");
+ window->SetName(base::StringPrintf("ExoShellSurface-%d", shell_id++));
window->AddChild(host_window());
// Works for both mash and non-mash. https://crbug.com/839521
window->SetEventTargetingPolicy(
@@ -1012,8 +1031,6 @@ void ShellSurfaceBase::UpdateShadow() {
if (!widget_ || !root_surface())
return;
- shadow_bounds_changed_ = false;
-
aura::Window* window = widget_->GetNativeWindow();
if (!shadow_bounds_) {
@@ -1037,6 +1054,11 @@ void ShellSurfaceBase::UpdateShadow() {
}
}
+void ShellSurfaceBase::UpdateFrameType() {
+ // Nothing to do here for now as frame type is updated immediately in
+ // OnSetFrame() by default.
+}
+
gfx::Rect ShellSurfaceBase::GetVisibleBounds() const {
// Use |geometry_| if set, otherwise use the visual bounds of the surface.
if (geometry_.IsEmpty()) {
@@ -1104,6 +1126,14 @@ void ShellSurfaceBase::StartCapture() {
widget_->SetCapture(nullptr /* view */);
}
+void ShellSurfaceBase::OnPostWidgetCommit() {
+ // |shadow_bounds_changed_| represents whether |shadow_bounds_| has changed
+ // since the last commit, but as UpdateShadow() can be called multiple times
+ // in a single commit process, we need to ensure that it's not reset halfway
+ // in the current commit by resetting it here.
+ shadow_bounds_changed_ = false;
+}
+
void ShellSurfaceBase::CommitWidget() {
// Apply new window geometry.
geometry_ = pending_geometry_;
@@ -1127,6 +1157,7 @@ void ShellSurfaceBase::CommitWidget() {
UpdateWidgetBounds();
SurfaceTreeHost::UpdateHostWindowBounds();
+ UpdateFrameType();
UpdateShadow();
// System modal container is used by clients to implement overlay
diff --git a/chromium/components/exo/shell_surface_base.h b/chromium/components/exo/shell_surface_base.h
index 652950e3458..cfdec704180 100644
--- a/chromium/components/exo/shell_surface_base.h
+++ b/chromium/components/exo/shell_surface_base.h
@@ -181,6 +181,9 @@ class ShellSurfaceBase : public SurfaceTreeHost,
// aura::WindowObserver:
void OnWindowDestroying(aura::Window* window) override;
+ void OnWindowPropertyChanged(aura::Window* window,
+ const void* key,
+ intptr_t old_value) override;
// wm::ActivationChangeObserver:
void OnWindowActivated(ActivationReason reason,
@@ -218,6 +221,8 @@ class ShellSurfaceBase : public SurfaceTreeHost,
// |shadow_bounds_|.
void UpdateShadow();
+ virtual void UpdateFrameType();
+
// Applies |system_modal_| to |widget_|.
void UpdateSystemModal();
@@ -279,7 +284,7 @@ class ShellSurfaceBase : public SurfaceTreeHost,
// Commit is deferred if this returns false.
virtual bool OnPreWidgetCommit() = 0;
- virtual void OnPostWidgetCommit() = 0;
+ virtual void OnPostWidgetCommit();
void CommitWidget();
diff --git a/chromium/components/exo/shell_surface_unittest.cc b/chromium/components/exo/shell_surface_unittest.cc
index ed22f8fcd02..ecf1502e75a 100644
--- a/chromium/components/exo/shell_surface_unittest.cc
+++ b/chromium/components/exo/shell_surface_unittest.cc
@@ -11,14 +11,11 @@
#include "ash/shell.h"
#include "ash/wm/window_state.h"
#include "ash/wm/wm_event.h"
-#include "ash/wm/workspace/workspace_window_resizer.h"
#include "ash/wm/workspace_controller_test_api.h"
#include "base/bind.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "components/exo/buffer.h"
-#include "components/exo/client_controlled_shell_surface.h"
-#include "components/exo/display.h"
#include "components/exo/permission.h"
#include "components/exo/shell_surface_util.h"
#include "components/exo/sub_surface.h"
@@ -27,6 +24,7 @@
#include "components/exo/test/exo_test_helper.h"
#include "components/exo/wm_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/capture_client.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
@@ -864,42 +862,136 @@ TEST_F(ShellSurfaceTest, Popup) {
sub_popup_surface->Commit();
ASSERT_EQ(gfx::Rect(100, 50, 256, 256),
sub_popup_shell_surface->GetWidget()->GetWindowBoundsInScreen());
-
+ aura::Window* target =
+ sub_popup_shell_surface->GetWidget()->GetNativeWindow();
// The capture should be on sub_popup_shell_surface.
EXPECT_EQ(WMHelper::GetInstance()->GetCaptureClient()->GetCaptureWindow(),
- sub_popup_shell_surface->GetWidget()->GetNativeWindow());
- EXPECT_EQ(aura::client::WINDOW_TYPE_POPUP,
- sub_popup_shell_surface->GetWidget()->GetNativeWindow()->type());
+ target);
+ EXPECT_EQ(aura::client::WINDOW_TYPE_POPUP, target->type());
{
// Mouse is on the top most popup.
ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0),
gfx::Point(100, 50), ui::EventTimeForNow(), 0, 0);
+ ui::Event::DispatcherApi(&event).set_target(target);
EXPECT_EQ(sub_popup_surface.get(), GetTargetSurfaceForLocatedEvent(&event));
}
{
// Move the mouse to the parent popup.
ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(-25, 0),
gfx::Point(75, 50), ui::EventTimeForNow(), 0, 0);
+ ui::Event::DispatcherApi(&event).set_target(target);
EXPECT_EQ(popup_surface.get(), GetTargetSurfaceForLocatedEvent(&event));
}
{
// Move the mouse to the main window.
ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(-25, -25),
gfx::Point(75, 25), ui::EventTimeForNow(), 0, 0);
+ ui::Event::DispatcherApi(&event).set_target(target);
EXPECT_EQ(surface.get(), GetTargetSurfaceForLocatedEvent(&event));
}
// Removing top most popup moves the grab to parent popup.
sub_popup_shell_surface.reset();
+ target = popup_shell_surface->GetWidget()->GetNativeWindow();
EXPECT_EQ(WMHelper::GetInstance()->GetCaptureClient()->GetCaptureWindow(),
- popup_shell_surface->GetWidget()->GetNativeWindow());
+ target);
{
// Targetting should still work.
ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0),
gfx::Point(50, 50), ui::EventTimeForNow(), 0, 0);
+ ui::Event::DispatcherApi(&event).set_target(target);
+ EXPECT_EQ(popup_surface.get(), GetTargetSurfaceForLocatedEvent(&event));
+ }
+}
+
+TEST_F(ShellSurfaceTest, PopupWithInputRegion) {
+ gfx::Size buffer_size(256, 256);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ std::unique_ptr<Surface> surface(new Surface);
+ std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+
+ surface->Attach(buffer.get());
+ surface->SetInputRegion(cc::Region());
+
+ std::unique_ptr<Buffer> child_buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ std::unique_ptr<Surface> child_surface(new Surface);
+ child_surface->Attach(child_buffer.get());
+
+ auto subsurface =
+ std::make_unique<SubSurface>(child_surface.get(), surface.get());
+ subsurface->SetPosition(gfx::Point(10, 10));
+ child_surface->SetInputRegion(cc::Region(gfx::Rect(0, 0, 256, 2560)));
+ child_surface->Commit();
+ surface->Commit();
+ shell_surface->GetWidget()->SetBounds(gfx::Rect(0, 0, 256, 256));
+
+ std::unique_ptr<Buffer> popup_buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ std::unique_ptr<Surface> popup_surface(new Surface);
+ popup_surface->Attach(popup_buffer.get());
+ std::unique_ptr<ShellSurface> popup_shell_surface(CreatePopupShellSurface(
+ popup_surface.get(), shell_surface.get(), gfx::Point(50, 50)));
+ popup_shell_surface->Grab();
+ popup_surface->Commit();
+ ASSERT_EQ(gfx::Rect(50, 50, 256, 256),
+ popup_shell_surface->GetWidget()->GetWindowBoundsInScreen());
+
+ // Verify that created shell surface is popup and has capture.
+ EXPECT_EQ(aura::client::WINDOW_TYPE_POPUP,
+ popup_shell_surface->GetWidget()->GetNativeWindow()->type());
+ EXPECT_EQ(WMHelper::GetInstance()->GetCaptureClient()->GetCaptureWindow(),
+ popup_shell_surface->GetWidget()->GetNativeWindow());
+
+ // Setting frame type on popup should have no effect.
+ popup_surface->SetFrame(SurfaceFrameType::NORMAL);
+ EXPECT_FALSE(popup_shell_surface->frame_enabled());
+
+ aura::Window* target = popup_shell_surface->GetWidget()->GetNativeWindow();
+
+ {
+ // Mouse is on the popup.
+ ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0),
+ gfx::Point(50, 50), ui::EventTimeForNow(), 0, 0);
+ ui::Event::DispatcherApi(&event).set_target(target);
EXPECT_EQ(popup_surface.get(), GetTargetSurfaceForLocatedEvent(&event));
}
+
+ {
+ // If it matches the parent's sub surface, use it.
+ ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(-25, 0),
+ gfx::Point(25, 50), ui::EventTimeForNow(), 0, 0);
+ ui::Event::DispatcherApi(&event).set_target(target);
+ EXPECT_EQ(child_surface.get(), GetTargetSurfaceForLocatedEvent(&event));
+ }
+ {
+ // If it didnt't match any surface in the parent, fallback to
+ // the popup's surface.
+ ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(-50, 0),
+ gfx::Point(0, 50), ui::EventTimeForNow(), 0, 0);
+ ui::Event::DispatcherApi(&event).set_target(target);
+ EXPECT_EQ(popup_surface.get(), GetTargetSurfaceForLocatedEvent(&event));
+ }
+ popup_surface.reset();
+ EXPECT_EQ(WMHelper::GetInstance()->GetCaptureClient()->GetCaptureWindow(),
+ nullptr);
+
+ auto window = std::make_unique<aura::Window>(nullptr);
+ window->Init(ui::LAYER_TEXTURED);
+ window->SetBounds(gfx::Rect(0, 0, 256, 256));
+ shell_surface->GetWidget()->GetNativeWindow()->AddChild(window.get());
+ window->Show();
+
+ {
+ // If non surface window covers the window,
+ /// GetTargetSurfaceForLocatedEvent should return nullptr.
+ ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0),
+ gfx::Point(50, 50), ui::EventTimeForNow(), 0, 0);
+ ui::Event::DispatcherApi(&event).set_target(window.get());
+ EXPECT_EQ(nullptr, GetTargetSurfaceForLocatedEvent(&event));
+ }
}
TEST_F(ShellSurfaceTest, Caption) {
@@ -914,13 +1006,15 @@ TEST_F(ShellSurfaceTest, Caption) {
surface->Commit();
shell_surface->GetWidget()->SetBounds(gfx::Rect(0, 0, 256, 256));
- shell_surface->GetWidget()->GetNativeWindow()->SetCapture();
+ aura::Window* target = shell_surface->GetWidget()->GetNativeWindow();
+ target->SetCapture();
EXPECT_EQ(WMHelper::GetInstance()->GetCaptureClient()->GetCaptureWindow(),
shell_surface->GetWidget()->GetNativeWindow());
{
// Move the mouse at the caption of the captured window.
ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(5, 5), gfx::Point(5, 5),
ui::EventTimeForNow(), 0, 0);
+ ui::Event::DispatcherApi(&event).set_target(target);
EXPECT_EQ(nullptr, GetTargetSurfaceForLocatedEvent(&event));
}
@@ -930,6 +1024,7 @@ TEST_F(ShellSurfaceTest, Caption) {
gfx::Point center = bounds.CenterPoint();
ui::MouseEvent event(ui::ET_MOUSE_MOVED, center - bounds.OffsetFromOrigin(),
center, ui::EventTimeForNow(), 0, 0);
+ ui::Event::DispatcherApi(&event).set_target(target);
EXPECT_EQ(surface.get(), GetTargetSurfaceForLocatedEvent(&event));
}
}
@@ -954,13 +1049,14 @@ TEST_F(ShellSurfaceTest, CaptionWithPopup) {
popup_surface.get(), shell_surface.get(), gfx::Point(50, 50)));
popup_shell_surface->Grab();
popup_surface->Commit();
-
+ aura::Window* target = popup_shell_surface->GetWidget()->GetNativeWindow();
EXPECT_EQ(WMHelper::GetInstance()->GetCaptureClient()->GetCaptureWindow(),
- popup_shell_surface->GetWidget()->GetNativeWindow());
+ target);
{
// Move the mouse at the popup window.
ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(5, 5),
gfx::Point(55, 55), ui::EventTimeForNow(), 0, 0);
+ ui::Event::DispatcherApi(&event).set_target(target);
EXPECT_EQ(popup_surface.get(), GetTargetSurfaceForLocatedEvent(&event));
}
@@ -968,6 +1064,7 @@ TEST_F(ShellSurfaceTest, CaptionWithPopup) {
// Move the mouse at the caption of the main window.
ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(-45, -45),
gfx::Point(5, 5), ui::EventTimeForNow(), 0, 0);
+ ui::Event::DispatcherApi(&event).set_target(target);
EXPECT_EQ(nullptr, GetTargetSurfaceForLocatedEvent(&event));
}
@@ -975,8 +1072,31 @@ TEST_F(ShellSurfaceTest, CaptionWithPopup) {
// Move the mouse in the main window.
ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(-25, 0),
gfx::Point(25, 50), ui::EventTimeForNow(), 0, 0);
+ ui::Event::DispatcherApi(&event).set_target(target);
EXPECT_EQ(surface.get(), GetTargetSurfaceForLocatedEvent(&event));
}
}
+TEST_F(ShellSurfaceTest, SkipImeProcessingPropagateToSurface) {
+ gfx::Size buffer_size(256, 256);
+ auto buffer = std::make_unique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ auto surface = std::make_unique<Surface>();
+ auto shell_surface = std::make_unique<ShellSurface>(surface.get());
+
+ surface->Attach(buffer.get());
+ surface->Commit();
+ shell_surface->GetWidget()->SetBounds(gfx::Rect(0, 0, 256, 256));
+ shell_surface->OnSetFrame(SurfaceFrameType::NORMAL);
+
+ aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
+ ASSERT_FALSE(window->GetProperty(aura::client::kSkipImeProcessing));
+ ASSERT_FALSE(
+ surface->window()->GetProperty(aura::client::kSkipImeProcessing));
+
+ window->SetProperty(aura::client::kSkipImeProcessing, true);
+ EXPECT_TRUE(window->GetProperty(aura::client::kSkipImeProcessing));
+ EXPECT_TRUE(surface->window()->GetProperty(aura::client::kSkipImeProcessing));
+}
+
} // namespace exo
diff --git a/chromium/components/exo/shell_surface_util.cc b/chromium/components/exo/shell_surface_util.cc
index b53d60c62a2..a6a523d83e3 100644
--- a/chromium/components/exo/shell_surface_util.cc
+++ b/chromium/components/exo/shell_surface_util.cc
@@ -17,6 +17,7 @@
#include "ui/aura/client/capture_client.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
+#include "ui/aura/window_targeter.h"
#include "ui/events/event.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/window_util.h"
@@ -57,6 +58,18 @@ bool ShouldHTComponentBlocked(int component) {
}
}
+// Find the lowest targeter in the parent chain.
+aura::WindowTargeter* FindTargeter(ui::EventTarget* target) {
+ do {
+ ui::EventTargeter* targeter = target->GetEventTargeter();
+ if (targeter)
+ return static_cast<aura::WindowTargeter*>(targeter);
+ target = target->GetParentTarget();
+ } while (target);
+
+ return nullptr;
+}
+
} // namespace
void SetShellApplicationId(aura::Window* window,
@@ -130,13 +143,14 @@ ShellSurfaceBase* GetShellSurfaceBaseForWindow(aura::Window* window) {
return static_cast<ShellSurfaceBase*>(widget->widget_delegate());
}
-Surface* GetTargetSurfaceForLocatedEvent(ui::LocatedEvent* event) {
+Surface* GetTargetSurfaceForLocatedEvent(
+ const ui::LocatedEvent* original_event) {
aura::Window* window =
WMHelper::GetInstance()->GetCaptureClient()->GetCaptureWindow();
- gfx::PointF location_in_target_f = event->location_f();
-
- if (!window)
- return Surface::AsSurface(static_cast<aura::Window*>(event->target()));
+ if (!window) {
+ return Surface::AsSurface(
+ static_cast<aura::Window*>(original_event->target()));
+ }
Surface* main_surface = GetShellMainSurface(window);
// Skip if the event is captured by non exo windows.
@@ -148,13 +162,33 @@ Surface* GetTargetSurfaceForLocatedEvent(ui::LocatedEvent* event) {
if (!main_surface)
return nullptr;
}
+ DCHECK_EQ(window, static_cast<aura::Window*>(original_event->target()));
- while (true) {
- gfx::Point location_in_target = gfx::ToFlooredPoint(location_in_target_f);
- aura::Window* focused = window->GetEventHandlerForPoint(location_in_target);
+ // Create a clone of the event as targeter may update it during the
+ // search.
+ auto cloned = ui::Event::Clone(*original_event);
+ ui::LocatedEvent* event = cloned->AsLocatedEvent();
- if (focused)
- return Surface::AsSurface(focused);
+ while (true) {
+ gfx::PointF location_in_target_f = event->location_f();
+ gfx::Point location_in_target = event->location();
+ ui::EventTarget* event_target = window;
+ aura::WindowTargeter* targeter = FindTargeter(event_target);
+ DCHECK(targeter);
+
+ aura::Window* focused =
+ static_cast<aura::Window*>(targeter->FindTargetForEvent(window, event));
+
+ if (focused) {
+ Surface* surface = Surface::AsSurface(focused);
+ if (focused != window)
+ return surface;
+ else if (surface && surface->HitTest(location_in_target)) {
+ // If the targeting fallback to the root (first) window, test the
+ // hit region again.
+ return surface;
+ }
+ }
// If the event falls into the place where the window system should care
// about (i.e. window caption), do not check the transient parent but just
@@ -170,8 +204,8 @@ Surface* GetTargetSurfaceForLocatedEvent(ui::LocatedEvent* event) {
if (!parent_window)
return main_surface;
- aura::Window::ConvertPointToTarget(window, parent_window,
- &location_in_target_f);
+ event->set_location_f(location_in_target_f);
+ event_target->ConvertEventToTarget(parent_window, event);
window = parent_window;
}
}
diff --git a/chromium/components/exo/shell_surface_util.h b/chromium/components/exo/shell_surface_util.h
index ac0a7f94e56..746ffeb4f13 100644
--- a/chromium/components/exo/shell_surface_util.h
+++ b/chromium/components/exo/shell_surface_util.h
@@ -65,7 +65,7 @@ ShellSurfaceBase* GetShellSurfaceBaseForWindow(aura::Window* window);
// event handling is grabbed by an window, it'll first examine that
// window, then traverse to its transient parent if the parent also
// requested grab.
-Surface* GetTargetSurfaceForLocatedEvent(ui::LocatedEvent* event);
+Surface* GetTargetSurfaceForLocatedEvent(const ui::LocatedEvent* event);
// Allow the |window| to activate itself for the diration of |timeout|. Returns
// the permission object, where deleting the object ammounts to Revoke()ing the
diff --git a/chromium/components/exo/sub_surface.cc b/chromium/components/exo/sub_surface.cc
index b18beb319e5..8c81ed507fe 100644
--- a/chromium/components/exo/sub_surface.cc
+++ b/chromium/components/exo/sub_surface.cc
@@ -8,6 +8,7 @@
#include "base/trace_event/trace_event.h"
#include "base/trace_event/traced_value.h"
#include "components/exo/surface.h"
+#include "ui/aura/client/aura_constants.h"
namespace exo {
@@ -113,6 +114,11 @@ bool SubSurface::IsInputEnabled(Surface* surface) const {
return !parent_ || parent_->IsInputEnabled(surface);
}
+void SubSurface::OnSetParent(Surface* parent, const gfx::Point&) {
+ if (parent->window()->GetProperty(aura::client::kSkipImeProcessing))
+ surface_->window()->SetProperty(aura::client::kSkipImeProcessing, true);
+}
+
////////////////////////////////////////////////////////////////////////////////
// SurfaceObserver overrides:
diff --git a/chromium/components/exo/sub_surface.h b/chromium/components/exo/sub_surface.h
index 634de9d81e1..97daeacbc04 100644
--- a/chromium/components/exo/sub_surface.h
+++ b/chromium/components/exo/sub_surface.h
@@ -55,7 +55,7 @@ class SubSurface : public SurfaceDelegate, public SurfaceObserver {
void OnSetFrame(SurfaceFrameType type) override {}
void OnSetFrameColors(SkColor active_color, SkColor inactive_color) override {
}
- void OnSetParent(Surface* parent, const gfx::Point& position) override {}
+ void OnSetParent(Surface* parent, const gfx::Point& position) override;
void OnSetStartupId(const char* startup_id) override {}
void OnSetApplicationId(const char* application_id) override {}
void OnActivationRequested() override {}
diff --git a/chromium/components/exo/sub_surface_unittest.cc b/chromium/components/exo/sub_surface_unittest.cc
index dd18c8c95dc..946008680d4 100644
--- a/chromium/components/exo/sub_surface_unittest.cc
+++ b/chromium/components/exo/sub_surface_unittest.cc
@@ -4,11 +4,13 @@
#include "components/exo/sub_surface.h"
+#include "components/exo/buffer.h"
#include "components/exo/shell_surface.h"
#include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/client/aura_constants.h"
namespace exo {
namespace {
@@ -158,5 +160,25 @@ TEST_F(SubSurfaceTest, SetCommitBehavior) {
grandchild->window()->bounds().origin().ToString());
}
+TEST_F(SubSurfaceTest, SetOnParent) {
+ gfx::Size buffer_size(32, 32);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ auto parent = std::make_unique<Surface>();
+ auto shell_surface = std::make_unique<ShellSurface>(parent.get());
+ parent->Attach(buffer.get());
+ parent->Commit();
+
+ shell_surface->GetWidget()->GetNativeWindow()->SetProperty(
+ aura::client::kSkipImeProcessing, true);
+ ASSERT_TRUE(parent->window()->GetProperty(aura::client::kSkipImeProcessing));
+
+ // SkipImeProcessing property is propagated to SubSurface.
+ auto surface = std::make_unique<Surface>();
+ auto sub_surface = std::make_unique<SubSurface>(surface.get(), parent.get());
+ surface->SetParent(parent.get(), gfx::Point(10, 10));
+ EXPECT_TRUE(surface->window()->GetProperty(aura::client::kSkipImeProcessing));
+}
+
} // namespace
} // namespace exo
diff --git a/chromium/components/exo/surface.cc b/chromium/components/exo/surface.cc
index d9979147092..01fb6a805b7 100644
--- a/chromium/components/exo/surface.cc
+++ b/chromium/components/exo/surface.cc
@@ -221,6 +221,8 @@ const std::string& GetApplicationId(aura::Window* window) {
return empty_app_id;
}
+int surface_id = 0;
+
} // namespace
DEFINE_UI_CLASS_PROPERTY_KEY(int32_t, kClientSurfaceIdKey, 0)
@@ -241,7 +243,7 @@ Surface::Surface()
: window_(
std::make_unique<aura::Window>(new CustomWindowDelegate(this),
aura::client::WINDOW_TYPE_CONTROL)) {
- window_->SetName("ExoSurface");
+ window_->SetName(base::StringPrintf("ExoSurface-%d", surface_id++));
window_->SetProperty(kSurfaceKey, this);
window_->Init(ui::LAYER_NOT_DRAWN);
window_->SetEventTargeter(std::make_unique<CustomWindowTargeter>());
@@ -610,7 +612,8 @@ void Surface::CommitSurfaceHierarchy(bool synchronized) {
state_.only_visible_on_secure_output ||
pending_state_.blend_mode != state_.blend_mode ||
pending_state_.alpha != state_.alpha ||
- pending_state_.color_space != state_.color_space;
+ pending_state_.color_space != state_.color_space ||
+ pending_state_.is_tracking_occlusion != state_.is_tracking_occlusion;
bool needs_update_buffer_transform =
pending_state_.buffer_scale != state_.buffer_scale ||
@@ -638,6 +641,13 @@ void Surface::CommitSurfaceHierarchy(bool synchronized) {
? aura::EventTargetingPolicy::kDescendantsOnly
: aura::EventTargetingPolicy::kTargetAndDescendants);
+ if (state_.is_tracking_occlusion) {
+ // TODO(edcourtney): Currently, it doesn't seem to be possible to stop
+ // tracking the occlusion state once started, but it would be nice to stop
+ // if the tracked occlusion region becomes empty.
+ window_->TrackOcclusionState();
+ }
+
#if defined(OS_CHROMEOS)
if (needs_output_protection) {
if (!output_protection_) {
@@ -859,12 +869,11 @@ bool Surface::FillsBoundsOpaquely() const {
}
void Surface::SetOcclusionTracking(bool tracking) {
- is_tracking_occlusion_ = tracking;
- // TODO(edcourtney): Currently, it doesn't seem to be possible to stop
- // tracking the occlusion state once started, but it would be nice to stop if
- // the tracked occlusion region becomes empty.
- if (is_tracking_occlusion_)
- window()->TrackOcclusionState();
+ pending_state_.is_tracking_occlusion = tracking;
+}
+
+bool Surface::IsTrackingOcclusion() {
+ return state_.is_tracking_occlusion;
}
void Surface::SetSurfaceHierarchyContentBoundsForTest(
@@ -999,6 +1008,7 @@ void Surface::AppendContentsToFrame(const gfx::Point& origin,
render_pass->damage_rect.Union(
gfx::ConvertRectToPixel(device_scale_factor, damage_rect));
}
+ damage_.Clear();
gfx::PointF scale(content_size_.width(), content_size_.height());
@@ -1157,7 +1167,7 @@ void Surface::UpdateContentSize() {
}
void Surface::OnWindowOcclusionChanged() {
- if (!is_tracking_occlusion_)
+ if (!state_.is_tracking_occlusion)
return;
for (SurfaceObserver& observer : observers_)
diff --git a/chromium/components/exo/surface.h b/chromium/components/exo/surface.h
index b49e8e9315d..d8a944af11f 100644
--- a/chromium/components/exo/surface.h
+++ b/chromium/components/exo/surface.h
@@ -281,7 +281,7 @@ class Surface final : public ui::PropertyHandler {
void OnWindowOcclusionChanged();
// True if the window for this surface has its occlusion tracked.
- bool is_tracking_occlusion() const { return is_tracking_occlusion_; }
+ bool IsTrackingOcclusion();
// Sets the |surface_hierarchy_content_bounds_|.
void SetSurfaceHierarchyContentBoundsForTest(const gfx::Rect& content_bounds);
@@ -309,6 +309,7 @@ class Surface final : public ui::PropertyHandler {
float alpha = 1.0f;
gfx::Vector2d offset;
gfx::ColorSpace color_space;
+ bool is_tracking_occlusion = false;
};
class BufferAttachment {
public:
@@ -451,9 +452,6 @@ class Surface final : public ui::PropertyHandler {
// Surface observer list. Surface does not own the observers.
base::ObserverList<SurfaceObserver, true>::Unchecked observers_;
- // Whether this surface is tracking occlusion for the client.
- bool is_tracking_occlusion_ = false;
-
#if defined(OS_CHROMEOS)
std::unique_ptr<ash::OutputProtectionDelegate> output_protection_;
#endif // defined(OS_CHROMEOS)
diff --git a/chromium/components/exo/surface_unittest.cc b/chromium/components/exo/surface_unittest.cc
index 680135e1159..9cdb9565cfc 100644
--- a/chromium/components/exo/surface_unittest.cc
+++ b/chromium/components/exo/surface_unittest.cc
@@ -190,6 +190,69 @@ TEST_P(SurfaceTest, Damage) {
}
}
+TEST_P(SurfaceTest, SubsurfaceDamageAggregation) {
+ gfx::Size buffer_size(256, 512);
+ auto buffer = std::make_unique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ auto surface = std::make_unique<Surface>();
+ auto shell_surface = std::make_unique<ShellSurface>(surface.get());
+ surface->Attach(buffer.get());
+
+ gfx::Size child_buffer_size(64, 128);
+ auto child_buffer = std::make_unique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(child_buffer_size));
+ auto child_surface = std::make_unique<Surface>();
+ auto sub_surface =
+ std::make_unique<SubSurface>(child_surface.get(), surface.get());
+ child_surface->Attach(child_buffer.get());
+ child_surface->Commit();
+ surface->Commit();
+ base::RunLoop().RunUntilIdle();
+
+ {
+ // Initial frame has full damage.
+ const viz::CompositorFrame& frame =
+ GetFrameFromSurface(shell_surface.get());
+ const gfx::Rect scaled_damage = gfx::ToNearestRect(gfx::ScaleRect(
+ gfx::RectF(gfx::Rect(buffer_size)), device_scale_factor()));
+ EXPECT_EQ(scaled_damage, frame.render_pass_list.back()->damage_rect);
+ }
+
+ const gfx::RectF surface_damage(16, 16);
+ const gfx::RectF subsurface_damage(32, 32, 16, 16);
+ int margin = ceil(device_scale_factor());
+
+ child_surface->Damage(gfx::ToNearestRect(subsurface_damage));
+ child_surface->Commit();
+ surface->Commit();
+ base::RunLoop().RunUntilIdle();
+
+ {
+ // Subsurface damage should be propagated.
+ const viz::CompositorFrame& frame =
+ GetFrameFromSurface(shell_surface.get());
+ const gfx::Rect scaled_damage = gfx::ToNearestRect(
+ gfx::ScaleRect(subsurface_damage, device_scale_factor()));
+ EXPECT_TRUE(scaled_damage.ApproximatelyEqual(
+ frame.render_pass_list.back()->damage_rect, margin));
+ }
+
+ surface->Damage(gfx::ToNearestRect(surface_damage));
+ surface->Commit();
+ base::RunLoop().RunUntilIdle();
+
+ {
+ // When commit is called on the root with no call on the child, the damage
+ // from the previous frame shouldn't persist.
+ const viz::CompositorFrame& frame =
+ GetFrameFromSurface(shell_surface.get());
+ const gfx::Rect scaled_damage = gfx::ToNearestRect(
+ gfx::ScaleRect(surface_damage, device_scale_factor()));
+ EXPECT_TRUE(scaled_damage.ApproximatelyEqual(
+ frame.render_pass_list.back()->damage_rect, margin));
+ }
+}
+
void SetFrameTime(base::TimeTicks* result, base::TimeTicks frame_time) {
*result = frame_time;
}
@@ -1102,11 +1165,11 @@ TEST_P(SurfaceTest, UpdatesOcclusionOnDestroyingSubsurface) {
auto sub_surface =
std::make_unique<SubSurface>(child_surface.get(), surface.get());
child_surface->Attach(child_buffer.get());
+ // Turn on occlusion tracking.
+ child_surface->SetOcclusionTracking(true);
child_surface->Commit();
surface->Commit();
- // Turn on occlusion tracking.
- child_surface->SetOcclusionTracking(true);
SurfaceObserverForTest observer;
ScopedSurface scoped_child_surface(child_surface.get(), &observer);
diff --git a/chromium/components/exo/text_input.cc b/chromium/components/exo/text_input.cc
index d004a1f8cd3..370a77ee995 100644
--- a/chromium/components/exo/text_input.cc
+++ b/chromium/components/exo/text_input.cc
@@ -324,6 +324,13 @@ bool TextInput::SetCompositionFromExistingText(
return false;
}
+// TODO(crbug.com/1091088) Implement setAutocorrectRange
+bool TextInput::SetAutocorrectRange(const base::string16& autocorrect_text,
+ const gfx::Range& range) {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
void TextInput::OnKeyboardVisibilityChanged(bool is_visible) {
delegate_->OnVirtualKeyboardVisibilityChanged(is_visible);
}
diff --git a/chromium/components/exo/text_input.h b/chromium/components/exo/text_input.h
index e3f89fdd81a..f463cfd298d 100644
--- a/chromium/components/exo/text_input.h
+++ b/chromium/components/exo/text_input.h
@@ -140,6 +140,8 @@ class TextInput : public ui::TextInputClient,
bool SetCompositionFromExistingText(
const gfx::Range& range,
const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override;
+ bool SetAutocorrectRange(const base::string16& autocorrect_text,
+ const gfx::Range& range) override;
// ash::KeyboardControllerObserver:
void OnKeyboardVisibilityChanged(bool is_visible) override;
diff --git a/chromium/components/exo/touch.cc b/chromium/components/exo/touch.cc
index b59b11efca2..c1dc6b3ad6e 100644
--- a/chromium/components/exo/touch.cc
+++ b/chromium/components/exo/touch.cc
@@ -60,6 +60,8 @@ bool Touch::HasStylusDelegate() const {
// ui::EventHandler overrides:
void Touch::OnTouchEvent(ui::TouchEvent* event) {
+ seat_->SetLastLocation(event->root_location());
+
bool send_details = false;
const int touch_pointer_id = event->pointer_details().id;
diff --git a/chromium/components/exo/wayland/BUILD.gn b/chromium/components/exo/wayland/BUILD.gn
index 28c660133d4..6800a87c54d 100644
--- a/chromium/components/exo/wayland/BUILD.gn
+++ b/chromium/components/exo/wayland/BUILD.gn
@@ -36,7 +36,6 @@ source_set("wayland") {
"wayland_touch_delegate.cc",
"wayland_touch_delegate.h",
"wayland_watcher.cc",
- "wayland_watcher.h",
"wl_compositor.cc",
"wl_compositor.h",
"wl_data_device_manager.cc",
@@ -120,10 +119,12 @@ source_set("wayland") {
deps += [
"//build/config/linux/libdrm",
"//third_party/wayland-protocols:linux_dmabuf_protocol",
+ "//ui/ozone",
]
if (is_chromeos) {
deps += [
+ "//ash",
"//ash/public/cpp",
"//ui/events/ozone/layout",
]
@@ -152,6 +153,8 @@ source_set("wayland") {
"wayland_positioner.h",
"wl_shell.cc",
"wl_shell.h",
+ "xdg_shell.cc",
+ "xdg_shell.h",
"zcr_color_space.cc",
"zcr_color_space.h",
"zcr_cursor_shapes.cc",
diff --git a/chromium/components/exo/wayland/DEPS b/chromium/components/exo/wayland/DEPS
index 33a9ebc4583..074321a0083 100644
--- a/chromium/components/exo/wayland/DEPS
+++ b/chromium/components/exo/wayland/DEPS
@@ -1,4 +1,5 @@
include_rules = [
"+services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h",
"+third_party/wayland/include",
+ "+ui/ozone/public",
]
diff --git a/chromium/components/exo/wayland/clients/blur.cc b/chromium/components/exo/wayland/clients/blur.cc
index 4b37d4db4d3..e30e562cd8a 100644
--- a/chromium/components/exo/wayland/clients/blur.cc
+++ b/chromium/components/exo/wayland/clients/blur.cc
@@ -215,7 +215,7 @@ void Blur::Run(double sigma_x,
}
if (gr_context_) {
- gr_context_->flush();
+ gr_context_->flushAndSubmit();
glFinish();
}
diff --git a/chromium/components/exo/wayland/clients/blur_main.cc b/chromium/components/exo/wayland/clients/blur_main.cc
index 477041346cd..f1718f8dfe6 100644
--- a/chromium/components/exo/wayland/clients/blur_main.cc
+++ b/chromium/components/exo/wayland/clients/blur_main.cc
@@ -8,6 +8,7 @@
#include "base/at_exit.h"
#include "base/command_line.h"
+#include "base/logging.h"
#include "base/message_loop/message_pump_type.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/single_thread_task_executor.h"
diff --git a/chromium/components/exo/wayland/clients/client_base.cc b/chromium/components/exo/wayland/clients/client_base.cc
index e2f0dd9ac27..95323b80b57 100644
--- a/chromium/components/exo/wayland/clients/client_base.cc
+++ b/chromium/components/exo/wayland/clients/client_base.cc
@@ -968,7 +968,7 @@ std::unique_ptr<ClientBase::Buffer> ClientBase::CreateDrmBuffer(
texture_info.fFormat = kSizedInternalFormat;
GrBackendTexture backend_texture(size.width(), size.height(),
GrMipMapped::kNo, texture_info);
- buffer->sk_surface = SkSurface::MakeFromBackendTextureAsRenderTarget(
+ buffer->sk_surface = SkSurface::MakeFromBackendTexture(
gr_context_.get(), backend_texture, kTopLeft_GrSurfaceOrigin,
/* sampleCnt */ 0, kColorType, /* colorSpace */ nullptr,
/* props */ nullptr);
diff --git a/chromium/components/exo/wayland/clients/color_space.cc b/chromium/components/exo/wayland/clients/color_space.cc
index 6e366d84a06..27931638ef4 100644
--- a/chromium/components/exo/wayland/clients/color_space.cc
+++ b/chromium/components/exo/wayland/clients/color_space.cc
@@ -11,6 +11,7 @@
#include "base/at_exit.h"
#include "base/command_line.h"
+#include "base/logging.h"
#include "base/message_loop/message_pump_type.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
diff --git a/chromium/components/exo/wayland/clients/explicit_synchronization.cc b/chromium/components/exo/wayland/clients/explicit_synchronization.cc
index cc346d2c231..a54d2cc0f94 100644
--- a/chromium/components/exo/wayland/clients/explicit_synchronization.cc
+++ b/chromium/components/exo/wayland/clients/explicit_synchronization.cc
@@ -88,7 +88,7 @@ void ExplicitSynchronizationClient::Run() {
.toSkColor());
// Create an EGLSyncKHR object to signal when rendering is done.
- gr_context_->flush();
+ gr_context_->flushAndSubmit();
buffer->egl_sync.reset(new ScopedEglSync(
eglCreateSyncKHR(eglGetCurrentDisplay(), egl_sync_type_, nullptr)));
DCHECK(buffer->egl_sync->is_valid());
diff --git a/chromium/components/exo/wayland/clients/fullscreen_shell.cc b/chromium/components/exo/wayland/clients/fullscreen_shell.cc
index 19024dafae2..59a5a76022e 100644
--- a/chromium/components/exo/wayland/clients/fullscreen_shell.cc
+++ b/chromium/components/exo/wayland/clients/fullscreen_shell.cc
@@ -112,7 +112,7 @@ void FullscreenClient::Paint(const wl_callback_listener& frame_listener) {
canvas->drawRect(rect, paint);
if (gr_context_) {
- gr_context_->flush();
+ gr_context_->flushAndSubmit();
glFinish();
}
diff --git a/chromium/components/exo/wayland/clients/rects.cc b/chromium/components/exo/wayland/clients/rects.cc
index d4d101cc03d..8f34046b6b9 100644
--- a/chromium/components/exo/wayland/clients/rects.cc
+++ b/chromium/components/exo/wayland/clients/rects.cc
@@ -438,7 +438,7 @@ int RectsClient::Run(const ClientBase::InitParams& params,
}
GrContext* gr_context = gr_context_.get();
if (gr_context) {
- gr_context->flush();
+ gr_context->flushAndSubmit();
#if defined(USE_GBM)
if (egl_sync_type_) {
diff --git a/chromium/components/exo/wayland/clients/simple.cc b/chromium/components/exo/wayland/clients/simple.cc
index 1a517247ca2..37015530eb2 100644
--- a/chromium/components/exo/wayland/clients/simple.cc
+++ b/chromium/components/exo/wayland/clients/simple.cc
@@ -140,7 +140,7 @@ void Simple::Run(int frames,
canvas->clear(kColors[++frame_count % base::size(kColors)]);
if (gr_context_) {
- gr_context_->flush();
+ gr_context_->flushAndSubmit();
glFinish();
}
diff --git a/chromium/components/exo/wayland/clients/subsurface.cc b/chromium/components/exo/wayland/clients/subsurface.cc
index 0ef02b65bc0..41afd463c22 100644
--- a/chromium/components/exo/wayland/clients/subsurface.cc
+++ b/chromium/components/exo/wayland/clients/subsurface.cc
@@ -98,7 +98,7 @@ void SubSurfaceClient::Run(const ClientBase::InitParams& params) {
canvas->drawIRect(rect, paint);
canvas->restore();
if (gr_context_) {
- gr_context_->flush();
+ gr_context_->flushAndSubmit();
glFinish();
}
wl_surface_damage(child_surface.get(), 0, 0, kSubsurfaceWidth,
@@ -114,7 +114,7 @@ void SubSurfaceClient::Run(const ClientBase::InitParams& params) {
static const SkColor kColors[] = {SK_ColorRED, SK_ColorBLACK};
canvas->clear(kColors[frame_count % base::size(kColors)]);
if (gr_context_) {
- gr_context_->flush();
+ gr_context_->flushAndSubmit();
glFinish();
}
wl_surface_set_buffer_scale(surface_.get(), scale_);
diff --git a/chromium/components/exo/wayland/clients/yuv.cc b/chromium/components/exo/wayland/clients/yuv.cc
index 026c8091448..e626a58f129 100644
--- a/chromium/components/exo/wayland/clients/yuv.cc
+++ b/chromium/components/exo/wayland/clients/yuv.cc
@@ -9,6 +9,7 @@
#include "base/at_exit.h"
#include "base/command_line.h"
+#include "base/logging.h"
#include "base/message_loop/message_pump_type.h"
#include "base/task/single_thread_task_executor.h"
#include "components/exo/wayland/clients/client_base.h"
diff --git a/chromium/components/exo/wayland/server.cc b/chromium/components/exo/wayland/server.cc
index 281e49f7876..7aadc0b13fc 100644
--- a/chromium/components/exo/wayland/server.cc
+++ b/chromium/components/exo/wayland/server.cc
@@ -28,6 +28,7 @@
#include <vsync-feedback-unstable-v1-server-protocol.h>
#include <wayland-server-core.h>
#include <wayland-server-protocol-core.h>
+#include <xdg-shell-server-protocol.h>
#include <xdg-shell-unstable-v6-server-protocol.h>
#include <memory>
@@ -60,6 +61,7 @@
#if defined(OS_CHROMEOS)
#include "components/exo/wayland/wl_shell.h"
+#include "components/exo/wayland/xdg_shell.h"
#include "components/exo/wayland/zcr_color_space.h"
#include "components/exo/wayland/zcr_cursor_shapes.h"
#include "components/exo/wayland/zcr_gaming_input.h"
@@ -79,6 +81,7 @@
#if defined(USE_OZONE)
#include <linux-dmabuf-unstable-v1-server-protocol.h>
#include "components/exo/wayland/zwp_linux_dmabuf.h"
+#include "ui/ozone/public/ozone_platform.h"
#endif
#if defined(USE_FULLSCREEN_SHELL)
@@ -104,6 +107,18 @@ const base::FilePath::CharType kSocketName[] = FILE_PATH_LITERAL("wayland-0");
// Group used for wayland socket.
const char kWaylandSocketGroup[] = "wayland";
+bool IsDrmAtomicAvailable() {
+#if defined(USE_OZONE)
+ auto& host_properties =
+ ui::OzonePlatform::GetInstance()->GetInitializedHostProperties();
+ return host_properties.supports_overlays;
+#else
+ LOG(WARNING) << "Ozone disabled, cannot determine whether DrmAtomic is "
+ "present. Assuming it is not";
+ return false;
+#endif
+}
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -150,9 +165,14 @@ Server::Server(Display* display)
wl_global_create(wl_display_.get(), &wl_seat_interface, kWlSeatVersion,
seat_data_.get(), bind_seat);
- wl_global_create(wl_display_.get(),
- &zwp_linux_explicit_synchronization_v1_interface, 1,
- display_, bind_linux_explicit_synchronization);
+ if (IsDrmAtomicAvailable()) {
+ // The release fence needed by linux-explicit-sync comes from DRM-atomic.
+ // If DRM atomic is not supported, linux-explicit-sync interface is
+ // disabled.
+ wl_global_create(wl_display_.get(),
+ &zwp_linux_explicit_synchronization_v1_interface, 1,
+ display_, bind_linux_explicit_synchronization);
+ }
wl_global_create(wl_display_.get(), &zaura_shell_interface,
kZAuraShellVersion, display_, bind_aura_shell);
#if defined(OS_CHROMEOS)
@@ -192,10 +212,15 @@ Server::Server(Display* display)
wl_global_create(wl_display_.get(), &zwp_text_input_manager_v1_interface, 1,
zwp_text_manager_data_.get(), bind_text_input_manager);
+ zxdg_shell_data_ =
+ std::make_unique<WaylandZxdgShell>(display_, serial_tracker_.get());
+ wl_global_create(wl_display_.get(), &zxdg_shell_v6_interface, 1,
+ zxdg_shell_data_.get(), bind_zxdg_shell_v6);
+
xdg_shell_data_ =
std::make_unique<WaylandXdgShell>(display_, serial_tracker_.get());
- wl_global_create(wl_display_.get(), &zxdg_shell_v6_interface, 1,
- xdg_shell_data_.get(), bind_xdg_shell_v6);
+ wl_global_create(wl_display_.get(), &xdg_wm_base_interface, 1,
+ xdg_shell_data_.get(), bind_xdg_shell);
#endif
#if defined(USE_FULLSCREEN_SHELL)
diff --git a/chromium/components/exo/wayland/server.h b/chromium/components/exo/wayland/server.h
index 3f36907b9af..971164e2e00 100644
--- a/chromium/components/exo/wayland/server.h
+++ b/chromium/components/exo/wayland/server.h
@@ -25,6 +25,7 @@ class WaylandDisplayOutput;
struct WaylandSeat;
struct WaylandTextInputManager;
struct WaylandXdgShell;
+struct WaylandZxdgShell;
// This class is a thin wrapper around a Wayland display server. All Wayland
// requests are dispatched into the given Exosphere display.
@@ -67,6 +68,7 @@ class Server : public display::DisplayObserver {
#if defined(OS_CHROMEOS)
std::unique_ptr<WaylandTextInputManager> zwp_text_manager_data_;
+ std::unique_ptr<WaylandZxdgShell> zxdg_shell_data_;
std::unique_ptr<WaylandXdgShell> xdg_shell_data_;
#endif
diff --git a/chromium/components/exo/wayland/wayland_display_observer.cc b/chromium/components/exo/wayland/wayland_display_observer.cc
index 850781e00e2..6633ddf7c17 100644
--- a/chromium/components/exo/wayland/wayland_display_observer.cc
+++ b/chromium/components/exo/wayland/wayland_display_observer.cc
@@ -8,6 +8,7 @@
#include <string>
+#include "components/exo/wayland/wayland_display_output.h"
#include "components/exo/wm_helper.h"
#include "ui/display/manager/managed_display_info.h"
#include "ui/display/screen.h"
@@ -15,14 +16,16 @@
namespace exo {
namespace wayland {
-WaylandDisplayObserver::WaylandDisplayObserver(int64_t id,
+WaylandDisplayObserver::WaylandDisplayObserver(WaylandDisplayOutput* output,
wl_resource* output_resource)
- : id_(id), output_resource_(output_resource) {
+ : output_(output), output_resource_(output_resource) {
+ output_->RegisterOutput(output_resource_);
display::Screen::GetScreen()->AddObserver(this);
SendDisplayMetrics();
}
WaylandDisplayObserver::~WaylandDisplayObserver() {
+ output_->UnregisterOutput(output_resource_);
display::Screen::GetScreen()->RemoveObserver(this);
}
@@ -39,7 +42,7 @@ bool WaylandDisplayObserver::HasScaleObserver() const {
void WaylandDisplayObserver::OnDisplayMetricsChanged(
const display::Display& display,
uint32_t changed_metrics) {
- if (id_ != display.id())
+ if (output_->id() != display.id())
return;
// There is no need to check DISPLAY_METRIC_PRIMARY because when primary
@@ -59,8 +62,8 @@ void WaylandDisplayObserver::OnDisplayMetricsChanged(
void WaylandDisplayObserver::SendDisplayMetrics() {
display::Display display;
- bool rv =
- display::Screen::GetScreen()->GetDisplayWithDisplayId(id_, &display);
+ bool rv = display::Screen::GetScreen()->GetDisplayWithDisplayId(output_->id(),
+ &display);
DCHECK(rv);
const display::ManagedDisplayInfo& info =
diff --git a/chromium/components/exo/wayland/wayland_display_observer.h b/chromium/components/exo/wayland/wayland_display_observer.h
index 9bd126651f6..fcd67650b11 100644
--- a/chromium/components/exo/wayland/wayland_display_observer.h
+++ b/chromium/components/exo/wayland/wayland_display_observer.h
@@ -15,6 +15,7 @@ struct wl_resource;
namespace exo {
namespace wayland {
+class WaylandDisplayOutput;
class WaylandDisplayObserver : public display::DisplayObserver {
public:
@@ -28,7 +29,8 @@ class WaylandDisplayObserver : public display::DisplayObserver {
virtual ~ScaleObserver() {}
};
- WaylandDisplayObserver(int64_t id, wl_resource* output_resource);
+ WaylandDisplayObserver(WaylandDisplayOutput* output,
+ wl_resource* output_resource);
~WaylandDisplayObserver() override;
void SetScaleObserver(base::WeakPtr<ScaleObserver> scale_observer);
bool HasScaleObserver() const;
@@ -43,8 +45,8 @@ class WaylandDisplayObserver : public display::DisplayObserver {
// compensate for the rotation of an output device.
wl_output_transform OutputTransform(display::Display::Rotation rotation);
- // The ID of the display being observed.
- const int64_t id_;
+ // Output.
+ WaylandDisplayOutput* output_;
// The output resource associated with the display.
wl_resource* const output_resource_;
diff --git a/chromium/components/exo/wayland/wayland_display_output.cc b/chromium/components/exo/wayland/wayland_display_output.cc
index 6d451f4d6c0..560cf5a08c5 100644
--- a/chromium/components/exo/wayland/wayland_display_output.cc
+++ b/chromium/components/exo/wayland/wayland_display_output.cc
@@ -7,12 +7,22 @@
#include <wayland-server-core.h>
#include <wayland-server-protocol-core.h>
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "components/exo/surface.h"
+#include "components/exo/wayland/server_util.h"
+
namespace exo {
namespace wayland {
WaylandDisplayOutput::WaylandDisplayOutput(int64_t id) : id_(id) {}
WaylandDisplayOutput::~WaylandDisplayOutput() {
+ // Empty the output_ids_ so that Unregister will be no op.
+ auto ids = std::move(output_ids_);
+ for (auto pair : ids)
+ wl_resource_destroy(pair.second);
+
if (global_)
wl_global_destroy(global_);
}
@@ -25,5 +35,24 @@ void WaylandDisplayOutput::set_global(wl_global* global) {
global_ = global;
}
+void WaylandDisplayOutput::UnregisterOutput(wl_resource* output_resource) {
+ base::EraseIf(output_ids_, [output_resource](auto& pair) {
+ return pair.second == output_resource;
+ });
+}
+
+void WaylandDisplayOutput::RegisterOutput(wl_resource* output_resource) {
+ auto* client = wl_resource_get_client(output_resource);
+ output_ids_.insert(std::make_pair(client, output_resource));
+}
+
+wl_resource* WaylandDisplayOutput::GetOutputResourceForClient(
+ wl_client* client) {
+ auto iter = output_ids_.find(client);
+ if (iter == output_ids_.end())
+ return nullptr;
+ return iter->second;
+}
+
} // namespace wayland
} // namespace exo
diff --git a/chromium/components/exo/wayland/wayland_display_output.h b/chromium/components/exo/wayland/wayland_display_output.h
index 711fef685f1..eeae307b040 100644
--- a/chromium/components/exo/wayland/wayland_display_output.h
+++ b/chromium/components/exo/wayland/wayland_display_output.h
@@ -7,9 +7,12 @@
#include <stdint.h>
+#include "base/containers/flat_map.h"
#include "base/macros.h"
+struct wl_client;
struct wl_global;
+struct wl_resource;
namespace exo {
namespace wayland {
@@ -18,15 +21,23 @@ namespace wayland {
// and associated with a global.
class WaylandDisplayOutput {
public:
- explicit WaylandDisplayOutput(int64_t id);
+ explicit WaylandDisplayOutput(int64_t display_id);
~WaylandDisplayOutput();
int64_t id() const;
void set_global(wl_global* global);
+ // Register/Unregister output resources, which will be used to
+ // notify surface when enter/leave the output.
+ void UnregisterOutput(wl_resource* output_resource);
+ void RegisterOutput(wl_resource* output_resource);
+
+ wl_resource* GetOutputResourceForClient(wl_client* client);
+
private:
const int64_t id_;
wl_global* global_ = nullptr;
+ base::flat_map<wl_client*, wl_resource*> output_ids_;
DISALLOW_COPY_AND_ASSIGN(WaylandDisplayOutput);
};
diff --git a/chromium/components/exo/wayland/wayland_positioner.cc b/chromium/components/exo/wayland/wayland_positioner.cc
index 625fad4a5e8..65b9ec694e0 100644
--- a/chromium/components/exo/wayland/wayland_positioner.cc
+++ b/chromium/components/exo/wayland/wayland_positioner.cc
@@ -4,28 +4,129 @@
#include "components/exo/wayland/wayland_positioner.h"
+#include <xdg-shell-unstable-v6-server-protocol.h>
+
namespace exo {
namespace wayland {
namespace {
-// Represents the 1-dimensional projection of the gravity/anchor values.
-enum Direction { kNegative = -1, kNeutral = 0, kPositive = 1 };
+std::pair<WaylandPositioner::Direction, WaylandPositioner::Direction>
+DecomposeUnstableAnchor(uint32_t anchor) {
+ WaylandPositioner::Direction x, y;
+
+ if (anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) {
+ x = WaylandPositioner::Direction::kNegative;
+ } else if (anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT) {
+ x = WaylandPositioner::Direction::kPositive;
+ } else {
+ x = WaylandPositioner::Direction::kNeutral;
+ }
+
+ if (anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP) {
+ y = WaylandPositioner::Direction::kNegative;
+ } else if (anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM) {
+ y = WaylandPositioner::Direction::kPositive;
+ } else {
+ y = WaylandPositioner::Direction::kNeutral;
+ }
+
+ return std::make_pair(x, y);
+}
+
+std::pair<WaylandPositioner::Direction, WaylandPositioner::Direction>
+DecomposeStableAnchor(uint32_t anchor) {
+ switch (anchor) {
+ default:
+ case XDG_POSITIONER_ANCHOR_NONE:
+ return std::make_pair(WaylandPositioner::Direction::kNeutral,
+ WaylandPositioner::Direction::kNeutral);
+ case XDG_POSITIONER_ANCHOR_TOP:
+ return std::make_pair(WaylandPositioner::Direction::kNeutral,
+ WaylandPositioner::Direction::kNegative);
+ case XDG_POSITIONER_ANCHOR_BOTTOM:
+ return std::make_pair(WaylandPositioner::Direction::kNeutral,
+ WaylandPositioner::Direction::kPositive);
+ case XDG_POSITIONER_ANCHOR_LEFT:
+ return std::make_pair(WaylandPositioner::Direction::kNegative,
+ WaylandPositioner::Direction::kNeutral);
+ case XDG_POSITIONER_ANCHOR_RIGHT:
+ return std::make_pair(WaylandPositioner::Direction::kPositive,
+ WaylandPositioner::Direction::kNeutral);
+ case XDG_POSITIONER_ANCHOR_TOP_LEFT:
+ return std::make_pair(WaylandPositioner::Direction::kNegative,
+ WaylandPositioner::Direction::kNegative);
+ case XDG_POSITIONER_ANCHOR_TOP_RIGHT:
+ return std::make_pair(WaylandPositioner::Direction::kPositive,
+ WaylandPositioner::Direction::kNegative);
+ case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT:
+ return std::make_pair(WaylandPositioner::Direction::kNegative,
+ WaylandPositioner::Direction::kPositive);
+ case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT:
+ return std::make_pair(WaylandPositioner::Direction::kPositive,
+ WaylandPositioner::Direction::kPositive);
+ }
+}
+
+std::pair<WaylandPositioner::Direction, WaylandPositioner::Direction>
+DecomposeUnstableGravity(uint32_t gravity) {
+ WaylandPositioner::Direction x, y;
+
+ if (gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT) {
+ x = WaylandPositioner::Direction::kNegative;
+ } else if (gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT) {
+ x = WaylandPositioner::Direction::kPositive;
+ } else {
+ x = WaylandPositioner::Direction::kNeutral;
+ }
+
+ if (gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) {
+ y = WaylandPositioner::Direction::kNegative;
+ } else if (gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM) {
+ y = WaylandPositioner::Direction::kPositive;
+ } else {
+ y = WaylandPositioner::Direction::kNeutral;
+ }
-static Direction Flip(Direction d) {
- return (Direction)-d;
+ return std::make_pair(x, y);
+}
+
+std::pair<WaylandPositioner::Direction, WaylandPositioner::Direction>
+DecomposeStableGravity(uint32_t gravity) {
+ switch (gravity) {
+ default:
+ case XDG_POSITIONER_GRAVITY_NONE:
+ return std::make_pair(WaylandPositioner::Direction::kNeutral,
+ WaylandPositioner::Direction::kNeutral);
+ case XDG_POSITIONER_GRAVITY_TOP:
+ return std::make_pair(WaylandPositioner::Direction::kNeutral,
+ WaylandPositioner::Direction::kNegative);
+ case XDG_POSITIONER_GRAVITY_BOTTOM:
+ return std::make_pair(WaylandPositioner::Direction::kNeutral,
+ WaylandPositioner::Direction::kPositive);
+ case XDG_POSITIONER_GRAVITY_LEFT:
+ return std::make_pair(WaylandPositioner::Direction::kNegative,
+ WaylandPositioner::Direction::kNeutral);
+ case XDG_POSITIONER_GRAVITY_RIGHT:
+ return std::make_pair(WaylandPositioner::Direction::kPositive,
+ WaylandPositioner::Direction::kNeutral);
+ case XDG_POSITIONER_GRAVITY_TOP_LEFT:
+ return std::make_pair(WaylandPositioner::Direction::kNegative,
+ WaylandPositioner::Direction::kNegative);
+ case XDG_POSITIONER_GRAVITY_TOP_RIGHT:
+ return std::make_pair(WaylandPositioner::Direction::kPositive,
+ WaylandPositioner::Direction::kNegative);
+ case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT:
+ return std::make_pair(WaylandPositioner::Direction::kNegative,
+ WaylandPositioner::Direction::kPositive);
+ case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT:
+ return std::make_pair(WaylandPositioner::Direction::kPositive,
+ WaylandPositioner::Direction::kPositive);
+ }
}
-// Decodes a masked anchor/gravity bitfield to the direction.
-Direction MaskToDirection(uint32_t field,
- uint32_t negative_mask,
- uint32_t positive_mask) {
- DCHECK(!((field & negative_mask) && (field & positive_mask)));
- if (field & negative_mask)
- return kNegative;
- if (field & positive_mask)
- return kPositive;
- return kNeutral;
+static WaylandPositioner::Direction Flip(WaylandPositioner::Direction d) {
+ return (WaylandPositioner::Direction)-d;
}
// Represents the possible/actual positioner adjustments for this window.
@@ -63,8 +164,8 @@ Range1D Calculate(const ConstraintAdjustment& adjustments,
Range1D anchor_range,
uint32_t size,
int32_t offset,
- Direction anchor,
- Direction gravity) {
+ WaylandPositioner::Direction anchor,
+ WaylandPositioner::Direction gravity) {
if (adjustments.flip) {
return Calculate({/*flip=*/false, adjustments.slide, adjustments.resize},
work_size, anchor_range, size, -offset, Flip(anchor),
@@ -91,25 +192,25 @@ Range1D Calculate(const ConstraintAdjustment& adjustments,
int32_t start = offset;
switch (anchor) {
- case Direction::kNegative:
+ case WaylandPositioner::Direction::kNegative:
start += anchor_range.start;
break;
- case Direction::kNeutral:
+ case WaylandPositioner::Direction::kNeutral:
start += anchor_range.center();
break;
- case Direction::kPositive:
+ case WaylandPositioner::Direction::kPositive:
start += anchor_range.end;
break;
}
switch (gravity) {
- case Direction::kNegative:
+ case WaylandPositioner::Direction::kNegative:
start -= size;
break;
- case Direction::kNeutral:
+ case WaylandPositioner::Direction::kNeutral:
start -= size / 2;
break;
- case Direction::kPositive:
+ case WaylandPositioner::Direction::kPositive:
break;
}
return {start, start + size};
@@ -124,8 +225,8 @@ std::pair<Range1D, ConstraintAdjustment> DetermineBestConstraintAdjustment(
const Range1D& anchor_range,
uint32_t size,
int32_t offset,
- Direction anchor,
- Direction gravity,
+ WaylandPositioner::Direction anchor,
+ WaylandPositioner::Direction gravity,
const ConstraintAdjustment& valid_adjustments) {
if (work_area.start != 0) {
int32_t shift = -work_area.start;
@@ -174,29 +275,47 @@ std::pair<Range1D, ConstraintAdjustment> DetermineBestConstraintAdjustment(
} // namespace
+void WaylandPositioner::SetAnchor(uint32_t anchor) {
+ std::pair<WaylandPositioner::Direction, WaylandPositioner::Direction>
+ decompose;
+ if (version_ == UNSTABLE) {
+ decompose = DecomposeUnstableAnchor(anchor);
+ } else {
+ decompose = DecomposeStableAnchor(anchor);
+ }
+ anchor_x_ = decompose.first;
+ anchor_y_ = decompose.second;
+}
+
+void WaylandPositioner::SetGravity(uint32_t gravity) {
+ std::pair<WaylandPositioner::Direction, WaylandPositioner::Direction>
+ decompose;
+ if (version_ == UNSTABLE) {
+ decompose = DecomposeUnstableGravity(gravity);
+ } else {
+ decompose = DecomposeStableGravity(gravity);
+ }
+ gravity_x_ = decompose.first;
+ gravity_y_ = decompose.second;
+}
+
WaylandPositioner::Result WaylandPositioner::CalculatePosition(
const gfx::Rect& work_area,
bool flip_x,
bool flip_y) const {
- Direction anchor_x = MaskToDirection(anchor_, ZXDG_POSITIONER_V6_ANCHOR_LEFT,
- ZXDG_POSITIONER_V6_ANCHOR_RIGHT);
- Direction anchor_y = MaskToDirection(anchor_, ZXDG_POSITIONER_V6_ANCHOR_TOP,
- ZXDG_POSITIONER_V6_ANCHOR_BOTTOM);
- Direction gravity_x =
- MaskToDirection(gravity_, ZXDG_POSITIONER_V6_GRAVITY_LEFT,
- ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
- Direction gravity_y =
- MaskToDirection(gravity_, ZXDG_POSITIONER_V6_GRAVITY_TOP,
- ZXDG_POSITIONER_V6_GRAVITY_BOTTOM);
+ auto anchor_x = anchor_x_;
+ auto anchor_y = anchor_y_;
+ auto gravity_x = gravity_x_;
+ auto gravity_y = gravity_y_;
ConstraintAdjustment adjustments_x = MaskToConstraintAdjustment(
- adjustment_, ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X,
- ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X,
- ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X);
+ adjustment_, XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X,
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X,
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X);
ConstraintAdjustment adjustments_y = MaskToConstraintAdjustment(
- adjustment_, ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y,
- ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y,
- ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y);
+ adjustment_, XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y,
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y,
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y);
int32_t offset_x = offset_.x();
int32_t offset_y = offset_.y();
diff --git a/chromium/components/exo/wayland/wayland_positioner.h b/chromium/components/exo/wayland/wayland_positioner.h
index a623e0d4326..ccd5427838f 100644
--- a/chromium/components/exo/wayland/wayland_positioner.h
+++ b/chromium/components/exo/wayland/wayland_positioner.h
@@ -5,7 +5,7 @@
#ifndef COMPONENTS_EXO_WAYLAND_WAYLAND_POSITIONER_H_
#define COMPONENTS_EXO_WAYLAND_WAYLAND_POSITIONER_H_
-#include <xdg-shell-unstable-v6-server-protocol.h>
+#include <xdg-shell-server-protocol.h>
#include "base/macros.h"
#include "ui/gfx/geometry/point.h"
@@ -26,7 +26,14 @@ class WaylandPositioner {
bool y_flipped;
};
- WaylandPositioner() = default;
+ // Represents the 1-dimensional projection of the gravity/anchor values.
+ enum Direction { kNegative = -1, kNeutral = 0, kPositive = 1 };
+
+ // Controls whether anchor and gravity are set using the unstable bitfields or
+ // the stable enums.
+ enum Version { UNSTABLE, STABLE };
+
+ WaylandPositioner(Version v) : version_(v) {}
// Calculate and return position from current state.
Result CalculatePosition(const gfx::Rect& work_area,
@@ -39,27 +46,31 @@ class WaylandPositioner {
anchor_rect_ = std::move(anchor_rect);
}
- void SetAnchor(uint32_t anchor) { anchor_ = anchor; }
+ void SetAnchor(uint32_t anchor);
- void SetGravity(uint32_t gravity) { gravity_ = gravity; }
+ void SetGravity(uint32_t gravity);
void SetAdjustment(uint32_t adjustment) { adjustment_ = adjustment; }
void SetOffset(gfx::Vector2d offset) { offset_ = std::move(offset); }
private:
+ Version version_;
+
gfx::Size size_;
gfx::Rect anchor_rect_;
- uint32_t anchor_ = ZXDG_POSITIONER_V6_ANCHOR_NONE;
+ Direction anchor_x_ = kNeutral;
+ Direction anchor_y_ = kNeutral;
- uint32_t gravity_ = ZXDG_POSITIONER_V6_GRAVITY_NONE;
+ Direction gravity_x_ = kNeutral;
+ Direction gravity_y_ = kNeutral;
// A bitmask that defines the subset of modifications to the position/size
// that are allowed, see zxdg_positioner.constraint_adjustment() for more
// details.
- uint32_t adjustment_ = ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_NONE;
+ uint32_t adjustment_ = XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE;
// Defines an absolute translation (i.e. unaffected by flipping, scaling or
// resizing) for the placement of the window relative to the |anchor_rect_|.
diff --git a/chromium/components/exo/wayland/wayland_positioner_unittest.cc b/chromium/components/exo/wayland/wayland_positioner_unittest.cc
index 035f3b91f90..c30ea99d7db 100644
--- a/chromium/components/exo/wayland/wayland_positioner_unittest.cc
+++ b/chromium/components/exo/wayland/wayland_positioner_unittest.cc
@@ -5,6 +5,7 @@
#include "components/exo/wayland/wayland_positioner.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "xdg-shell-server-protocol.h"
#include "xdg-shell-unstable-v6-server-protocol.h"
namespace exo {
@@ -21,7 +22,9 @@ class WaylandPositionerTest : public testing::Test {
bool flip_x = false;
bool flip_y = false;
- TestCaseBuilder() { positioner.SetAnchorRect({2, 2, 1, 1}); }
+ explicit TestCaseBuilder(WaylandPositioner::Version v) : positioner(v) {
+ positioner.SetAnchorRect({2, 2, 1, 1});
+ }
TestCaseBuilder& SetFlipState(bool x, bool y) {
flip_x = x;
@@ -66,31 +69,35 @@ class WaylandPositionerTest : public testing::Test {
};
};
-TEST_F(WaylandPositionerTest, UnconstrainedCases) {
+// Tests for the unstable protocol.
+
+TEST_F(WaylandPositionerTest, UnconstrainedCasesUnstable) {
// No gravity or anchor.
- EXPECT_EQ(TestCaseBuilder().SetSize(1, 1).SolveToRect(),
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE)
+ .SetSize(1, 1)
+ .SolveToRect(),
gfx::Rect(2, 2, 1, 1));
// Anchor without gravity.
- EXPECT_EQ(TestCaseBuilder()
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE)
.SetSize(2, 1)
.SetAnchor(ZXDG_POSITIONER_V6_ANCHOR_RIGHT)
.SolveToRect(),
gfx::Rect(2, 2, 2, 1));
- EXPECT_EQ(TestCaseBuilder()
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE)
.SetSize(2, 1)
.SetAnchor(ZXDG_POSITIONER_V6_ANCHOR_LEFT)
.SolveToRect(),
gfx::Rect(1, 2, 2, 1));
// Gravity without anchor.
- EXPECT_EQ(TestCaseBuilder()
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE)
.SetSize(1, 2)
.SetAnchorRect(2, 2, 0, 0)
.SetGravity(ZXDG_POSITIONER_V6_GRAVITY_TOP)
.SolveToRect(),
gfx::Rect(2, 0, 1, 2));
- EXPECT_EQ(TestCaseBuilder()
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE)
.SetSize(1, 2)
.SetAnchorRect(2, 2, 0, 0)
.SetGravity(ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)
@@ -98,7 +105,7 @@ TEST_F(WaylandPositionerTest, UnconstrainedCases) {
gfx::Rect(2, 2, 1, 2));
// Gravity + anchor in the same direction.
- EXPECT_EQ(TestCaseBuilder()
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE)
.SetSize(2, 2)
.SetGravity(ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
ZXDG_POSITIONER_V6_GRAVITY_LEFT)
@@ -108,7 +115,7 @@ TEST_F(WaylandPositionerTest, UnconstrainedCases) {
gfx::Rect(0, 3, 2, 2));
// Gravity + anchor in opposing directions.
- EXPECT_EQ(TestCaseBuilder()
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE)
.SetSize(2, 2)
.SetGravity(ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
ZXDG_POSITIONER_V6_GRAVITY_LEFT)
@@ -118,8 +125,8 @@ TEST_F(WaylandPositionerTest, UnconstrainedCases) {
gfx::Rect(1, 2, 2, 2));
}
-TEST_F(WaylandPositionerTest, FlipSlideResizePriority) {
- TestCaseBuilder builder;
+TEST_F(WaylandPositionerTest, FlipSlideResizePriorityUnstable) {
+ TestCaseBuilder builder{WaylandPositioner::Version::UNSTABLE};
builder.SetAnchorRect(4, 4, 0, 0)
.SetSize(2, 2)
.SetGravity(ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
@@ -150,10 +157,10 @@ TEST_F(WaylandPositionerTest, FlipSlideResizePriority) {
gfx::Rect(4, 4, 1, 1));
}
-TEST_F(WaylandPositionerTest, TriesToMaximizeArea) {
+TEST_F(WaylandPositionerTest, TriesToMaximizeAreaUnstable) {
// The size is too large to fit where the anchor is.
WaylandPositioner::Result result =
- TestCaseBuilder()
+ TestCaseBuilder(WaylandPositioner::Version::UNSTABLE)
.SetAnchorRect(2, 4, 0, 0)
.SetSize(4, 10)
.SetGravity(ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
@@ -171,9 +178,9 @@ TEST_F(WaylandPositionerTest, TriesToMaximizeArea) {
EXPECT_FALSE(result.y_flipped);
}
-TEST_F(WaylandPositionerTest, PropagatesAnInitialFlip) {
+TEST_F(WaylandPositionerTest, PropagatesAnInitialFlipUnstable) {
WaylandPositioner::Result result =
- TestCaseBuilder()
+ TestCaseBuilder(WaylandPositioner::Version::UNSTABLE)
.SetAnchorRect(3, 1, 0, 0)
.SetSize(2, 2)
.SetGravity(ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
@@ -195,8 +202,8 @@ TEST_F(WaylandPositionerTest, PropagatesAnInitialFlip) {
// This is a common case for dropdown menus. In ChromeOS we do not let them
// slide if they might occlude the anchor rectangle. For this case, x axis does
// slide but the y axis resized instead.
-TEST_F(WaylandPositionerTest, PreventsSlidingThatOccludesAnchorRect) {
- EXPECT_EQ(TestCaseBuilder()
+TEST_F(WaylandPositionerTest, PreventsSlidingThatOccludesAnchorRectUnstable) {
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE)
.SetSize(3, 3)
.SetGravity(ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
ZXDG_POSITIONER_V6_GRAVITY_RIGHT)
@@ -208,7 +215,7 @@ TEST_F(WaylandPositionerTest, PreventsSlidingThatOccludesAnchorRect) {
// Here we ensure that the 4x4 popup does slide, which is allowed because
// the anchor rect is already occluded.
- EXPECT_EQ(TestCaseBuilder()
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::UNSTABLE)
.SetSize(4, 4)
.SetGravity(ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
ZXDG_POSITIONER_V6_GRAVITY_RIGHT)
@@ -219,6 +226,145 @@ TEST_F(WaylandPositionerTest, PreventsSlidingThatOccludesAnchorRect) {
gfx::Rect(1, 1, 4, 4));
}
+// Tests for the stable protocol.
+
+TEST_F(WaylandPositionerTest, UnconstrainedCases) {
+ // No gravity or anchor.
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE)
+ .SetSize(1, 1)
+ .SolveToRect(),
+ gfx::Rect(2, 2, 1, 1));
+
+ // Anchor without gravity.
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE)
+ .SetSize(2, 1)
+ .SetAnchor(XDG_POSITIONER_ANCHOR_RIGHT)
+ .SolveToRect(),
+ gfx::Rect(2, 2, 2, 1));
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE)
+ .SetSize(2, 1)
+ .SetAnchor(XDG_POSITIONER_ANCHOR_LEFT)
+ .SolveToRect(),
+ gfx::Rect(1, 2, 2, 1));
+
+ // Gravity without anchor.
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE)
+ .SetSize(1, 2)
+ .SetAnchorRect(2, 2, 0, 0)
+ .SetGravity(XDG_POSITIONER_GRAVITY_TOP)
+ .SolveToRect(),
+ gfx::Rect(2, 0, 1, 2));
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE)
+ .SetSize(1, 2)
+ .SetAnchorRect(2, 2, 0, 0)
+ .SetGravity(XDG_POSITIONER_GRAVITY_BOTTOM)
+ .SolveToRect(),
+ gfx::Rect(2, 2, 1, 2));
+
+ // Gravity + anchor in the same direction.
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE)
+ .SetSize(2, 2)
+ .SetGravity(XDG_POSITIONER_GRAVITY_BOTTOM_LEFT)
+ .SetAnchor(XDG_POSITIONER_ANCHOR_BOTTOM_LEFT)
+ .SolveToRect(),
+ gfx::Rect(0, 3, 2, 2));
+
+ // Gravity + anchor in opposing directions.
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE)
+ .SetSize(2, 2)
+ .SetGravity(XDG_POSITIONER_GRAVITY_BOTTOM_LEFT)
+ .SetAnchor(XDG_POSITIONER_ANCHOR_TOP_RIGHT)
+ .SolveToRect(),
+ gfx::Rect(1, 2, 2, 2));
+}
+
+TEST_F(WaylandPositionerTest, FlipSlideResizePriority) {
+ TestCaseBuilder builder{WaylandPositioner::Version::STABLE};
+ builder.SetAnchorRect(4, 4, 0, 0)
+ .SetSize(2, 2)
+ .SetGravity(XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT)
+ .SetAnchor(XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT);
+ // Flip is enabled, so the result will be at 2,2 (i.e. flipping a 2-wide
+ // square around 4,4).
+ EXPECT_EQ(builder.SetAdjustment(~XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE)
+ .SolveToRect(),
+ gfx::Rect(2, 2, 2, 2));
+ // If we cant flip on an axis, that axis will slide to 3 instead.
+ EXPECT_EQ(builder.SetAdjustment(~XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X)
+ .SolveToRect(),
+ gfx::Rect(3, 2, 2, 2));
+ EXPECT_EQ(builder.SetAdjustment(~XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y)
+ .SolveToRect(),
+ gfx::Rect(2, 3, 2, 2));
+ // If we cant flip or slide, we resize.
+ EXPECT_EQ(builder
+ .SetAdjustment(XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X |
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y)
+ .SolveToRect(),
+ gfx::Rect(4, 4, 1, 1));
+}
+
+TEST_F(WaylandPositionerTest, TriesToMaximizeArea) {
+ // The size is too large to fit where the anchor is.
+ WaylandPositioner::Result result =
+ TestCaseBuilder(WaylandPositioner::Version::STABLE)
+ .SetAnchorRect(2, 4, 0, 0)
+ .SetSize(4, 10)
+ .SetGravity(XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT)
+ .SetAnchor(XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT)
+ .SetAdjustment(~XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE)
+ .Solve();
+ // We can slide to 1 on x, but we must resize on y (after sliding to 0).
+ EXPECT_EQ(result.origin, gfx::Point(1, 0));
+ // The x size will be preserved but y shrinks to the work area.
+ EXPECT_EQ(result.size, gfx::Size(4, 5));
+ // Neither axis will be flipped.
+ EXPECT_FALSE(result.x_flipped);
+ EXPECT_FALSE(result.y_flipped);
+}
+
+TEST_F(WaylandPositionerTest, PropagatesAnInitialFlip) {
+ WaylandPositioner::Result result =
+ TestCaseBuilder(WaylandPositioner::Version::STABLE)
+ .SetAnchorRect(3, 1, 0, 0)
+ .SetSize(2, 2)
+ .SetGravity(XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT)
+ .SetAnchor(XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT)
+ .SetAdjustment(~XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE)
+ .SetFlipState(true, true)
+ .Solve();
+ // With a propagated flip state:
+ // - Normally the x would not need to flip, but it propagates the flip.
+ // - Y also propagates, but that makes it constrained so it flips back.
+ EXPECT_EQ(result.origin, gfx::Point(1, 1));
+ EXPECT_EQ(result.size, gfx::Size(2, 2));
+ EXPECT_TRUE(result.x_flipped);
+ EXPECT_FALSE(result.y_flipped);
+}
+
+// This is a common case for dropdown menus. In ChromeOS we do not let them
+// slide if they might occlude the anchor rectangle. For this case, x axis does
+// slide but the y axis resized instead.
+TEST_F(WaylandPositionerTest, PreventsSlidingThatOccludesAnchorRect) {
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE)
+ .SetSize(3, 3)
+ .SetGravity(XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT)
+ .SetAnchor(XDG_POSITIONER_ANCHOR_BOTTOM_LEFT)
+ .SetAdjustment(~XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE)
+ .SolveToRect(),
+ gfx::Rect(2, 3, 3, 2));
+
+ // Here we ensure that the 4x4 popup does slide, which is allowed because
+ // the anchor rect is already occluded.
+ EXPECT_EQ(TestCaseBuilder(WaylandPositioner::Version::STABLE)
+ .SetSize(4, 4)
+ .SetGravity(XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT)
+ .SetAnchor(XDG_POSITIONER_ANCHOR_TOP_LEFT)
+ .SetAdjustment(~XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE)
+ .SolveToRect(),
+ gfx::Rect(1, 1, 4, 4));
+}
+
} // namespace
} // namespace wayland
} // namespace exo
diff --git a/chromium/components/exo/wayland/wl_compositor.cc b/chromium/components/exo/wayland/wl_compositor.cc
index 9096d2b87d6..0f01baee969 100644
--- a/chromium/components/exo/wayland/wl_compositor.cc
+++ b/chromium/components/exo/wayland/wl_compositor.cc
@@ -12,14 +12,17 @@
#include "components/exo/buffer.h"
#include "components/exo/display.h"
#include "components/exo/surface.h"
+#include "components/exo/wayland/server.h"
#include "components/exo/wayland/server_util.h"
#include "third_party/skia/include/core/SkRegion.h"
+#include "ui/display/types/display_constants.h"
#if defined(OS_CHROMEOS)
#include "components/exo/wayland/zwp_linux_explicit_synchronization.h"
#endif
namespace exo {
+class Server;
namespace wayland {
namespace {
@@ -202,8 +205,8 @@ const struct wl_surface_interface surface_implementation = {
void compositor_create_surface(wl_client* client,
wl_resource* resource,
uint32_t id) {
- std::unique_ptr<Surface> surface =
- GetUserDataAs<Display>(resource)->CreateSurface();
+ Display* display = GetUserDataAs<Display>(resource);
+ std::unique_ptr<Surface> surface = display->CreateSurface();
wl_resource* surface_resource = wl_resource_create(
client, &wl_surface_interface, wl_resource_get_version(resource), id);
diff --git a/chromium/components/exo/wayland/wl_data_device_manager.cc b/chromium/components/exo/wayland/wl_data_device_manager.cc
index b4ee13f4f56..5d08696c85e 100644
--- a/chromium/components/exo/wayland/wl_data_device_manager.cc
+++ b/chromium/components/exo/wayland/wl_data_device_manager.cc
@@ -303,6 +303,11 @@ class WaylandDataDeviceDelegate : public DataDeviceDelegate {
uint32_t serial) {
base::Optional<wayland::SerialTracker::EventType> event_type =
serial_tracker_->GetEventType(serial);
+ if (event_type == base::nullopt) {
+ LOG(ERROR) << "The serial passed to StartDrag does not exist.";
+ source->Cancelled();
+ return;
+ }
if (event_type == wayland::SerialTracker::EventType::POINTER_BUTTON_DOWN &&
serial_tracker_->GetPointerDownSerial() == serial) {
data_device->StartDrag(
@@ -314,8 +319,23 @@ class WaylandDataDeviceDelegate : public DataDeviceDelegate {
source, origin, icon,
ui::DragDropTypes::DragEventSource::DRAG_EVENT_SOURCE_TOUCH);
} else {
+ LOG(ERROR) << "The serial passed to StartDrag does not match its "
+ "expected types.";
+ source->Cancelled();
+ }
+ }
+
+ void SetSelection(DataDevice* data_device,
+ DataSource* source,
+ uint32_t serial) {
+ base::Optional<wayland::SerialTracker::EventType> event_type =
+ serial_tracker_->GetEventType(serial);
+ if (event_type == base::nullopt) {
+ LOG(ERROR) << "The serial passed to SetSelection does not exist.";
source->Cancelled();
+ return;
}
+ data_device->SetSelection(source);
}
private:
@@ -347,10 +367,15 @@ void data_device_start_drag(wl_client* client,
void data_device_set_selection(wl_client* client,
wl_resource* resource,
- wl_resource* data_source,
+ wl_resource* source_resource,
uint32_t serial) {
- GetUserDataAs<DataDevice>(resource)->SetSelection(
- data_source ? GetUserDataAs<DataSource>(data_source) : nullptr, serial);
+ DataDevice* data_device = GetUserDataAs<DataDevice>(resource);
+ static_cast<WaylandDataDeviceDelegate*>(data_device->get_delegate())
+ ->SetSelection(data_device,
+ source_resource
+ ? GetUserDataAs<DataSource>(source_resource)
+ : nullptr,
+ serial);
}
void data_device_release(wl_client* client, wl_resource* resource) {
diff --git a/chromium/components/exo/wayland/wl_output.cc b/chromium/components/exo/wayland/wl_output.cc
index b6b80bf515b..b95c1969890 100644
--- a/chromium/components/exo/wayland/wl_output.cc
+++ b/chromium/components/exo/wayland/wl_output.cc
@@ -28,15 +28,17 @@ void output_release(wl_client* client, wl_resource* resource) {
const struct wl_output_interface output_implementation = {output_release};
-void bind_output(wl_client* client, void* data, uint32_t version, uint32_t id) {
+void bind_output(wl_client* client,
+ void* data,
+ uint32_t version,
+ uint32_t output_id) {
WaylandDisplayOutput* output = static_cast<WaylandDisplayOutput*>(data);
- wl_resource* resource = wl_resource_create(
- client, &wl_output_interface, std::min(version, kWlOutputVersion), id);
-
- SetImplementation(
- resource, &output_implementation,
- std::make_unique<WaylandDisplayObserver>(output->id(), resource));
+ wl_resource* resource =
+ wl_resource_create(client, &wl_output_interface,
+ std::min(version, kWlOutputVersion), output_id);
+ SetImplementation(resource, &output_implementation,
+ std::make_unique<WaylandDisplayObserver>(output, resource));
}
} // namespace wayland
diff --git a/chromium/components/exo/wayland/xdg_shell.cc b/chromium/components/exo/wayland/xdg_shell.cc
new file mode 100644
index 00000000000..8e8f0b4db68
--- /dev/null
+++ b/chromium/components/exo/wayland/xdg_shell.cc
@@ -0,0 +1,692 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/exo/wayland/xdg_shell.h"
+
+#include <wayland-server-core.h>
+#include <wayland-server-protocol-core.h>
+#include <xdg-shell-server-protocol.h>
+
+#include "ash/public/cpp/shell_window_ids.h"
+#include "ash/public/cpp/window_properties.h"
+#include "ash/public/cpp/window_state_type.h"
+#include "base/bind.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/exo/display.h"
+#include "components/exo/wayland/serial_tracker.h"
+#include "components/exo/wayland/server_util.h"
+#include "components/exo/wayland/wayland_positioner.h"
+#include "components/exo/xdg_shell_surface.h"
+#include "ui/aura/window_observer.h"
+#include "ui/base/hit_test.h"
+#include "ui/display/screen.h"
+#include "ui/views/widget/widget.h"
+#include "ui/wm/core/coordinate_conversion.h"
+
+namespace exo {
+namespace wayland {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+// xdg_positioner_interface:
+
+void xdg_positioner_destroy(wl_client* client, wl_resource* resource) {
+ wl_resource_destroy(resource);
+}
+
+void xdg_positioner_set_size(wl_client* client,
+ wl_resource* resource,
+ int32_t width,
+ int32_t height) {
+ if (width < 1 || height < 1) {
+ wl_resource_post_error(resource, XDG_POSITIONER_ERROR_INVALID_INPUT,
+ "width and height must be positive and non-zero");
+ return;
+ }
+
+ GetUserDataAs<WaylandPositioner>(resource)->SetSize(gfx::Size(width, height));
+}
+
+void xdg_positioner_set_anchor_rect(wl_client* client,
+ wl_resource* resource,
+ int32_t x,
+ int32_t y,
+ int32_t width,
+ int32_t height) {
+ if (width < 1 || height < 1) {
+ wl_resource_post_error(resource, XDG_POSITIONER_ERROR_INVALID_INPUT,
+ "width and height must be positive and non-zero");
+ return;
+ }
+
+ GetUserDataAs<WaylandPositioner>(resource)->SetAnchorRect(
+ gfx::Rect(x, y, width, height));
+}
+
+void xdg_positioner_set_anchor(wl_client* client,
+ wl_resource* resource,
+ uint32_t anchor) {
+ if (((anchor & XDG_POSITIONER_ANCHOR_LEFT) &&
+ (anchor & XDG_POSITIONER_ANCHOR_RIGHT)) ||
+ ((anchor & XDG_POSITIONER_ANCHOR_TOP) &&
+ (anchor & XDG_POSITIONER_ANCHOR_BOTTOM))) {
+ wl_resource_post_error(resource, XDG_POSITIONER_ERROR_INVALID_INPUT,
+ "same-axis values are not allowed");
+ return;
+ }
+
+ GetUserDataAs<WaylandPositioner>(resource)->SetAnchor(anchor);
+}
+
+void xdg_positioner_set_gravity(wl_client* client,
+ wl_resource* resource,
+ uint32_t gravity) {
+ if (((gravity & XDG_POSITIONER_GRAVITY_LEFT) &&
+ (gravity & XDG_POSITIONER_GRAVITY_RIGHT)) ||
+ ((gravity & XDG_POSITIONER_GRAVITY_TOP) &&
+ (gravity & XDG_POSITIONER_GRAVITY_BOTTOM))) {
+ wl_resource_post_error(resource, XDG_POSITIONER_ERROR_INVALID_INPUT,
+ "same-axis values are not allowed");
+ return;
+ }
+
+ GetUserDataAs<WaylandPositioner>(resource)->SetGravity(gravity);
+}
+
+void xdg_positioner_set_constraint_adjustment(wl_client* client,
+ wl_resource* resource,
+ uint32_t adjustment) {
+ GetUserDataAs<WaylandPositioner>(resource)->SetAdjustment(adjustment);
+}
+
+void xdg_positioner_set_offset(wl_client* client,
+ wl_resource* resource,
+ int32_t x,
+ int32_t y) {
+ GetUserDataAs<WaylandPositioner>(resource)->SetOffset(gfx::Vector2d(x, y));
+}
+
+const struct xdg_positioner_interface xdg_positioner_implementation = {
+ xdg_positioner_destroy, xdg_positioner_set_size,
+ xdg_positioner_set_anchor_rect, xdg_positioner_set_anchor,
+ xdg_positioner_set_gravity, xdg_positioner_set_constraint_adjustment,
+ xdg_positioner_set_offset};
+
+////////////////////////////////////////////////////////////////////////////////
+// xdg_toplevel_interface:
+
+int XdgToplevelResizeComponent(uint32_t edges) {
+ switch (edges) {
+ case XDG_TOPLEVEL_RESIZE_EDGE_TOP:
+ return HTTOP;
+ case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM:
+ return HTBOTTOM;
+ case XDG_TOPLEVEL_RESIZE_EDGE_LEFT:
+ return HTLEFT;
+ case XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT:
+ return HTTOPLEFT;
+ case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT:
+ return HTBOTTOMLEFT;
+ case XDG_TOPLEVEL_RESIZE_EDGE_RIGHT:
+ return HTRIGHT;
+ case XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT:
+ return HTTOPRIGHT;
+ case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT:
+ return HTBOTTOMRIGHT;
+ default:
+ return HTBOTTOMRIGHT;
+ }
+}
+
+using XdgSurfaceConfigureCallback =
+ base::RepeatingCallback<void(const gfx::Size& size,
+ ash::WindowStateType state_type,
+ bool resizing,
+ bool activated)>;
+
+uint32_t HandleXdgSurfaceConfigureCallback(
+ wl_resource* resource,
+ SerialTracker* serial_tracker,
+ const XdgSurfaceConfigureCallback& callback,
+ const gfx::Size& size,
+ ash::WindowStateType state_type,
+ bool resizing,
+ bool activated,
+ const gfx::Vector2d& origin_offset) {
+ uint32_t serial =
+ serial_tracker->GetNextSerial(SerialTracker::EventType::OTHER_EVENT);
+ callback.Run(size, state_type, resizing, activated);
+ xdg_surface_send_configure(resource, serial);
+ wl_client_flush(wl_resource_get_client(resource));
+ return serial;
+}
+
+struct WaylandXdgSurface {
+ WaylandXdgSurface(std::unique_ptr<XdgShellSurface> shell_surface,
+ SerialTracker* const serial_tracker)
+ : shell_surface(std::move(shell_surface)),
+ serial_tracker(serial_tracker) {}
+
+ std::unique_ptr<XdgShellSurface> shell_surface;
+
+ // Owned by Server, which always outlives this surface.
+ SerialTracker* const serial_tracker;
+
+ DISALLOW_COPY_AND_ASSIGN(WaylandXdgSurface);
+};
+
+// Wrapper around shell surface that allows us to handle the case where the
+// xdg surface resource is destroyed before the toplevel resource.
+class WaylandToplevel : public aura::WindowObserver {
+ public:
+ WaylandToplevel(wl_resource* resource, wl_resource* surface_resource)
+ : resource_(resource),
+ shell_surface_data_(
+ GetUserDataAs<WaylandXdgSurface>(surface_resource)) {
+ shell_surface_data_->shell_surface->host_window()->AddObserver(this);
+ shell_surface_data_->shell_surface->set_close_callback(base::BindRepeating(
+ &WaylandToplevel::OnClose, weak_ptr_factory_.GetWeakPtr()));
+ shell_surface_data_->shell_surface->set_configure_callback(
+ base::BindRepeating(
+ &HandleXdgSurfaceConfigureCallback, surface_resource,
+ shell_surface_data_->serial_tracker,
+ base::BindRepeating(&WaylandToplevel::OnConfigure,
+ weak_ptr_factory_.GetWeakPtr())));
+ }
+ ~WaylandToplevel() override {
+ if (shell_surface_data_)
+ shell_surface_data_->shell_surface->host_window()->RemoveObserver(this);
+ }
+
+ // Overridden from aura::WindowObserver:
+ void OnWindowDestroying(aura::Window* window) override {
+ shell_surface_data_ = nullptr;
+ }
+
+ void SetParent(WaylandToplevel* parent) {
+ if (!shell_surface_data_)
+ return;
+
+ if (!parent) {
+ shell_surface_data_->shell_surface->SetParent(nullptr);
+ return;
+ }
+
+ // This is a no-op if parent is not mapped.
+ if (parent->shell_surface_data_ &&
+ parent->shell_surface_data_->shell_surface->GetWidget())
+ shell_surface_data_->shell_surface->SetParent(
+ parent->shell_surface_data_->shell_surface.get());
+ }
+
+ void SetTitle(const base::string16& title) {
+ if (shell_surface_data_)
+ shell_surface_data_->shell_surface->SetTitle(title);
+ }
+
+ void SetApplicationId(const char* application_id) {
+ if (shell_surface_data_)
+ shell_surface_data_->shell_surface->SetApplicationId(application_id);
+ }
+
+ void Move() {
+ if (shell_surface_data_)
+ shell_surface_data_->shell_surface->StartMove();
+ }
+
+ void Resize(int component) {
+ if (!shell_surface_data_)
+ return;
+
+ if (component != HTNOWHERE)
+ shell_surface_data_->shell_surface->StartResize(component);
+ }
+
+ void SetMaximumSize(const gfx::Size& size) {
+ if (shell_surface_data_)
+ shell_surface_data_->shell_surface->SetMaximumSize(size);
+ }
+
+ void SetMinimumSize(const gfx::Size& size) {
+ if (shell_surface_data_)
+ shell_surface_data_->shell_surface->SetMinimumSize(size);
+ }
+
+ void Maximize() {
+ if (shell_surface_data_)
+ shell_surface_data_->shell_surface->Maximize();
+ }
+
+ void Restore() {
+ if (shell_surface_data_)
+ shell_surface_data_->shell_surface->Restore();
+ }
+
+ void SetFullscreen(bool fullscreen) {
+ if (shell_surface_data_)
+ shell_surface_data_->shell_surface->SetFullscreen(fullscreen);
+ }
+
+ void Minimize() {
+ if (shell_surface_data_)
+ shell_surface_data_->shell_surface->Minimize();
+ }
+
+ private:
+ void OnClose() {
+ xdg_toplevel_send_close(resource_);
+ wl_client_flush(wl_resource_get_client(resource_));
+ }
+
+ static void AddState(wl_array* states, xdg_toplevel_state state) {
+ xdg_toplevel_state* value = static_cast<xdg_toplevel_state*>(
+ wl_array_add(states, sizeof(xdg_toplevel_state)));
+ DCHECK(value);
+ *value = state;
+ }
+
+ void OnConfigure(const gfx::Size& size,
+ ash::WindowStateType state_type,
+ bool resizing,
+ bool activated) {
+ wl_array states;
+ wl_array_init(&states);
+ if (state_type == ash::WindowStateType::kMaximized)
+ AddState(&states, XDG_TOPLEVEL_STATE_MAXIMIZED);
+ if (state_type == ash::WindowStateType::kFullscreen)
+ AddState(&states, XDG_TOPLEVEL_STATE_FULLSCREEN);
+ if (resizing)
+ AddState(&states, XDG_TOPLEVEL_STATE_RESIZING);
+ if (activated)
+ AddState(&states, XDG_TOPLEVEL_STATE_ACTIVATED);
+ xdg_toplevel_send_configure(resource_, size.width(), size.height(),
+ &states);
+ wl_array_release(&states);
+ }
+
+ wl_resource* const resource_;
+ WaylandXdgSurface* shell_surface_data_;
+ base::WeakPtrFactory<WaylandToplevel> weak_ptr_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(WaylandToplevel);
+};
+
+void xdg_toplevel_destroy(wl_client* client, wl_resource* resource) {
+ wl_resource_destroy(resource);
+}
+
+void xdg_toplevel_set_parent(wl_client* client,
+ wl_resource* resource,
+ wl_resource* parent) {
+ WaylandToplevel* parent_surface = nullptr;
+ if (parent)
+ parent_surface = GetUserDataAs<WaylandToplevel>(parent);
+
+ GetUserDataAs<WaylandToplevel>(resource)->SetParent(parent_surface);
+}
+
+void xdg_toplevel_set_title(wl_client* client,
+ wl_resource* resource,
+ const char* title) {
+ GetUserDataAs<WaylandToplevel>(resource)->SetTitle(
+ base::string16(base::UTF8ToUTF16(title)));
+}
+
+void xdg_toplevel_set_app_id(wl_client* client,
+ wl_resource* resource,
+ const char* app_id) {
+ GetUserDataAs<WaylandToplevel>(resource)->SetApplicationId(app_id);
+}
+
+void xdg_toplevel_show_window_menu(wl_client* client,
+ wl_resource* resource,
+ wl_resource* seat,
+ uint32_t serial,
+ int32_t x,
+ int32_t y) {
+ NOTIMPLEMENTED();
+}
+
+void xdg_toplevel_move(wl_client* client,
+ wl_resource* resource,
+ wl_resource* seat,
+ uint32_t serial) {
+ GetUserDataAs<WaylandToplevel>(resource)->Move();
+}
+
+void xdg_toplevel_resize(wl_client* client,
+ wl_resource* resource,
+ wl_resource* seat,
+ uint32_t serial,
+ uint32_t edges) {
+ GetUserDataAs<WaylandToplevel>(resource)->Resize(
+ XdgToplevelResizeComponent(edges));
+}
+
+void xdg_toplevel_set_max_size(wl_client* client,
+ wl_resource* resource,
+ int32_t width,
+ int32_t height) {
+ GetUserDataAs<WaylandToplevel>(resource)->SetMaximumSize(
+ gfx::Size(width, height));
+}
+
+void xdg_toplevel_set_min_size(wl_client* client,
+ wl_resource* resource,
+ int32_t width,
+ int32_t height) {
+ GetUserDataAs<WaylandToplevel>(resource)->SetMinimumSize(
+ gfx::Size(width, height));
+}
+
+void xdg_toplevel_set_maximized(wl_client* client, wl_resource* resource) {
+ GetUserDataAs<WaylandToplevel>(resource)->Maximize();
+}
+
+void xdg_toplevel_unset_maximized(wl_client* client, wl_resource* resource) {
+ GetUserDataAs<WaylandToplevel>(resource)->Restore();
+}
+
+void xdg_toplevel_set_fullscreen(wl_client* client,
+ wl_resource* resource,
+ wl_resource* output) {
+ GetUserDataAs<WaylandToplevel>(resource)->SetFullscreen(true);
+}
+
+void xdg_toplevel_unset_fullscreen(wl_client* client, wl_resource* resource) {
+ GetUserDataAs<WaylandToplevel>(resource)->SetFullscreen(false);
+}
+
+void xdg_toplevel_set_minimized(wl_client* client, wl_resource* resource) {
+ GetUserDataAs<WaylandToplevel>(resource)->Minimize();
+}
+
+const struct xdg_toplevel_interface xdg_toplevel_implementation = {
+ xdg_toplevel_destroy, xdg_toplevel_set_parent,
+ xdg_toplevel_set_title, xdg_toplevel_set_app_id,
+ xdg_toplevel_show_window_menu, xdg_toplevel_move,
+ xdg_toplevel_resize, xdg_toplevel_set_max_size,
+ xdg_toplevel_set_min_size, xdg_toplevel_set_maximized,
+ xdg_toplevel_unset_maximized, xdg_toplevel_set_fullscreen,
+ xdg_toplevel_unset_fullscreen, xdg_toplevel_set_minimized};
+
+////////////////////////////////////////////////////////////////////////////////
+// xdg_popup_interface:
+
+// Wrapper around shell surface that allows us to handle the case where the
+// xdg surface resource is destroyed before the popup resource.
+class WaylandPopup : aura::WindowObserver {
+ public:
+ WaylandPopup(wl_resource* resource, wl_resource* surface_resource)
+ : resource_(resource),
+ shell_surface_data_(
+ GetUserDataAs<WaylandXdgSurface>(surface_resource)) {
+ shell_surface_data_->shell_surface->host_window()->AddObserver(this);
+ shell_surface_data_->shell_surface->set_close_callback(base::BindRepeating(
+ &WaylandPopup::OnClose, weak_ptr_factory_.GetWeakPtr()));
+ shell_surface_data_->shell_surface->set_configure_callback(
+ base::BindRepeating(
+ &HandleXdgSurfaceConfigureCallback, surface_resource,
+ shell_surface_data_->serial_tracker,
+ base::BindRepeating(&WaylandPopup::OnConfigure,
+ weak_ptr_factory_.GetWeakPtr())));
+ }
+ ~WaylandPopup() override {
+ if (shell_surface_data_)
+ shell_surface_data_->shell_surface->host_window()->RemoveObserver(this);
+ }
+
+ void Grab() {
+ if (!shell_surface_data_) {
+ wl_resource_post_error(resource_, XDG_POPUP_ERROR_INVALID_GRAB,
+ "the surface has already been destroyed");
+ return;
+ }
+ if (shell_surface_data_->shell_surface->GetWidget()) {
+ wl_resource_post_error(resource_, XDG_POPUP_ERROR_INVALID_GRAB,
+ "grab must be called before construction");
+ return;
+ }
+ shell_surface_data_->shell_surface->Grab();
+ }
+
+ // Overridden from aura::WindowObserver:
+ void OnWindowDestroying(aura::Window* window) override {
+ shell_surface_data_ = nullptr;
+ }
+
+ private:
+ void OnClose() {
+ xdg_popup_send_popup_done(resource_);
+ wl_client_flush(wl_resource_get_client(resource_));
+ }
+
+ void OnConfigure(const gfx::Size& size,
+ ash::WindowStateType state_type,
+ bool resizing,
+ bool activated) {
+ // Nothing to do here as popups don't have additional configure state.
+ }
+
+ wl_resource* const resource_;
+ WaylandXdgSurface* shell_surface_data_;
+ base::WeakPtrFactory<WaylandPopup> weak_ptr_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(WaylandPopup);
+};
+
+void xdg_popup_destroy(wl_client* client, wl_resource* resource) {
+ wl_resource_destroy(resource);
+}
+
+void xdg_popup_grab(wl_client* client,
+ wl_resource* resource,
+ wl_resource* seat,
+ uint32_t serial) {
+ GetUserDataAs<WaylandPopup>(resource)->Grab();
+}
+
+const struct xdg_popup_interface xdg_popup_implementation = {xdg_popup_destroy,
+ xdg_popup_grab};
+
+////////////////////////////////////////////////////////////////////////////////
+// xdg_surface_interface:
+
+void xdg_surface_destroy(wl_client* client, wl_resource* resource) {
+ wl_resource_destroy(resource);
+}
+
+void xdg_surface_get_toplevel(wl_client* client,
+ wl_resource* resource,
+ uint32_t id) {
+ auto* shell_surface_data = GetUserDataAs<WaylandXdgSurface>(resource);
+ if (shell_surface_data->shell_surface->GetEnabled()) {
+ wl_resource_post_error(resource, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED,
+ "surface has already been constructed");
+ return;
+ }
+
+ shell_surface_data->shell_surface->SetCanMinimize(true);
+ shell_surface_data->shell_surface->SetEnabled(true);
+
+ wl_resource* xdg_toplevel_resource =
+ wl_resource_create(client, &xdg_toplevel_interface, 1, id);
+
+ SetImplementation(
+ xdg_toplevel_resource, &xdg_toplevel_implementation,
+ std::make_unique<WaylandToplevel>(xdg_toplevel_resource, resource));
+}
+
+void xdg_surface_get_popup(wl_client* client,
+ wl_resource* resource,
+ uint32_t id,
+ wl_resource* parent_resource,
+ wl_resource* positioner_resource) {
+ auto* shell_surface_data = GetUserDataAs<WaylandXdgSurface>(resource);
+ if (shell_surface_data->shell_surface->GetEnabled()) {
+ wl_resource_post_error(resource, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED,
+ "surface has already been constructed");
+ return;
+ }
+
+ if (!parent_resource) {
+ wl_resource_post_error(resource, XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
+ "popup parent not supplied");
+ return;
+ }
+
+ auto* parent_data = GetUserDataAs<WaylandXdgSurface>(parent_resource);
+ if (!parent_data->shell_surface->GetWidget()) {
+ wl_resource_post_error(resource, XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
+ "popup parent not constructed");
+ return;
+ }
+
+ if (shell_surface_data->shell_surface->GetWidget()) {
+ wl_resource_post_error(resource, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED,
+ "get_popup is called after constructed");
+ return;
+ }
+
+ display::Display display =
+ display::Screen::GetScreen()->GetDisplayNearestWindow(
+ parent_data->shell_surface->GetWidget()->GetNativeWindow());
+ gfx::Rect work_area = display.work_area();
+ wm::ConvertRectFromScreen(
+ parent_data->shell_surface->GetWidget()->GetNativeWindow(), &work_area);
+
+ // Try layout using parent's flip state.
+ WaylandPositioner* positioner =
+ GetUserDataAs<WaylandPositioner>(positioner_resource);
+ WaylandPositioner::Result position = positioner->CalculatePosition(
+ work_area, parent_data->shell_surface->x_flipped(),
+ parent_data->shell_surface->y_flipped());
+
+ // Remember the new flip state for its child popups.
+ shell_surface_data->shell_surface->set_x_flipped(position.x_flipped);
+ shell_surface_data->shell_surface->set_y_flipped(position.y_flipped);
+
+ // |position| is relative to the parent's contents view origin, and |origin|
+ // is in screen coordinates.
+ gfx::Point origin = position.origin;
+ views::View::ConvertPointToScreen(parent_data->shell_surface->GetWidget()
+ ->widget_delegate()
+ ->GetContentsView(),
+ &origin);
+ shell_surface_data->shell_surface->SetOrigin(origin);
+ shell_surface_data->shell_surface->SetSize(position.size);
+ shell_surface_data->shell_surface->DisableMovement();
+ shell_surface_data->shell_surface->SetActivatable(false);
+ shell_surface_data->shell_surface->SetCanMinimize(false);
+ shell_surface_data->shell_surface->SetParent(
+ parent_data->shell_surface.get());
+ shell_surface_data->shell_surface->SetPopup();
+ shell_surface_data->shell_surface->SetEnabled(true);
+
+ wl_resource* xdg_popup_resource =
+ wl_resource_create(client, &xdg_popup_interface, 1, id);
+
+ SetImplementation(
+ xdg_popup_resource, &xdg_popup_implementation,
+ std::make_unique<WaylandPopup>(xdg_popup_resource, resource));
+
+ // We send the configure event here as this event needs x,y coordinates
+ // relative to the parent window.
+ xdg_popup_send_configure(xdg_popup_resource, position.origin.x(),
+ position.origin.y(), position.size.width(),
+ position.size.height());
+}
+
+void xdg_surface_set_window_geometry(wl_client* client,
+ wl_resource* resource,
+ int32_t x,
+ int32_t y,
+ int32_t width,
+ int32_t height) {
+ GetUserDataAs<WaylandXdgSurface>(resource)->shell_surface->SetGeometry(
+ gfx::Rect(x, y, width, height));
+}
+
+void xdg_surface_ack_configure(wl_client* client,
+ wl_resource* resource,
+ uint32_t serial) {
+ GetUserDataAs<WaylandXdgSurface>(resource)
+ ->shell_surface->AcknowledgeConfigure(serial);
+}
+
+const struct xdg_surface_interface xdg_surface_implementation = {
+ xdg_surface_destroy, xdg_surface_get_toplevel, xdg_surface_get_popup,
+ xdg_surface_set_window_geometry, xdg_surface_ack_configure};
+
+////////////////////////////////////////////////////////////////////////////////
+// xdg_wm_base_interface:
+
+void xdg_wm_base_destroy(wl_client* client, wl_resource* resource) {
+ // Nothing to do here.
+}
+
+void xdg_wm_base_create_positioner(wl_client* client,
+ wl_resource* resource,
+ uint32_t id) {
+ wl_resource* positioner_resource =
+ wl_resource_create(client, &xdg_positioner_interface, 1, id);
+
+ SetImplementation(
+ positioner_resource, &xdg_positioner_implementation,
+ std::make_unique<WaylandPositioner>(WaylandPositioner::Version::STABLE));
+}
+
+void xdg_wm_base_get_xdg_surface(wl_client* client,
+ wl_resource* resource,
+ uint32_t id,
+ wl_resource* surface) {
+ auto* data = GetUserDataAs<WaylandXdgShell>(resource);
+ std::unique_ptr<XdgShellSurface> shell_surface =
+ data->display->CreateXdgShellSurface(GetUserDataAs<Surface>(surface));
+ if (!shell_surface) {
+ wl_resource_post_error(resource, XDG_WM_BASE_ERROR_ROLE,
+ "surface has already been assigned a role");
+ return;
+ }
+
+ // Xdg shell surfaces are initially disabled and needs to be explicitly mapped
+ // before they are enabled and can become visible.
+ shell_surface->SetEnabled(false);
+
+ std::unique_ptr<WaylandXdgSurface> wayland_shell_surface =
+ std::make_unique<WaylandXdgSurface>(std::move(shell_surface),
+ data->serial_tracker);
+
+ wl_resource* xdg_surface_resource =
+ wl_resource_create(client, &xdg_surface_interface, 1, id);
+
+ SetImplementation(xdg_surface_resource, &xdg_surface_implementation,
+ std::move(wayland_shell_surface));
+}
+
+void xdg_wm_base_pong(wl_client* client,
+ wl_resource* resource,
+ uint32_t serial) {
+ NOTIMPLEMENTED();
+}
+
+const struct xdg_wm_base_interface xdg_wm_base_implementation = {
+ xdg_wm_base_destroy, xdg_wm_base_create_positioner,
+ xdg_wm_base_get_xdg_surface, xdg_wm_base_pong};
+
+} // namespace
+
+void bind_xdg_shell(wl_client* client,
+ void* data,
+ uint32_t version,
+ uint32_t id) {
+ wl_resource* resource =
+ wl_resource_create(client, &xdg_wm_base_interface, 1, id);
+
+ wl_resource_set_implementation(resource, &xdg_wm_base_implementation, data,
+ nullptr);
+}
+
+} // namespace wayland
+} // namespace exo
diff --git a/chromium/components/exo/wayland/xdg_shell.h b/chromium/components/exo/wayland/xdg_shell.h
new file mode 100644
index 00000000000..9619efdea12
--- /dev/null
+++ b/chromium/components/exo/wayland/xdg_shell.h
@@ -0,0 +1,41 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_EXO_WAYLAND_XDG_SHELL_H_
+#define COMPONENTS_EXO_WAYLAND_XDG_SHELL_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+
+struct wl_client;
+
+namespace exo {
+class Display;
+
+namespace wayland {
+class SerialTracker;
+
+struct WaylandXdgShell {
+ WaylandXdgShell(Display* display, SerialTracker* serial_tracker)
+ : display(display), serial_tracker(serial_tracker) {}
+
+ // Owned by WaylandServerController, which always outlives xdg_shell.
+ Display* const display;
+
+ // Owned by Server, which always outlives xdg_shell.
+ SerialTracker* const serial_tracker;
+
+ DISALLOW_COPY_AND_ASSIGN(WaylandXdgShell);
+};
+
+void bind_xdg_shell(wl_client* client,
+ void* data,
+ uint32_t version,
+ uint32_t id);
+
+} // namespace wayland
+} // namespace exo
+
+#endif // COMPONENTS_EXO_WAYLAND_XDG_SHELL_H_
diff --git a/chromium/components/exo/wayland/zaura_shell.cc b/chromium/components/exo/wayland/zaura_shell.cc
index a3b0a7b6fcd..b80e9ebb559 100644
--- a/chromium/components/exo/wayland/zaura_shell.cc
+++ b/chromium/components/exo/wayland/zaura_shell.cc
@@ -224,7 +224,7 @@ void AuraSurface::OnSurfaceDestroying(Surface* surface) {
}
void AuraSurface::OnWindowOcclusionChanged(Surface* surface) {
- if (!surface_ || !surface_->is_tracking_occlusion())
+ if (!surface_ || !surface_->IsTrackingOcclusion())
return;
auto* window = surface_->window();
ComputeAndSendOcclusionFraction(window->occlusion_state(),
@@ -241,7 +241,7 @@ void AuraSurface::OnWindowActivating(ActivationReason reason,
// Check if this surface is a child of a window that is losing focus.
auto* widget = views::Widget::GetTopLevelWidgetForNativeView(window);
if (!widget || losing_active != widget->GetNativeWindow() ||
- !surface_->is_tracking_occlusion())
+ !surface_->IsTrackingOcclusion())
return;
// Result may be changed by animated windows, so compute it explicitly.
diff --git a/chromium/components/exo/wayland/zaura_shell_unittest.cc b/chromium/components/exo/wayland/zaura_shell_unittest.cc
index 4a7218ca626..90db54f3845 100644
--- a/chromium/components/exo/wayland/zaura_shell_unittest.cc
+++ b/chromium/components/exo/wayland/zaura_shell_unittest.cc
@@ -11,6 +11,7 @@
#include "ash/wm/desks/desks_util.h"
#include "ash/wm/window_util.h"
#include "base/time/time.h"
+#include "components/exo/buffer.h"
#include "components/exo/test/exo_test_base.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/window_occlusion_tracker.h"
@@ -67,7 +68,13 @@ class ZAuraSurfaceTest : public test::ExoTestBase,
void SetUp() override {
test::ExoTestBase::SetUp();
+ gfx::Size buffer_size(10, 10);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+
surface_.reset(new Surface);
+ surface_->Attach(buffer.get());
+
aura_surface_.reset(new TestAuraSurface(surface_.get()));
gfx::Transform transform;
@@ -128,8 +135,25 @@ class ZAuraSurfaceTest : public test::ExoTestBase,
DISALLOW_COPY_AND_ASSIGN(ZAuraSurfaceTest);
};
+TEST_F(ZAuraSurfaceTest, OcclusionTrackingStartsAfterCommit) {
+ surface().OnWindowOcclusionChanged();
+
+ EXPECT_EQ(-1.0f, aura_surface().last_sent_occlusion_fraction());
+ EXPECT_EQ(0, aura_surface().num_occlusion_updates());
+ EXPECT_FALSE(surface().IsTrackingOcclusion());
+
+ auto widget = CreateOpaqueWidget(gfx::Rect(0, 0, 10, 10));
+ widget->Show();
+ surface().Commit();
+
+ EXPECT_EQ(0.2f, aura_surface().last_sent_occlusion_fraction());
+ EXPECT_EQ(1, aura_surface().num_occlusion_updates());
+ EXPECT_TRUE(surface().IsTrackingOcclusion());
+}
+
TEST_F(ZAuraSurfaceTest,
LosingActivationWithNoAnimatingWindowsSendsCorrectOcclusionFraction) {
+ surface().Commit();
EXPECT_EQ(0.0f, aura_surface().last_sent_occlusion_fraction());
EXPECT_EQ(1, aura_surface().num_occlusion_updates());
::wm::ActivateWindow(parent_widget().GetNativeWindow());
@@ -146,6 +170,7 @@ TEST_F(ZAuraSurfaceTest,
TEST_F(ZAuraSurfaceTest,
LosingActivationWithAnimatingWindowsSendsTargetOcclusionFraction) {
+ surface().Commit();
EXPECT_EQ(0.0f, aura_surface().last_sent_occlusion_fraction());
EXPECT_EQ(1, aura_surface().num_occlusion_updates());
::wm::ActivateWindow(parent_widget().GetNativeWindow());
@@ -194,6 +219,7 @@ TEST_F(ZAuraSurfaceTest,
TEST_F(ZAuraSurfaceTest,
LosingActivationByTriggeringTheLockScreenDoesNotSendOccludedFraction) {
+ surface().Commit();
EXPECT_EQ(0.0f, aura_surface().last_sent_occlusion_fraction());
EXPECT_EQ(1, aura_surface().num_occlusion_updates());
::wm::ActivateWindow(parent_widget().GetNativeWindow());
@@ -227,9 +253,16 @@ TEST_F(ZAuraSurfaceTest,
TEST_F(ZAuraSurfaceTest, OcclusionIncludesOffScreenArea) {
UpdateDisplay("150x150");
+
+ gfx::Size buffer_size(80, 100);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
// This is scaled by 1.5 - set the bounds to (-60, 75, 120, 150) in screen
// coordinates so 75% of it is outside of the 100x100 screen.
surface().window()->SetBounds(gfx::Rect(-40, 50, 80, 100));
+ surface().Attach(buffer.get());
+ surface().Commit();
+
surface().OnWindowOcclusionChanged();
EXPECT_EQ(0.75f, aura_surface().last_sent_occlusion_fraction());
@@ -238,6 +271,7 @@ TEST_F(ZAuraSurfaceTest, OcclusionIncludesOffScreenArea) {
TEST_F(ZAuraSurfaceTest, ZeroSizeWindowSendsZeroOcclusionFraction) {
// Zero sized window should not be occluded.
surface().window()->SetBounds(gfx::Rect(0, 0, 0, 0));
+ surface().Commit();
surface().OnWindowOcclusionChanged();
EXPECT_EQ(0.0f, aura_surface().last_sent_occlusion_fraction());
}
diff --git a/chromium/components/exo/wayland/zcr_gaming_input.cc b/chromium/components/exo/wayland/zcr_gaming_input.cc
index ad9a7464fad..a8d61c04d6d 100644
--- a/chromium/components/exo/wayland/zcr_gaming_input.cc
+++ b/chromium/components/exo/wayland/zcr_gaming_input.cc
@@ -8,6 +8,8 @@
#include <wayland-server-core.h>
#include <wayland-server-protocol-core.h>
+#include <memory>
+
#include "base/feature_list.h"
#include "base/macros.h"
#include "components/exo/gamepad_delegate.h"
@@ -64,27 +66,30 @@ class WaylandGamepadDelegate : public GamepadDelegate {
wl_resource_set_user_data(gamepad_resource_, nullptr);
delete this;
}
- void OnAxis(int axis, double value) override {
+ void OnAxis(int axis, double value, base::TimeTicks time_stamp) override {
if (!gamepad_resource_) {
return;
}
- zcr_gamepad_v2_send_axis(gamepad_resource_, NowInMilliseconds(), axis,
+ zcr_gamepad_v2_send_axis(gamepad_resource_,
+ TimeTicksToMilliseconds(time_stamp), axis,
wl_fixed_from_double(value));
}
- void OnButton(int button, bool pressed) override {
+ void OnButton(int button, bool pressed, base::TimeTicks time_stamp) override {
if (!gamepad_resource_) {
return;
}
uint32_t state = pressed ? ZCR_GAMEPAD_V2_BUTTON_STATE_PRESSED
: ZCR_GAMEPAD_V2_BUTTON_STATE_RELEASED;
- zcr_gamepad_v2_send_button(gamepad_resource_, NowInMilliseconds(), button,
+ zcr_gamepad_v2_send_button(gamepad_resource_,
+ TimeTicksToMilliseconds(time_stamp), button,
state, wl_fixed_from_double(0));
}
- void OnFrame() override {
+ void OnFrame(base::TimeTicks time_stamp) override {
if (!gamepad_resource_) {
return;
}
- zcr_gamepad_v2_send_frame(gamepad_resource_, NowInMilliseconds());
+ zcr_gamepad_v2_send_frame(gamepad_resource_,
+ TimeTicksToMilliseconds(time_stamp));
wl_client_flush(client());
}
diff --git a/chromium/components/exo/wayland/zwp_text_input_manager.cc b/chromium/components/exo/wayland/zwp_text_input_manager.cc
index 35df45bb43a..3d115a5b528 100644
--- a/chromium/components/exo/wayland/zwp_text_input_manager.cc
+++ b/chromium/components/exo/wayland/zwp_text_input_manager.cc
@@ -71,6 +71,7 @@ class WaylandTextInputDelegate : public TextInput::Delegate {
style = ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_SELECTION;
break;
case ui::ImeTextSpan::Type::kMisspellingSuggestion:
+ case ui::ImeTextSpan::Type::kAutocorrect:
style = ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_INCORRECT;
break;
}
diff --git a/chromium/components/exo/wayland/zxdg_shell.cc b/chromium/components/exo/wayland/zxdg_shell.cc
index fde5aec2fbc..a4284484676 100644
--- a/chromium/components/exo/wayland/zxdg_shell.cc
+++ b/chromium/components/exo/wayland/zxdg_shell.cc
@@ -632,14 +632,15 @@ void xdg_shell_v6_create_positioner(wl_client* client,
wl_resource_create(client, &zxdg_positioner_v6_interface, 1, id);
SetImplementation(positioner_resource, &xdg_positioner_v6_implementation,
- std::make_unique<WaylandPositioner>());
+ std::make_unique<WaylandPositioner>(
+ WaylandPositioner::Version::UNSTABLE));
}
void xdg_shell_v6_get_xdg_surface(wl_client* client,
wl_resource* resource,
uint32_t id,
wl_resource* surface) {
- auto* data = GetUserDataAs<WaylandXdgShell>(resource);
+ auto* data = GetUserDataAs<WaylandZxdgShell>(resource);
std::unique_ptr<XdgShellSurface> shell_surface =
data->display->CreateXdgShellSurface(GetUserDataAs<Surface>(surface));
if (!shell_surface) {
@@ -675,10 +676,10 @@ const struct zxdg_shell_v6_interface xdg_shell_v6_implementation = {
} // namespace
-void bind_xdg_shell_v6(wl_client* client,
- void* data,
- uint32_t version,
- uint32_t id) {
+void bind_zxdg_shell_v6(wl_client* client,
+ void* data,
+ uint32_t version,
+ uint32_t id) {
wl_resource* resource =
wl_resource_create(client, &zxdg_shell_v6_interface, 1, id);
diff --git a/chromium/components/exo/wayland/zxdg_shell.h b/chromium/components/exo/wayland/zxdg_shell.h
index f5112d36170..026a8bbc690 100644
--- a/chromium/components/exo/wayland/zxdg_shell.h
+++ b/chromium/components/exo/wayland/zxdg_shell.h
@@ -17,8 +17,8 @@ class Display;
namespace wayland {
class SerialTracker;
-struct WaylandXdgShell {
- WaylandXdgShell(Display* display, SerialTracker* serial_tracker)
+struct WaylandZxdgShell {
+ WaylandZxdgShell(Display* display, SerialTracker* serial_tracker)
: display(display), serial_tracker(serial_tracker) {}
// Owned by WaylandServerController, which always outlives zxdg_shell.
@@ -27,13 +27,13 @@ struct WaylandXdgShell {
// Owned by Server, which always outlives zxdg_shell.
SerialTracker* const serial_tracker;
- DISALLOW_COPY_AND_ASSIGN(WaylandXdgShell);
+ DISALLOW_COPY_AND_ASSIGN(WaylandZxdgShell);
};
-void bind_xdg_shell_v6(wl_client* client,
- void* data,
- uint32_t version,
- uint32_t id);
+void bind_zxdg_shell_v6(wl_client* client,
+ void* data,
+ uint32_t version,
+ uint32_t id);
} // namespace wayland
} // namespace exo
diff --git a/chromium/components/exo/wm_helper_chromeos.cc b/chromium/components/exo/wm_helper_chromeos.cc
index 93fb49a93b9..4086f953a96 100644
--- a/chromium/components/exo/wm_helper_chromeos.cc
+++ b/chromium/components/exo/wm_helper_chromeos.cc
@@ -120,11 +120,10 @@ void WMHelperChromeOS::OnDragExited() {
int WMHelperChromeOS::OnPerformDrop(const ui::DropTargetEvent& event,
std::unique_ptr<ui::OSExchangeData> data) {
+ int valid_operation = ui::DragDropTypes::DRAG_NONE;
for (DragDropObserver& observer : drag_drop_observers_)
- observer.OnPerformDrop(event);
- // TODO(hirono): Return the correct result instead of always returning
- // DRAG_MOVE.
- return ui::DragDropTypes::DRAG_MOVE;
+ valid_operation = valid_operation | observer.OnPerformDrop(event);
+ return valid_operation;
}
void WMHelperChromeOS::AddVSyncParameterObserver(
diff --git a/chromium/components/exo/xdg_shell_surface.h b/chromium/components/exo/xdg_shell_surface.h
index 6ac38df90aa..49f8e05088b 100644
--- a/chromium/components/exo/xdg_shell_surface.h
+++ b/chromium/components/exo/xdg_shell_surface.h
@@ -11,7 +11,6 @@
#include "ash/display/window_tree_host_manager.h"
#include "ash/wm/window_state_observer.h"
-#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/optional.h"
#include "base/strings/string16.h"