summaryrefslogtreecommitdiff
path: root/chromium/ui/views/widget
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/ui/views/widget
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-chromium-85-based.tar.gz
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/ui/views/widget')
-rw-r--r--chromium/ui/views/widget/ax_native_widget_mac_unittest.mm2
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc61
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h10
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc468
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc313
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h86
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc77
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc51
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h10
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc11
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen.cc2
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_linux.cc35
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc6
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc4
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_win.h2
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc34
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h9
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc17
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h8
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_unittest.cc228
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc64
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc26
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h8
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc16
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h5
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc52
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc675
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_drag_drop_client_unittest.cc827
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc217
-rw-r--r--chromium/ui/views/widget/native_widget_aura_unittest.cc21
-rw-r--r--chromium/ui/views/widget/root_view_unittest.cc28
-rw-r--r--chromium/ui/views/widget/unique_widget_ptr.cc97
-rw-r--r--chromium/ui/views/widget/unique_widget_ptr.h43
-rw-r--r--chromium/ui/views/widget/unique_widget_ptr_unittest.cc133
-rw-r--r--chromium/ui/views/widget/widget.cc24
-rw-r--r--chromium/ui/views/widget/widget_delegate.cc47
-rw-r--r--chromium/ui/views/widget/widget_delegate.h68
-rw-r--r--chromium/ui/views/widget/widget_deletion_observer.cc1
-rw-r--r--chromium/ui/views/widget/widget_hwnd_utils.cc2
-rw-r--r--chromium/ui/views/widget/widget_interactive_uitest.cc30
-rw-r--r--chromium/ui/views/widget/window_reorderer_unittest.cc12
41 files changed, 2330 insertions, 1500 deletions
diff --git a/chromium/ui/views/widget/ax_native_widget_mac_unittest.mm b/chromium/ui/views/widget/ax_native_widget_mac_unittest.mm
index faf79e0e6c7..ca7575056b0 100644
--- a/chromium/ui/views/widget/ax_native_widget_mac_unittest.mm
+++ b/chromium/ui/views/widget/ax_native_widget_mac_unittest.mm
@@ -772,7 +772,7 @@ class TestComboboxModel : public ui::ComboboxModel {
// ui::ComboboxModel:
int GetItemCount() const override { return 2; }
- base::string16 GetItemAt(int index) override {
+ base::string16 GetItemAt(int index) const override {
return index == 0 ? base::SysNSStringToUTF16(kTestStringValue)
: base::ASCIIToUTF16("Second Item");
}
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
index 3ee330f3598..80090c42e7d 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
@@ -11,7 +11,6 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/aura/client/capture_client.h"
#include "ui/aura/client/drag_drop_client.h"
@@ -24,6 +23,7 @@
#include "ui/base/dragdrop/os_exchange_data_provider_x11.h"
#include "ui/base/layout.h"
#include "ui/base/x/selection_utils.h"
+#include "ui/base/x/x11_cursor.h"
#include "ui/base/x/x11_drag_context.h"
#include "ui/base/x/x11_util.h"
#include "ui/base/x/x11_whole_screen_move_loop.h"
@@ -32,6 +32,7 @@
#include "ui/events/event_utils.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/x/x11.h"
+#include "ui/gfx/x/xproto.h"
#include "ui/platform_window/x11/x11_topmost_window_finder.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
@@ -115,9 +116,8 @@ DesktopDragDropClientAuraX11*
DesktopDragDropClientAuraX11::DesktopDragDropClientAuraX11(
aura::Window* root_window,
views::DesktopNativeCursorManager* cursor_manager,
- ::Display* display,
- XID window)
- : XDragDropClient(this, display, window),
+ x11::Window window)
+ : XDragDropClient(this, window),
root_window_(root_window),
cursor_manager_(cursor_manager) {}
@@ -140,9 +140,6 @@ int DesktopDragDropClientAuraX11::StartDragAndDrop(
const gfx::Point& /*screen_location*/,
int operation,
ui::DragDropTypes::DragEventSource source) {
- UMA_HISTOGRAM_ENUMERATION("Event.DragDrop.Start", source,
- ui::DragDropTypes::DRAG_EVENT_SOURCE_COUNT);
-
DCHECK(!g_current_drag_drop_client);
g_current_drag_drop_client = this;
@@ -171,28 +168,24 @@ int DesktopDragDropClientAuraX11::StartDragAndDrop(
// Windows has a specific method, DoDragDrop(), which performs the entire
// drag. We have to emulate this, so we spin off a nested runloop which will
// track all cursor movement and reroute events to a specific handler.
+ auto* last_cursor = static_cast<ui::X11Cursor*>(
+ source_window->GetHost()->last_cursor().platform());
move_loop_->RunMoveLoop(
!source_window->HasCapture(),
- source_window->GetHost()->last_cursor().platform(),
- cursor_manager_->GetInitializedCursor(ui::mojom::CursorType::kGrabbing)
- .platform());
+ last_cursor ? last_cursor->xcursor() : x11::None,
+ static_cast<ui::X11Cursor*>(
+ cursor_manager_
+ ->GetInitializedCursor(ui::mojom::CursorType::kGrabbing)
+ .platform())
+ ->xcursor());
if (alive) {
auto resulting_operation = negotiated_operation();
- if (resulting_operation == ui::DragDropTypes::DRAG_NONE) {
- UMA_HISTOGRAM_ENUMERATION("Event.DragDrop.Cancel", source,
- ui::DragDropTypes::DRAG_EVENT_SOURCE_COUNT);
- } else {
- UMA_HISTOGRAM_ENUMERATION("Event.DragDrop.Drop", source,
- ui::DragDropTypes::DRAG_EVENT_SOURCE_COUNT);
- }
drag_widget_.reset();
g_current_drag_drop_client = nullptr;
CleanupDrag();
return resulting_operation;
}
- UMA_HISTOGRAM_ENUMERATION("Event.DragDrop.Cancel", source,
- ui::DragDropTypes::DRAG_EVENT_SOURCE_COUNT);
return ui::DragDropTypes::DRAG_NONE;
}
@@ -214,12 +207,13 @@ void DesktopDragDropClientAuraX11::RemoveObserver(
NOTIMPLEMENTED();
}
-bool DesktopDragDropClientAuraX11::DispatchXEvent(XEvent* event) {
- if (!target_current_context() ||
- event->xany.window != target_current_context()->source_window()) {
+bool DesktopDragDropClientAuraX11::DispatchXEvent(x11::Event* event) {
+ auto* prop = event->As<x11::PropertyNotifyEvent>();
+ if (!target_current_context() || !prop ||
+ prop->window != target_current_context()->source_window()) {
return false;
}
- return target_current_context()->DispatchXEvent(event);
+ return target_current_context()->DispatchPropertyNotifyEvent(*prop);
}
void DesktopDragDropClientAuraX11::OnWindowDestroyed(aura::Window* window) {
@@ -339,13 +333,8 @@ int DesktopDragDropClientAuraX11::UpdateDrag(const gfx::Point& screen_point) {
std::unique_ptr<ui::DropTargetEvent> drop_target_event;
DragDropDelegate* delegate = nullptr;
DragTranslate(screen_point, &data, &drop_target_event, &delegate);
- int drag_operation =
- delegate ? drag_operation = delegate->OnDragUpdated(*drop_target_event)
- : ui::DragDropTypes::DRAG_NONE;
- UMA_HISTOGRAM_BOOLEAN("Event.DragDrop.AcceptDragUpdate",
- drag_operation != ui::DragDropTypes::DRAG_NONE);
-
- return drag_operation;
+ return delegate ? delegate->OnDragUpdated(*drop_target_event)
+ : ui::DragDropTypes::DRAG_NONE;
}
void DesktopDragDropClientAuraX11::UpdateCursor(
@@ -366,10 +355,12 @@ void DesktopDragDropClientAuraX11::UpdateCursor(
break;
}
move_loop_->UpdateCursor(
- cursor_manager_->GetInitializedCursor(cursor_type).platform());
+ static_cast<ui::X11Cursor*>(
+ cursor_manager_->GetInitializedCursor(cursor_type).platform())
+ ->xcursor());
}
-void DesktopDragDropClientAuraX11::OnBeginForeignDrag(XID window) {
+void DesktopDragDropClientAuraX11::OnBeginForeignDrag(x11::Window window) {
DCHECK(target_current_context());
DCHECK(!target_current_context()->source_client());
@@ -413,10 +404,6 @@ int DesktopDragDropClientAuraX11::PerformDrop() {
drop_event.set_flags(ui::XGetMaskAsEventFlags());
}
- if (!IsDragDropInProgress()) {
- UMA_HISTOGRAM_COUNTS_1M("Event.DragDrop.ExternalOriginDrop", 1);
- }
-
drag_operation = delegate->OnPerformDrop(drop_event, std::move(data));
}
@@ -426,7 +413,7 @@ int DesktopDragDropClientAuraX11::PerformDrop() {
return drag_operation;
}
-void DesktopDragDropClientAuraX11::EndMoveLoop() {
+void DesktopDragDropClientAuraX11::EndDragLoop() {
move_loop_->EndMoveLoop();
}
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
index a06220b1864..b8f6cceafbf 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
@@ -22,6 +22,7 @@
#include "ui/events/x/x11_window_event_manager.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/x/event.h"
#include "ui/gfx/x/x11.h"
#include "ui/views/views_export.h"
@@ -61,8 +62,7 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
DesktopDragDropClientAuraX11(
aura::Window* root_window,
views::DesktopNativeCursorManager* cursor_manager,
- Display* xdisplay,
- XID xwindow);
+ x11::Window xwindow);
~DesktopDragDropClientAuraX11() override;
void Init();
@@ -80,7 +80,7 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
void RemoveObserver(aura::client::DragDropClientObserver* observer) override;
// XEventDispatcher:
- bool DispatchXEvent(XEvent* event) override;
+ bool DispatchXEvent(x11::Event* event) override;
// aura::WindowObserver:
void OnWindowDestroyed(aura::Window* window) override;
@@ -118,11 +118,11 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
int UpdateDrag(const gfx::Point& screen_point) override;
void UpdateCursor(
ui::DragDropTypes::DragOperation negotiated_operation) override;
- void OnBeginForeignDrag(XID window) override;
+ void OnBeginForeignDrag(x11::Window window) override;
void OnEndForeignDrag() override;
void OnBeforeDragLeave() override;
int PerformDrop() override;
- void EndMoveLoop() override;
+ void EndDragLoop() override;
// A nested run loop that notifies this object of events through the
// ui::X11MoveLoopDelegate interface.
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
index 68c1ba2c47d..1ab88c73c14 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
+
#include <map>
#include <memory>
#include <utility>
@@ -26,23 +28,26 @@
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_types.h"
+#include "ui/gfx/x/xproto.h"
#include "ui/views/test/views_test_base.h"
-#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/widget/widget.h"
+// TODO(crbug.com/990756): Transfer all tests from this file to better places
+// when DDDClientAuraX11 goes away.
+
namespace views {
namespace {
class TestDragDropClient;
-// Collects messages which would otherwise be sent to |xid_| via
+// Collects messages which would otherwise be sent to |window_| via
// SendXClientEvent().
class ClientMessageEventCollector {
public:
- ClientMessageEventCollector(::Window xid, TestDragDropClient* client);
+ ClientMessageEventCollector(x11::Window window, TestDragDropClient* client);
virtual ~ClientMessageEventCollector();
// Returns true if |events_| is non-empty.
@@ -50,18 +55,18 @@ class ClientMessageEventCollector {
// Pops all of |events_| and returns the popped events in the order that they
// were on the stack
- std::vector<XClientMessageEvent> PopAllEvents();
+ std::vector<x11::ClientMessageEvent> PopAllEvents();
// Adds |event| to the stack.
- void RecordEvent(const XClientMessageEvent& event);
+ void RecordEvent(const x11::ClientMessageEvent& event);
private:
- ::Window xid_;
+ x11::Window window_;
// Not owned.
TestDragDropClient* client_;
- std::vector<XClientMessageEvent> events_;
+ std::vector<x11::ClientMessageEvent> events_;
DISALLOW_COPY_AND_ASSIGN(ClientMessageEventCollector);
};
@@ -101,8 +106,8 @@ class SimpleTestDragDropClient : public DesktopDragDropClientAuraX11 {
DesktopNativeCursorManager* cursor_manager);
~SimpleTestDragDropClient() override;
- // Sets |xid| as the topmost window for all mouse positions.
- void SetTopmostXWindow(XID xid);
+ // Sets |window| as the topmost window for all mouse positions.
+ void SetTopmostXWindow(x11::Window window);
// Returns true if the move loop is running.
bool IsMoveLoopRunning();
@@ -113,10 +118,10 @@ class SimpleTestDragDropClient : public DesktopDragDropClientAuraX11 {
// DesktopDragDropClientAuraX11:
std::unique_ptr<ui::X11MoveLoop> CreateMoveLoop(
ui::X11MoveLoopDelegate* delegate) override;
- XID FindWindowFor(const gfx::Point& screen_point) override;
+ x11::Window FindWindowFor(const gfx::Point& screen_point) override;
- // The XID of the window which is simulated to be the topmost window.
- XID target_xid_ = x11::None;
+ // The x11::Window of the window which is simulated to be the topmost window.
+ x11::Window target_window_ = x11::Window::None;
// The move loop. Not owned.
TestMoveLoop* loop_ = nullptr;
@@ -137,46 +142,47 @@ class TestDragDropClient : public SimpleTestDragDropClient {
DesktopNativeCursorManager* cursor_manager);
~TestDragDropClient() override;
- // Returns the XID of the window which initiated the drag.
- ::Window source_xwindow() { return source_xid_; }
+ // Returns the x11::Window of the window which initiated the drag.
+ x11::Window source_xwindow() { return source_window_; }
// Returns the Atom with |name|.
- Atom GetAtom(const char* name);
+ x11::Atom GetAtom(const char* name);
// Returns true if the event's message has |type|.
- bool MessageHasType(const XClientMessageEvent& event, const char* type);
+ bool MessageHasType(const x11::ClientMessageEvent& event, const char* type);
- // Sets |collector| to collect XClientMessageEvents which would otherwise
+ // Sets |collector| to collect x11::ClientMessageEvents which would otherwise
// have been sent to the drop target window.
- void SetEventCollectorFor(::Window xid,
+ void SetEventCollectorFor(x11::Window window,
ClientMessageEventCollector* collector);
// Builds an XdndStatus message and sends it to
// DesktopDragDropClientAuraX11.
- void OnStatus(XID target_window,
+ void OnStatus(x11::Window target_window,
bool will_accept_drop,
- ::Atom accepted_action);
+ x11::Atom accepted_action);
// Builds an XdndFinished message and sends it to
// DesktopDragDropClientAuraX11.
- void OnFinished(XID target_window,
+ void OnFinished(x11::Window target_window,
bool accepted_drop,
- ::Atom performed_action);
+ x11::Atom performed_action);
- // Sets |xid| as the topmost window at the current mouse position and
+ // Sets |window| as the topmost window at the current mouse position and
// generates a synthetic mouse move.
- void SetTopmostXWindowAndMoveMouse(::Window xid);
+ void SetTopmostXWindowAndMoveMouse(x11::Window window);
private:
// DesktopDragDropClientAuraX11:
- void SendXClientEvent(::Window xid, XEvent* event) override;
+ void SendXClientEvent(x11::Window window,
+ const x11::ClientMessageEvent& event) override;
- // The XID of the window which initiated the drag.
- ::Window source_xid_;
+ // The x11::Window of the window which initiated the drag.
+ x11::Window source_window_;
- // Map of ::Windows to the collector which intercepts XClientMessageEvents
- // for that window.
- std::map<::Window, ClientMessageEventCollector*> collectors_;
+ // Map of x11::Windows to the collector which intercepts
+ // x11::ClientMessageEvents for that window.
+ std::map<x11::Window, ClientMessageEventCollector*> collectors_;
DISALLOW_COPY_AND_ASSIGN(TestDragDropClient);
};
@@ -185,24 +191,25 @@ class TestDragDropClient : public SimpleTestDragDropClient {
// ClientMessageEventCollector
ClientMessageEventCollector::ClientMessageEventCollector(
- ::Window xid,
+ x11::Window window,
TestDragDropClient* client)
- : xid_(xid), client_(client) {
- client->SetEventCollectorFor(xid, this);
+ : window_(window), client_(client) {
+ client->SetEventCollectorFor(window, this);
}
ClientMessageEventCollector::~ClientMessageEventCollector() {
- client_->SetEventCollectorFor(xid_, nullptr);
+ client_->SetEventCollectorFor(window_, nullptr);
}
-std::vector<XClientMessageEvent> ClientMessageEventCollector::PopAllEvents() {
- std::vector<XClientMessageEvent> to_return;
+std::vector<x11::ClientMessageEvent>
+ClientMessageEventCollector::PopAllEvents() {
+ std::vector<x11::ClientMessageEvent> to_return;
to_return.swap(events_);
return to_return;
}
void ClientMessageEventCollector::RecordEvent(
- const XClientMessageEvent& event) {
+ const x11::ClientMessageEvent& event) {
events_.push_back(event);
}
@@ -246,13 +253,12 @@ SimpleTestDragDropClient::SimpleTestDragDropClient(
DesktopNativeCursorManager* cursor_manager)
: DesktopDragDropClientAuraX11(window,
cursor_manager,
- gfx::GetXDisplay(),
window->GetHost()->GetAcceleratedWidget()) {}
SimpleTestDragDropClient::~SimpleTestDragDropClient() = default;
-void SimpleTestDragDropClient::SetTopmostXWindow(XID xid) {
- target_xid_ = xid;
+void SimpleTestDragDropClient::SetTopmostXWindow(x11::Window window) {
+ target_window_ = window;
}
bool SimpleTestDragDropClient::IsMoveLoopRunning() {
@@ -265,8 +271,9 @@ std::unique_ptr<ui::X11MoveLoop> SimpleTestDragDropClient::CreateMoveLoop(
return base::WrapUnique(loop_);
}
-XID SimpleTestDragDropClient::FindWindowFor(const gfx::Point& screen_point) {
- return target_xid_;
+x11::Window SimpleTestDragDropClient::FindWindowFor(
+ const gfx::Point& screen_point) {
+ return target_window_;
}
///////////////////////////////////////////////////////////////////////////////
@@ -276,68 +283,70 @@ TestDragDropClient::TestDragDropClient(
aura::Window* window,
DesktopNativeCursorManager* cursor_manager)
: SimpleTestDragDropClient(window, cursor_manager),
- source_xid_(window->GetHost()->GetAcceleratedWidget()) {}
+ source_window_(window->GetHost()->GetAcceleratedWidget()) {}
TestDragDropClient::~TestDragDropClient() = default;
-Atom TestDragDropClient::GetAtom(const char* name) {
+x11::Atom TestDragDropClient::GetAtom(const char* name) {
return gfx::GetAtom(name);
}
-bool TestDragDropClient::MessageHasType(const XClientMessageEvent& event,
+bool TestDragDropClient::MessageHasType(const x11::ClientMessageEvent& event,
const char* type) {
- return event.message_type == GetAtom(type);
+ return event.type == GetAtom(type);
}
void TestDragDropClient::SetEventCollectorFor(
- ::Window xid,
+ x11::Window window,
ClientMessageEventCollector* collector) {
if (collector)
- collectors_[xid] = collector;
+ collectors_[window] = collector;
else
- collectors_.erase(xid);
+ collectors_.erase(window);
}
-void TestDragDropClient::OnStatus(XID target_window,
+void TestDragDropClient::OnStatus(x11::Window target_window,
bool will_accept_drop,
- ::Atom accepted_action) {
- XClientMessageEvent event;
- event.message_type = GetAtom("XdndStatus");
+ x11::Atom accepted_action) {
+ x11::ClientMessageEvent event;
+ event.type = GetAtom("XdndStatus");
event.format = 32;
- event.window = source_xid_;
- event.data.l[0] = target_window;
- event.data.l[1] = will_accept_drop ? 1 : 0;
- event.data.l[2] = 0;
- event.data.l[3] = 0;
- event.data.l[4] = accepted_action;
+ event.window = source_window_;
+ event.data.data32[0] = static_cast<uint32_t>(target_window);
+ event.data.data32[1] = will_accept_drop ? 1 : 0;
+ event.data.data32[2] = 0;
+ event.data.data32[3] = 0;
+ event.data.data32[4] = static_cast<uint32_t>(accepted_action);
HandleXdndEvent(event);
}
-void TestDragDropClient::OnFinished(XID target_window,
+void TestDragDropClient::OnFinished(x11::Window target_window,
bool accepted_drop,
- ::Atom performed_action) {
- XClientMessageEvent event;
- event.message_type = GetAtom("XdndFinished");
+ x11::Atom performed_action) {
+ x11::ClientMessageEvent event;
+ event.type = GetAtom("XdndFinished");
event.format = 32;
- event.window = source_xid_;
- event.data.l[0] = target_window;
- event.data.l[1] = accepted_drop ? 1 : 0;
- event.data.l[2] = performed_action;
- event.data.l[3] = 0;
- event.data.l[4] = 0;
+ event.window = source_window_;
+ event.data.data32[0] = static_cast<uint32_t>(target_window);
+ event.data.data32[1] = accepted_drop ? 1 : 0;
+ event.data.data32[2] = static_cast<uint32_t>(performed_action);
+ event.data.data32[3] = 0;
+ event.data.data32[4] = 0;
HandleXdndEvent(event);
}
-void TestDragDropClient::SetTopmostXWindowAndMoveMouse(::Window xid) {
- SetTopmostXWindow(xid);
+void TestDragDropClient::SetTopmostXWindowAndMoveMouse(x11::Window window) {
+ SetTopmostXWindow(window);
OnMouseMovement(gfx::Point(kMouseMoveX, kMouseMoveY), ui::EF_NONE,
ui::EventTimeForNow());
}
-void TestDragDropClient::SendXClientEvent(::Window xid, XEvent* event) {
- auto it = collectors_.find(xid);
+void TestDragDropClient::SendXClientEvent(
+ x11::Window window,
+ const x11::ClientMessageEvent& event) {
+ auto it = collectors_.find(window);
if (it != collectors_.end())
- it->second->RecordEvent(event->xclient);
+ it->second->RecordEvent(event);
}
} // namespace
@@ -402,103 +411,6 @@ class DesktopDragDropClientAuraX11Test : public ViewsTestBase {
DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientAuraX11Test);
};
-namespace {
-
-void BasicStep2(TestDragDropClient* client, XID toplevel) {
- EXPECT_TRUE(client->IsMoveLoopRunning());
-
- ClientMessageEventCollector collector(toplevel, client);
- client->SetTopmostXWindowAndMoveMouse(toplevel);
-
- // XdndEnter should have been sent to |toplevel| before the XdndPosition
- // message.
- std::vector<XClientMessageEvent> events = collector.PopAllEvents();
- ASSERT_EQ(2u, events.size());
-
- EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
- EXPECT_EQ(client->source_xwindow(), static_cast<XID>(events[0].data.l[0]));
- EXPECT_EQ(1, events[0].data.l[1] & 1);
- std::vector<Atom> targets;
- ui::GetAtomArrayProperty(client->source_xwindow(), "XdndTypeList", &targets);
- EXPECT_FALSE(targets.empty());
-
- EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
- EXPECT_EQ(client->source_xwindow(), static_cast<XID>(events[0].data.l[0]));
- const int kCoords =
- TestDragDropClient::kMouseMoveX << 16 | TestDragDropClient::kMouseMoveY;
- EXPECT_EQ(kCoords, events[1].data.l[2]);
- EXPECT_EQ(client->GetAtom("XdndActionCopy"),
- static_cast<Atom>(events[1].data.l[4]));
-
- client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
-
- // Because there is no unprocessed XdndPosition, the drag drop client should
- // send XdndDrop immediately after the mouse is released.
- client->OnMouseReleased();
-
- events = collector.PopAllEvents();
- ASSERT_EQ(1u, events.size());
- EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
- EXPECT_EQ(client->source_xwindow(), static_cast<XID>(events[0].data.l[0]));
-
- // Send XdndFinished to indicate that the drag drop client can cleanup any
- // data related to this drag. The move loop should end only after the
- // XdndFinished message was received.
- EXPECT_TRUE(client->IsMoveLoopRunning());
- client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy"));
- EXPECT_FALSE(client->IsMoveLoopRunning());
-}
-
-void BasicStep3(TestDragDropClient* client, XID toplevel) {
- EXPECT_TRUE(client->IsMoveLoopRunning());
-
- ClientMessageEventCollector collector(toplevel, client);
- client->SetTopmostXWindowAndMoveMouse(toplevel);
-
- std::vector<XClientMessageEvent> events = collector.PopAllEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
- EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
-
- client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
- client->SetTopmostXWindowAndMoveMouse(toplevel);
- events = collector.PopAllEvents();
- ASSERT_EQ(1u, events.size());
- EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition"));
-
- // We have not received an XdndStatus ack for the second XdndPosition message.
- // Test that sending XdndDrop is delayed till the XdndStatus ack is received.
- client->OnMouseReleased();
- EXPECT_FALSE(collector.HasEvents());
-
- client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
- events = collector.PopAllEvents();
- ASSERT_EQ(1u, events.size());
- EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
-
- EXPECT_TRUE(client->IsMoveLoopRunning());
- client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy"));
- EXPECT_FALSE(client->IsMoveLoopRunning());
-}
-
-} // namespace
-
-TEST_F(DesktopDragDropClientAuraX11Test, Basic) {
- XID toplevel = 1;
-
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&BasicStep2, client(), toplevel));
- int result = StartDragAndDrop();
- EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
-
- // Do another drag and drop to test that the data is properly cleaned up as a
- // result of the XdndFinished message.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&BasicStep3, client(), toplevel));
- result = StartDragAndDrop();
- EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
-}
-
void HighDPIStep(TestDragDropClient* client) {
float scale =
display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
@@ -520,6 +432,8 @@ void HighDPIStep(TestDragDropClient* client) {
client->OnMouseReleased();
}
+// TODO(crbug.com/990756): Turn this into tests of DesktopDragDropClientOzone
+// or its equivalent.
TEST_F(DesktopDragDropClientAuraX11Test, HighDPI200) {
aura::TestScreen* screen =
static_cast<aura::TestScreen*>(display::Screen::GetScreen());
@@ -531,6 +445,8 @@ TEST_F(DesktopDragDropClientAuraX11Test, HighDPI200) {
EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
}
+// TODO(crbug.com/990756): Turn this into tests of DesktopDragDropClientOzone
+// or its equivalent.
TEST_F(DesktopDragDropClientAuraX11Test, HighDPI150) {
aura::TestScreen* screen =
static_cast<aura::TestScreen*>(display::Screen::GetScreen());
@@ -544,212 +460,6 @@ TEST_F(DesktopDragDropClientAuraX11Test, HighDPI150) {
namespace {
-void TargetDoesNotRespondStep2(TestDragDropClient* client) {
- EXPECT_TRUE(client->IsMoveLoopRunning());
-
- XID toplevel = 1;
- ClientMessageEventCollector collector(toplevel, client);
- client->SetTopmostXWindowAndMoveMouse(toplevel);
-
- std::vector<XClientMessageEvent> events = collector.PopAllEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
- EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
-
- client->OnMouseReleased();
- events = collector.PopAllEvents();
- ASSERT_EQ(1u, events.size());
- EXPECT_TRUE(client->MessageHasType(events[0], "XdndLeave"));
- EXPECT_FALSE(client->IsMoveLoopRunning());
-}
-
-} // namespace
-
-// Test that we do not wait for the target to send XdndStatus if we have not
-// received any XdndStatus messages at all from the target. The Unity
-// DNDCollectionWindow is an example of an XdndAware target which does not
-// respond to XdndPosition messages at all.
-TEST_F(DesktopDragDropClientAuraX11Test, TargetDoesNotRespond) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&TargetDoesNotRespondStep2, client()));
- int result = StartDragAndDrop();
- EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
-}
-
-namespace {
-
-void QueuePositionStep2(TestDragDropClient* client) {
- EXPECT_TRUE(client->IsMoveLoopRunning());
-
- XID toplevel = 1;
- ClientMessageEventCollector collector(toplevel, client);
- client->SetTopmostXWindowAndMoveMouse(toplevel);
- client->SetTopmostXWindowAndMoveMouse(toplevel);
- client->SetTopmostXWindowAndMoveMouse(toplevel);
-
- std::vector<XClientMessageEvent> events = collector.PopAllEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
- EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
-
- client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
- events = collector.PopAllEvents();
- ASSERT_EQ(1u, events.size());
- EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition"));
-
- client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
- EXPECT_FALSE(collector.HasEvents());
-
- client->OnMouseReleased();
- events = collector.PopAllEvents();
- ASSERT_EQ(1u, events.size());
- EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
-
- EXPECT_TRUE(client->IsMoveLoopRunning());
- client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy"));
- EXPECT_FALSE(client->IsMoveLoopRunning());
-}
-
-} // namespace
-
-// Test that XdndPosition messages are queued till the pending XdndPosition
-// message is acked via an XdndStatus message.
-TEST_F(DesktopDragDropClientAuraX11Test, QueuePosition) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&QueuePositionStep2, client()));
- int result = StartDragAndDrop();
- EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
-}
-
-namespace {
-
-void TargetChangesStep2(TestDragDropClient* client) {
- EXPECT_TRUE(client->IsMoveLoopRunning());
-
- XID toplevel1 = 1;
- ClientMessageEventCollector collector1(toplevel1, client);
- client->SetTopmostXWindowAndMoveMouse(toplevel1);
-
- std::vector<XClientMessageEvent> events1 = collector1.PopAllEvents();
- ASSERT_EQ(2u, events1.size());
- EXPECT_TRUE(client->MessageHasType(events1[0], "XdndEnter"));
- EXPECT_TRUE(client->MessageHasType(events1[1], "XdndPosition"));
-
- XID toplevel2 = 2;
- ClientMessageEventCollector collector2(toplevel2, client);
- client->SetTopmostXWindowAndMoveMouse(toplevel2);
-
- // It is possible for |toplevel1| to send XdndStatus after the source has sent
- // XdndLeave but before |toplevel1| has received the XdndLeave message. The
- // XdndStatus message should be ignored.
- client->OnStatus(toplevel1, true, client->GetAtom("XdndActionCopy"));
- events1 = collector1.PopAllEvents();
- ASSERT_EQ(1u, events1.size());
- EXPECT_TRUE(client->MessageHasType(events1[0], "XdndLeave"));
-
- std::vector<XClientMessageEvent> events2 = collector2.PopAllEvents();
- ASSERT_EQ(2u, events2.size());
- EXPECT_TRUE(client->MessageHasType(events2[0], "XdndEnter"));
- EXPECT_TRUE(client->MessageHasType(events2[1], "XdndPosition"));
-
- client->OnStatus(toplevel2, true, client->GetAtom("XdndActionCopy"));
- client->OnMouseReleased();
- events2 = collector2.PopAllEvents();
- ASSERT_EQ(1u, events2.size());
- EXPECT_TRUE(client->MessageHasType(events2[0], "XdndDrop"));
-
- EXPECT_TRUE(client->IsMoveLoopRunning());
- client->OnFinished(toplevel2, true, client->GetAtom("XdndActionCopy"));
- EXPECT_FALSE(client->IsMoveLoopRunning());
-}
-
-} // namespace
-
-// Test the behavior when the target changes during a drag.
-TEST_F(DesktopDragDropClientAuraX11Test, TargetChanges) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&TargetChangesStep2, client()));
- int result = StartDragAndDrop();
- EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
-}
-
-namespace {
-
-void RejectAfterMouseReleaseStep2(TestDragDropClient* client) {
- EXPECT_TRUE(client->IsMoveLoopRunning());
-
- XID toplevel = 1;
- ClientMessageEventCollector collector(toplevel, client);
- client->SetTopmostXWindowAndMoveMouse(toplevel);
-
- std::vector<XClientMessageEvent> events = collector.PopAllEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
- EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
-
- client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
- EXPECT_FALSE(collector.HasEvents());
-
- // Send another mouse move such that there is a pending XdndPosition.
- client->SetTopmostXWindowAndMoveMouse(toplevel);
- events = collector.PopAllEvents();
- ASSERT_EQ(1u, events.size());
- EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition"));
-
- client->OnMouseReleased();
- // Reject the drop.
- client->OnStatus(toplevel, false, x11::None);
-
- events = collector.PopAllEvents();
- ASSERT_EQ(1u, events.size());
- EXPECT_TRUE(client->MessageHasType(events[0], "XdndLeave"));
- EXPECT_FALSE(client->IsMoveLoopRunning());
-}
-
-void RejectAfterMouseReleaseStep3(TestDragDropClient* client) {
- EXPECT_TRUE(client->IsMoveLoopRunning());
-
- XID toplevel = 2;
- ClientMessageEventCollector collector(toplevel, client);
- client->SetTopmostXWindowAndMoveMouse(toplevel);
-
- std::vector<XClientMessageEvent> events = collector.PopAllEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
- EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
-
- client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
- EXPECT_FALSE(collector.HasEvents());
-
- client->OnMouseReleased();
- events = collector.PopAllEvents();
- ASSERT_EQ(1u, events.size());
- EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
-
- EXPECT_TRUE(client->IsMoveLoopRunning());
- client->OnFinished(toplevel, false, x11::None);
- EXPECT_FALSE(client->IsMoveLoopRunning());
-}
-
-} // namespace
-
-// Test that the source sends XdndLeave instead of XdndDrop if the drag
-// operation is rejected after the mouse is released.
-TEST_F(DesktopDragDropClientAuraX11Test, RejectAfterMouseRelease) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&RejectAfterMouseReleaseStep2, client()));
- int result = StartDragAndDrop();
- EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
-
- // Repeat the test but reject the drop in the XdndFinished message instead.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&RejectAfterMouseReleaseStep3, client()));
- result = StartDragAndDrop();
- EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
-}
-
-namespace {
-
// DragDropDelegate which counts the number of each type of drag-drop event and
// keeps track of the most recent drag-drop event.
class TestDragDropDelegate : public aura::client::DragDropDelegate {
@@ -928,6 +638,8 @@ void ChromeSourceTargetStep2(SimpleTestDragDropClient* client,
} // namespace
+// TODO(crbug.com/990756): Turn this into tests of DesktopDragDropClientOzone
+// or its equivalent.
TEST_F(DesktopDragDropClientAuraX11ChromeSourceTargetTest, Basic) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
@@ -936,6 +648,8 @@ TEST_F(DesktopDragDropClientAuraX11ChromeSourceTargetTest, Basic) {
EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
}
+// TODO(crbug.com/990756): Turn this into tests of DesktopDragDropClientOzone
+// or its equivalent.
// Test that if 'Ctrl' is pressed during a drag and drop operation, that
// the aura::client::DragDropDelegate is properly notified.
TEST_F(DesktopDragDropClientAuraX11ChromeSourceTargetTest, CtrlPressed) {
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
index 24a959b321d..dd9232bb7e9 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
@@ -21,10 +21,13 @@
#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/drop_target_event.h"
-#include "ui/base/dragdrop/os_exchange_data_provider_aura.h"
+#include "ui/base/layout.h"
+#include "ui/display/screen.h"
#include "ui/platform_window/platform_window_delegate.h"
#include "ui/platform_window/platform_window_handler/wm_drag_handler.h"
+#include "ui/views/controls/image_view.h"
#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
+#include "ui/views/widget/widget.h"
namespace views {
@@ -37,8 +40,64 @@ aura::Window* GetTargetWindow(aura::Window* root_window,
return root_window->GetEventHandlerForPoint(root_location);
}
+// The minimum alpha required so we would treat the pixel as visible.
+constexpr uint32_t kMinAlpha = 32;
+
+// Returns true if |image| has any visible regions (defined as having a pixel
+// with alpha > |kMinAlpha|).
+bool IsValidDragImage(const gfx::ImageSkia& image) {
+ if (image.isNull())
+ return false;
+
+ // Because we need a GL context per window, we do a quick check so that we
+ // don't make another context if the window would just be displaying a mostly
+ // transparent image.
+ const SkBitmap* in_bitmap = image.bitmap();
+ for (int y = 0; y < in_bitmap->height(); ++y) {
+ uint32_t* in_row = in_bitmap->getAddr32(0, y);
+
+ for (int x = 0; x < in_bitmap->width(); ++x) {
+ if (SkColorGetA(in_row[x]) > kMinAlpha)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+std::unique_ptr<views::Widget> CreateDragWidget(
+ const gfx::Point& root_location,
+ const gfx::ImageSkia& image,
+ const gfx::Vector2d& drag_widget_offset) {
+ auto widget = std::make_unique<views::Widget>();
+ views::Widget::InitParams params(views::Widget::InitParams::TYPE_DRAG);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.accept_events = false;
+
+ gfx::Point location = root_location - drag_widget_offset;
+ params.bounds = gfx::Rect(location, image.size());
+ widget->set_focus_on_creation(false);
+ widget->set_frame_type(views::Widget::FrameType::kForceNative);
+ widget->Init(std::move(params));
+ widget->GetNativeWindow()->SetName("DragWindow");
+
+ std::unique_ptr<views::ImageView> image_view =
+ std::make_unique<views::ImageView>();
+ image_view->SetImage(image);
+ widget->SetContentsView(std::move(image_view));
+ widget->Show();
+ widget->GetNativeWindow()->layer()->SetFillsBoundsOpaquely(false);
+ widget->StackAtTop();
+
+ return widget;
+}
+
} // namespace
+DesktopDragDropClientOzone::DragContext::DragContext() = default;
+
+DesktopDragDropClientOzone::DragContext::~DragContext() = default;
+
DesktopDragDropClientOzone::DesktopDragDropClientOzone(
aura::Window* root_window,
views::DesktopNativeCursorManager* cursor_manager,
@@ -50,7 +109,7 @@ DesktopDragDropClientOzone::DesktopDragDropClientOzone(
DesktopDragDropClientOzone::~DesktopDragDropClientOzone() {
ResetDragDropTarget();
- if (in_move_loop_)
+ if (IsDragDropInProgress())
DragCancel();
}
@@ -64,9 +123,11 @@ int DesktopDragDropClientOzone::StartDragAndDrop(
if (!drag_handler_)
return ui::DragDropTypes::DragOperation::DRAG_NONE;
- DCHECK(!in_move_loop_);
+ DCHECK(!drag_context_);
+ drag_context_ = std::make_unique<DragContext>();
+
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
- quit_closure_ = run_loop.QuitClosure();
+ drag_context_->quit_closure = run_loop.QuitClosure();
// Chrome expects starting drag and drop to release capture.
aura::Window* capture_window =
@@ -77,18 +138,38 @@ int DesktopDragDropClientOzone::StartDragAndDrop(
aura::client::CursorClient* cursor_client =
aura::client::GetCursorClient(root_window);
- initial_cursor_ = source_window->GetHost()->last_cursor();
+ auto initial_cursor = source_window->GetHost()->last_cursor();
drag_operation_ = operation;
- cursor_client->SetCursor(
- cursor_manager_->GetInitializedCursor(ui::mojom::CursorType::kGrabbing));
-
- drag_handler_->StartDrag(
- *data.get(), operation, cursor_client->GetCursor(),
- base::BindOnce(&DesktopDragDropClientOzone::OnDragSessionClosed,
- base::Unretained(this)));
- in_move_loop_ = true;
+ if (cursor_client) {
+ cursor_client->SetCursor(cursor_manager_->GetInitializedCursor(
+ ui::mojom::CursorType::kGrabbing));
+ }
+
+ const auto& provider = data->provider();
+ gfx::ImageSkia drag_image = provider.GetDragImage();
+ if (IsValidDragImage(drag_image)) {
+ drag_context_->size = drag_image.size();
+ drag_context_->offset = provider.GetDragImageOffset();
+ drag_context_->widget =
+ CreateDragWidget(root_location, drag_image, drag_context_->offset);
+ }
+
+ // This object is owned by a DesktopNativeWidgetAura that can be destroyed
+ // during the drag loop, which will also destroy this object. So keep track
+ // of whether we are still alive after the drag ends.
+ auto alive = weak_factory_.GetWeakPtr();
+
+ drag_handler_->StartDrag(*data.get(), operation, cursor_client->GetCursor(),
+ this);
run_loop.Run();
- DragDropSessionCompleted();
+
+ if (!alive)
+ return ui::DragDropTypes::DRAG_NONE;
+
+ if (cursor_client)
+ cursor_client->SetCursor(initial_cursor);
+ drag_context_.reset();
+
return drag_operation_;
}
@@ -97,7 +178,7 @@ void DesktopDragDropClientOzone::DragCancel() {
}
bool DesktopDragDropClientOzone::IsDragDropInProgress() {
- return in_move_loop_;
+ return bool(drag_context_) && bool(drag_context_->quit_closure);
}
void DesktopDragDropClientOzone::AddObserver(
@@ -117,129 +198,193 @@ void DesktopDragDropClientOzone::OnDragEnter(
last_drag_point_ = point;
drag_operation_ = operation;
- // If it doesn't have |data|, it defers sending events to
- // |drag_drop_delegate_|. It will try again before handling drop.
+ // If |data| is empty, we defer sending any events to the
+ // |drag_drop_delegate_|. All necessary events will be sent on dropping.
if (!data)
return;
- os_exchange_data_ = std::move(data);
- std::unique_ptr<ui::DropTargetEvent> event = CreateDropTargetEvent(point);
- if (drag_drop_delegate_ && event)
- drag_drop_delegate_->OnDragEntered(*event);
+ data_to_drop_ = std::move(data);
+ UpdateTargetAndCreateDropEvent(point);
}
int DesktopDragDropClientOzone::OnDragMotion(const gfx::PointF& point,
int operation) {
last_drag_point_ = point;
drag_operation_ = operation;
- int client_operation =
- ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE;
-
- if (os_exchange_data_) {
- std::unique_ptr<ui::DropTargetEvent> event = CreateDropTargetEvent(point);
- // If |os_exchange_data_| has a valid data, |drag_drop_delegate_| returns
- // the operation which it expects.
- if (drag_drop_delegate_ && event)
- client_operation = drag_drop_delegate_->OnDragUpdated(*event);
- }
+
+ // If |data_to_drop_| doesn't have data, return that we accept everything.
+ if (!data_to_drop_)
+ return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE;
+
+ // Ask the delegate what operation it would accept for the current data.
+ int client_operation = ui::DragDropTypes::DRAG_NONE;
+ std::unique_ptr<ui::DropTargetEvent> event =
+ UpdateTargetAndCreateDropEvent(point);
+ if (drag_drop_delegate_ && event)
+ client_operation = drag_drop_delegate_->OnDragUpdated(*event);
return client_operation;
}
void DesktopDragDropClientOzone::OnDragDrop(
std::unique_ptr<ui::OSExchangeData> data) {
- // If it doesn't have |os_exchange_data_|, it needs to update it with |data|.
- if (!os_exchange_data_) {
- DCHECK(data);
- os_exchange_data_ = std::move(data);
- std::unique_ptr<ui::DropTargetEvent> event =
- CreateDropTargetEvent(last_drag_point_);
- // Sends the deferred drag events to |drag_drop_delegate_| before handling
- // drop.
- if (drag_drop_delegate_ && event) {
- drag_drop_delegate_->OnDragEntered(*event);
- // TODO(jkim): It doesn't use the return value from 'OnDragUpdated' and
- // doesn't have a chance to update the expected operation.
- // https://crbug.com/875164
+ // If we didn't have |data_to_drop_|, then |drag_drop_delegate_| had never
+ // been updated, and now it needs to receive deferred enter and update events
+ // before handling the actual drop.
+ const bool posponed_enter_and_update = !data_to_drop_;
+
+ // If we had |data_to_drop_| already since the drag had entered the window,
+ // then we don't expect new data to come now, and vice versa.
+ DCHECK((data_to_drop_ && !data) || (!data_to_drop_ && data));
+ if (!data_to_drop_)
+ data_to_drop_ = std::move(data);
+
+ // This will call the delegate's OnDragEntered if needed.
+ auto event = UpdateTargetAndCreateDropEvent(last_drag_point_);
+ if (drag_drop_delegate_ && event) {
+ if (posponed_enter_and_update) {
+ // TODO(https://crbug.com/1014860): deal with drop refusals.
+ // The delegate's OnDragUpdated returns an operation that the delegate
+ // would accept. Normally the accepted operation would be propagated
+ // properly, and if the delegate didn't accept it, the drop would never
+ // be called, but in this scenario of postponed updates we send all events
+ // at once. Now we just drop, but perhaps we could call OnDragLeave
+ // and quit?
drag_drop_delegate_->OnDragUpdated(*event);
}
- } else {
- // If it has |os_exchange_data_|, it doesn't expect |data| on OnDragDrop.
- DCHECK(!data);
+ drag_operation_ =
+ drag_drop_delegate_->OnPerformDrop(*event, std::move(data_to_drop_));
}
- PerformDrop();
+ ResetDragDropTarget();
}
void DesktopDragDropClientOzone::OnDragLeave() {
- os_exchange_data_.reset();
+ data_to_drop_.reset();
ResetDragDropTarget();
}
-void DesktopDragDropClientOzone::OnDragSessionClosed(int dnd_action) {
- drag_operation_ = dnd_action;
- QuitRunLoop();
+void DesktopDragDropClientOzone::OnWindowDestroyed(aura::Window* window) {
+ DCHECK_EQ(window, current_window_);
+
+ current_window_->RemoveObserver(this);
+ current_window_ = nullptr;
+ drag_drop_delegate_ = nullptr;
}
-void DesktopDragDropClientOzone::DragDropSessionCompleted() {
+void DesktopDragDropClientOzone::OnDragLocationChanged(
+ const gfx::Point& screen_point_px) {
+ DCHECK(drag_context_);
+
+ if (!drag_context_->widget)
+ return;
+
+ const bool dispatch_mouse_event = !drag_context_->last_screen_location_px;
+ drag_context_->last_screen_location_px = screen_point_px;
+ if (dispatch_mouse_event) {
+ // Post a task to dispatch mouse movement event when control returns to the
+ // message loop. This allows smoother dragging since the events are
+ // dispatched without waiting for the drag widget updates.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&DesktopDragDropClientOzone::UpdateDragWidgetLocation,
+ weak_factory_.GetWeakPtr()));
+ }
+}
+
+void DesktopDragDropClientOzone::OnDragOperationChanged(
+ ui::DragDropTypes::DragOperation operation) {
aura::client::CursorClient* cursor_client =
aura::client::GetCursorClient(root_window_);
if (!cursor_client)
return;
- cursor_client->SetCursor(initial_cursor_);
+ ui::mojom::CursorType cursor_type = ui::mojom::CursorType::kNull;
+ switch (operation) {
+ case ui::DragDropTypes::DRAG_NONE:
+ cursor_type = ui::mojom::CursorType::kDndNone;
+ break;
+ case ui::DragDropTypes::DRAG_MOVE:
+ cursor_type = ui::mojom::CursorType::kDndMove;
+ break;
+ case ui::DragDropTypes::DRAG_COPY:
+ cursor_type = ui::mojom::CursorType::kDndCopy;
+ break;
+ case ui::DragDropTypes::DRAG_LINK:
+ cursor_type = ui::mojom::CursorType::kDndLink;
+ break;
+ }
+ cursor_client->SetCursor(cursor_manager_->GetInitializedCursor(cursor_type));
+}
+
+void DesktopDragDropClientOzone::OnDragFinished(int dnd_action) {
+ drag_operation_ = dnd_action;
+ QuitRunLoop();
}
void DesktopDragDropClientOzone::QuitRunLoop() {
- in_move_loop_ = false;
- if (quit_closure_.is_null())
+ if (!drag_context_->quit_closure)
return;
- std::move(quit_closure_).Run();
+ std::move(drag_context_->quit_closure).Run();
}
std::unique_ptr<ui::DropTargetEvent>
-DesktopDragDropClientOzone::CreateDropTargetEvent(const gfx::PointF& location) {
+DesktopDragDropClientOzone::UpdateTargetAndCreateDropEvent(
+ const gfx::PointF& location) {
const gfx::Point point(location.x(), location.y());
aura::Window* window = GetTargetWindow(root_window_, point);
- if (!window)
+ if (!window) {
+ ResetDragDropTarget();
+ return nullptr;
+ }
+
+ auto* new_delegate = aura::client::GetDragDropDelegate(window);
+ const bool delegate_has_changed = (new_delegate != drag_drop_delegate_);
+ if (delegate_has_changed) {
+ ResetDragDropTarget();
+ drag_drop_delegate_ = new_delegate;
+ current_window_ = window;
+ current_window_->AddObserver(this);
+ }
+
+ if (!drag_drop_delegate_)
return nullptr;
- UpdateDragDropDelegate(window);
gfx::Point root_location(location.x(), location.y());
root_window_->GetHost()->ConvertScreenInPixelsToDIP(&root_location);
gfx::PointF target_location(root_location);
aura::Window::ConvertPointToTarget(root_window_, window, &target_location);
- return std::make_unique<ui::DropTargetEvent>(
- *os_exchange_data_, target_location, gfx::PointF(root_location),
+ auto event = std::make_unique<ui::DropTargetEvent>(
+ *data_to_drop_, target_location, gfx::PointF(root_location),
drag_operation_);
+ if (delegate_has_changed)
+ drag_drop_delegate_->OnDragEntered(*event);
+ return event;
}
-void DesktopDragDropClientOzone::UpdateDragDropDelegate(aura::Window* window) {
- aura::client::DragDropDelegate* delegate =
- aura::client::GetDragDropDelegate(window);
-
- if (drag_drop_delegate_ == delegate)
+void DesktopDragDropClientOzone::UpdateDragWidgetLocation() {
+ if (!drag_context_)
return;
- ResetDragDropTarget();
- if (delegate)
- drag_drop_delegate_ = delegate;
-}
+ float scale_factor =
+ ui::GetScaleFactorForNativeView(drag_context_->widget->GetNativeWindow());
+ gfx::Point scaled_point = gfx::ScaleToRoundedPoint(
+ *drag_context_->last_screen_location_px, 1.f / scale_factor);
+ drag_context_->widget->SetBounds(
+ gfx::Rect(scaled_point - drag_context_->offset, drag_context_->size));
+ drag_context_->widget->StackAtTop();
-void DesktopDragDropClientOzone::ResetDragDropTarget() {
- if (!drag_drop_delegate_)
- return;
- drag_drop_delegate_->OnDragExited();
- drag_drop_delegate_ = nullptr;
+ drag_context_->last_screen_location_px.reset();
}
-void DesktopDragDropClientOzone::PerformDrop() {
- std::unique_ptr<ui::DropTargetEvent> event =
- CreateDropTargetEvent(last_drag_point_);
- if (drag_drop_delegate_ && event)
- drag_operation_ = drag_drop_delegate_->OnPerformDrop(
- *event, std::move(os_exchange_data_));
- DragDropSessionCompleted();
- ResetDragDropTarget();
+void DesktopDragDropClientOzone::ResetDragDropTarget() {
+ if (drag_drop_delegate_) {
+ drag_drop_delegate_->OnDragExited();
+ drag_drop_delegate_ = nullptr;
+ }
+ if (current_window_) {
+ current_window_->RemoveObserver(this);
+ current_window_ = nullptr;
+ }
}
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h
index 05b2fd24af6..d4e93838750 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h
@@ -8,7 +8,9 @@
#include <memory>
#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
#include "ui/aura/client/drag_drop_client.h"
+#include "ui/aura/window_observer.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/gfx/geometry/point_f.h"
@@ -29,17 +31,50 @@ class DropTargetEvent;
namespace views {
class DesktopNativeCursorManager;
+class Widget;
class VIEWS_EXPORT DesktopDragDropClientOzone
: public aura::client::DragDropClient,
- public ui::WmDropHandler {
+ public ui::WmDragHandler::Delegate,
+ public ui::WmDropHandler,
+ public aura::WindowObserver {
public:
DesktopDragDropClientOzone(aura::Window* root_window,
views::DesktopNativeCursorManager* cursor_manager,
ui::WmDragHandler* drag_handler);
~DesktopDragDropClientOzone() override;
- // Overridden from aura::client::DragDropClient:
+ private:
+ friend class DesktopDragDropClientOzoneTest;
+
+ // Holds data related to the drag operation started by this client.
+ struct DragContext {
+ DragContext();
+ ~DragContext();
+
+ // Exits the drag loop.
+ base::OnceClosure quit_closure;
+
+ // Widget that the user drags around. May be nullptr.
+ std::unique_ptr<Widget> widget;
+
+ // The size of drag image.
+ gfx::Size size;
+
+ // The offset of |drag_widget_| relative to the mouse position.
+ gfx::Vector2d offset;
+
+ // The last received drag location. The drag widget is moved asynchronously
+ // so its position is updated when the UI thread has time for that. When
+ // the first change to the location happens, a call to UpdateDragWidget()
+ // is posted, and this location is set. The location can be updated a few
+ // more times until the posted task is executed, but no more than a single
+ // call to UpdateDragWidget() is scheduled at any time; this optional is set
+ // means that the task is scheduled.
+ base::Optional<gfx::Point> last_screen_location_px;
+ };
+
+ // aura::client::DragDropClient
int StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,
aura::Window* root_window,
aura::Window* source_window,
@@ -51,7 +86,7 @@ class VIEWS_EXPORT DesktopDragDropClientOzone
void AddObserver(aura::client::DragDropClientObserver* observer) override;
void RemoveObserver(aura::client::DragDropClientObserver* observer) override;
- // Overridden from void ui::WmDropHandler:
+ // ui::WmDropHandler
void OnDragEnter(const gfx::PointF& point,
std::unique_ptr<ui::OSExchangeData> data,
int operation) override;
@@ -59,24 +94,33 @@ class VIEWS_EXPORT DesktopDragDropClientOzone
void OnDragDrop(std::unique_ptr<ui::OSExchangeData> data) override;
void OnDragLeave() override;
- void OnDragSessionClosed(int operation);
+ // aura::WindowObserver
+ void OnWindowDestroyed(aura::Window* window) override;
+
+ // ui::WmDragHandler::Delegate
+ void OnDragLocationChanged(const gfx::Point& screen_point_px) override;
+ void OnDragOperationChanged(
+ ui::DragDropTypes::DragOperation operation) override;
+ void OnDragFinished(int operation) override;
- private:
- void DragDropSessionCompleted();
void QuitRunLoop();
- // Returns a DropTargetEvent to be passed to the DragDropDelegate, or null to
- // abort the drag.
- std::unique_ptr<ui::DropTargetEvent> CreateDropTargetEvent(
+ // Returns a DropTargetEvent to be passed to the DragDropDelegate.
+ // Updates the delegate if needed, which in its turn calls their
+ // OnDragExited/OnDragEntered, so after getting the event the delegate
+ // is ready to accept OnDragUpdated or OnPerformDrop. Returns nullptr if
+ // drop is not possible.
+ std::unique_ptr<ui::DropTargetEvent> UpdateTargetAndCreateDropEvent(
const gfx::PointF& point);
// Updates |drag_drop_delegate_| along with |window|.
void UpdateDragDropDelegate(aura::Window* window);
- // Resets |drag_drop_delegate_|.
- void ResetDragDropTarget();
+ // Updates |drag_widget_| so it is aligned with the last drag location.
+ void UpdateDragWidgetLocation();
- void PerformDrop();
+ // Resets |drag_drop_delegate_|. Calls OnDragExited() before resetting.
+ void ResetDragDropTarget();
aura::Window* const root_window_;
@@ -84,26 +128,24 @@ class VIEWS_EXPORT DesktopDragDropClientOzone
ui::WmDragHandler* const drag_handler_;
+ // Last window under the mouse.
+ aura::Window* current_window_ = nullptr;
// The delegate corresponding to the window located at the mouse position.
aura::client::DragDropDelegate* drag_drop_delegate_ = nullptr;
// The data to be delivered through the drag and drop.
- std::unique_ptr<ui::OSExchangeData> os_exchange_data_ = nullptr;
+ std::unique_ptr<ui::OSExchangeData> data_to_drop_;
- // The most recent native coordinates of a drag.
+ // The most recent native coordinates of an incoming drag. Updated while
+ // the mouse is moved, and used at dropping.
gfx::PointF last_drag_point_;
- // Cursor in use prior to the move loop starting. Restored when the move loop
- // quits.
- gfx::NativeCursor initial_cursor_;
-
- base::OnceClosure quit_closure_;
-
// The operation bitfield.
int drag_operation_ = 0;
- // The flag that controls whether it has a nested run loop.
- bool in_move_loop_ = false;
+ std::unique_ptr<DragContext> drag_context_;
+
+ base::WeakPtrFactory<DesktopDragDropClientOzone> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientOzone);
};
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc
index d159e5130b8..cfb7bcca00b 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc
@@ -66,8 +66,8 @@ class FakePlatformWindow : public ui::PlatformWindow, public ui::WmDragHandler {
void StartDrag(const OSExchangeData& data,
int operation,
gfx::NativeCursor cursor,
- base::OnceCallback<void(int)> callback) override {
- drag_closed_callback_ = std::move(callback);
+ WmDragHandler::Delegate* delegate) override {
+ drag_handler_delegate_ = delegate;
source_data_ = std::make_unique<OSExchangeData>(data.provider().Clone());
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
@@ -107,7 +107,7 @@ class FakePlatformWindow : public ui::PlatformWindow, public ui::WmDragHandler {
}
void CloseDrag(uint32_t dnd_action) {
- std::move(drag_closed_callback_).Run(dnd_action);
+ drag_handler_delegate_->OnDragFinished(dnd_action);
}
void ProcessDrag(std::unique_ptr<OSExchangeData> data, int operation) {
@@ -119,7 +119,7 @@ class FakePlatformWindow : public ui::PlatformWindow, public ui::WmDragHandler {
}
private:
- base::OnceCallback<void(int)> drag_closed_callback_;
+ WmDragHandler::Delegate* drag_handler_delegate_ = nullptr;
std::unique_ptr<ui::OSExchangeData> source_data_;
DISALLOW_COPY_AND_ASSIGN(FakePlatformWindow);
@@ -288,10 +288,77 @@ TEST_F(DesktopDragDropClientOzoneTest, ReceiveDrag) {
EXPECT_EQ(sample_data, string_data);
EXPECT_EQ(1, dragdrop_delegate_->num_enters());
- EXPECT_EQ(1, dragdrop_delegate_->num_enters());
EXPECT_EQ(1, dragdrop_delegate_->num_updates());
EXPECT_EQ(1, dragdrop_delegate_->num_drops());
EXPECT_EQ(1, dragdrop_delegate_->num_exits());
}
+TEST_F(DesktopDragDropClientOzoneTest, TargetDestroyedDuringDrag) {
+ const int suggested_operation =
+ ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE;
+
+ // Set the operation which the destination can accept.
+ dragdrop_delegate_->SetOperation(ui::DragDropTypes::DRAG_MOVE);
+
+ // Set the data which will be delivered.
+ const base::string16 sample_data = base::ASCIIToUTF16("ReceiveDrag");
+ std::unique_ptr<ui::OSExchangeData> data =
+ std::make_unique<ui::OSExchangeData>();
+ data->SetString(sample_data);
+
+ // Simulate that the drag enter/motion/leave events happen with the
+ // |suggested_operation| in the main window.
+ platform_window_->OnDragEnter(gfx::PointF(), std::move(data),
+ suggested_operation);
+ platform_window_->OnDragMotion(gfx::PointF(), suggested_operation);
+ platform_window_->OnDragLeave();
+
+ // Create another window with its own DnD facility and simulate that the drag
+ // enters it and then the window is destroyed.
+ auto another_widget = std::make_unique<Widget>();
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(100, 100);
+ another_widget->Init(std::move(params));
+ another_widget->Show();
+
+ aura::Window* another_window = another_widget->GetNativeWindow();
+ auto another_dragdrop_delegate = std::make_unique<FakeDragDropDelegate>();
+ aura::client::SetDragDropDelegate(another_window,
+ another_dragdrop_delegate.get());
+ another_dragdrop_delegate->SetOperation(ui::DragDropTypes::DRAG_COPY);
+
+ auto another_cursor_manager = std::make_unique<DesktopNativeCursorManager>();
+ auto another_platform_window = std::make_unique<FakePlatformWindow>();
+ ui::WmDragHandler* drag_handler =
+ ui::GetWmDragHandler(*(another_platform_window));
+ auto another_client = std::make_unique<DesktopDragDropClientOzone>(
+ another_window, another_cursor_manager.get(), drag_handler);
+ SetWmDropHandler(another_platform_window.get(), another_client.get());
+
+ std::unique_ptr<ui::OSExchangeData> another_data =
+ std::make_unique<ui::OSExchangeData>();
+ another_data->SetString(sample_data);
+ another_platform_window->OnDragEnter(gfx::PointF(), std::move(another_data),
+ suggested_operation);
+ another_platform_window->OnDragMotion(gfx::PointF(), suggested_operation);
+
+ another_widget->CloseWithReason(Widget::ClosedReason::kUnspecified);
+ another_widget.reset();
+
+ // The main window should have the typical record of a drag started and left.
+ EXPECT_EQ(1, dragdrop_delegate_->num_enters());
+ EXPECT_EQ(1, dragdrop_delegate_->num_updates());
+ EXPECT_EQ(0, dragdrop_delegate_->num_drops());
+ EXPECT_EQ(1, dragdrop_delegate_->num_exits());
+
+ // As the target window has closed and we have never provided another one,
+ // the number of exits should be zero despite that the platform window has
+ // notified the client about leaving the drag.
+ EXPECT_EQ(1, another_dragdrop_delegate->num_enters());
+ EXPECT_EQ(1, another_dragdrop_delegate->num_updates());
+ EXPECT_EQ(0, another_dragdrop_delegate->num_drops());
+ EXPECT_EQ(0, another_dragdrop_delegate->num_exits());
+}
+
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc
index 806e4a883a0..e3bd6355071 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc
@@ -6,19 +6,24 @@
#include <memory>
-#include "base/metrics/histogram_macros.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/drag_source_win.h"
#include "ui/base/dragdrop/drop_target_event.h"
#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
+#include "ui/base/win/event_creation_utils.h"
+#include "ui/display/win/screen_win.h"
#include "ui/views/widget/desktop_aura/desktop_drop_target_win.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
namespace views {
-DesktopDragDropClientWin::DesktopDragDropClientWin(aura::Window* root_window,
- HWND window)
- : drag_drop_in_progress_(false), drag_operation_(0) {
+DesktopDragDropClientWin::DesktopDragDropClientWin(
+ aura::Window* root_window,
+ HWND window,
+ DesktopWindowTreeHostWin* desktop_host)
+ : drag_drop_in_progress_(false),
+ drag_operation_(0),
+ desktop_host_(desktop_host) {
drop_target_ = new DesktopDropTargetWin(root_window);
drop_target_->Init(window);
}
@@ -37,24 +42,36 @@ int DesktopDragDropClientWin::StartDragAndDrop(
ui::DragDropTypes::DragEventSource source) {
drag_drop_in_progress_ = true;
drag_operation_ = operation;
-
+ if (source == ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH) {
+ gfx::Point screen_point = display::win::ScreenWin::DIPToScreenPoint(
+ {screen_location.x(), screen_location.y()});
+ // Send a mouse down and mouse move before do drag drop runs its own event
+ // loop. This is required for ::DoDragDrop to start the drag.
+ ui::SendMouseEvent(screen_point,
+ MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_ABSOLUTE);
+ ui::SendMouseEvent(screen_point, MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE);
+ desktop_host_->SetInTouchDrag(true);
+ }
base::WeakPtr<DesktopDragDropClientWin> alive(weak_factory_.GetWeakPtr());
drag_source_ = ui::DragSourceWin::Create();
Microsoft::WRL::ComPtr<ui::DragSourceWin> drag_source_copy = drag_source_;
drag_source_copy->set_data(data.get());
- ui::OSExchangeDataProviderWin::GetDataObjectImpl(*data.get())
- ->set_in_drag_loop(true);
+ ui::OSExchangeDataProviderWin::GetDataObjectImpl(*data)->set_in_drag_loop(
+ true);
DWORD effect;
- UMA_HISTOGRAM_ENUMERATION("Event.DragDrop.Start", source,
- ui::DragDropTypes::DRAG_EVENT_SOURCE_COUNT);
-
- HRESULT result = DoDragDrop(
+ HRESULT result = ::DoDragDrop(
ui::OSExchangeDataProviderWin::GetIDataObject(*data.get()),
drag_source_.Get(),
ui::DragDropTypes::DragOperationToDropEffect(operation), &effect);
+ if (alive && source == ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH) {
+ desktop_host_->SetInTouchDrag(false);
+ // Gesture state gets left in a state where you can't start
+ // another drag, unless it's cleaned up.
+ source_window->CleanupGestureState();
+ }
drag_source_copy->set_data(nullptr);
if (alive)
@@ -63,17 +80,7 @@ int DesktopDragDropClientWin::StartDragAndDrop(
if (result != DRAGDROP_S_DROP)
effect = DROPEFFECT_NONE;
- int drag_operation = ui::DragDropTypes::DropEffectToDragOperation(effect);
-
- if (drag_operation == ui::DragDropTypes::DRAG_NONE) {
- UMA_HISTOGRAM_ENUMERATION("Event.DragDrop.Cancel", source,
- ui::DragDropTypes::DRAG_EVENT_SOURCE_COUNT);
- } else {
- UMA_HISTOGRAM_ENUMERATION("Event.DragDrop.Drop", source,
- ui::DragDropTypes::DRAG_EVENT_SOURCE_COUNT);
- }
-
- return drag_operation;
+ return ui::DragDropTypes::DropEffectToDragOperation(effect);
}
void DesktopDragDropClientWin::DragCancel() {
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h
index 74c40adff7e..a55fe963a04 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h
@@ -28,11 +28,14 @@ class DragSourceWin;
namespace views {
class DesktopDropTargetWin;
+class DesktopWindowTreeHostWin;
class VIEWS_EXPORT DesktopDragDropClientWin
: public aura::client::DragDropClient {
public:
- DesktopDragDropClientWin(aura::Window* root_window, HWND window);
+ DesktopDragDropClientWin(aura::Window* root_window,
+ HWND window,
+ DesktopWindowTreeHostWin* desktop_host);
~DesktopDragDropClientWin() override;
// Overridden from aura::client::DragDropClient:
@@ -58,6 +61,11 @@ class VIEWS_EXPORT DesktopDragDropClientWin
scoped_refptr<DesktopDropTargetWin> drop_target_;
+ // |this| will get deleted DesktopNativeWidgetAura is notified that the
+ // DesktopWindowTreeHost is being destroyed. So desktop_host_ should outlive
+ // |this|.
+ DesktopWindowTreeHostWin* desktop_host_ = nullptr;
+
base::WeakPtrFactory<DesktopDragDropClientWin> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientWin);
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
index a1703ed51c4..eac8953797e 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
@@ -6,7 +6,6 @@
#include <utility>
-#include "base/metrics/histogram_macros.h"
#include "base/win/win_util.h"
#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/client/drag_drop_delegate.h"
@@ -80,8 +79,6 @@ DWORD DesktopDropTargetWin::OnDragOver(IDataObject* data_object,
if (delegate)
drag_operation = delegate->OnDragUpdated(*event);
- UMA_HISTOGRAM_BOOLEAN("Event.DragDrop.AcceptDragUpdate",
- drag_operation != ui::DragDropTypes::DRAG_NONE);
return ui::DragDropTypes::DragOperationToDropEffect(drag_operation);
}
@@ -98,14 +95,8 @@ DWORD DesktopDropTargetWin::OnDrop(IDataObject* data_object,
std::unique_ptr<ui::DropTargetEvent> event;
DragDropDelegate* delegate;
Translate(data_object, key_state, position, effect, &data, &event, &delegate);
- if (delegate) {
+ if (delegate)
drag_operation = delegate->OnPerformDrop(*event, std::move(data));
- DragDropClient* client = aura::client::GetDragDropClient(root_window_);
- if (client && !client->IsDragDropInProgress() &&
- drag_operation != ui::DragDropTypes::DRAG_NONE) {
- UMA_HISTOGRAM_COUNTS_1M("Event.DragDrop.ExternalOriginDrop", 1);
- }
- }
if (target_window_) {
target_window_->RemoveObserver(this);
target_window_ = nullptr;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen.cc
index b656c14e4f7..50ac4c71dbf 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen.cc
@@ -17,7 +17,7 @@ void InstallDesktopScreenIfNecessary() {
// The screen may have already been set in test initialization.
if (!display::Screen::GetScreen())
- display::Screen::SetScreenInstance(CreateDesktopScreen());
+ CreateDesktopScreen();
}
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_linux.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_linux.cc
new file mode 100644
index 00000000000..6a11abce534
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_linux.cc
@@ -0,0 +1,35 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_screen.h"
+
+#include "base/notreached.h"
+
+#if defined(USE_X11)
+#include "ui/views/widget/desktop_aura/desktop_screen_x11.h"
+#endif
+
+#if defined(USE_OZONE)
+#include "ui/base/ui_base_features.h"
+#include "ui/views/widget/desktop_aura/desktop_screen_ozone.h"
+#endif
+
+namespace views {
+
+display::Screen* CreateDesktopScreen() {
+#if defined(USE_OZONE)
+ if (features::IsUsingOzonePlatform())
+ return new DesktopScreenOzone();
+#endif
+#if defined(USE_X11)
+ auto* screen = new DesktopScreenX11();
+ screen->Init();
+ return screen;
+#else
+ NOTREACHED();
+ return nullptr;
+#endif
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
index 6f9d29fbcbb..05fc9cde057 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
@@ -4,6 +4,7 @@
#include "ui/views/widget/desktop_aura/desktop_screen_ozone.h"
+#include "build/build_config.h"
#include "ui/aura/screen_ozone.h"
#include "ui/views/widget/desktop_aura/desktop_screen.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h"
@@ -22,8 +23,13 @@ gfx::NativeWindow DesktopScreenOzone::GetNativeWindowFromAcceleratedWidget(
widget);
}
+// To avoid multiple definitions when use_x11 && use_ozone is true, disable this
+// factory method for OS_LINUX as Linux has a factory method that decides what
+// screen to use based on IsUsingOzonePlatform feature flag.
+#if !defined(OS_LINUX)
display::Screen* CreateDesktopScreen() {
return new DesktopScreenOzone();
}
+#endif
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc
index 963e7053e7a..e9bb45ad238 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc
@@ -13,7 +13,9 @@ namespace views {
DesktopScreenWin::DesktopScreenWin() = default;
-DesktopScreenWin::~DesktopScreenWin() = default;
+DesktopScreenWin::~DesktopScreenWin() {
+ display::Screen::SetScreenInstance(old_screen_);
+}
HWND DesktopScreenWin::GetHWNDFromNativeWindow(gfx::NativeWindow window) const {
aura::WindowTreeHost* host = window->GetHost();
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h
index 97442c424d8..52f54f2e6b8 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h
@@ -21,6 +21,8 @@ class VIEWS_EXPORT DesktopScreenWin : public display::win::ScreenWin {
// display::win::ScreenWin:
HWND GetHWNDFromNativeWindow(gfx::NativeWindow window) const override;
gfx::NativeWindow GetNativeWindowFromHWND(HWND hwnd) const override;
+
+ display::Screen* const old_screen_ = display::Screen::SetScreenInstance(this);
};
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
index 4f4a5d1c395..084ba94bd9a 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -32,7 +32,9 @@ DesktopScreenX11::DesktopScreenX11() {
display_scale_factor_observer_.Add(LinuxUI::instance());
}
-DesktopScreenX11::~DesktopScreenX11() = default;
+DesktopScreenX11::~DesktopScreenX11() {
+ display::Screen::SetScreenInstance(old_screen_);
+}
void DesktopScreenX11::Init() {
if (x11_display_manager_->IsXrandrAvailable() &&
@@ -60,12 +62,11 @@ bool DesktopScreenX11::IsWindowUnderCursor(gfx::NativeWindow window) {
gfx::NativeWindow DesktopScreenX11::GetWindowAtScreenPoint(
const gfx::Point& point) {
- auto accelerated_widget =
- ui::X11TopmostWindowFinder().FindLocalProcessWindowAt(
- gfx::ConvertPointToPixel(GetXDisplayScaleFactor(), point), {});
- return accelerated_widget
+ auto window = ui::X11TopmostWindowFinder().FindLocalProcessWindowAt(
+ gfx::ConvertPointToPixel(GetXDisplayScaleFactor(), point), {});
+ return window != x11::Window::None
? views::DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
- static_cast<gfx::AcceleratedWidget>(accelerated_widget))
+ window)
: nullptr;
}
@@ -75,13 +76,12 @@ gfx::NativeWindow DesktopScreenX11::GetLocalProcessWindowAtPoint(
std::set<gfx::AcceleratedWidget> ignore_widgets;
for (auto* const window : ignore)
ignore_widgets.emplace(window->GetHost()->GetAcceleratedWidget());
- auto accelerated_widget =
- ui::X11TopmostWindowFinder().FindLocalProcessWindowAt(
- gfx::ConvertPointToPixel(GetXDisplayScaleFactor(), point),
- ignore_widgets);
- return accelerated_widget
+ auto window = ui::X11TopmostWindowFinder().FindLocalProcessWindowAt(
+ gfx::ConvertPointToPixel(GetXDisplayScaleFactor(), point),
+ ignore_widgets);
+ return window != x11::Window::None
? views::DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
- static_cast<gfx::AcceleratedWidget>(accelerated_widget))
+ window)
: nullptr;
}
@@ -148,7 +148,7 @@ std::string DesktopScreenX11::GetCurrentWorkspace() {
return x11_display_manager_->GetCurrentWorkspace();
}
-bool DesktopScreenX11::DispatchXEvent(XEvent* event) {
+bool DesktopScreenX11::DispatchXEvent(x11::Event* event) {
return x11_display_manager_->CanProcessEvent(*event) &&
x11_display_manager_->ProcessEvent(event);
}
@@ -176,12 +176,4 @@ float DesktopScreenX11::GetXDisplayScaleFactor() const {
: 1.0f;
}
-////////////////////////////////////////////////////////////////////////////////
-
-display::Screen* CreateDesktopScreen() {
- auto* screen = new DesktopScreenX11;
- screen->Init();
- return screen;
-}
-
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
index b391f41caf2..54954d61993 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
@@ -12,6 +12,7 @@
#include "ui/base/x/x11_display_manager.h"
#include "ui/display/screen.h"
#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/x/event.h"
#include "ui/views/linux_ui/device_scale_factor_observer.h"
#include "ui/views/linux_ui/linux_ui.h"
#include "ui/views/views_export.h"
@@ -19,10 +20,6 @@
namespace views {
class DesktopScreenX11Test;
-namespace test {
-class DesktopScreenX11TestApi;
-}
-
// Screen implementation that talks to XRandR
class VIEWS_EXPORT DesktopScreenX11 : public display::Screen,
public ui::XEventDispatcher,
@@ -57,7 +54,7 @@ class VIEWS_EXPORT DesktopScreenX11 : public display::Screen,
std::string GetCurrentWorkspace() override;
// ui::XEventDispatcher:
- bool DispatchXEvent(XEvent* event) override;
+ bool DispatchXEvent(x11::Event* event) override;
// DeviceScaleFactorObserver:
void OnDeviceScaleFactorChanged() override;
@@ -66,12 +63,12 @@ class VIEWS_EXPORT DesktopScreenX11 : public display::Screen,
private:
friend class DesktopScreenX11Test;
- friend class test::DesktopScreenX11TestApi;
// ui::XDisplayManager::Delegate:
void OnXDisplayListUpdated() override;
float GetXDisplayScaleFactor() const override;
+ display::Screen* const old_screen_ = display::Screen::SetScreenInstance(this);
std::unique_ptr<ui::XDisplayManager> x11_display_manager_ =
std::make_unique<ui::XDisplayManager>(this);
ScopedObserver<LinuxUI,
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
index 4168fa1a51f..61d8b3a0678 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
@@ -184,23 +184,6 @@ Widget::MoveLoopResult DesktopWindowTreeHostLinux::RunMoveLoop(
escape_behavior);
}
-void DesktopWindowTreeHostLinux::OnDisplayMetricsChanged(
- const display::Display& display,
- uint32_t changed_metrics) {
- aura::WindowTreeHost::OnDisplayMetricsChanged(display, changed_metrics);
-
- if ((changed_metrics & DISPLAY_METRIC_DEVICE_SCALE_FACTOR) &&
- display::Screen::GetScreen()->GetDisplayNearestWindow(window()).id() ==
- display.id()) {
- // When the scale factor changes, also pretend that a resize
- // occurred so that the window layout will be refreshed and a
- // compositor redraw will be scheduled. This is weird, but works.
- // TODO(thomasanderson): Figure out a more direct way of doing
- // this.
- OnHostResizedInPixels(GetBoundsInPixels().size());
- }
-}
-
void DesktopWindowTreeHostLinux::DispatchEvent(ui::Event* event) {
// The input can be disabled and the widget marked as non-active in case of
// opened file-dialogs.
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h
index 79bef5fe949..bec4d76adb1 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h
@@ -89,12 +89,10 @@ class VIEWS_EXPORT DesktopWindowTreeHostLinux
const ui::X11Extension* GetX11Extension() const;
private:
- friend class DesktopWindowTreeHostX11Test;
FRIEND_TEST_ALL_PREFIXES(DesktopWindowTreeHostLinuxTest, HitTest);
-
- // Overridden from display::DisplayObserver via aura::WindowTreeHost:
- void OnDisplayMetricsChanged(const display::Display& display,
- uint32_t changed_metrics) override;
+ FRIEND_TEST_ALL_PREFIXES(DesktopWindowTreeHostLinuxTest, MouseNCEvents);
+ FRIEND_TEST_ALL_PREFIXES(DesktopWindowTreeHostLinuxHighDPITest,
+ MouseNCEvents);
// DesktopWindowTreeHostPlatform overrides:
void AddAdditionalInitProperties(
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_unittest.cc
new file mode 100644
index 00000000000..15d8c29db55
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_unittest.cc
@@ -0,0 +1,228 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h"
+
+#include "base/command_line.h"
+#include "ui/base/hit_test.h"
+#include "ui/display/display_switches.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/widget_delegate.h"
+
+namespace views {
+
+namespace {
+// A NonClientFrameView with a window mask with the bottom right corner cut out.
+class ShapedNonClientFrameView : public NonClientFrameView {
+ public:
+ ShapedNonClientFrameView() = default;
+
+ ~ShapedNonClientFrameView() override = default;
+
+ // NonClientFrameView:
+ gfx::Rect GetBoundsForClientView() const override { return bounds(); }
+ gfx::Rect GetWindowBoundsForClientBounds(
+ const gfx::Rect& client_bounds) const override {
+ return client_bounds;
+ }
+ int NonClientHitTest(const gfx::Point& point) override {
+ // Fake bottom for non client event test.
+ if (point == gfx::Point(500, 500))
+ return HTBOTTOM;
+ return HTNOWHERE;
+ }
+ void GetWindowMask(const gfx::Size& size, SkPath* window_mask) override {
+ int right = size.width();
+ int bottom = size.height();
+
+ window_mask->moveTo(0, 0);
+ window_mask->lineTo(0, bottom);
+ window_mask->lineTo(right, bottom);
+ window_mask->lineTo(right, 10);
+ window_mask->lineTo(right - 10, 10);
+ window_mask->lineTo(right - 10, 0);
+ window_mask->close();
+ }
+ void ResetWindowControls() override {}
+ void UpdateWindowIcon() override {}
+ void UpdateWindowTitle() override {}
+ void SizeConstraintsChanged() override {}
+
+ bool GetAndResetLayoutRequest() {
+ bool layout_requested = layout_requested_;
+ layout_requested_ = false;
+ return layout_requested;
+ }
+
+ private:
+ void Layout() override { layout_requested_ = true; }
+
+ bool layout_requested_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(ShapedNonClientFrameView);
+};
+
+class ShapedWidgetDelegate : public WidgetDelegateView {
+ public:
+ ShapedWidgetDelegate() = default;
+
+ ~ShapedWidgetDelegate() override = default;
+
+ // WidgetDelegateView:
+ NonClientFrameView* CreateNonClientFrameView(Widget* widget) override {
+ return new ShapedNonClientFrameView;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ShapedWidgetDelegate);
+};
+
+class MouseEventRecorder : public ui::EventHandler {
+ public:
+ MouseEventRecorder() = default;
+ ~MouseEventRecorder() override = default;
+
+ void Reset() { mouse_events_.clear(); }
+
+ const std::vector<ui::MouseEvent>& mouse_events() const {
+ return mouse_events_;
+ }
+
+ private:
+ // ui::EventHandler:
+ void OnMouseEvent(ui::MouseEvent* mouse) override {
+ mouse_events_.push_back(*mouse);
+ }
+
+ std::vector<ui::MouseEvent> mouse_events_;
+
+ DISALLOW_COPY_AND_ASSIGN(MouseEventRecorder);
+};
+
+} // namespace
+
+class DesktopWindowTreeHostLinuxTest : public ViewsTestBase {
+ public:
+ DesktopWindowTreeHostLinuxTest() = default;
+ DesktopWindowTreeHostLinuxTest(const DesktopWindowTreeHostLinuxTest&) =
+ delete;
+ DesktopWindowTreeHostLinuxTest& operator=(
+ const DesktopWindowTreeHostLinuxTest&) = delete;
+ ~DesktopWindowTreeHostLinuxTest() override = default;
+
+ void SetUp() override {
+ set_native_widget_type(NativeWidgetType::kDesktop);
+
+ ViewsTestBase::SetUp();
+ }
+
+ protected:
+ // Creates a widget of size 100x100.
+ std::unique_ptr<Widget> CreateWidget(WidgetDelegate* delegate) {
+ std::unique_ptr<Widget> widget(new Widget);
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
+ params.delegate = delegate;
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.remove_standard_frame = true;
+ params.bounds = gfx::Rect(100, 100, 100, 100);
+ widget->Init(std::move(params));
+ return widget;
+ }
+};
+
+TEST_F(DesktopWindowTreeHostLinuxTest, ChildWindowDestructionDuringTearDown) {
+ Widget parent_widget;
+ Widget::InitParams parent_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ parent_widget.Init(std::move(parent_params));
+ parent_widget.Show();
+
+ Widget child_widget;
+ Widget::InitParams child_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ child_params.parent = parent_widget.GetNativeWindow();
+ child_widget.Init(std::move(child_params));
+ child_widget.Show();
+
+ // Sanity check that the two widgets each have their own XID.
+ ASSERT_NE(parent_widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget(),
+ child_widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+ Widget::CloseAllSecondaryWidgets();
+ EXPECT_TRUE(DesktopWindowTreeHostLinux::GetAllOpenWindows().empty());
+}
+
+TEST_F(DesktopWindowTreeHostLinuxTest, MouseNCEvents) {
+ std::unique_ptr<Widget> widget = CreateWidget(new ShapedWidgetDelegate());
+ widget->Show();
+
+ base::RunLoop().RunUntilIdle();
+
+ widget->SetBounds(gfx::Rect(100, 100, 501, 501));
+
+ base::RunLoop().RunUntilIdle();
+
+ MouseEventRecorder recorder;
+ widget->GetNativeWindow()->AddPreTargetHandler(&recorder);
+
+ auto* host_linux = static_cast<DesktopWindowTreeHostLinux*>(
+ widget->GetNativeWindow()->GetHost());
+ ASSERT_TRUE(host_linux);
+
+ ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::PointF(500, 500),
+ gfx::PointF(500, 500), base::TimeTicks::Now(), 0, 0, {});
+ host_linux->DispatchEvent(&event);
+
+ ASSERT_EQ(1u, recorder.mouse_events().size());
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, recorder.mouse_events()[0].type());
+ EXPECT_TRUE(recorder.mouse_events()[0].flags() & ui::EF_IS_NON_CLIENT);
+
+ widget->GetNativeWindow()->RemovePreTargetHandler(&recorder);
+}
+
+class DesktopWindowTreeHostLinuxHighDPITest
+ : public DesktopWindowTreeHostLinuxTest {
+ public:
+ DesktopWindowTreeHostLinuxHighDPITest() = default;
+ ~DesktopWindowTreeHostLinuxHighDPITest() override = default;
+
+ private:
+ void SetUp() override {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ command_line->AppendSwitchASCII(switches::kForceDeviceScaleFactor, "2");
+
+ DesktopWindowTreeHostLinuxTest::SetUp();
+ }
+};
+
+TEST_F(DesktopWindowTreeHostLinuxHighDPITest, MouseNCEvents) {
+ std::unique_ptr<Widget> widget = CreateWidget(new ShapedWidgetDelegate());
+ widget->Show();
+
+ widget->SetBounds(gfx::Rect(100, 100, 1000, 1000));
+ base::RunLoop().RunUntilIdle();
+
+ MouseEventRecorder recorder;
+ widget->GetNativeWindow()->AddPreTargetHandler(&recorder);
+
+ auto* host_linux = static_cast<DesktopWindowTreeHostLinux*>(
+ widget->GetNativeWindow()->GetHost());
+ ASSERT_TRUE(host_linux);
+
+ ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::PointF(1001, 1001),
+ gfx::PointF(1001, 1001), base::TimeTicks::Now(), 0, 0,
+ {});
+ host_linux->DispatchEvent(&event);
+
+ EXPECT_EQ(1u, recorder.mouse_events().size());
+ EXPECT_EQ(gfx::Point(500, 500), recorder.mouse_events()[0].location());
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, recorder.mouse_events()[0].type());
+ EXPECT_TRUE(recorder.mouse_events()[0].flags() & ui::EF_IS_NON_CLIENT);
+
+ widget->GetNativeWindow()->RemovePreTargetHandler(&recorder);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
index 62e2a8fd5ab..c9119b8606c 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
@@ -143,4 +143,68 @@ TEST_F(DesktopWindowTreeHostPlatformTest, CallOnNativeWidgetVisibilityChanged) {
EXPECT_TRUE(observer.visible());
}
+// Tests that the minimization information is propagated to the content window.
+TEST_F(DesktopWindowTreeHostPlatformTest,
+ ToggleMinimizePropogateToContentWindow) {
+ std::unique_ptr<Widget> widget = CreateWidgetWithNativeWidget();
+ widget->Show();
+
+ auto* host_platform = DesktopWindowTreeHostPlatform::GetHostForWidget(
+ widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+ ASSERT_TRUE(host_platform);
+
+ EXPECT_TRUE(widget->GetNativeWindow()->IsVisible());
+
+ // Pretend a PlatformWindow enters the minimized state.
+ host_platform->OnWindowStateChanged(ui::PlatformWindowState::kMinimized);
+
+ EXPECT_FALSE(widget->GetNativeWindow()->IsVisible());
+
+ // Pretend a PlatformWindow exits the minimized state.
+ host_platform->OnWindowStateChanged(ui::PlatformWindowState::kNormal);
+ EXPECT_TRUE(widget->GetNativeWindow()->IsVisible());
+}
+
+// A Widget that allows setting the min/max size for the widget.
+class CustomSizeWidget : public Widget {
+ public:
+ CustomSizeWidget() = default;
+ ~CustomSizeWidget() override = default;
+
+ void set_min_size(const gfx::Size& size) { min_size_ = size; }
+ void set_max_size(const gfx::Size& size) { max_size_ = size; }
+
+ // Widget:
+ gfx::Size GetMinimumSize() const override { return min_size_; }
+ gfx::Size GetMaximumSize() const override { return max_size_; }
+
+ private:
+ gfx::Size min_size_;
+ gfx::Size max_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(CustomSizeWidget);
+};
+
+TEST_F(DesktopWindowTreeHostPlatformTest, SetBoundsWithMinMax) {
+ CustomSizeWidget widget;
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(200, 100);
+ widget.Init(std::move(params));
+ widget.Show();
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(gfx::Size(200, 100).ToString(),
+ widget.GetWindowBoundsInScreen().size().ToString());
+ widget.SetBounds(gfx::Rect(300, 200));
+ EXPECT_EQ(gfx::Size(300, 200).ToString(),
+ widget.GetWindowBoundsInScreen().size().ToString());
+
+ widget.set_min_size(gfx::Size(100, 100));
+ widget.SetBounds(gfx::Rect(50, 500));
+ EXPECT_EQ(gfx::Size(100, 500).ToString(),
+ widget.GetWindowBoundsInScreen().size().ToString());
+}
+
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
index 6051aadee62..b5430b871cf 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
@@ -25,6 +25,7 @@
#include "ui/base/cursor/cursor_loader_win.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ui_base_features.h"
+#include "ui/base/win/event_creation_utils.h"
#include "ui/base/win/shell.h"
#include "ui/compositor/paint_context.h"
#include "ui/display/win/dpi.h"
@@ -32,6 +33,7 @@
#include "ui/events/keyboard_hook.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/dom_keyboard_layout_map.h"
+#include "ui/events/platform/platform_event_source.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/native_widget_types.h"
@@ -118,6 +120,10 @@ aura::Window* DesktopWindowTreeHostWin::GetContentWindowForHWND(HWND hwnd) {
return host ? host->window()->GetProperty(kContentWindowForRootWindow) : NULL;
}
+void DesktopWindowTreeHostWin::SetInTouchDrag(bool in_touch_drag) {
+ in_touch_drag_ = in_touch_drag;
+}
+
////////////////////////////////////////////////////////////////////////////////
// DesktopWindowTreeHostWin, DesktopWindowTreeHost implementation:
@@ -185,7 +191,7 @@ std::unique_ptr<corewm::Tooltip> DesktopWindowTreeHostWin::CreateTooltip() {
std::unique_ptr<aura::client::DragDropClient>
DesktopWindowTreeHostWin::CreateDragDropClient(
DesktopNativeCursorManager* cursor_manager) {
- drag_drop_client_ = new DesktopDragDropClientWin(window(), GetHWND());
+ drag_drop_client_ = new DesktopDragDropClientWin(window(), GetHWND(), this);
return base::WrapUnique(drag_drop_client_);
}
@@ -920,6 +926,9 @@ void DesktopWindowTreeHostWin::HandleNativeBlur(HWND focused_window) {
}
bool DesktopWindowTreeHostWin::HandleMouseEvent(ui::MouseEvent* event) {
+ // Ignore native platform events for test purposes
+ if (ui::PlatformEventSource::ShouldIgnoreNativePlatformEvents())
+ return true;
// Mouse events in occluded windows should be very rare. If this stat isn't
// very close to 0, that would indicate that windows are incorrectly getting
// marked occluded, or getting stuck in the occluded state. Event can cause
@@ -967,6 +976,21 @@ void DesktopWindowTreeHostWin::HandleTouchEvent(ui::TouchEvent* event) {
if (!GetWidget()->GetNativeView())
return;
+ if (in_touch_drag_) {
+ POINT event_point;
+ event_point.x = event->location().x();
+ event_point.y = event->location().y();
+ ::ClientToScreen(GetHWND(), &event_point);
+ gfx::Point screen_point(event_point);
+ // Send equivalent mouse events, because Ole32 drag drop doesn't seem to
+ // handle pointer events.
+ if (event->type() == ui::ET_TOUCH_MOVED) {
+ ui::SendMouseEvent(screen_point, MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE);
+ } else if (event->type() == ui::ET_TOUCH_RELEASED) {
+ ui::SendMouseEvent(screen_point,
+ MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_ABSOLUTE);
+ }
+ }
// Currently we assume the window that has capture gets touch events too.
aura::WindowTreeHost* host =
aura::WindowTreeHost::GetForAcceleratedWidget(GetCapture());
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
index 75ca9e99f2c..c0f00b6d86d 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
@@ -59,6 +59,12 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
// A way of converting an HWND into a content window.
static aura::Window* GetContentWindowForHWND(HWND hwnd);
+ // Set to true when DesktopDragDropClientWin starts a touch-initiated drag
+ // drop and false when it finishes. While in touch drag, if pointer events are
+ // received, the equivalent mouse events are generated, because ole32
+ // ::DoDragDrop does not seem to handle pointer events.
+ void SetInTouchDrag(bool in_touch_drag);
+
protected:
// Overridden from DesktopWindowTreeHost:
void Init(const Widget::InitParams& params) override;
@@ -312,6 +318,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
// when that stat is no longer tracked.
gfx::Point occluded_window_mouse_event_loc_;
+ bool in_touch_drag_ = false;
+
// The z-order level of the window; the window exhibits "always on top"
// behavior if > 0.
ui::ZOrderLevel z_order_ = ui::ZOrderLevel::kNormal;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
index 44e9eef3492..af81a254b0c 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -52,6 +52,7 @@
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_path.h"
+#include "ui/gfx/x/xproto.h"
#include "ui/views/linux_ui/linux_ui.h"
#include "ui/views/views_switches.h"
#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
@@ -82,9 +83,9 @@ void DesktopWindowTreeHostX11::Init(const Widget::InitParams& params) {
// Set XEventDelegate to receive selection, drag&drop and raw key events.
//
// TODO(https://crbug.com/990756): There are two cases of this delegate:
- // XEvents for DragAndDrop client and raw key events. DragAndDrop could be
- // unified so that DragAndrDropClientOzone is used and XEvent are handled on
- // platform level.
+ // x11::Events for DragAndDrop client and raw key events. DragAndDrop could be
+ // unified so that DragAndrDropClientOzone is used and x11::Event are handled
+ // on platform level.
static_cast<ui::X11Window*>(platform_window())->SetXEventDelegate(this);
}
@@ -92,7 +93,6 @@ std::unique_ptr<aura::client::DragDropClient>
DesktopWindowTreeHostX11::CreateDragDropClient(
DesktopNativeCursorManager* cursor_manager) {
drag_drop_client_ = new DesktopDragDropClientAuraX11(window(), cursor_manager,
- GetXWindow()->display(),
GetXWindow()->window());
drag_drop_client_->Init();
return base::WrapUnique(drag_drop_client_);
@@ -101,16 +101,16 @@ DesktopWindowTreeHostX11::CreateDragDropClient(
////////////////////////////////////////////////////////////////////////////////
// DesktopWindowTreeHostX11 implementation:
-void DesktopWindowTreeHostX11::OnXWindowSelectionEvent(XEvent* xev) {
+void DesktopWindowTreeHostX11::OnXWindowSelectionEvent(x11::Event* xev) {
DCHECK(xev);
DCHECK(drag_drop_client_);
- drag_drop_client_->OnSelectionNotify(xev->xselection);
+ drag_drop_client_->OnSelectionNotify(*xev->As<x11::SelectionNotifyEvent>());
}
-void DesktopWindowTreeHostX11::OnXWindowDragDropEvent(XEvent* xev) {
+void DesktopWindowTreeHostX11::OnXWindowDragDropEvent(x11::Event* xev) {
DCHECK(xev);
DCHECK(drag_drop_client_);
- drag_drop_client_->HandleXdndEvent(xev->xclient);
+ drag_drop_client_->HandleXdndEvent(*xev->As<x11::ClientMessageEvent>());
}
const ui::XWindow* DesktopWindowTreeHostX11::GetXWindow() const {
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
index 8cd6b80ee1e..69501945464 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/macros.h"
+#include "ui/gfx/x/event.h"
#include "ui/gfx/x/x11_types.h"
#include "ui/platform_window/platform_window_delegate.h"
#include "ui/platform_window/x11/x11_window.h"
@@ -40,8 +41,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11 : public DesktopWindowTreeHostLinux,
friend class DesktopWindowTreeHostX11HighDPITest;
// Overridden from ui::XEventDelegate.
- void OnXWindowSelectionEvent(XEvent* xev) override;
- void OnXWindowDragDropEvent(XEvent* xev) override;
+ void OnXWindowSelectionEvent(x11::Event* xev) override;
+ void OnXWindowDragDropEvent(x11::Event* xev) override;
// Casts PlatformWindow into XWindow and returns the result. This is a temp
// solution to access XWindow, which is subclassed by the X11Window, which is
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc
index c63bfe26350..b7c96511462 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc
@@ -4,6 +4,8 @@
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
+#include <xcb/xproto.h>
+
#include <memory>
#include "base/macros.h"
@@ -17,6 +19,7 @@
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/events/x/x11_event_translation.h"
#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/x/event.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/views/controls/textfield/textfield.h"
@@ -30,7 +33,7 @@ namespace {
// Blocks till |window| gets activated.
class ActivationWaiter : public ui::X11PropertyChangeWaiter {
public:
- explicit ActivationWaiter(XID window)
+ explicit ActivationWaiter(x11::Window window)
: ui::X11PropertyChangeWaiter(ui::GetX11RootWindow(),
"_NET_ACTIVE_WINDOW"),
window_(window) {}
@@ -39,13 +42,14 @@ class ActivationWaiter : public ui::X11PropertyChangeWaiter {
private:
// ui::X11PropertyChangeWaiter:
- bool ShouldKeepOnWaiting(XEvent* event) override {
- XID xid = 0;
- ui::GetXIDProperty(ui::GetX11RootWindow(), "_NET_ACTIVE_WINDOW", &xid);
- return xid != window_;
+ bool ShouldKeepOnWaiting(x11::Event* event) override {
+ x11::Window window = x11::Window::None;
+ ui::GetProperty(ui::GetX11RootWindow(), gfx::GetAtom("_NET_ACTIVE_WINDOW"),
+ &window);
+ return window != window_;
}
- XID window_;
+ x11::Window window_;
DISALLOW_COPY_AND_ASSIGN(ActivationWaiter);
};
@@ -88,23 +92,25 @@ void DispatchMouseMotionEvent(DesktopWindowTreeHostX11* desktop_host,
const gfx::Point& point_in_screen) {
gfx::Rect bounds_in_screen = desktop_host->window()->GetBoundsInScreen();
- Display* display = gfx::GetXDisplay();
- XEvent xev;
- xev.xmotion.type = MotionNotify;
- xev.xmotion.display = display;
- xev.xmotion.window = desktop_host->GetAcceleratedWidget();
- xev.xmotion.root = DefaultRootWindow(display);
- xev.xmotion.subwindow = 0;
- xev.xmotion.time = x11::CurrentTime;
- xev.xmotion.x = point_in_screen.x() - bounds_in_screen.x();
- xev.xmotion.y = point_in_screen.y() - bounds_in_screen.y();
- xev.xmotion.x_root = point_in_screen.x();
- xev.xmotion.y_root = point_in_screen.y();
- xev.xmotion.state = 0;
- xev.xmotion.is_hint = NotifyNormal;
- xev.xmotion.same_screen = x11::True;
-
- ui::X11EventSource::GetInstance()->ProcessXEvent(&xev);
+ auto* connection = x11::Connection::Get();
+ xcb_generic_event_t ge;
+ memset(&ge, 0, sizeof(ge));
+ auto* xev = reinterpret_cast<xcb_motion_notify_event_t*>(&ge);
+ xev->response_type = MotionNotify;
+ xev->event = static_cast<uint32_t>(desktop_host->GetAcceleratedWidget());
+ xev->root = static_cast<uint32_t>(connection->default_screen().root);
+ xev->child = 0;
+ xev->time = x11::CurrentTime;
+ xev->event_x = point_in_screen.x() - bounds_in_screen.x();
+ xev->event_y = point_in_screen.y() - bounds_in_screen.y();
+ xev->root_x = point_in_screen.x();
+ xev->root_y = point_in_screen.y();
+ xev->state = 0;
+ xev->detail = NotifyNormal;
+ xev->same_screen = x11::True;
+
+ x11::Event x11_event(&ge, connection);
+ ui::X11EventSource::GetInstance()->ProcessXEvent(&x11_event);
}
} // namespace
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
deleted file mode 100644
index 1f4b3a5244c..00000000000
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
+++ /dev/null
@@ -1,675 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stddef.h>
-
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/command_line.h"
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "base/stl_util.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/base/hit_test.h"
-#include "ui/base/x/test/x11_property_change_waiter.h"
-#include "ui/base/x/x11_util.h"
-#include "ui/display/display_switches.h"
-#include "ui/events/devices/x11/touch_factory_x11.h"
-#include "ui/events/platform/x11/x11_event_source.h"
-#include "ui/events/test/events_test_utils_x11.h"
-#include "ui/events/test/platform_event_source_test_api.h"
-#include "ui/events/x/x11_event_translation.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/x/x11.h"
-#include "ui/gfx/x/x11_atom_cache.h"
-#include "ui/views/test/views_test_base.h"
-#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
-#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
-#include "ui/views/widget/widget_delegate.h"
-#include "ui/views/window/non_client_view.h"
-
-namespace views {
-
-namespace {
-
-const int kPointerDeviceId = 1;
-
-// Blocks till the window state hint, |hint|, is set or unset.
-class WMStateWaiter : public ui::X11PropertyChangeWaiter {
- public:
- WMStateWaiter(XID window, const char* hint, bool wait_till_set)
- : ui::X11PropertyChangeWaiter(window, "_NET_WM_STATE"),
- hint_(hint),
- wait_till_set_(wait_till_set) {}
-
- ~WMStateWaiter() override = default;
-
- private:
- // X11PropertyChangeWaiter:
- bool ShouldKeepOnWaiting(XEvent* event) override {
- std::vector<Atom> hints;
- if (ui::GetAtomArrayProperty(xwindow(), "_NET_WM_STATE", &hints))
- return base::Contains(hints, gfx::GetAtom(hint_)) != wait_till_set_;
- return true;
- }
-
- // The name of the hint to wait to get set or unset.
- const char* hint_;
-
- // Whether we are waiting for |hint| to be set or unset.
- bool wait_till_set_;
-
- DISALLOW_COPY_AND_ASSIGN(WMStateWaiter);
-};
-
-// A NonClientFrameView with a window mask with the bottom right corner cut out.
-class ShapedNonClientFrameView : public NonClientFrameView {
- public:
- ShapedNonClientFrameView() = default;
-
- ~ShapedNonClientFrameView() override = default;
-
- // NonClientFrameView:
- gfx::Rect GetBoundsForClientView() const override { return bounds(); }
- gfx::Rect GetWindowBoundsForClientBounds(
- const gfx::Rect& client_bounds) const override {
- return client_bounds;
- }
- int NonClientHitTest(const gfx::Point& point) override {
- // Fake bottom for non client event test.
- if (point == gfx::Point(500, 500))
- return HTBOTTOM;
- return HTNOWHERE;
- }
- void GetWindowMask(const gfx::Size& size, SkPath* window_mask) override {
- int right = size.width();
- int bottom = size.height();
-
- window_mask->moveTo(0, 0);
- window_mask->lineTo(0, bottom);
- window_mask->lineTo(right, bottom);
- window_mask->lineTo(right, 10);
- window_mask->lineTo(right - 10, 10);
- window_mask->lineTo(right - 10, 0);
- window_mask->close();
- }
- void ResetWindowControls() override {}
- void UpdateWindowIcon() override {}
- void UpdateWindowTitle() override {}
- void SizeConstraintsChanged() override {}
-
- bool GetAndResetLayoutRequest() {
- bool layout_requested = layout_requested_;
- layout_requested_ = false;
- return layout_requested;
- }
-
- private:
- void Layout() override { layout_requested_ = true; }
-
- bool layout_requested_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(ShapedNonClientFrameView);
-};
-
-class ShapedWidgetDelegate : public WidgetDelegateView {
- public:
- ShapedWidgetDelegate() = default;
-
- ~ShapedWidgetDelegate() override = default;
-
- // WidgetDelegateView:
- NonClientFrameView* CreateNonClientFrameView(Widget* widget) override {
- return new ShapedNonClientFrameView;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ShapedWidgetDelegate);
-};
-
-// Creates a widget of size 100x100.
-std::unique_ptr<Widget> CreateWidget(WidgetDelegate* delegate) {
- std::unique_ptr<Widget> widget(new Widget);
- Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
- params.delegate = delegate;
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.remove_standard_frame = true;
- params.bounds = gfx::Rect(100, 100, 100, 100);
- widget->Init(std::move(params));
- return widget;
-}
-
-// Returns the list of rectangles which describe |xid|'s bounding region via the
-// X shape extension.
-std::vector<gfx::Rect> GetShapeRects(XID xid) {
- int dummy;
- int shape_rects_size;
- gfx::XScopedPtr<XRectangle[]> shape_rects(XShapeGetRectangles(
- gfx::GetXDisplay(), xid, ShapeBounding, &shape_rects_size, &dummy));
-
- std::vector<gfx::Rect> shape_vector;
- for (int i = 0; i < shape_rects_size; ++i) {
- const XRectangle& rect = shape_rects[i];
- shape_vector.emplace_back(rect.x, rect.y, rect.width, rect.height);
- }
- return shape_vector;
-}
-
-// Returns true if one of |rects| contains point (x,y).
-bool ShapeRectContainsPoint(const std::vector<gfx::Rect>& shape_rects,
- int x,
- int y) {
- gfx::Point point(x, y);
- return std::any_of(
- shape_rects.cbegin(), shape_rects.cend(),
- [&point](const auto& rect) { return rect.Contains(point); });
-}
-
-} // namespace
-
-class DesktopWindowTreeHostX11Test : public ViewsTestBase {
- public:
- DesktopWindowTreeHostX11Test()
- : event_source_(ui::X11EventSource::GetInstance()) {}
- ~DesktopWindowTreeHostX11Test() override = default;
-
- void SetUp() override {
- set_native_widget_type(NativeWidgetType::kDesktop);
-
- std::vector<int> pointer_devices;
- pointer_devices.push_back(kPointerDeviceId);
- ui::TouchFactory::GetInstance()->SetPointerDeviceForTest(pointer_devices);
-
- ViewsTestBase::SetUp();
-
- // Make X11 synchronous for our display connection. This does not force the
- // window manager to behave synchronously.
- XSynchronize(gfx::GetXDisplay(), x11::True);
- }
-
- void TearDown() override {
- XSynchronize(gfx::GetXDisplay(), x11::False);
- ViewsTestBase::TearDown();
- }
-
- void DispatchSingleEventToWidget(XEvent* xev, Widget* widget) {
- DCHECK_EQ(GenericEvent, xev->type);
- XIDeviceEvent* device_event =
- static_cast<XIDeviceEvent*>(xev->xcookie.data);
- device_event->event =
- widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
- event_source_->ProcessXEvent(xev);
- }
-
- private:
- ui::X11EventSource* event_source_;
- DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostX11Test);
-};
-
-// https://crbug.com/898742: Test is flaky.
-// Tests that the shape is properly set on the x window.
-TEST_F(DesktopWindowTreeHostX11Test, DISABLED_Shape) {
- if (!ui::IsShapeExtensionAvailable())
- return;
-
- // 1) Test setting the window shape via the NonClientFrameView. This technique
- // is used to get rounded corners on Chrome windows when not using the native
- // window frame.
- std::unique_ptr<Widget> widget1 = CreateWidget(new ShapedWidgetDelegate());
- widget1->Show();
- ui::X11EventSource::GetInstance()->DispatchXEvents();
-
- XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
- std::vector<gfx::Rect> shape_rects = GetShapeRects(xid1);
- ASSERT_FALSE(shape_rects.empty());
-
- // The widget was supposed to be 100x100, but the WM might have ignored this
- // suggestion.
- int widget_width = widget1->GetWindowBoundsInScreen().width();
- EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, widget_width - 15, 5));
- EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, widget_width - 5, 5));
- EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, widget_width - 5, 15));
- EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, widget_width + 5, 15));
-
- // Changing widget's size should update the shape.
- widget1->SetBounds(gfx::Rect(100, 100, 200, 200));
- ui::X11EventSource::GetInstance()->DispatchXEvents();
-
- if (widget1->GetWindowBoundsInScreen().width() == 200) {
- shape_rects = GetShapeRects(xid1);
- ASSERT_FALSE(shape_rects.empty());
- EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 85, 5));
- EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 95, 5));
- EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 185, 5));
- EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 195, 5));
- EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 195, 15));
- EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 205, 15));
- }
-
- if (ui::WmSupportsHint(gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"))) {
- // The shape should be changed to a rectangle which fills the entire screen
- // when |widget1| is maximized.
- {
- WMStateWaiter waiter(xid1, "_NET_WM_STATE_MAXIMIZED_VERT", true);
- widget1->Maximize();
- waiter.Wait();
- }
-
- // Ensure that the task which is posted when a window is resized is run.
- base::RunLoop().RunUntilIdle();
-
- // xvfb does not support Xrandr so we cannot check the maximized window's
- // bounds.
- gfx::Rect maximized_bounds;
- ui::GetOuterWindowBounds(xid1, &maximized_bounds);
-
- shape_rects = GetShapeRects(xid1);
- ASSERT_FALSE(shape_rects.empty());
- EXPECT_TRUE(
- ShapeRectContainsPoint(shape_rects, maximized_bounds.width() - 1, 5));
- EXPECT_TRUE(
- ShapeRectContainsPoint(shape_rects, maximized_bounds.width() - 1, 15));
- }
-
- // 2) Test setting the window shape via Widget::SetShape().
- auto shape_region = std::make_unique<Widget::ShapeRects>();
- shape_region->emplace_back(10, 0, 90, 10);
- shape_region->emplace_back(0, 10, 10, 90);
- shape_region->emplace_back(10, 10, 90, 90);
-
- std::unique_ptr<Widget> widget2(CreateWidget(nullptr));
- widget2->Show();
- widget2->SetShape(std::move(shape_region));
- ui::X11EventSource::GetInstance()->DispatchXEvents();
-
- XID xid2 = widget2->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
- shape_rects = GetShapeRects(xid2);
- ASSERT_FALSE(shape_rects.empty());
- EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 5, 5));
- EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 15, 5));
- EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 95, 15));
- EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 105, 15));
-
- // Changing the widget's size should not affect the shape.
- widget2->SetBounds(gfx::Rect(100, 100, 200, 200));
- shape_rects = GetShapeRects(xid2);
- ASSERT_FALSE(shape_rects.empty());
- EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 5, 5));
- EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 15, 5));
- EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 95, 15));
- EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 105, 15));
-
- // Setting the shape to NULL resets the shape back to the entire
- // window bounds.
- widget2->SetShape(nullptr);
- shape_rects = GetShapeRects(xid2);
- ASSERT_FALSE(shape_rects.empty());
- EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 5, 5));
- EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 15, 5));
- EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 95, 15));
- EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 105, 15));
- EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 500, 500));
-}
-
-// Test that the widget reacts on changes in fullscreen state initiated by the
-// window manager (e.g. via a window manager accelerator key).
-TEST_F(DesktopWindowTreeHostX11Test, WindowManagerTogglesFullscreen) {
- if (!ui::WmSupportsHint(gfx::GetAtom("_NET_WM_STATE_FULLSCREEN")))
- return;
-
- Display* display = gfx::GetXDisplay();
-
- std::unique_ptr<Widget> widget = CreateWidget(new ShapedWidgetDelegate());
- auto* non_client_view = static_cast<ShapedNonClientFrameView*>(
- widget->non_client_view()->frame_view());
- ASSERT_TRUE(non_client_view);
- XID xid = widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
- widget->Show();
- ui::X11EventSource::GetInstance()->DispatchXEvents();
-
- gfx::Rect initial_bounds = widget->GetWindowBoundsInScreen();
- {
- WMStateWaiter waiter(xid, "_NET_WM_STATE_FULLSCREEN", true);
- widget->SetFullscreen(true);
- waiter.Wait();
- }
- EXPECT_TRUE(widget->IsFullscreen());
-
- // After the fullscreen state has been set, there must be a relayout request
- EXPECT_TRUE(non_client_view->GetAndResetLayoutRequest());
-
- // Ensure there is not request before we proceed.
- EXPECT_FALSE(non_client_view->GetAndResetLayoutRequest());
-
- // Emulate the window manager exiting fullscreen via a window manager
- // accelerator key.
- {
- XEvent xclient;
- memset(&xclient, 0, sizeof(xclient));
- xclient.type = ClientMessage;
- xclient.xclient.window = xid;
- xclient.xclient.message_type = gfx::GetAtom("_NET_WM_STATE");
- xclient.xclient.format = 32;
- xclient.xclient.data.l[0] = 0;
- xclient.xclient.data.l[1] = gfx::GetAtom("_NET_WM_STATE_FULLSCREEN");
- xclient.xclient.data.l[2] = 0;
- xclient.xclient.data.l[3] = 1;
- xclient.xclient.data.l[4] = 0;
- XSendEvent(display, DefaultRootWindow(display), x11::False,
- SubstructureRedirectMask | SubstructureNotifyMask, &xclient);
-
- WMStateWaiter waiter(xid, "_NET_WM_STATE_FULLSCREEN", false);
- waiter.Wait();
- }
- // Ensure it continues in browser fullscreen mode and bounds are restored to
- // |initial_bounds|.
- EXPECT_TRUE(widget->IsFullscreen());
- EXPECT_EQ(initial_bounds.ToString(),
- widget->GetWindowBoundsInScreen().ToString());
-
- // Emulate window resize (through X11 configure events) while in browser
- // fullscreen mode and ensure bounds are tracked correctly.
- initial_bounds.set_size({400, 400});
- {
- XWindowChanges changes = {0};
- changes.width = initial_bounds.width();
- changes.height = initial_bounds.height();
- XConfigureWindow(display, xid, CWHeight | CWWidth, &changes);
- // Ensure that the task which is posted when a window is resized is run.
- base::RunLoop().RunUntilIdle();
- }
- EXPECT_TRUE(widget->IsFullscreen());
- EXPECT_EQ(initial_bounds.ToString(),
- widget->GetWindowBoundsInScreen().ToString());
-
- // Calling Widget::SetFullscreen(false) should clear the widget's fullscreen
- // state and clean things up.
- widget->SetFullscreen(false);
- EXPECT_FALSE(widget->IsFullscreen());
- EXPECT_EQ(initial_bounds.ToString(),
- widget->GetWindowBoundsInScreen().ToString());
-
- // Even though the unfullscreen request came from the window manager, we must
- // still react and relayout.
- EXPECT_TRUE(non_client_view->GetAndResetLayoutRequest());
-}
-
-// Tests that the minimization information is propagated to the content window.
-TEST_F(DesktopWindowTreeHostX11Test, ToggleMinimizePropogateToContentWindow) {
- Widget widget;
- Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- widget.Init(std::move(params));
- widget.Show();
- ui::X11EventSource::GetInstance()->DispatchXEvents();
-
- XID xid = widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget();
- Display* display = gfx::GetXDisplay();
-
- // Minimize by sending _NET_WM_STATE_HIDDEN
- {
- std::vector<::Atom> atom_list;
- atom_list.push_back(gfx::GetAtom("_NET_WM_STATE_HIDDEN"));
- ui::SetAtomArrayProperty(xid, "_NET_WM_STATE", "ATOM", atom_list);
-
- XEvent xevent;
- memset(&xevent, 0, sizeof(xevent));
- xevent.type = PropertyNotify;
- xevent.xproperty.type = PropertyNotify;
- xevent.xproperty.send_event = 1;
- xevent.xproperty.display = display;
- xevent.xproperty.window = xid;
- xevent.xproperty.atom = gfx::GetAtom("_NET_WM_STATE");
- xevent.xproperty.state = 0;
- XSendEvent(display, DefaultRootWindow(display), x11::False,
- SubstructureRedirectMask | SubstructureNotifyMask, &xevent);
-
- WMStateWaiter waiter(xid, "_NET_WM_STATE_HIDDEN", true);
- waiter.Wait();
- }
- EXPECT_FALSE(widget.GetNativeWindow()->IsVisible());
-
- // Show from minimized by sending _NET_WM_STATE_FOCUSED
- {
- std::vector<::Atom> atom_list;
- atom_list.push_back(gfx::GetAtom("_NET_WM_STATE_FOCUSED"));
- ui::SetAtomArrayProperty(xid, "_NET_WM_STATE", "ATOM", atom_list);
-
- XEvent xevent;
- memset(&xevent, 0, sizeof(xevent));
- xevent.type = PropertyNotify;
- xevent.xproperty.type = PropertyNotify;
- xevent.xproperty.send_event = 1;
- xevent.xproperty.display = display;
- xevent.xproperty.window = xid;
- xevent.xproperty.atom = gfx::GetAtom("_NET_WM_STATE");
- xevent.xproperty.state = 0;
- XSendEvent(display, DefaultRootWindow(display), x11::False,
- SubstructureRedirectMask | SubstructureNotifyMask, &xevent);
-
- WMStateWaiter waiter(xid, "_NET_WM_STATE_FOCUSED", true);
- waiter.Wait();
- }
- EXPECT_TRUE(widget.GetNativeWindow()->IsVisible());
-}
-
-TEST_F(DesktopWindowTreeHostX11Test, ChildWindowDestructionDuringTearDown) {
- Widget parent_widget;
- Widget::InitParams parent_params =
- CreateParams(Widget::InitParams::TYPE_WINDOW);
- parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- parent_widget.Init(std::move(parent_params));
- parent_widget.Show();
- ui::X11EventSource::GetInstance()->DispatchXEvents();
-
- Widget child_widget;
- Widget::InitParams child_params =
- CreateParams(Widget::InitParams::TYPE_WINDOW);
- child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- child_params.parent = parent_widget.GetNativeWindow();
- child_widget.Init(std::move(child_params));
- child_widget.Show();
- ui::X11EventSource::GetInstance()->DispatchXEvents();
-
- // Sanity check that the two widgets each have their own XID.
- ASSERT_NE(parent_widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget(),
- child_widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget());
- Widget::CloseAllSecondaryWidgets();
- EXPECT_TRUE(DesktopWindowTreeHostLinux::GetAllOpenWindows().empty());
-}
-
-// A Widget that allows setting the min/max size for the widget.
-class CustomSizeWidget : public Widget {
- public:
- CustomSizeWidget() = default;
- ~CustomSizeWidget() override = default;
-
- void set_min_size(const gfx::Size& size) { min_size_ = size; }
- void set_max_size(const gfx::Size& size) { max_size_ = size; }
-
- // Widget:
- gfx::Size GetMinimumSize() const override { return min_size_; }
- gfx::Size GetMaximumSize() const override { return max_size_; }
-
- private:
- gfx::Size min_size_;
- gfx::Size max_size_;
-
- DISALLOW_COPY_AND_ASSIGN(CustomSizeWidget);
-};
-
-TEST_F(DesktopWindowTreeHostX11Test, SetBoundsWithMinMax) {
- CustomSizeWidget widget;
- Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.bounds = gfx::Rect(200, 100);
- widget.Init(std::move(params));
- widget.Show();
- ui::X11EventSource::GetInstance()->DispatchXEvents();
-
- EXPECT_EQ(gfx::Size(200, 100).ToString(),
- widget.GetWindowBoundsInScreen().size().ToString());
- widget.SetBounds(gfx::Rect(300, 200));
- EXPECT_EQ(gfx::Size(300, 200).ToString(),
- widget.GetWindowBoundsInScreen().size().ToString());
-
- widget.set_min_size(gfx::Size(100, 100));
- widget.SetBounds(gfx::Rect(50, 500));
- EXPECT_EQ(gfx::Size(100, 500).ToString(),
- widget.GetWindowBoundsInScreen().size().ToString());
-}
-
-class MouseEventRecorder : public ui::EventHandler {
- public:
- MouseEventRecorder() = default;
- ~MouseEventRecorder() override = default;
-
- void Reset() { mouse_events_.clear(); }
-
- const std::vector<ui::MouseEvent>& mouse_events() const {
- return mouse_events_;
- }
-
- private:
- // ui::EventHandler:
- void OnMouseEvent(ui::MouseEvent* mouse) override {
- mouse_events_.push_back(*mouse);
- }
-
- std::vector<ui::MouseEvent> mouse_events_;
-
- DISALLOW_COPY_AND_ASSIGN(MouseEventRecorder);
-};
-
-class DesktopWindowTreeHostX11HighDPITest
- : public DesktopWindowTreeHostX11Test {
- public:
- DesktopWindowTreeHostX11HighDPITest() = default;
- ~DesktopWindowTreeHostX11HighDPITest() override = default;
-
- void PretendCapture(views::Widget* capture_widget) {
- if (capture_widget)
- capture_widget->GetNativeWindow()->SetCapture();
- }
-
- private:
- void SetUp() override {
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- command_line->AppendSwitchASCII(switches::kForceDeviceScaleFactor, "2");
-
- DesktopWindowTreeHostX11Test::SetUp();
- }
-
- DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostX11HighDPITest);
-};
-
-// https://crbug.com/702687
-TEST_F(DesktopWindowTreeHostX11HighDPITest,
- DISABLED_LocatedEventDispatchWithCapture) {
- Widget first;
- Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.bounds = gfx::Rect(0, 0, 50, 50);
- first.Init(std::move(params));
- first.Show();
-
- Widget second;
- params = CreateParams(Widget::InitParams::TYPE_WINDOW);
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.bounds = gfx::Rect(50, 50, 50, 50);
- second.Init(std::move(params));
- second.Show();
-
- ui::X11EventSource::GetInstance()->DispatchXEvents();
-
- MouseEventRecorder first_recorder, second_recorder;
- first.GetNativeWindow()->AddPreTargetHandler(&first_recorder);
- second.GetNativeWindow()->AddPreTargetHandler(&second_recorder);
-
- // Dispatch an event on |first|. Verify it gets the event.
- ui::ScopedXI2Event event;
- event.InitGenericButtonEvent(kPointerDeviceId, ui::ET_MOUSEWHEEL,
- gfx::Point(50, 50), ui::EF_NONE);
- DispatchSingleEventToWidget(event, &first);
- ASSERT_EQ(1u, first_recorder.mouse_events().size());
- EXPECT_EQ(ui::ET_MOUSEWHEEL, first_recorder.mouse_events()[0].type());
- EXPECT_EQ(gfx::Point(25, 25).ToString(),
- first_recorder.mouse_events()[0].location().ToString());
- ASSERT_EQ(0u, second_recorder.mouse_events().size());
-
- first_recorder.Reset();
- second_recorder.Reset();
-
- // Set a capture on |second|, and dispatch the same event to |first|. This
- // event should reach |second| instead.
- PretendCapture(&second);
- event.InitGenericButtonEvent(kPointerDeviceId, ui::ET_MOUSEWHEEL,
- gfx::Point(50, 50), ui::EF_NONE);
- DispatchSingleEventToWidget(event, &first);
-
- ASSERT_EQ(0u, first_recorder.mouse_events().size());
- ASSERT_EQ(1u, second_recorder.mouse_events().size());
- EXPECT_EQ(ui::ET_MOUSEWHEEL, second_recorder.mouse_events()[0].type());
- EXPECT_EQ(gfx::Point(-25, -25).ToString(),
- second_recorder.mouse_events()[0].location().ToString());
-
- PretendCapture(nullptr);
- first.GetNativeWindow()->RemovePreTargetHandler(&first_recorder);
- second.GetNativeWindow()->RemovePreTargetHandler(&second_recorder);
-}
-
-TEST_F(DesktopWindowTreeHostX11Test, MouseNCEvents) {
- std::unique_ptr<Widget> widget = CreateWidget(new ShapedWidgetDelegate());
- widget->Show();
-
- ui::X11EventSource::GetInstance()->DispatchXEvents();
-
- widget->SetBounds(gfx::Rect(100, 100, 501, 501));
- ui::X11EventSource::GetInstance()->DispatchXEvents();
-
- MouseEventRecorder recorder;
- widget->GetNativeWindow()->AddPreTargetHandler(&recorder);
-
- ui::ScopedXI2Event event;
- event.InitGenericButtonEvent(kPointerDeviceId, ui::ET_MOUSE_PRESSED,
- gfx::Point(500, 500), ui::EF_LEFT_MOUSE_BUTTON);
-
- DispatchSingleEventToWidget(event, widget.get());
- ASSERT_EQ(1u, recorder.mouse_events().size());
- EXPECT_EQ(ui::ET_MOUSE_PRESSED, recorder.mouse_events()[0].type());
- EXPECT_TRUE(recorder.mouse_events()[0].flags() & ui::EF_IS_NON_CLIENT);
-
- widget->GetNativeWindow()->RemovePreTargetHandler(&recorder);
-}
-
-TEST_F(DesktopWindowTreeHostX11HighDPITest, MouseNCEvents) {
- std::unique_ptr<Widget> widget = CreateWidget(new ShapedWidgetDelegate());
- widget->Show();
-
- ui::X11EventSource::GetInstance()->DispatchXEvents();
-
- widget->SetBounds(gfx::Rect(100, 100, 1000, 1000));
- ui::X11EventSource::GetInstance()->DispatchXEvents();
-
- MouseEventRecorder recorder;
- widget->GetNativeWindow()->AddPreTargetHandler(&recorder);
-
- ui::ScopedXI2Event event;
- event.InitGenericButtonEvent(kPointerDeviceId, ui::ET_MOUSE_PRESSED,
- gfx::Point(1001, 1001),
- ui::EF_LEFT_MOUSE_BUTTON);
- DispatchSingleEventToWidget(event, widget.get());
- ASSERT_EQ(1u, recorder.mouse_events().size());
- EXPECT_EQ(ui::ET_MOUSE_PRESSED, recorder.mouse_events()[0].type());
- EXPECT_TRUE(recorder.mouse_events()[0].flags() & ui::EF_IS_NON_CLIENT);
-
- widget->GetNativeWindow()->RemovePreTargetHandler(&recorder);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_drag_drop_client_unittest.cc b/chromium/ui/views/widget/desktop_aura/x11_drag_drop_client_unittest.cc
new file mode 100644
index 00000000000..c9946d29596
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/x11_drag_drop_client_unittest.cc
@@ -0,0 +1,827 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/x/x11_drag_drop_client.h"
+
+#include <map>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "ui/aura/client/drag_drop_client.h"
+#include "ui/aura/client/drag_drop_delegate.h"
+#include "ui/aura/test/test_screen.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/base/x/x11_cursor.h"
+#include "ui/base/x/x11_move_loop.h"
+#include "ui/base/x/x11_move_loop_delegate.h"
+#include "ui/base/x/x11_os_exchange_data_provider.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/events/event_utils.h"
+#include "ui/gfx/x/x11.h"
+#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/x11_types.h"
+#include "ui/gfx/x/xproto.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+namespace {
+
+class TestDragDropClient;
+
+// Collects messages which would otherwise be sent to |window_| via
+// SendXClientEvent().
+class ClientMessageEventCollector {
+ public:
+ ClientMessageEventCollector(x11::Window window, TestDragDropClient* client);
+ virtual ~ClientMessageEventCollector();
+
+ // Returns true if |events_| is non-empty.
+ bool HasEvents() const { return !events_.empty(); }
+
+ // Pops all of |events_| and returns the popped events in the order that they
+ // were on the stack
+ std::vector<x11::ClientMessageEvent> PopAllEvents();
+
+ // Adds |event| to the stack.
+ void RecordEvent(const x11::ClientMessageEvent& event);
+
+ private:
+ x11::Window window_;
+
+ // Not owned.
+ TestDragDropClient* client_;
+
+ std::vector<x11::ClientMessageEvent> events_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientMessageEventCollector);
+};
+
+// An implementation of ui::X11MoveLoop where RunMoveLoop() always starts the
+// move loop.
+class TestMoveLoop : public ui::X11MoveLoop {
+ public:
+ explicit TestMoveLoop(ui::X11MoveLoopDelegate* delegate);
+ ~TestMoveLoop() override;
+
+ // Returns true if the move loop is running.
+ bool IsRunning() const;
+
+ // ui::X11MoveLoop:
+ bool RunMoveLoop(bool can_grab_pointer,
+ ::Cursor old_cursor,
+ ::Cursor new_cursor) override;
+ void UpdateCursor(::Cursor cursor) override;
+ void EndMoveLoop() override;
+
+ private:
+ // Not owned.
+ ui::X11MoveLoopDelegate* delegate_;
+
+ // Ends the move loop.
+ base::OnceClosure quit_closure_;
+
+ bool is_running_ = false;
+};
+
+// Implementation of XDragDropClient which short circuits FindWindowFor().
+class SimpleTestDragDropClient : public aura::client::DragDropClient,
+ public ui::XDragDropClient,
+ public ui::XDragDropClient::Delegate,
+ public ui::X11MoveLoopDelegate {
+ public:
+ SimpleTestDragDropClient(aura::Window*,
+ DesktopNativeCursorManager* cursor_manager);
+ ~SimpleTestDragDropClient() override;
+
+ // Sets |window| as the topmost window for all mouse positions.
+ void SetTopmostXWindow(x11::Window window);
+
+ // Returns true if the move loop is running.
+ bool IsMoveLoopRunning();
+
+ // aura::client::DragDropClient:
+ int StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,
+ aura::Window* root_window,
+ aura::Window* source_window,
+ const gfx::Point& screen_location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) override;
+ void DragCancel() override;
+ bool IsDragDropInProgress() override;
+ void AddObserver(aura::client::DragDropClientObserver* observer) override;
+ void RemoveObserver(aura::client::DragDropClientObserver* observer) override;
+
+ private:
+ // ui::XDragDropClient::Delegate:
+ std::unique_ptr<ui::XTopmostWindowFinder> CreateWindowFinder() override;
+ int UpdateDrag(const gfx::Point& screen_point) override;
+ void UpdateCursor(
+ ui::DragDropTypes::DragOperation negotiated_operation) override;
+ void OnBeginForeignDrag(x11::Window window) override;
+ void OnEndForeignDrag() override;
+ void OnBeforeDragLeave() override;
+ int PerformDrop() override;
+ void EndDragLoop() override;
+
+ // XDragDropClient:
+ x11::Window FindWindowFor(const gfx::Point& screen_point) override;
+
+ // ui::X11MoveLoopDelegate:
+ void OnMouseMovement(const gfx::Point& screen_point,
+ int flags,
+ base::TimeTicks event_time) override;
+ void OnMouseReleased() override;
+ void OnMoveLoopEnded() override;
+
+ std::unique_ptr<ui::X11MoveLoop> CreateMoveLoop(
+ ui::X11MoveLoopDelegate* delegate);
+
+ // The x11::Window of the window which is simulated to be the topmost window.
+ x11::Window target_window_ = x11::Window::None;
+
+ // The move loop. Not owned.
+ TestMoveLoop* loop_ = nullptr;
+
+ base::OnceClosure quit_closure_;
+
+ DISALLOW_COPY_AND_ASSIGN(SimpleTestDragDropClient);
+};
+
+// Implementation of XDragDropClient which works with a fake
+// |XDragDropClient::source_current_window_|.
+class TestDragDropClient : public SimpleTestDragDropClient {
+ public:
+ // The location in screen coordinates used for the synthetic mouse moves
+ // generated in SetTopmostXWindowAndMoveMouse().
+ static constexpr int kMouseMoveX = 100;
+ static constexpr int kMouseMoveY = 200;
+
+ TestDragDropClient(aura::Window* window,
+ DesktopNativeCursorManager* cursor_manager);
+ ~TestDragDropClient() override;
+
+ // Returns the x11::Window of the window which initiated the drag.
+ x11::Window source_xwindow() { return source_window_; }
+
+ // Returns the Atom with |name|.
+ x11::Atom GetAtom(const char* name);
+
+ // Returns true if the event's message has |type|.
+ bool MessageHasType(const x11::ClientMessageEvent& event, const char* type);
+
+ // Sets |collector| to collect x11::ClientMessageEvents which would otherwise
+ // have been sent to the drop target window.
+ void SetEventCollectorFor(x11::Window window,
+ ClientMessageEventCollector* collector);
+
+ // Builds an XdndStatus message and sends it to
+ // XDragDropClient.
+ void OnStatus(x11::Window target_window,
+ bool will_accept_drop,
+ x11::Atom accepted_action);
+
+ // Builds an XdndFinished message and sends it to
+ // XDragDropClient.
+ void OnFinished(x11::Window target_window,
+ bool accepted_drop,
+ x11::Atom performed_action);
+
+ // Sets |window| as the topmost window at the current mouse position and
+ // generates a synthetic mouse move.
+ void SetTopmostXWindowAndMoveMouse(x11::Window window);
+
+ private:
+ // XDragDropClient:
+ void SendXClientEvent(x11::Window window,
+ const x11::ClientMessageEvent& event) override;
+
+ // The x11::Window of the window which initiated the drag.
+ x11::Window source_window_;
+
+ // Map of x11::Windows to the collector which intercepts
+ // x11::ClientMessageEvents for that window.
+ std::map<x11::Window, ClientMessageEventCollector*> collectors_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestDragDropClient);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// ClientMessageEventCollector
+
+ClientMessageEventCollector::ClientMessageEventCollector(
+ x11::Window window,
+ TestDragDropClient* client)
+ : window_(window), client_(client) {
+ client->SetEventCollectorFor(window, this);
+}
+
+ClientMessageEventCollector::~ClientMessageEventCollector() {
+ client_->SetEventCollectorFor(window_, nullptr);
+}
+
+std::vector<x11::ClientMessageEvent>
+ClientMessageEventCollector::PopAllEvents() {
+ std::vector<x11::ClientMessageEvent> to_return;
+ to_return.swap(events_);
+ return to_return;
+}
+
+void ClientMessageEventCollector::RecordEvent(
+ const x11::ClientMessageEvent& event) {
+ events_.push_back(event);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// TestMoveLoop
+
+TestMoveLoop::TestMoveLoop(ui::X11MoveLoopDelegate* delegate)
+ : delegate_(delegate) {}
+
+TestMoveLoop::~TestMoveLoop() = default;
+
+bool TestMoveLoop::IsRunning() const {
+ return is_running_;
+}
+
+bool TestMoveLoop::RunMoveLoop(bool can_grab_pointer,
+ ::Cursor old_cursor,
+ ::Cursor new_cursor) {
+ is_running_ = true;
+ base::RunLoop run_loop;
+ quit_closure_ = run_loop.QuitClosure();
+ run_loop.Run();
+ return true;
+}
+
+void TestMoveLoop::UpdateCursor(::Cursor cursor) {}
+
+void TestMoveLoop::EndMoveLoop() {
+ if (is_running_) {
+ delegate_->OnMoveLoopEnded();
+ is_running_ = false;
+ std::move(quit_closure_).Run();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// SimpleTestDragDropClient
+
+SimpleTestDragDropClient::SimpleTestDragDropClient(
+ aura::Window* window,
+ DesktopNativeCursorManager* cursor_manager)
+ : ui::XDragDropClient(this, window->GetHost()->GetAcceleratedWidget()) {}
+
+SimpleTestDragDropClient::~SimpleTestDragDropClient() = default;
+
+void SimpleTestDragDropClient::SetTopmostXWindow(x11::Window window) {
+ target_window_ = window;
+}
+
+bool SimpleTestDragDropClient::IsMoveLoopRunning() {
+ return loop_->IsRunning();
+}
+
+std::unique_ptr<ui::X11MoveLoop> SimpleTestDragDropClient::CreateMoveLoop(
+ ui::X11MoveLoopDelegate* delegate) {
+ loop_ = new TestMoveLoop(delegate);
+ return base::WrapUnique(loop_);
+}
+
+int SimpleTestDragDropClient::StartDragAndDrop(
+ std::unique_ptr<ui::OSExchangeData> data,
+ aura::Window* root_window,
+ aura::Window* source_window,
+ const gfx::Point& screen_location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) {
+ InitDrag(operation, data.get());
+
+ auto loop = CreateMoveLoop(this);
+
+ // Windows has a specific method, DoDragDrop(), which performs the entire
+ // drag. We have to emulate this, so we spin off a nested runloop which will
+ // track all cursor movement and reroute events to a specific handler.
+ auto cursor_manager_ = std::make_unique<DesktopNativeCursorManager>();
+ auto* last_cursor = static_cast<ui::X11Cursor*>(
+ source_window->GetHost()->last_cursor().platform());
+ loop_->RunMoveLoop(
+ !source_window->HasCapture(),
+ last_cursor ? last_cursor->xcursor() : x11::None,
+ static_cast<ui::X11Cursor*>(
+ cursor_manager_
+ ->GetInitializedCursor(ui::mojom::CursorType::kGrabbing)
+ .platform())
+ ->xcursor());
+
+ auto resulting_operation = negotiated_operation();
+ CleanupDrag();
+ return resulting_operation;
+}
+
+void SimpleTestDragDropClient::DragCancel() {}
+bool SimpleTestDragDropClient::IsDragDropInProgress() {
+ return false;
+}
+void SimpleTestDragDropClient::AddObserver(
+ aura::client::DragDropClientObserver* observer) {}
+void SimpleTestDragDropClient::RemoveObserver(
+ aura::client::DragDropClientObserver* observer) {}
+
+int SimpleTestDragDropClient::UpdateDrag(const gfx::Point& screen_point) {
+ return 0;
+}
+
+std::unique_ptr<ui::XTopmostWindowFinder>
+SimpleTestDragDropClient::CreateWindowFinder() {
+ return {};
+}
+void SimpleTestDragDropClient::UpdateCursor(
+ ui::DragDropTypes::DragOperation negotiated_operation) {}
+void SimpleTestDragDropClient::OnBeginForeignDrag(x11::Window window) {}
+void SimpleTestDragDropClient::OnEndForeignDrag() {}
+void SimpleTestDragDropClient::OnBeforeDragLeave() {}
+int SimpleTestDragDropClient::PerformDrop() {
+ return 0;
+}
+void SimpleTestDragDropClient::EndDragLoop() {
+ // std::move(quit_closure_).Run();
+ loop_->EndMoveLoop();
+}
+
+x11::Window SimpleTestDragDropClient::FindWindowFor(
+ const gfx::Point& screen_point) {
+ return target_window_;
+}
+
+void SimpleTestDragDropClient::OnMouseMovement(const gfx::Point& screen_point,
+ int flags,
+ base::TimeTicks event_time) {
+ HandleMouseMovement(screen_point, flags, event_time);
+}
+
+void SimpleTestDragDropClient::OnMouseReleased() {
+ HandleMouseReleased();
+}
+
+void SimpleTestDragDropClient::OnMoveLoopEnded() {
+ HandleMoveLoopEnded();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// TestDragDropClient
+
+TestDragDropClient::TestDragDropClient(
+ aura::Window* window,
+ DesktopNativeCursorManager* cursor_manager)
+ : SimpleTestDragDropClient(window, cursor_manager),
+ source_window_(window->GetHost()->GetAcceleratedWidget()) {}
+
+TestDragDropClient::~TestDragDropClient() = default;
+
+x11::Atom TestDragDropClient::GetAtom(const char* name) {
+ return gfx::GetAtom(name);
+}
+
+bool TestDragDropClient::MessageHasType(const x11::ClientMessageEvent& event,
+ const char* type) {
+ return event.type == GetAtom(type);
+}
+
+void TestDragDropClient::SetEventCollectorFor(
+ x11::Window window,
+ ClientMessageEventCollector* collector) {
+ if (collector)
+ collectors_[window] = collector;
+ else
+ collectors_.erase(window);
+}
+
+void TestDragDropClient::OnStatus(x11::Window target_window,
+ bool will_accept_drop,
+ x11::Atom accepted_action) {
+ x11::ClientMessageEvent event;
+ event.type = GetAtom("XdndStatus");
+ event.format = 32;
+ event.window = source_window_;
+ event.data.data32[0] = static_cast<uint32_t>(target_window);
+ event.data.data32[1] = will_accept_drop ? 1 : 0;
+ event.data.data32[2] = 0;
+ event.data.data32[3] = 0;
+ event.data.data32[4] = static_cast<uint32_t>(accepted_action);
+ HandleXdndEvent(event);
+}
+
+void TestDragDropClient::OnFinished(x11::Window target_window,
+ bool accepted_drop,
+ x11::Atom performed_action) {
+ x11::ClientMessageEvent event;
+ event.type = GetAtom("XdndFinished");
+ event.format = 32;
+ event.window = source_window_;
+ event.data.data32[0] = static_cast<uint32_t>(target_window);
+ event.data.data32[1] = accepted_drop ? 1 : 0;
+ event.data.data32[2] = static_cast<uint32_t>(performed_action);
+ event.data.data32[3] = 0;
+ event.data.data32[4] = 0;
+ HandleXdndEvent(event);
+}
+
+void TestDragDropClient::SetTopmostXWindowAndMoveMouse(x11::Window window) {
+ SetTopmostXWindow(window);
+ HandleMouseMovement(gfx::Point(kMouseMoveX, kMouseMoveY), ui::EF_NONE,
+ ui::EventTimeForNow());
+}
+
+void TestDragDropClient::SendXClientEvent(
+ x11::Window window,
+ const x11::ClientMessageEvent& event) {
+ auto it = collectors_.find(window);
+ if (it != collectors_.end())
+ it->second->RecordEvent(event);
+}
+
+} // namespace
+
+class X11DragDropClientTest : public ViewsTestBase {
+ public:
+ X11DragDropClientTest() = default;
+ ~X11DragDropClientTest() override = default;
+
+ int StartDragAndDrop() {
+ auto data(std::make_unique<ui::OSExchangeData>());
+ data->SetString(base::ASCIIToUTF16("Test"));
+ SkBitmap drag_bitmap;
+ drag_bitmap.allocN32Pixels(10, 10);
+ drag_bitmap.eraseARGB(0xFF, 0, 0, 0);
+ gfx::ImageSkia drag_image(gfx::ImageSkia::CreateFrom1xBitmap(drag_bitmap));
+ data->provider().SetDragImage(drag_image, gfx::Vector2d());
+
+ return client_->StartDragAndDrop(
+ std::move(data), widget_->GetNativeWindow()->GetRootWindow(),
+ widget_->GetNativeWindow(), gfx::Point(), ui::DragDropTypes::DRAG_COPY,
+ ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
+ }
+
+ // ViewsTestBase:
+ void SetUp() override {
+ set_native_widget_type(NativeWidgetType::kDesktop);
+
+ ViewsTestBase::SetUp();
+
+ // Create widget to initiate the drags.
+ widget_ = std::make_unique<Widget>();
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(100, 100);
+ widget_->Init(std::move(params));
+ widget_->Show();
+
+ cursor_manager_ = std::make_unique<DesktopNativeCursorManager>();
+
+ client_ = std::make_unique<TestDragDropClient>(widget_->GetNativeWindow(),
+ cursor_manager_.get());
+ // client_->Init();
+ }
+
+ void TearDown() override {
+ client_.reset();
+ cursor_manager_.reset();
+ widget_.reset();
+ ViewsTestBase::TearDown();
+ }
+
+ TestDragDropClient* client() { return client_.get(); }
+
+ private:
+ std::unique_ptr<TestDragDropClient> client_;
+ std::unique_ptr<DesktopNativeCursorManager> cursor_manager_;
+
+ // The widget used to initiate drags.
+ std::unique_ptr<Widget> widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(X11DragDropClientTest);
+};
+
+namespace {
+
+void BasicStep2(TestDragDropClient* client, x11::Window toplevel) {
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+
+ ClientMessageEventCollector collector(toplevel, client);
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+
+ // XdndEnter should have been sent to |toplevel| before the XdndPosition
+ // message.
+ std::vector<x11::ClientMessageEvent> events = collector.PopAllEvents();
+ ASSERT_EQ(2u, events.size());
+
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
+ EXPECT_EQ(client->source_xwindow(),
+ static_cast<x11::Window>(events[0].data.data32[0]));
+ EXPECT_EQ(1u, events[0].data.data32[1] & 1);
+ std::vector<x11::Atom> targets;
+ ui::GetAtomArrayProperty(client->source_xwindow(), "XdndTypeList", &targets);
+ EXPECT_FALSE(targets.empty());
+
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
+ EXPECT_EQ(client->source_xwindow(),
+ static_cast<x11::Window>(events[0].data.data32[0]));
+ const uint32_t kCoords =
+ TestDragDropClient::kMouseMoveX << 16 | TestDragDropClient::kMouseMoveY;
+ EXPECT_EQ(kCoords, events[1].data.data32[2]);
+ EXPECT_EQ(client->GetAtom("XdndActionCopy"),
+ static_cast<x11::Atom>(events[1].data.data32[4]));
+
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
+
+ // Because there is no unprocessed XdndPosition, the drag drop client should
+ // send XdndDrop immediately after the mouse is released.
+ client->HandleMouseReleased();
+
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
+ EXPECT_EQ(client->source_xwindow(),
+ static_cast<x11::Window>(events[0].data.data32[0]));
+
+ // Send XdndFinished to indicate that the drag drop client can cleanup any
+ // data related to this drag. The move loop should end only after the
+ // XdndFinished message was received.
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+ client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy"));
+ EXPECT_FALSE(client->IsMoveLoopRunning());
+}
+
+void BasicStep3(TestDragDropClient* client, x11::Window toplevel) {
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+
+ ClientMessageEventCollector collector(toplevel, client);
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+
+ std::vector<x11::ClientMessageEvent> events = collector.PopAllEvents();
+ ASSERT_EQ(2u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
+
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition"));
+
+ // We have not received an XdndStatus ack for the second XdndPosition message.
+ // Test that sending XdndDrop is delayed till the XdndStatus ack is received.
+ client->HandleMouseReleased();
+ EXPECT_FALSE(collector.HasEvents());
+
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
+
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+ client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy"));
+ EXPECT_FALSE(client->IsMoveLoopRunning());
+}
+
+} // namespace
+
+TEST_F(X11DragDropClientTest, Basic) {
+ x11::Window toplevel = static_cast<x11::Window>(1);
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&BasicStep2, client(), toplevel));
+ int result = StartDragAndDrop();
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
+
+ // Do another drag and drop to test that the data is properly cleaned up as a
+ // result of the XdndFinished message.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&BasicStep3, client(), toplevel));
+ result = StartDragAndDrop();
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
+}
+
+namespace {
+
+void TargetDoesNotRespondStep2(TestDragDropClient* client) {
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+
+ x11::Window toplevel = static_cast<x11::Window>(1);
+ ClientMessageEventCollector collector(toplevel, client);
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+
+ std::vector<x11::ClientMessageEvent> events = collector.PopAllEvents();
+ ASSERT_EQ(2u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
+
+ client->HandleMouseReleased();
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndLeave"));
+ EXPECT_FALSE(client->IsMoveLoopRunning());
+}
+
+} // namespace
+
+// Test that we do not wait for the target to send XdndStatus if we have not
+// received any XdndStatus messages at all from the target. The Unity
+// DNDCollectionWindow is an example of an XdndAware target which does not
+// respond to XdndPosition messages at all.
+TEST_F(X11DragDropClientTest, TargetDoesNotRespond) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&TargetDoesNotRespondStep2, client()));
+ int result = StartDragAndDrop();
+ EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
+}
+
+namespace {
+
+void QueuePositionStep2(TestDragDropClient* client) {
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+
+ x11::Window toplevel = static_cast<x11::Window>(1);
+ ClientMessageEventCollector collector(toplevel, client);
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+
+ std::vector<x11::ClientMessageEvent> events = collector.PopAllEvents();
+ ASSERT_EQ(2u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
+
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition"));
+
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
+ EXPECT_FALSE(collector.HasEvents());
+
+ client->HandleMouseReleased();
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
+
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+ client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy"));
+ EXPECT_FALSE(client->IsMoveLoopRunning());
+}
+
+} // namespace
+
+// Test that XdndPosition messages are queued till the pending XdndPosition
+// message is acked via an XdndStatus message.
+TEST_F(X11DragDropClientTest, QueuePosition) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&QueuePositionStep2, client()));
+ int result = StartDragAndDrop();
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
+}
+
+namespace {
+
+void TargetChangesStep2(TestDragDropClient* client) {
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+
+ x11::Window toplevel1 = static_cast<x11::Window>(1);
+ ClientMessageEventCollector collector1(toplevel1, client);
+ client->SetTopmostXWindowAndMoveMouse(toplevel1);
+
+ std::vector<x11::ClientMessageEvent> events1 = collector1.PopAllEvents();
+ ASSERT_EQ(2u, events1.size());
+ EXPECT_TRUE(client->MessageHasType(events1[0], "XdndEnter"));
+ EXPECT_TRUE(client->MessageHasType(events1[1], "XdndPosition"));
+
+ x11::Window toplevel2 = static_cast<x11::Window>(2);
+ ClientMessageEventCollector collector2(toplevel2, client);
+ client->SetTopmostXWindowAndMoveMouse(toplevel2);
+
+ // It is possible for |toplevel1| to send XdndStatus after the source has sent
+ // XdndLeave but before |toplevel1| has received the XdndLeave message. The
+ // XdndStatus message should be ignored.
+ client->OnStatus(toplevel1, true, client->GetAtom("XdndActionCopy"));
+ events1 = collector1.PopAllEvents();
+ ASSERT_EQ(1u, events1.size());
+ EXPECT_TRUE(client->MessageHasType(events1[0], "XdndLeave"));
+
+ std::vector<x11::ClientMessageEvent> events2 = collector2.PopAllEvents();
+ ASSERT_EQ(2u, events2.size());
+ EXPECT_TRUE(client->MessageHasType(events2[0], "XdndEnter"));
+ EXPECT_TRUE(client->MessageHasType(events2[1], "XdndPosition"));
+
+ client->OnStatus(toplevel2, true, client->GetAtom("XdndActionCopy"));
+ client->HandleMouseReleased();
+ events2 = collector2.PopAllEvents();
+ ASSERT_EQ(1u, events2.size());
+ EXPECT_TRUE(client->MessageHasType(events2[0], "XdndDrop"));
+
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+ client->OnFinished(toplevel2, true, client->GetAtom("XdndActionCopy"));
+ EXPECT_FALSE(client->IsMoveLoopRunning());
+}
+
+} // namespace
+
+// Test the behavior when the target changes during a drag.
+TEST_F(X11DragDropClientTest, TargetChanges) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&TargetChangesStep2, client()));
+ int result = StartDragAndDrop();
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
+}
+
+namespace {
+
+void RejectAfterMouseReleaseStep2(TestDragDropClient* client) {
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+
+ x11::Window toplevel = static_cast<x11::Window>(1);
+ ClientMessageEventCollector collector(toplevel, client);
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+
+ std::vector<x11::ClientMessageEvent> events = collector.PopAllEvents();
+ ASSERT_EQ(2u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
+
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
+ EXPECT_FALSE(collector.HasEvents());
+
+ // Send another mouse move such that there is a pending XdndPosition.
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition"));
+
+ client->HandleMouseReleased();
+ // Reject the drop.
+ client->OnStatus(toplevel, false, x11::Atom::None);
+
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndLeave"));
+ EXPECT_FALSE(client->IsMoveLoopRunning());
+}
+
+void RejectAfterMouseReleaseStep3(TestDragDropClient* client) {
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+
+ x11::Window toplevel = static_cast<x11::Window>(2);
+ ClientMessageEventCollector collector(toplevel, client);
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+
+ std::vector<x11::ClientMessageEvent> events = collector.PopAllEvents();
+ ASSERT_EQ(2u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
+
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
+ EXPECT_FALSE(collector.HasEvents());
+
+ client->HandleMouseReleased();
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
+
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+ client->OnFinished(toplevel, false, x11::Atom::None);
+ EXPECT_FALSE(client->IsMoveLoopRunning());
+}
+
+} // namespace
+
+// Test that the source sends XdndLeave instead of XdndDrop if the drag
+// operation is rejected after the mouse is released.
+TEST_F(X11DragDropClientTest, RejectAfterMouseRelease) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&RejectAfterMouseReleaseStep2, client()));
+ int result = StartDragAndDrop();
+ EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
+
+ // Repeat the test but reject the drop in the XdndFinished message instead.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&RejectAfterMouseReleaseStep3, client()));
+ result = StartDragAndDrop();
+ EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
index aa249625d3f..fadecc97d9d 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
+++ b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
@@ -15,7 +15,12 @@
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/x/test/x11_property_change_waiter.h"
+#include "ui/base/x/x11_util.h"
#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/event.h"
+#include "ui/gfx/x/shape.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_path.h"
@@ -31,15 +36,15 @@ namespace {
// Waits till |window| is minimized.
class MinimizeWaiter : public ui::X11PropertyChangeWaiter {
public:
- explicit MinimizeWaiter(XID window)
+ explicit MinimizeWaiter(x11::Window window)
: ui::X11PropertyChangeWaiter(window, "_NET_WM_STATE") {}
~MinimizeWaiter() override = default;
private:
// ui::X11PropertyChangeWaiter:
- bool ShouldKeepOnWaiting(XEvent* event) override {
- std::vector<Atom> wm_states;
+ bool ShouldKeepOnWaiting(x11::Event* event) override {
+ std::vector<x11::Atom> wm_states;
if (ui::GetAtomArrayProperty(xwindow(), "_NET_WM_STATE", &wm_states)) {
return !base::Contains(wm_states, gfx::GetAtom("_NET_WM_STATE_HIDDEN"));
}
@@ -53,7 +58,7 @@ class MinimizeWaiter : public ui::X11PropertyChangeWaiter {
// |expected_windows|.
class StackingClientListWaiter : public ui::X11PropertyChangeWaiter {
public:
- StackingClientListWaiter(XID* expected_windows, size_t count)
+ StackingClientListWaiter(x11::Window* expected_windows, size_t count)
: ui::X11PropertyChangeWaiter(ui::GetX11RootWindow(),
"_NET_CLIENT_LIST_STACKING"),
expected_windows_(expected_windows, expected_windows + count) {}
@@ -72,15 +77,15 @@ class StackingClientListWaiter : public ui::X11PropertyChangeWaiter {
private:
// ui::X11PropertyChangeWaiter:
- bool ShouldKeepOnWaiting(XEvent* event) override {
- std::vector<XID> stack;
+ bool ShouldKeepOnWaiting(x11::Event* event) override {
+ std::vector<x11::Window> stack;
ui::GetXWindowStack(ui::GetX11RootWindow(), &stack);
return !std::all_of(
expected_windows_.cbegin(), expected_windows_.cend(),
- [&stack](XID window) { return base::Contains(stack, window); });
+ [&stack](x11::Window window) { return base::Contains(stack, window); });
}
- std::vector<XID> expected_windows_;
+ std::vector<x11::Window> expected_windows_;
DISALLOW_COPY_AND_ASSIGN(StackingClientListWaiter);
};
@@ -120,34 +125,36 @@ class X11TopmostWindowFinderTest : public test::DesktopWidgetTestInteractive {
}
// Creates and shows an X window with |bounds|.
- XID CreateAndShowXWindow(const gfx::Rect& bounds) {
- XID root = DefaultRootWindow(xdisplay());
- XID xid = XCreateSimpleWindow(xdisplay(), root, 0, 0, 1, 1,
- 0, // border_width
- 0, // border
- 0); // background
-
- ui::SetUseOSWindowFrame(xid, false);
- ShowAndSetXWindowBounds(xid, bounds);
- return xid;
+ x11::Window CreateAndShowXWindow(const gfx::Rect& bounds) {
+ x11::Window root = ui::GetX11RootWindow();
+ x11::Window window = static_cast<x11::Window>(
+ XCreateSimpleWindow(xdisplay(), static_cast<uint32_t>(root), 0, 0, 1, 1,
+ 0, // border_width
+ 0, // border
+ 0)); // background
+
+ ui::SetUseOSWindowFrame(window, false);
+ ShowAndSetXWindowBounds(window, bounds);
+ return window;
}
- // Shows |xid| and sets its bounds.
- void ShowAndSetXWindowBounds(XID xid, const gfx::Rect& bounds) {
- XMapWindow(xdisplay(), xid);
+ // Shows |window| and sets its bounds.
+ void ShowAndSetXWindowBounds(x11::Window window, const gfx::Rect& bounds) {
+ XMapWindow(xdisplay(), static_cast<uint32_t>(window));
XWindowChanges changes = {0};
changes.x = bounds.x();
changes.y = bounds.y();
changes.width = bounds.width();
changes.height = bounds.height();
- XConfigureWindow(xdisplay(), xid, CWX | CWY | CWWidth | CWHeight, &changes);
+ XConfigureWindow(xdisplay(), static_cast<uint32_t>(window),
+ CWX | CWY | CWWidth | CWHeight, &changes);
}
Display* xdisplay() { return gfx::GetXDisplay(); }
// Returns the topmost X window at the passed in screen position.
- XID FindTopmostXWindowAt(int screen_x, int screen_y) {
+ x11::Window FindTopmostXWindowAt(int screen_x, int screen_y) {
ui::X11TopmostWindowFinder finder;
return finder.FindWindowAt(gfx::Point(screen_x, screen_y));
}
@@ -158,9 +165,10 @@ class X11TopmostWindowFinderTest : public test::DesktopWidgetTestInteractive {
ui::X11TopmostWindowFinder finder;
auto widget =
finder.FindLocalProcessWindowAt(gfx::Point(screen_x, screen_y), {});
- return widget ? DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
- static_cast<gfx::AcceleratedWidget>(widget))
- : nullptr;
+ return widget != gfx::kNullAcceleratedWidget
+ ? DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
+ static_cast<gfx::AcceleratedWidget>(widget))
+ : nullptr;
}
// Returns the topmost aura::Window at the passed in screen position ignoring
@@ -175,9 +183,10 @@ class X11TopmostWindowFinderTest : public test::DesktopWidgetTestInteractive {
ui::X11TopmostWindowFinder finder;
auto widget =
finder.FindLocalProcessWindowAt(gfx::Point(screen_x, screen_y), ignore);
- return widget ? DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
- static_cast<gfx::AcceleratedWidget>(widget))
- : nullptr;
+ return widget != gfx::kNullAcceleratedWidget
+ ? DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
+ static_cast<gfx::AcceleratedWidget>(widget))
+ : nullptr;
}
private:
@@ -191,38 +200,38 @@ TEST_F(X11TopmostWindowFinderTest, Basic) {
std::unique_ptr<Widget> widget1(
CreateAndShowWidget(gfx::Rect(100, 100, 200, 100)));
aura::Window* window1 = widget1->GetNativeWindow();
- XID xid1 = window1->GetHost()->GetAcceleratedWidget();
+ x11::Window x11_window1 = window1->GetHost()->GetAcceleratedWidget();
- XID xid2 = CreateAndShowXWindow(gfx::Rect(200, 100, 100, 200));
+ x11::Window x11_window2 = CreateAndShowXWindow(gfx::Rect(200, 100, 100, 200));
std::unique_ptr<Widget> widget3(
CreateAndShowWidget(gfx::Rect(100, 190, 200, 110)));
aura::Window* window3 = widget3->GetNativeWindow();
- XID xid3 = window3->GetHost()->GetAcceleratedWidget();
+ x11::Window x11_window3 = window3->GetHost()->GetAcceleratedWidget();
- XID xids[] = {xid1, xid2, xid3};
- StackingClientListWaiter waiter(xids, base::size(xids));
+ x11::Window windows[] = {x11_window1, x11_window2, x11_window3};
+ StackingClientListWaiter waiter(windows, base::size(windows));
waiter.Wait();
ui::X11EventSource::GetInstance()->DispatchXEvents();
- EXPECT_EQ(xid1, FindTopmostXWindowAt(150, 150));
+ EXPECT_EQ(x11_window1, FindTopmostXWindowAt(150, 150));
EXPECT_EQ(window1, FindTopmostLocalProcessWindowAt(150, 150));
- EXPECT_EQ(xid2, FindTopmostXWindowAt(250, 150));
+ EXPECT_EQ(x11_window2, FindTopmostXWindowAt(250, 150));
EXPECT_FALSE(FindTopmostLocalProcessWindowAt(250, 150));
- EXPECT_EQ(xid3, FindTopmostXWindowAt(250, 250));
+ EXPECT_EQ(x11_window3, FindTopmostXWindowAt(250, 250));
EXPECT_EQ(window3, FindTopmostLocalProcessWindowAt(250, 250));
- EXPECT_EQ(xid3, FindTopmostXWindowAt(150, 250));
+ EXPECT_EQ(x11_window3, FindTopmostXWindowAt(150, 250));
EXPECT_EQ(window3, FindTopmostLocalProcessWindowAt(150, 250));
- EXPECT_EQ(xid3, FindTopmostXWindowAt(150, 195));
+ EXPECT_EQ(x11_window3, FindTopmostXWindowAt(150, 195));
EXPECT_EQ(window3, FindTopmostLocalProcessWindowAt(150, 195));
- EXPECT_NE(xid1, FindTopmostXWindowAt(1000, 1000));
- EXPECT_NE(xid2, FindTopmostXWindowAt(1000, 1000));
- EXPECT_NE(xid3, FindTopmostXWindowAt(1000, 1000));
+ EXPECT_NE(x11_window1, FindTopmostXWindowAt(1000, 1000));
+ EXPECT_NE(x11_window2, FindTopmostXWindowAt(1000, 1000));
+ EXPECT_NE(x11_window3, FindTopmostXWindowAt(1000, 1000));
EXPECT_FALSE(FindTopmostLocalProcessWindowAt(1000, 1000));
EXPECT_EQ(window1,
@@ -232,7 +241,7 @@ TEST_F(X11TopmostWindowFinderTest, Basic) {
EXPECT_EQ(window1,
FindTopmostLocalProcessWindowWithIgnore(150, 195, window3));
- XDestroyWindow(xdisplay(), xid2);
+ XDestroyWindow(xdisplay(), static_cast<uint32_t>(x11_window2));
}
// Test that the minimized state is properly handled.
@@ -240,35 +249,35 @@ TEST_F(X11TopmostWindowFinderTest, Minimized) {
std::unique_ptr<Widget> widget1(
CreateAndShowWidget(gfx::Rect(100, 100, 100, 100)));
aura::Window* window1 = widget1->GetNativeWindow();
- XID xid1 = window1->GetHost()->GetAcceleratedWidget();
- XID xid2 = CreateAndShowXWindow(gfx::Rect(300, 100, 100, 100));
+ x11::Window x11_window1 = window1->GetHost()->GetAcceleratedWidget();
+ x11::Window x11_window2 = CreateAndShowXWindow(gfx::Rect(300, 100, 100, 100));
- XID xids[] = {xid1, xid2};
- StackingClientListWaiter stack_waiter(xids, base::size(xids));
+ x11::Window windows[] = {x11_window1, x11_window2};
+ StackingClientListWaiter stack_waiter(windows, base::size(windows));
stack_waiter.Wait();
ui::X11EventSource::GetInstance()->DispatchXEvents();
- EXPECT_EQ(xid1, FindTopmostXWindowAt(150, 150));
+ EXPECT_EQ(x11_window1, FindTopmostXWindowAt(150, 150));
{
- MinimizeWaiter minimize_waiter(xid1);
- XIconifyWindow(xdisplay(), xid1, 0);
+ MinimizeWaiter minimize_waiter(x11_window1);
+ XIconifyWindow(xdisplay(), static_cast<uint32_t>(x11_window1), 0);
minimize_waiter.Wait();
}
- EXPECT_NE(xid1, FindTopmostXWindowAt(150, 150));
- EXPECT_NE(xid2, FindTopmostXWindowAt(150, 150));
+ EXPECT_NE(x11_window1, FindTopmostXWindowAt(150, 150));
+ EXPECT_NE(x11_window2, FindTopmostXWindowAt(150, 150));
// Repeat test for an X window which does not belong to a views::Widget
// because the code path is different.
- EXPECT_EQ(xid2, FindTopmostXWindowAt(350, 150));
+ EXPECT_EQ(x11_window2, FindTopmostXWindowAt(350, 150));
{
- MinimizeWaiter minimize_waiter(xid2);
- XIconifyWindow(xdisplay(), xid2, 0);
+ MinimizeWaiter minimize_waiter(x11_window2);
+ XIconifyWindow(xdisplay(), static_cast<uint32_t>(x11_window2), 0);
minimize_waiter.Wait();
}
- EXPECT_NE(xid1, FindTopmostXWindowAt(350, 150));
- EXPECT_NE(xid2, FindTopmostXWindowAt(350, 150));
+ EXPECT_NE(x11_window1, FindTopmostXWindowAt(350, 150));
+ EXPECT_NE(x11_window2, FindTopmostXWindowAt(350, 150));
- XDestroyWindow(xdisplay(), xid2);
+ XDestroyWindow(xdisplay(), static_cast<uint32_t>(x11_window2));
}
// Test that non-rectangular windows are properly handled.
@@ -278,7 +287,8 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangular) {
std::unique_ptr<Widget> widget1(
CreateAndShowWidget(gfx::Rect(100, 100, 100, 100)));
- XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
+ x11::Window window1 =
+ widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
auto shape1 = std::make_unique<Widget::ShapeRects>();
shape1->emplace_back(0, 10, 10, 90);
shape1->emplace_back(10, 0, 90, 100);
@@ -287,27 +297,31 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangular) {
SkRegion skregion2;
skregion2.op(SkIRect::MakeXYWH(0, 10, 10, 90), SkRegion::kUnion_Op);
skregion2.op(SkIRect::MakeXYWH(10, 0, 90, 100), SkRegion::kUnion_Op);
- XID xid2 = CreateAndShowXWindow(gfx::Rect(300, 100, 100, 100));
- gfx::XScopedPtr<REGION, gfx::XObjectDeleter<REGION, int, XDestroyRegion>>
- region2(gfx::CreateRegionFromSkRegion(skregion2));
- XShapeCombineRegion(xdisplay(), xid2, ShapeBounding, 0, 0, region2.get(),
- false);
- XID xids[] = {xid1, xid2};
- StackingClientListWaiter stack_waiter(xids, base::size(xids));
+ x11::Window window2 = CreateAndShowXWindow(gfx::Rect(300, 100, 100, 100));
+ auto region2 = gfx::CreateRegionFromSkRegion(skregion2);
+ x11::Connection::Get()->shape().Rectangles({
+ .operation = x11::Shape::So::Set,
+ .destination_kind = x11::Shape::Sk::Bounding,
+ .ordering = x11::ClipOrdering::YXBanded,
+ .destination_window = window2,
+ .rectangles = *region2,
+ });
+ x11::Window windows[] = {window1, window2};
+ StackingClientListWaiter stack_waiter(windows, base::size(windows));
stack_waiter.Wait();
ui::X11EventSource::GetInstance()->DispatchXEvents();
- EXPECT_EQ(xid1, FindTopmostXWindowAt(105, 120));
- EXPECT_NE(xid1, FindTopmostXWindowAt(105, 105));
- EXPECT_NE(xid2, FindTopmostXWindowAt(105, 105));
+ EXPECT_EQ(window1, FindTopmostXWindowAt(105, 120));
+ EXPECT_NE(window1, FindTopmostXWindowAt(105, 105));
+ EXPECT_NE(window2, FindTopmostXWindowAt(105, 105));
// Repeat test for an X window which does not belong to a views::Widget
// because the code path is different.
- EXPECT_EQ(xid2, FindTopmostXWindowAt(305, 120));
- EXPECT_NE(xid1, FindTopmostXWindowAt(305, 105));
- EXPECT_NE(xid2, FindTopmostXWindowAt(305, 105));
+ EXPECT_EQ(window2, FindTopmostXWindowAt(305, 120));
+ EXPECT_NE(window1, FindTopmostXWindowAt(305, 105));
+ EXPECT_NE(window2, FindTopmostXWindowAt(305, 105));
- XDestroyWindow(xdisplay(), xid2);
+ XDestroyWindow(xdisplay(), static_cast<uint32_t>(window2));
}
// Test that a window with an empty shape are properly handled.
@@ -317,18 +331,19 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangularEmptyShape) {
std::unique_ptr<Widget> widget1(
CreateAndShowWidget(gfx::Rect(100, 100, 100, 100)));
- XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
+ x11::Window window1 =
+ widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
auto shape1 = std::make_unique<Widget::ShapeRects>();
shape1->emplace_back();
// Widget takes ownership of |shape1|.
widget1->SetShape(std::move(shape1));
- XID xids[] = {xid1};
- StackingClientListWaiter stack_waiter(xids, base::size(xids));
+ x11::Window windows[] = {window1};
+ StackingClientListWaiter stack_waiter(windows, base::size(windows));
stack_waiter.Wait();
ui::X11EventSource::GetInstance()->DispatchXEvents();
- EXPECT_NE(xid1, FindTopmostXWindowAt(105, 105));
+ EXPECT_NE(window1, FindTopmostXWindowAt(105, 105));
}
// Test that setting a Null shape removes the shape.
@@ -338,7 +353,8 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangularNullShape) {
std::unique_ptr<Widget> widget1(
CreateAndShowWidget(gfx::Rect(100, 100, 100, 100)));
- XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
+ x11::Window window1 =
+ widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
auto shape1 = std::make_unique<Widget::ShapeRects>();
shape1->emplace_back();
widget1->SetShape(std::move(shape1));
@@ -346,47 +362,48 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangularNullShape) {
// Remove the shape - this is now just a normal window.
widget1->SetShape(nullptr);
- XID xids[] = {xid1};
- StackingClientListWaiter stack_waiter(xids, base::size(xids));
+ x11::Window windows[] = {window1};
+ StackingClientListWaiter stack_waiter(windows, base::size(windows));
stack_waiter.Wait();
ui::X11EventSource::GetInstance()->DispatchXEvents();
- EXPECT_EQ(xid1, FindTopmostXWindowAt(105, 105));
+ EXPECT_EQ(window1, FindTopmostXWindowAt(105, 105));
}
// Test that the TopmostWindowFinder finds windows which belong to menus
// (which may or may not belong to Chrome).
TEST_F(X11TopmostWindowFinderTest, Menu) {
- XID xid = CreateAndShowXWindow(gfx::Rect(100, 100, 100, 100));
+ x11::Window window = CreateAndShowXWindow(gfx::Rect(100, 100, 100, 100));
- XID root = DefaultRootWindow(xdisplay());
+ x11::Window root = ui::GetX11RootWindow();
XSetWindowAttributes swa;
swa.override_redirect = x11::True;
- XID menu_xid = XCreateWindow(xdisplay(), root, 0, 0, 1, 1,
- 0, // border width
- CopyFromParent, // depth
- InputOutput,
- CopyFromParent, // visual
- CWOverrideRedirect, &swa);
+ x11::Window menu_window = static_cast<x11::Window>(XCreateWindow(
+ xdisplay(), static_cast<uint32_t>(root), 0, 0, 1, 1,
+ 0, // border width
+ static_cast<int>(x11::WindowClass::CopyFromParent), // depth
+ static_cast<int>(x11::WindowClass::InputOutput),
+ nullptr, // visual
+ CWOverrideRedirect, &swa));
{
- ui::SetAtomProperty(menu_xid, "_NET_WM_WINDOW_TYPE", "ATOM",
+ ui::SetAtomProperty(menu_window, "_NET_WM_WINDOW_TYPE", "ATOM",
gfx::GetAtom("_NET_WM_WINDOW_TYPE_MENU"));
}
- ui::SetUseOSWindowFrame(menu_xid, false);
- ShowAndSetXWindowBounds(menu_xid, gfx::Rect(140, 110, 100, 100));
+ ui::SetUseOSWindowFrame(menu_window, false);
+ ShowAndSetXWindowBounds(menu_window, gfx::Rect(140, 110, 100, 100));
ui::X11EventSource::GetInstance()->DispatchXEvents();
- // |menu_xid| is never added to _NET_CLIENT_LIST_STACKING.
- XID xids[] = {xid};
- StackingClientListWaiter stack_waiter(xids, base::size(xids));
+ // |menu_window| is never added to _NET_CLIENT_LIST_STACKING.
+ x11::Window windows[] = {window};
+ StackingClientListWaiter stack_waiter(windows, base::size(windows));
stack_waiter.Wait();
- EXPECT_EQ(xid, FindTopmostXWindowAt(110, 110));
- EXPECT_EQ(menu_xid, FindTopmostXWindowAt(150, 120));
- EXPECT_EQ(menu_xid, FindTopmostXWindowAt(210, 120));
+ EXPECT_EQ(window, FindTopmostXWindowAt(110, 110));
+ EXPECT_EQ(menu_window, FindTopmostXWindowAt(150, 120));
+ EXPECT_EQ(menu_window, FindTopmostXWindowAt(210, 120));
- XDestroyWindow(xdisplay(), xid);
- XDestroyWindow(xdisplay(), menu_xid);
+ XDestroyWindow(xdisplay(), static_cast<uint32_t>(window));
+ XDestroyWindow(xdisplay(), static_cast<uint32_t>(menu_window));
}
} // namespace views
diff --git a/chromium/ui/views/widget/native_widget_aura_unittest.cc b/chromium/ui/views/widget/native_widget_aura_unittest.cc
index 4e9ce929364..a0a3fb4a69e 100644
--- a/chromium/ui/views/widget/native_widget_aura_unittest.cc
+++ b/chromium/ui/views/widget/native_widget_aura_unittest.cc
@@ -318,14 +318,13 @@ class PropertyTestLayoutManager : public TestLayoutManagerBase {
class PropertyTestWidgetDelegate : public WidgetDelegate {
public:
- explicit PropertyTestWidgetDelegate(Widget* widget) : widget_(widget) {}
+ explicit PropertyTestWidgetDelegate(Widget* widget) : widget_(widget) {
+ SetHasWindowSizeControls(true);
+ }
~PropertyTestWidgetDelegate() override = default;
private:
// WidgetDelegate:
- bool CanMaximize() const override { return true; }
- bool CanMinimize() const override { return true; }
- bool CanResize() const override { return true; }
void DeleteDelegate() override { delete this; }
Widget* GetWidget() override { return widget_; }
const Widget* GetWidget() const override { return widget_; }
@@ -399,18 +398,18 @@ class GestureTrackingView : public View {
TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) {
// Create two views (both sized the same). |child| is configured not to
// consume the gesture event.
- GestureTrackingView* view = new GestureTrackingView();
+ auto content_view = std::make_unique<GestureTrackingView>();
GestureTrackingView* child = new GestureTrackingView();
child->set_consume_gesture_event(false);
- view->SetLayoutManager(std::make_unique<FillLayout>());
- view->AddChildView(child);
+ content_view->SetLayoutManager(std::make_unique<FillLayout>());
+ content_view->AddChildView(child);
std::unique_ptr<TestWidget> widget(new TestWidget());
Widget::InitParams params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.context = root_window();
params.bounds = gfx::Rect(0, 0, 100, 200);
widget->Init(std::move(params));
- widget->SetContentsView(view);
+ GestureTrackingView* view = widget->SetContentsView(std::move(content_view));
widget->Show();
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(41, 51),
@@ -441,13 +440,12 @@ TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) {
// Verifies views with layers are targeted for events properly.
TEST_F(NativeWidgetAuraTest, PreferViewLayersToChildWindows) {
// Create two widgets: |parent| and |child|. |child| is a child of |parent|.
- View* parent_root = new View;
std::unique_ptr<Widget> parent(new Widget());
Widget::InitParams parent_params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
parent_params.context = root_window();
parent->Init(std::move(parent_params));
- parent->SetContentsView(parent_root);
+ View* parent_root = parent->SetContentsView(std::make_unique<View>());
parent->SetBounds(gfx::Rect(0, 0, 400, 400));
parent->Show();
@@ -499,13 +497,12 @@ TEST_F(NativeWidgetAuraTest, PreferViewLayersToChildWindows) {
TEST_F(NativeWidgetAuraTest,
ShouldDescendIntoChildForEventHandlingChecksVisibleBounds) {
// Create two widgets: |parent| and |child|. |child| is a child of |parent|.
- View* parent_root_view = new View;
Widget parent;
Widget::InitParams parent_params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
parent_params.context = root_window();
parent.Init(std::move(parent_params));
- parent.SetContentsView(parent_root_view);
+ View* parent_root_view = parent.SetContentsView(std::make_unique<View>());
parent.SetBounds(gfx::Rect(0, 0, 400, 400));
parent.Show();
diff --git a/chromium/ui/views/widget/root_view_unittest.cc b/chromium/ui/views/widget/root_view_unittest.cc
index a0640142341..6994e4864bf 100644
--- a/chromium/ui/views/widget/root_view_unittest.cc
+++ b/chromium/ui/views/widget/root_view_unittest.cc
@@ -56,8 +56,7 @@ TEST_F(RootViewTest, DeleteViewDuringKeyEventDispatch) {
bool got_key_event = false;
- View* content = new View;
- widget.SetContentsView(content);
+ View* content = widget.SetContentsView(std::make_unique<View>());
View* child = new DeleteOnKeyEventView(&got_key_event);
content->AddChildView(child);
@@ -413,8 +412,7 @@ TEST_F(RootViewTest, DeleteViewOnMouseExitDispatch) {
widget.Init(std::move(init_params));
widget.SetBounds(gfx::Rect(10, 10, 500, 500));
- View* content = new View;
- widget.SetContentsView(content);
+ View* content = widget.SetContentsView(std::make_unique<View>());
bool view_destroyed = false;
View* child = new DeleteViewOnEvent(ui::ET_MOUSE_EXITED, &view_destroyed);
@@ -450,8 +448,7 @@ TEST_F(RootViewTest, DeleteViewOnMouseEnterDispatch) {
widget.Init(std::move(init_params));
widget.SetBounds(gfx::Rect(10, 10, 500, 500));
- View* content = new View;
- widget.SetContentsView(content);
+ View* content = widget.SetContentsView(std::make_unique<View>());
bool view_destroyed = false;
View* child = new DeleteViewOnEvent(ui::ET_MOUSE_ENTERED, &view_destroyed);
@@ -489,8 +486,7 @@ TEST_F(RootViewTest, RemoveViewOnMouseEnterDispatch) {
widget.Init(std::move(init_params));
widget.SetBounds(gfx::Rect(10, 10, 500, 500));
- View* content = new View;
- widget.SetContentsView(content);
+ View* content = widget.SetContentsView(std::make_unique<View>());
// |child| gets removed without being deleted, so make it a local
// to prevent test memory leak.
@@ -529,8 +525,7 @@ TEST_F(RootViewTest, ClearMouseMoveHandlerOnMouseExitDispatch) {
widget.Init(std::move(init_params));
widget.SetBounds(gfx::Rect(10, 10, 500, 500));
- View* content = new View;
- widget.SetContentsView(content);
+ View* content = widget.SetContentsView(std::make_unique<View>());
View* root_view = widget.GetRootView();
@@ -565,8 +560,7 @@ TEST_F(RootViewTest,
widget.Init(std::move(init_params));
widget.SetBounds(gfx::Rect(10, 10, 500, 500));
- View* content = new View;
- widget.SetContentsView(content);
+ View* content = widget.SetContentsView(std::make_unique<View>());
View* root_view = widget.GetRootView();
@@ -603,8 +597,7 @@ TEST_F(RootViewTest, ClearMouseMoveHandlerOnMouseEnterDispatch) {
widget.Init(std::move(init_params));
widget.SetBounds(gfx::Rect(10, 10, 500, 500));
- View* content = new View;
- widget.SetContentsView(content);
+ View* content = widget.SetContentsView(std::make_unique<View>());
View* root_view = widget.GetRootView();
@@ -657,10 +650,10 @@ TEST_F(RootViewTest, DeleteWidgetOnMouseExitDispatch) {
widget->SetBounds(gfx::Rect(10, 10, 500, 500));
WidgetDeletionObserver widget_deletion_observer(widget);
- View* content = new View();
+ auto content = std::make_unique<View>();
View* child = new DeleteWidgetOnMouseExit(widget);
content->AddChildView(child);
- widget->SetContentsView(content);
+ widget->SetContentsView(std::move(content));
// Make |child| smaller than the containing Widget and RootView.
child->SetBounds(100, 100, 100, 100);
@@ -693,10 +686,9 @@ TEST_F(RootViewTest, DeleteWidgetOnMouseExitDispatchFromChild) {
widget->SetBounds(gfx::Rect(10, 10, 500, 500));
WidgetDeletionObserver widget_deletion_observer(widget);
- View* content = new View();
View* child = new DeleteWidgetOnMouseExit(widget);
View* subchild = new View();
- widget->SetContentsView(content);
+ View* content = widget->SetContentsView(std::make_unique<View>());
content->AddChildView(child);
child->AddChildView(subchild);
diff --git a/chromium/ui/views/widget/unique_widget_ptr.cc b/chromium/ui/views/widget/unique_widget_ptr.cc
new file mode 100644
index 00000000000..558c9f35b23
--- /dev/null
+++ b/chromium/ui/views/widget/unique_widget_ptr.cc
@@ -0,0 +1,97 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/unique_widget_ptr.h"
+
+#include <utility>
+
+#include "base/scoped_observer.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_observer.h"
+
+namespace views {
+
+namespace {
+
+struct WidgetAutoCloser {
+ void operator()(Widget* widget) {
+ widget->CloseWithReason(Widget::ClosedReason::kUnspecified);
+ }
+};
+
+using WidgetAutoClosePtr = std::unique_ptr<Widget, WidgetAutoCloser>;
+
+} // namespace
+
+class UniqueWidgetPtr::UniqueWidgetPtrImpl : public WidgetObserver {
+ public:
+ UniqueWidgetPtrImpl() = default;
+ // Deliberately implicit
+ // NOLINTNEXTLINE(runtime/explicit)
+ UniqueWidgetPtrImpl(std::unique_ptr<Widget> widget)
+ : widget_closer_(widget.release()) {
+ widget_observer_.Add(widget_closer_.get());
+ }
+
+ UniqueWidgetPtrImpl(const UniqueWidgetPtrImpl&) = delete;
+
+ UniqueWidgetPtrImpl& operator=(const UniqueWidgetPtrImpl&) = delete;
+
+ ~UniqueWidgetPtrImpl() override = default;
+
+ Widget* Get() const { return widget_closer_.get(); }
+
+ void Reset() {
+ if (!widget_closer_)
+ return;
+ widget_observer_.RemoveAll();
+ widget_closer_.reset();
+ }
+
+ // WidgetObserver overrides.
+ void OnWidgetDestroying(Widget* widget) override {
+ DCHECK_EQ(widget, widget_closer_.get());
+ widget_observer_.RemoveAll();
+ widget_closer_.release();
+ }
+
+ private:
+ ScopedObserver<Widget, WidgetObserver> widget_observer_{this};
+ WidgetAutoClosePtr widget_closer_;
+};
+
+UniqueWidgetPtr::UniqueWidgetPtr() = default;
+
+UniqueWidgetPtr::UniqueWidgetPtr(std::unique_ptr<Widget> widget)
+ : unique_widget_ptr_impl_(
+ std::make_unique<UniqueWidgetPtrImpl>(std::move(widget))) {}
+
+UniqueWidgetPtr::UniqueWidgetPtr(UniqueWidgetPtr&& other) = default;
+
+UniqueWidgetPtr& UniqueWidgetPtr::operator=(UniqueWidgetPtr&& other) = default;
+
+UniqueWidgetPtr::~UniqueWidgetPtr() = default;
+
+UniqueWidgetPtr::operator bool() const {
+ return !!get();
+}
+
+Widget& UniqueWidgetPtr::operator*() const {
+ return *get();
+}
+
+Widget* UniqueWidgetPtr::operator->() const {
+ return get();
+}
+
+void UniqueWidgetPtr::reset() {
+ unique_widget_ptr_impl_.reset();
+}
+
+Widget* UniqueWidgetPtr::get() const {
+ return unique_widget_ptr_impl_ ? unique_widget_ptr_impl_->Get() : nullptr;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/unique_widget_ptr.h b/chromium/ui/views/widget/unique_widget_ptr.h
new file mode 100644
index 00000000000..f493c367a73
--- /dev/null
+++ b/chromium/ui/views/widget/unique_widget_ptr.h
@@ -0,0 +1,43 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_UNIQUE_WIDGET_PTR_H_
+#define UI_VIEWS_WIDGET_UNIQUE_WIDGET_PTR_H_
+
+#include <memory>
+
+#include "ui/views/views_export.h"
+
+namespace views {
+
+class Widget;
+
+// Ensures the Widget is properly closed when this special
+// auto pointer goes out of scope.
+
+class VIEWS_EXPORT UniqueWidgetPtr {
+ public:
+ UniqueWidgetPtr();
+ // Deliberately implicit since it's supposed to resemble a std::unique_ptr.
+ // NOLINTNEXTLINE(runtime/explicit)
+ UniqueWidgetPtr(std::unique_ptr<Widget> widget);
+ UniqueWidgetPtr(UniqueWidgetPtr&&);
+ UniqueWidgetPtr& operator=(UniqueWidgetPtr&&);
+ ~UniqueWidgetPtr();
+
+ explicit operator bool() const;
+ Widget& operator*() const;
+ Widget* operator->() const;
+ void reset();
+ Widget* get() const;
+
+ private:
+ class UniqueWidgetPtrImpl;
+
+ std::unique_ptr<UniqueWidgetPtrImpl> unique_widget_ptr_impl_;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_UNIQUE_WIDGET_PTR_H_
diff --git a/chromium/ui/views/widget/unique_widget_ptr_unittest.cc b/chromium/ui/views/widget/unique_widget_ptr_unittest.cc
new file mode 100644
index 00000000000..df8804ab1f9
--- /dev/null
+++ b/chromium/ui/views/widget/unique_widget_ptr_unittest.cc
@@ -0,0 +1,133 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/unique_widget_ptr.h"
+
+#include <memory>
+
+#include "base/scoped_observer.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_observer.h"
+
+namespace views {
+
+class UniqueWidgetPtrTest : public ViewsTestBase, public WidgetObserver {
+ public:
+ UniqueWidgetPtrTest() = default;
+ ~UniqueWidgetPtrTest() override = default;
+
+ // ViewsTestBase overrides.
+ void TearDown() override {
+ ViewsTestBase::TearDown();
+ ASSERT_EQ(widget_, nullptr);
+ }
+
+ protected:
+ std::unique_ptr<Widget> AllocateTestWidget() override {
+ auto widget = ViewsTestBase::AllocateTestWidget();
+ widget->Init(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
+ widget_observer_.Add(widget.get());
+ return widget;
+ }
+
+ UniqueWidgetPtr CreateUniqueWidgetPtr() {
+ auto widget = UniqueWidgetPtr(AllocateTestWidget());
+ widget->SetContentsView(std::make_unique<View>());
+ widget_ = widget.get();
+ return widget;
+ }
+
+ Widget* widget() { return widget_; }
+
+ // WidgetObserver overrides.
+ void OnWidgetDestroying(Widget* widget) override {
+ ASSERT_NE(widget_, nullptr);
+ ASSERT_EQ(widget_, widget);
+ widget_observer_.Remove(widget_);
+ widget_ = nullptr;
+ }
+
+ private:
+ Widget* widget_ = nullptr;
+ ScopedObserver<Widget, WidgetObserver> widget_observer_{this};
+};
+
+// Make sure explicitly resetting the |unique_widget_ptr| variable properly
+// closes the widget. TearDown() will ensure |widget_| has been cleared.
+TEST_F(UniqueWidgetPtrTest, TestCloseContent) {
+ UniqueWidgetPtr unique_widget_ptr = CreateUniqueWidgetPtr();
+ EXPECT_EQ(unique_widget_ptr->GetContentsView(), widget()->GetContentsView());
+ unique_widget_ptr.reset();
+}
+
+// Same as above, only testing that going out of scope will accomplish the same
+// thing.
+TEST_F(UniqueWidgetPtrTest, TestScopeDestruct) {
+ UniqueWidgetPtr unique_widget_ptr = CreateUniqueWidgetPtr();
+ EXPECT_EQ(unique_widget_ptr->GetContentsView(), widget()->GetContentsView());
+ // Just go out of scope to close the view;
+}
+
+// Check that proper move semantics for assignments work.
+TEST_F(UniqueWidgetPtrTest, TestMoveAssign) {
+ UniqueWidgetPtr unique_widget_ptr2 = CreateUniqueWidgetPtr();
+ {
+ UniqueWidgetPtr unique_widget_ptr;
+ EXPECT_EQ(unique_widget_ptr2->GetContentsView(),
+ widget()->GetContentsView());
+ unique_widget_ptr = std::move(unique_widget_ptr2);
+ EXPECT_EQ(unique_widget_ptr->GetContentsView(),
+ widget()->GetContentsView());
+ EXPECT_FALSE(unique_widget_ptr2);
+ unique_widget_ptr.reset();
+ EXPECT_FALSE(unique_widget_ptr);
+ }
+ RunPendingMessages();
+ EXPECT_EQ(widget(), nullptr);
+}
+
+// Check that move construction functions correctly.
+TEST_F(UniqueWidgetPtrTest, TestMoveConstruct) {
+ UniqueWidgetPtr unique_widget_ptr2 = CreateUniqueWidgetPtr();
+ {
+ EXPECT_EQ(unique_widget_ptr2->GetContentsView(),
+ widget()->GetContentsView());
+ UniqueWidgetPtr unique_widget_ptr = std::move(unique_widget_ptr2);
+ EXPECT_EQ(unique_widget_ptr->GetContentsView(),
+ widget()->GetContentsView());
+ EXPECT_FALSE(unique_widget_ptr2);
+ unique_widget_ptr.reset();
+ EXPECT_FALSE(unique_widget_ptr);
+ }
+ RunPendingMessages();
+ EXPECT_EQ(widget(), nullptr);
+}
+
+// Make sure that any external closing of the widget is properly tracked in the
+// |unique_widget_ptr|.
+TEST_F(UniqueWidgetPtrTest, TestCloseWidget) {
+ UniqueWidgetPtr unique_widget_ptr = CreateUniqueWidgetPtr();
+ EXPECT_EQ(unique_widget_ptr->GetContentsView(), widget()->GetContentsView());
+ // Initiate widget destruction.
+ widget()->CloseWithReason(Widget::ClosedReason::kUnspecified);
+ // Cycle the run loop to allow the deferred destruction to happen.
+ RunPendingMessages();
+ // The UniqueWidgetPtr should have dropped its reference to the content view.
+ EXPECT_FALSE(unique_widget_ptr);
+}
+
+// When the NativeWidget is destroyed, ensure that the Widget is also destroyed
+// which in turn clears the |unique_widget_ptr|.
+TEST_F(UniqueWidgetPtrTest, TestCloseNativeWidget) {
+ UniqueWidgetPtr unique_widget_ptr = CreateUniqueWidgetPtr();
+ EXPECT_EQ(unique_widget_ptr->GetContentsView(), widget()->GetContentsView());
+ // Initiate an OS level native widget destruction.
+ SimulateNativeDestroy(widget());
+ // The UniqueWidgetPtr should have dropped its reference to the content view.
+ EXPECT_FALSE(unique_widget_ptr);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/widget.cc b/chromium/ui/views/widget/widget.cc
index ecd7be9185f..a06ebe82c33 100644
--- a/chromium/ui/views/widget/widget.cc
+++ b/chromium/ui/views/widget/widget.cc
@@ -93,7 +93,7 @@ bool Widget::g_disable_activation_change_handling_ = false;
// WidgetDelegate is supplied.
class DefaultWidgetDelegate : public WidgetDelegate {
public:
- explicit DefaultWidgetDelegate(Widget* widget) : widget_(widget) {
+ DefaultWidgetDelegate() {
// In most situations where a Widget is used without a delegate the Widget
// is used as a container, so that we want focus to advance to the top-level
// widget. A good example of this is the find bar.
@@ -103,12 +103,8 @@ class DefaultWidgetDelegate : public WidgetDelegate {
// WidgetDelegate:
void DeleteDelegate() override { delete this; }
- Widget* GetWidget() override { return widget_; }
- const Widget* GetWidget() const override { return widget_; }
private:
- Widget* widget_;
-
DISALLOW_COPY_AND_ASSIGN(DefaultWidgetDelegate);
};
@@ -179,6 +175,8 @@ Widget::Widget(InitParams params) {
}
Widget::~Widget() {
+ if (widget_delegate_)
+ widget_delegate_->WidgetDestroying();
DestroyRootView();
if (ownership_ == InitParams::WIDGET_OWNS_NATIVE_WIDGET) {
delete native_widget_;
@@ -298,8 +296,7 @@ void Widget::Init(InitParams params) {
// ViewsDelegate::OnBeforeWidgetInit() may change `params.delegate` either
// by setting it to null or assigning a different value to it, so handle
// both cases.
- auto default_widget_delegate =
- std::make_unique<DefaultWidgetDelegate>(this);
+ auto default_widget_delegate = std::make_unique<DefaultWidgetDelegate>();
widget_delegate_ =
params.delegate ? params.delegate : default_widget_delegate.get();
@@ -322,6 +319,9 @@ void Widget::Init(InitParams params) {
// Henceforth, ensure the delegate outlives the Widget.
widget_delegate_->can_delete_this_ = false;
+ if (params.delegate)
+ params.delegate->WidgetInitializing(this);
+
ownership_ = params.ownership;
native_widget_ = CreateNativeWidget(params, this)->AsNativeWidgetPrivate();
root_view_.reset(CreateRootView());
@@ -377,7 +377,7 @@ void Widget::Init(InitParams params) {
native_widget_->OnWidgetInitDone();
if (delegate)
- delegate->OnWidgetInitialized();
+ delegate->WidgetInitialized();
internal::AnyWidgetObserverSingleton::GetInstance()->OnAnyWidgetInitialized(
this);
@@ -1162,6 +1162,8 @@ gfx::Size Widget::GetMaximumSize() const {
}
void Widget::OnNativeWidgetMove() {
+ TRACE_EVENT0("ui", "Widget::OnNativeWidgetMove");
+
widget_delegate_->OnWidgetMove();
NotifyCaretBoundsChanged(GetInputMethod());
@@ -1170,6 +1172,8 @@ void Widget::OnNativeWidgetMove() {
}
void Widget::OnNativeWidgetSizeChanged(const gfx::Size& new_size) {
+ TRACE_EVENT0("ui", "Widget::OnNativeWidgetSizeChanged");
+
View* root = GetRootView();
if (root)
root->SetSize(new_size);
@@ -1229,6 +1233,8 @@ void Widget::OnKeyEvent(ui::KeyEvent* event) {
// RootView from anywhere in Widget. Use
// SendEventToSink() instead. See crbug.com/348087.
void Widget::OnMouseEvent(ui::MouseEvent* event) {
+ TRACE_EVENT0("ui", "Widget::OnMouseEvent");
+
View* root_view = GetRootView();
switch (event->type()) {
case ui::ET_MOUSE_PRESSED: {
@@ -1472,6 +1478,8 @@ View* Widget::GetFocusTraversableParentView() {
// Widget, ui::NativeThemeObserver implementation:
void Widget::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) {
+ TRACE_EVENT0("ui", "Widget::OnNativeThemeUpdated");
+
DCHECK(observer_manager_.IsObserving(observed_theme));
#if defined(OS_MACOSX) || defined(OS_WIN)
diff --git a/chromium/ui/views/widget/widget_delegate.cc b/chromium/ui/views/widget/widget_delegate.cc
index 4ba80f860b3..6916ad1c393 100644
--- a/chromium/ui/views/widget/widget_delegate.cc
+++ b/chromium/ui/views/widget/widget_delegate.cc
@@ -7,6 +7,7 @@
#include "base/check.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/image/image_skia.h"
@@ -46,7 +47,7 @@ View* WidgetDelegate::GetInitiallyFocusedView() {
return nullptr;
}
-BubbleDialogDelegateView* WidgetDelegate::AsBubbleDialogDelegate() {
+BubbleDialogDelegate* WidgetDelegate::AsBubbleDialogDelegate() {
return nullptr;
}
@@ -75,11 +76,12 @@ ui::ModalType WidgetDelegate::GetModalType() const {
}
ax::mojom::Role WidgetDelegate::GetAccessibleWindowRole() {
- return ax::mojom::Role::kWindow;
+ return params_.accessible_role;
}
base::string16 WidgetDelegate::GetAccessibleWindowTitle() const {
- return GetWindowTitle();
+ return params_.accessible_title.empty() ? GetWindowTitle()
+ : params_.accessible_title;
}
base::string16 WidgetDelegate::GetWindowTitle() const {
@@ -152,6 +154,19 @@ bool WidgetDelegate::ShouldRestoreWindowSize() const {
return true;
}
+void WidgetDelegate::WidgetInitializing(Widget* widget) {
+ widget_ = widget;
+ OnWidgetInitializing();
+}
+
+void WidgetDelegate::WidgetInitialized() {
+ OnWidgetInitialized();
+}
+
+void WidgetDelegate::WidgetDestroying() {
+ widget_ = nullptr;
+}
+
void WidgetDelegate::WindowWillClose() {
// TODO(ellyjones): For this and the other callback methods, establish whether
// any other code calls these methods. If not, DCHECK here and below that
@@ -170,6 +185,14 @@ void WidgetDelegate::DeleteDelegate() {
std::move(callback).Run();
}
+Widget* WidgetDelegate::GetWidget() {
+ return widget_;
+}
+
+const Widget* WidgetDelegate::GetWidget() const {
+ return widget_;
+}
+
View* WidgetDelegate::GetContentsView() {
if (!default_contents_view_)
default_contents_view_ = new View;
@@ -206,6 +229,14 @@ bool WidgetDelegate::ShouldDescendIntoChildForEventHandling(
return true;
}
+void WidgetDelegate::SetAccessibleRole(ax::mojom::Role role) {
+ params_.accessible_role = role;
+}
+
+void WidgetDelegate::SetAccessibleTitle(base::string16 title) {
+ params_.accessible_title = std::move(title);
+}
+
void WidgetDelegate::SetCanMaximize(bool can_maximize) {
params_.can_maximize = can_maximize;
}
@@ -246,12 +277,22 @@ void WidgetDelegate::SetTitle(const base::string16& title) {
GetWidget()->UpdateWindowTitle();
}
+void WidgetDelegate::SetTitle(int title_message_id) {
+ SetTitle(l10n_util::GetStringUTF16(title_message_id));
+}
+
#if defined(USE_AURA)
void WidgetDelegate::SetCenterTitle(bool center_title) {
params_.center_title = center_title;
}
#endif
+void WidgetDelegate::SetHasWindowSizeControls(bool has_controls) {
+ SetCanMaximize(has_controls);
+ SetCanMinimize(has_controls);
+ SetCanResize(has_controls);
+}
+
void WidgetDelegate::RegisterWindowWillCloseCallback(
base::OnceClosure callback) {
window_will_close_callbacks_.emplace_back(std::move(callback));
diff --git a/chromium/ui/views/widget/widget_delegate.h b/chromium/ui/views/widget/widget_delegate.h
index 23396ad8c3a..6b4ef19ee72 100644
--- a/chromium/ui/views/widget/widget_delegate.h
+++ b/chromium/ui/views/widget/widget_delegate.h
@@ -9,7 +9,7 @@
#include <vector>
#include "base/macros.h"
-#include "ui/accessibility/ax_enums.mojom-forward.h"
+#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/base/ui_base_types.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
@@ -20,7 +20,7 @@ class Rect;
} // namespace gfx
namespace views {
-class BubbleDialogDelegateView;
+class BubbleDialogDelegate;
class ClientView;
class DialogDelegate;
class NonClientFrameView;
@@ -33,6 +33,17 @@ class VIEWS_EXPORT WidgetDelegate {
Params();
~Params();
+ // The window's role. Useful values include kWindow (a plain window),
+ // kDialog (a dialog), and kAlertDialog (a high-priority dialog whose body
+ // is read when it appears). Using a role outside this set is not likely to
+ // work across platforms.
+ ax::mojom::Role accessible_role = ax::mojom::Role::kWindow;
+
+ // The accessible title for the window, often more descriptive than the
+ // plain title. If no accessible title is present the result of
+ // GetWindowTitle() will be used.
+ base::string16 accessible_title;
+
// Whether the window should display controls for the user to minimize,
// maximize, or resize it.
bool can_maximize = false;
@@ -68,6 +79,7 @@ class VIEWS_EXPORT WidgetDelegate {
};
WidgetDelegate();
+ virtual ~WidgetDelegate();
// Sets the return value of CanActivate(). Default is true.
void SetCanActivate(bool can_activate);
@@ -82,6 +94,10 @@ class VIEWS_EXPORT WidgetDelegate {
// menu bars, etc.) changes in size.
virtual void OnWorkAreaChanged();
+ // Called when the widget's initialization is beginning, right after the
+ // ViewsDelegate decides to use this WidgetDelegate for a Widget.
+ virtual void OnWidgetInitializing() {}
+
// Called when the widget's initialization is complete.
virtual void OnWidgetInitialized() {}
@@ -98,7 +114,7 @@ class VIEWS_EXPORT WidgetDelegate {
// NULL no view is focused.
virtual View* GetInitiallyFocusedView();
- virtual BubbleDialogDelegateView* AsBubbleDialogDelegate();
+ virtual BubbleDialogDelegate* AsBubbleDialogDelegate();
virtual DialogDelegate* AsDialogDelegate();
// Returns true if the window can be resized.
@@ -193,10 +209,28 @@ class VIEWS_EXPORT WidgetDelegate {
virtual void OnWindowEndUserBoundsChange() {}
// Returns the Widget associated with this delegate.
- virtual Widget* GetWidget() = 0;
- virtual const Widget* GetWidget() const = 0;
+ virtual Widget* GetWidget();
+ virtual const Widget* GetWidget() const;
- // Returns the View that is contained within this Widget.
+ // Get the view that is contained within this widget.
+ //
+ // WARNING: This method has unusual ownership behavior:
+ // * If the returned view is owned_by_client(), then the returned pointer is
+ // never an owning pointer;
+ // * If the returned view is !owned_by_client() (the default & the
+ // recommendation), then the returned pointer is *sometimes* an owning
+ // pointer and sometimes not. Specifically, it is an owning pointer exactly
+ // once, when this method is being used to construct the ClientView, which
+ // takes ownership of the ContentsView() when !owned_by_client().
+ //
+ // Apart from being difficult to reason about this introduces a problem: a
+ // WidgetDelegate can't know whether it owns its contents view or not, so
+ // constructing a WidgetDelegate which one does not then use to construct a
+ // Widget (often done in tests) leaks memory in a way that can't be locally
+ // fixed.
+ //
+ // TODO(ellyjones): This is not tenable - figure out how this should work and
+ // replace it.
virtual View* GetContentsView();
// Called by the Widget to create the Client View used to host the contents
@@ -237,6 +271,8 @@ class VIEWS_EXPORT WidgetDelegate {
// Setters for data parameters of the WidgetDelegate. If you use these
// setters, there is no need to override the corresponding virtual getters.
+ void SetAccessibleRole(ax::mojom::Role role);
+ void SetAccessibleTitle(base::string16 title);
void SetCanMaximize(bool can_maximize);
void SetCanMinimize(bool can_minimize);
void SetCanResize(bool can_resize);
@@ -246,16 +282,24 @@ class VIEWS_EXPORT WidgetDelegate {
void SetShowIcon(bool show_icon);
void SetShowTitle(bool show_title);
void SetTitle(const base::string16& title);
+ void SetTitle(int title_message_id);
#if defined(USE_AURA)
void SetCenterTitle(bool center_title);
#endif
+ // A convenience wrapper that does all three of SetCanMaximize,
+ // SetCanMinimize, and SetCanResize.
+ void SetHasWindowSizeControls(bool has_controls);
+
void RegisterWindowWillCloseCallback(base::OnceClosure callback);
void RegisterWindowClosingCallback(base::OnceClosure callback);
void RegisterDeleteDelegateCallback(base::OnceClosure callback);
- // Call this to notify the WidgetDelegate that its Widget is about to start
- // closing.
+ // Called to notify the WidgetDelegate of changes to the state of its Widget.
+ // It is not usually necessary to call these from client code.
+ void WidgetInitializing(Widget* widget);
+ void WidgetInitialized();
+ void WidgetDestroying();
void WindowWillClose();
// Returns true if the title text should be centered.
@@ -263,12 +307,12 @@ class VIEWS_EXPORT WidgetDelegate {
bool focus_traverses_out() const { return params_.focus_traverses_out; }
- protected:
- virtual ~WidgetDelegate();
-
private:
friend class Widget;
+ // The Widget that was initialized with this instance as its WidgetDelegate,
+ // if any.
+ Widget* widget_ = nullptr;
Params params_;
View* default_contents_view_ = nullptr;
@@ -299,7 +343,7 @@ class VIEWS_EXPORT WidgetDelegateView : public WidgetDelegate, public View {
void DeleteDelegate() override;
Widget* GetWidget() override;
const Widget* GetWidget() const override;
- views::View* GetContentsView() override;
+ View* GetContentsView() override;
private:
DISALLOW_COPY_AND_ASSIGN(WidgetDelegateView);
diff --git a/chromium/ui/views/widget/widget_deletion_observer.cc b/chromium/ui/views/widget/widget_deletion_observer.cc
index 15df9c391ce..3e64f1613b6 100644
--- a/chromium/ui/views/widget/widget_deletion_observer.cc
+++ b/chromium/ui/views/widget/widget_deletion_observer.cc
@@ -16,6 +16,7 @@ WidgetDeletionObserver::WidgetDeletionObserver(Widget* widget)
WidgetDeletionObserver::~WidgetDeletionObserver() {
CleanupWidget();
+ CHECK(!IsInObserverList());
}
void WidgetDeletionObserver::OnWidgetDestroying(Widget* widget) {
diff --git a/chromium/ui/views/widget/widget_hwnd_utils.cc b/chromium/ui/views/widget/widget_hwnd_utils.cc
index 40e66a212e3..89f5b62f95d 100644
--- a/chromium/ui/views/widget/widget_hwnd_utils.cc
+++ b/chromium/ui/views/widget/widget_hwnd_utils.cc
@@ -118,6 +118,8 @@ void CalculateWindowStylesFromInitParams(
else
*style |= WS_BORDER;
}
+ if (!params.force_show_in_taskbar)
+ *ex_style |= WS_EX_TOOLWINDOW;
break;
case Widget::InitParams::TYPE_TOOLTIP:
*style |= WS_POPUP;
diff --git a/chromium/ui/views/widget/widget_interactive_uitest.cc b/chromium/ui/views/widget/widget_interactive_uitest.cc
index f4ba5ba6cad..a333ca057ae 100644
--- a/chromium/ui/views/widget/widget_interactive_uitest.cc
+++ b/chromium/ui/views/widget/widget_interactive_uitest.cc
@@ -4,6 +4,7 @@
#include <stddef.h>
+#include <memory>
#include <utility>
#include "base/bind.h"
@@ -603,7 +604,7 @@ TEST_F(WidgetTestInteractive, ChildStackedRelativeToParent) {
// Test view focus retention when a widget's HWND is disabled and re-enabled.
TEST_F(WidgetTestInteractive, ViewFocusOnHWNDEnabledChanges) {
WidgetAutoclosePtr widget(CreateTopLevelFramelessPlatformWidget());
- widget->SetContentsView(new View);
+ widget->SetContentsView(std::make_unique<View>());
for (size_t i = 0; i < 2; ++i) {
auto child = std::make_unique<View>();
child->SetFocusBehavior(View::FocusBehavior::ALWAYS);
@@ -1456,10 +1457,10 @@ TEST_F(WidgetCaptureTest, FailedCaptureRequestIsNoop) {
MouseView* mouse_view1 = new MouseView;
MouseView* mouse_view2 = new MouseView;
- View* contents_view = new View;
+ auto contents_view = std::make_unique<View>();
contents_view->AddChildView(mouse_view1);
contents_view->AddChildView(mouse_view2);
- widget.SetContentsView(contents_view);
+ widget.SetContentsView(std::move(contents_view));
mouse_view1->SetBounds(0, 0, 200, 400);
mouse_view2->SetBounds(200, 0, 200, 400);
@@ -1480,8 +1481,7 @@ TEST_F(WidgetCaptureTest, FailedCaptureRequestIsNoop) {
TEST_F(WidgetCaptureTest, CaptureAutoReset) {
WidgetAutoclosePtr toplevel(CreateTopLevelFramelessPlatformWidget());
- View* container = new View;
- toplevel->SetContentsView(container);
+ toplevel->SetContentsView(std::make_unique<View>());
EXPECT_FALSE(toplevel->HasCapture());
toplevel->SetCapture(nullptr);
@@ -1507,8 +1507,7 @@ TEST_F(WidgetCaptureTest, CaptureAutoReset) {
TEST_F(WidgetCaptureTest, ResetCaptureOnGestureEnd) {
WidgetAutoclosePtr toplevel(CreateTopLevelFramelessPlatformWidget());
- View* container = new View;
- toplevel->SetContentsView(container);
+ View* container = toplevel->SetContentsView(std::make_unique<View>());
View* gesture = new GestureCaptureView;
gesture->SetBounds(0, 0, 30, 30);
@@ -1570,10 +1569,11 @@ TEST_F(WidgetCaptureTest, DisableCaptureWidgetFromMousePress) {
WidgetAutoclosePtr first(CreateTopLevelFramelessPlatformWidget());
Widget* second = CreateTopLevelFramelessPlatformWidget();
- NestedLoopCaptureView* container = new NestedLoopCaptureView(second);
- first->SetContentsView(container);
+ NestedLoopCaptureView* container =
+ first->SetContentsView(std::make_unique<NestedLoopCaptureView>(second));
- second->SetContentsView(new ExitLoopOnRelease(container->GetQuitClosure()));
+ second->SetContentsView(
+ std::make_unique<ExitLoopOnRelease>(container->GetQuitClosure()));
first->SetSize(gfx::Size(100, 100));
first->Show();
@@ -1597,21 +1597,21 @@ TEST_F(WidgetCaptureTest, DisableCaptureWidgetFromMousePress) {
// time.
TEST_F(WidgetCaptureTest, GrabUngrab) {
auto top_level = CreateTestWidget();
- top_level->SetContentsView(new MouseView());
+ top_level->SetContentsView(std::make_unique<MouseView>());
Widget* child1 = new Widget;
Widget::InitParams params1 = CreateParams(Widget::InitParams::TYPE_CONTROL);
params1.parent = top_level->GetNativeView();
params1.bounds = gfx::Rect(10, 10, 100, 100);
child1->Init(std::move(params1));
- child1->SetContentsView(new MouseView());
+ child1->SetContentsView(std::make_unique<MouseView>());
Widget* child2 = new Widget;
Widget::InitParams params2 = CreateParams(Widget::InitParams::TYPE_CONTROL);
params2.parent = top_level->GetNativeView();
params2.bounds = gfx::Rect(110, 10, 100, 100);
child2->Init(std::move(params2));
- child2->SetContentsView(new MouseView());
+ child2->SetContentsView(std::make_unique<MouseView>());
top_level->Show();
RunPendingMessages();
@@ -1732,8 +1732,8 @@ TEST_F(WidgetCaptureTest, MAYBE_MouseExitOnCaptureGrab) {
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
params1.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget1.Init(std::move(params1));
- MouseView* mouse_view1 = new MouseView;
- widget1.SetContentsView(mouse_view1);
+ MouseView* mouse_view1 =
+ widget1.SetContentsView(std::make_unique<MouseView>());
widget1.Show();
widget1.SetBounds(gfx::Rect(300, 300));
diff --git a/chromium/ui/views/widget/window_reorderer_unittest.cc b/chromium/ui/views/widget/window_reorderer_unittest.cc
index 670cc0f1238..c46fda38a8e 100644
--- a/chromium/ui/views/widget/window_reorderer_unittest.cc
+++ b/chromium/ui/views/widget/window_reorderer_unittest.cc
@@ -59,8 +59,7 @@ TEST_F(WindowReordererTest, Basic) {
parent->Show();
aura::Window* parent_window = parent->GetNativeWindow();
- View* contents_view = new View();
- parent->SetContentsView(contents_view);
+ View* contents_view = parent->SetContentsView(std::make_unique<View>());
// 1) Test that layers for views and layers for windows associated to a host
// view are stacked below the layers for any windows not associated to a host
@@ -130,8 +129,7 @@ TEST_F(WindowReordererTest, Association) {
parent->Show();
aura::Window* parent_window = parent->GetNativeWindow();
- View* contents_view = new View();
- parent->SetContentsView(contents_view);
+ View* contents_view = parent->SetContentsView(std::make_unique<View>());
aura::Window* w1 =
aura::test::CreateTestWindowWithId(0, parent->GetNativeWindow());
@@ -185,8 +183,7 @@ TEST_F(WindowReordererTest, HostViewParentHasLayer) {
parent->Show();
aura::Window* parent_window = parent->GetNativeWindow();
- View* contents_view = new View();
- parent->SetContentsView(contents_view);
+ View* contents_view = parent->SetContentsView(std::make_unique<View>());
// Create the following view hierarchy. (*) denotes views which paint to a
// layer.
@@ -251,8 +248,7 @@ TEST_F(WindowReordererTest, ViewWithLayerBeneath) {
aura::Window* parent_window = parent->GetNativeWindow();
- View* contents_view = new View;
- parent->SetContentsView(contents_view);
+ View* contents_view = parent->SetContentsView(std::make_unique<View>());
View* view_with_layer_beneath =
contents_view->AddChildView(std::make_unique<View>());