diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-16 11:45:35 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-17 08:59:23 +0000 |
commit | 552906b0f222c5d5dd11b9fd73829d510980461a (patch) | |
tree | 3a11e6ed0538a81dd83b20cf3a4783e297f26d91 /chromium/ui/views/widget | |
parent | 1b05827804eaf047779b597718c03e7d38344261 (diff) | |
download | qtwebengine-chromium-552906b0f222c5d5dd11b9fd73829d510980461a.tar.gz |
BASELINE: Update Chromium to 83.0.4103.122
Change-Id: Ie3a82f5bb0076eec2a7c6a6162326b4301ee291e
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/ui/views/widget')
77 files changed, 2276 insertions, 3067 deletions
diff --git a/chromium/ui/views/widget/any_widget_observer.cc b/chromium/ui/views/widget/any_widget_observer.cc new file mode 100644 index 00000000000..b0b1860cad2 --- /dev/null +++ b/chromium/ui/views/widget/any_widget_observer.cc @@ -0,0 +1,70 @@ +// 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/any_widget_observer.h" +#include "base/bind.h" +#include "ui/views/widget/any_widget_observer_singleton.h" +#include "ui/views/widget/widget.h" + +namespace views { + +AnyWidgetObserver::AnyWidgetObserver(AnyWidgetPasskey passkey) + : AnyWidgetObserver() {} +AnyWidgetObserver::AnyWidgetObserver(test::AnyWidgetTestPasskey passkey) + : AnyWidgetObserver() {} + +AnyWidgetObserver::AnyWidgetObserver() { + internal::AnyWidgetObserverSingleton::GetInstance()->AddObserver(this); +} + +AnyWidgetObserver::~AnyWidgetObserver() { + internal::AnyWidgetObserverSingleton::GetInstance()->RemoveObserver(this); +} + +#define PROPAGATE_NOTIFICATION(method, callback) \ + void AnyWidgetObserver::method(Widget* widget) { \ + if (callback) \ + callback.Run(widget); \ + } + +PROPAGATE_NOTIFICATION(OnAnyWidgetInitialized, initialized_callback_) +PROPAGATE_NOTIFICATION(OnAnyWidgetShown, shown_callback_) +PROPAGATE_NOTIFICATION(OnAnyWidgetHidden, hidden_callback_) +PROPAGATE_NOTIFICATION(OnAnyWidgetClosing, closing_callback_) + +#undef PROPAGATE_NOTIFICATION + +NamedWidgetShownWaiter::NamedWidgetShownWaiter(AnyWidgetPasskey passkey, + const std::string& name) + : NamedWidgetShownWaiter(name) {} + +NamedWidgetShownWaiter::NamedWidgetShownWaiter( + test::AnyWidgetTestPasskey passkey, + const std::string& name) + : NamedWidgetShownWaiter(name) {} + +NamedWidgetShownWaiter::~NamedWidgetShownWaiter() = default; + +Widget* NamedWidgetShownWaiter::WaitIfNeededAndGet() { + run_loop_.Run(); + DCHECK(widget_); + return widget_; +} + +NamedWidgetShownWaiter::NamedWidgetShownWaiter(const std::string& name) + : observer_(views::AnyWidgetPasskey{}), name_(name) { + observer_.set_shown_callback(base::BindRepeating( + &NamedWidgetShownWaiter::OnAnyWidgetShown, base::Unretained(this))); +} + +void NamedWidgetShownWaiter::OnAnyWidgetShown(Widget* widget) { + if (widget->GetName() == name_) { + widget_ = widget; + run_loop_.Quit(); + } +} + +AnyWidgetPasskey::AnyWidgetPasskey() = default; + +} // namespace views diff --git a/chromium/ui/views/widget/any_widget_observer.h b/chromium/ui/views/widget/any_widget_observer.h new file mode 100644 index 00000000000..be43ee03d38 --- /dev/null +++ b/chromium/ui/views/widget/any_widget_observer.h @@ -0,0 +1,203 @@ +// 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_ANY_WIDGET_OBSERVER_H_ +#define UI_VIEWS_WIDGET_ANY_WIDGET_OBSERVER_H_ + +#include <string> + +#include "base/callback.h" +#include "base/observer_list_types.h" +#include "base/run_loop.h" +#include "ui/views/views_export.h" + +namespace views { + +namespace internal { +class AnyWidgetObserverSingleton; +} + +namespace test { +class AnyWidgetTestPasskey; +} + +class AnyWidgetPasskey; +class Widget; + +// AnyWidgetObserver is used when you want to observe widget changes but don't +// have an easy way to get a reference to the Widget in question, usually +// because it is created behind a layer of abstraction that hides the Widget. +// +// This class should only be used as a last resort - if you find yourself +// reaching for it in production code, it probably means some parts of your +// system aren't coupled enough or your API boundaries are hiding too much. You +// will need review from an owner of this class to add new uses of it, because +// it requires a Passkey to construct it - see //docs/patterns/passkey.md for +// details. Uses in tests can be done freely using +// views::test::AnyWidgetTestPasskey. +// +// This class is useful when doing something like this: +// +// RunLoop run_loop; +// AnyWidgetCallbackObserver observer(views::test::AnyWidgetTestPasskey{}); +// Widget* widget; +// observer.set_initialized_callback( +// base::BindLambdaForTesting([&](Widget* w) { +// if (w->GetName() == "MyWidget") { +// widget = w; +// run_loop.Quit(); +// } +// })); +// ThingThatCreatesWidget(); +// run_loop.Run(); +// +// with your widget getting the name "MyWidget" via InitParams::name. +// +// Note: if you're trying to wait for a named widget to be *shown*, there is an +// ergonomic wrapper for that - see NamedWidgetShownWaiter below. You use it +// like this: +// +// NamedWidgetShownWaiter waiter( +// "MyWidget", views::test::AnyWidgetTestPasskey{}); +// ThingThatCreatesAndShowsWidget(); +// Widget* widget = waiter.WaitIfNeededAndGet(); +// +// TODO(ellyjones): Add Widget::SetDebugName and add a remark about that here. +// +// This allows you to create a test that is robust even if +// ThingThatCreatesAndShowsWidget() later becomes asynchronous, takes a few +// milliseconds, etc. +class VIEWS_EXPORT AnyWidgetObserver : public base::CheckedObserver { + public: + using AnyWidgetCallback = base::RepeatingCallback<void(Widget*)>; + + // Using this in production requires an AnyWidgetPasskey, which can only be + // constructed by a list of allowed friend classes... + explicit AnyWidgetObserver(AnyWidgetPasskey passkey); + + // ... but for tests or debugging, anyone can construct a + // views::test::AnyWidgetTestPasskey. + explicit AnyWidgetObserver(test::AnyWidgetTestPasskey passkey); + + ~AnyWidgetObserver() override; + + AnyWidgetObserver(const AnyWidgetObserver& other) = delete; + AnyWidgetObserver& operator=(const AnyWidgetObserver& other) = delete; + + // This sets the callback for when the Widget has finished initialization and + // is ready to use. This is the first point at which the widget is useable. + void set_initialized_callback(const AnyWidgetCallback& callback) { + initialized_callback_ = callback; + } + + // These set the callbacks for when the backing native widget has just been + // asked to change visibility. Note that the native widget may or may not + // actually be drawn on the screen when these callbacks are run, because there + // are more layers of asynchronousness at the OS layer. + void set_shown_callback(const AnyWidgetCallback& callback) { + // Check out NamedWidgetShownWaiter for an alternative to this method. + shown_callback_ = callback; + } + void set_hidden_callback(const AnyWidgetCallback& callback) { + hidden_callback_ = callback; + } + + // This sets the callback for when the Widget has decided that it is about to + // close, but not yet begun to tear down the backing native Widget or the + // RootView. This is the last point at which the Widget is in a consistent, + // useable state. + void set_closing_callback(const AnyWidgetCallback& callback) { + closing_callback_ = callback; + } + + // These two methods deliberately don't exist: + // void set_created_callback(...) + // void set_destroyed_callback(...) + // They would be called respectively too early and too late in the Widget's + // lifecycle for it to be usefully identified - at construction time the + // Widget has no properties or contents yet (and therefore can't be + // meaningfully identified as "your widget" for test purposes), and at + // destruction time the Widget's state is already partly destroyed by the + // closure process. Both methods are deliberately left out to avoid dangerous + // designs based on them. + + private: + friend class internal::AnyWidgetObserverSingleton; + + AnyWidgetObserver(); + + // Called from the singleton to propagate events to each AnyWidgetObserver. + void OnAnyWidgetInitialized(Widget* widget); + void OnAnyWidgetShown(Widget* widget); + void OnAnyWidgetHidden(Widget* widget); + void OnAnyWidgetClosing(Widget* widget); + + AnyWidgetCallback initialized_callback_; + AnyWidgetCallback shown_callback_; + AnyWidgetCallback hidden_callback_; + AnyWidgetCallback closing_callback_; +}; + +// NamedWidgetShownWaiter provides a more ergonomic way to do the most common +// thing clients want to use AnyWidgetObserver for: waiting for a Widget with a +// specific name to be shown. Use it like: +// +// NamedWidgetShownWaiter waiter(Passkey{}, "MyDialogView"); +// ThingThatShowsDialog(); +// Widget* dialog_widget = waiter.WaitIfNeededAndGet(); +// +// It is important that NamedWidgetShownWaiter be constructed before any code +// that might show the named Widget, because if the Widget is shown before the +// waiter is constructed, the waiter won't have observed the show and will +// instead hang forever. Worse, if the widget *sometimes* shows before the +// waiter is constructed and sometimes doesn't, you will be introducing flake. +// THIS IS A DANGEROUS PATTERN, DON'T DO THIS: +// +// ThingThatShowsDialogAsynchronously(); +// NamedWidgetShownWaiter waiter(...); +// waiter.WaitIfNeededAndGet(); +class VIEWS_EXPORT NamedWidgetShownWaiter { + public: + NamedWidgetShownWaiter(AnyWidgetPasskey passkey, const std::string& name); + NamedWidgetShownWaiter(test::AnyWidgetTestPasskey passkey, + const std::string& name); + + virtual ~NamedWidgetShownWaiter(); + + Widget* WaitIfNeededAndGet(); + + private: + explicit NamedWidgetShownWaiter(const std::string& name); + + void OnAnyWidgetShown(Widget* widget); + + AnyWidgetObserver observer_; + Widget* widget_ = nullptr; + base::RunLoop run_loop_; + const std::string name_; +}; + +class AnyWidgetPasskey { + private: + AnyWidgetPasskey(); + + // Add friend classes here that are allowed to use AnyWidgetObserver in + // production code. + friend class NamedWidgetShownWaiter; +}; + +namespace test { + +// A passkey class to allow tests to use AnyWidgetObserver without needing a +// views owner signoff. +class AnyWidgetTestPasskey { + public: + AnyWidgetTestPasskey() = default; +}; + +} // namespace test + +} // namespace views + +#endif // UI_VIEWS_WIDGET_ANY_WIDGET_OBSERVER_H_ diff --git a/chromium/ui/views/widget/any_widget_observer_singleton.cc b/chromium/ui/views/widget/any_widget_observer_singleton.cc new file mode 100644 index 00000000000..0868045de6c --- /dev/null +++ b/chromium/ui/views/widget/any_widget_observer_singleton.cc @@ -0,0 +1,44 @@ +// 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/any_widget_observer_singleton.h" +#include "ui/views/widget/any_widget_observer.h" + +#include "base/no_destructor.h" + +namespace views { +namespace internal { + +// static +AnyWidgetObserverSingleton* AnyWidgetObserverSingleton::GetInstance() { + static base::NoDestructor<AnyWidgetObserverSingleton> observer; + return observer.get(); +} + +#define PROPAGATE_NOTIFICATION(method) \ + void AnyWidgetObserverSingleton::method(Widget* widget) { \ + for (AnyWidgetObserver & obs : observers_) \ + obs.method(widget); \ + } + +PROPAGATE_NOTIFICATION(OnAnyWidgetInitialized) +PROPAGATE_NOTIFICATION(OnAnyWidgetShown) +PROPAGATE_NOTIFICATION(OnAnyWidgetHidden) +PROPAGATE_NOTIFICATION(OnAnyWidgetClosing) + +#undef PROPAGATE_NOTIFICATION + +void AnyWidgetObserverSingleton::AddObserver(AnyWidgetObserver* observer) { + observers_.AddObserver(observer); +} + +void AnyWidgetObserverSingleton::RemoveObserver(AnyWidgetObserver* observer) { + observers_.RemoveObserver(observer); +} + +AnyWidgetObserverSingleton::AnyWidgetObserverSingleton() = default; +AnyWidgetObserverSingleton::~AnyWidgetObserverSingleton() = default; + +} // namespace internal +} // namespace views diff --git a/chromium/ui/views/widget/any_widget_observer_singleton.h b/chromium/ui/views/widget/any_widget_observer_singleton.h new file mode 100644 index 00000000000..46ed9bfc0f1 --- /dev/null +++ b/chromium/ui/views/widget/any_widget_observer_singleton.h @@ -0,0 +1,48 @@ +// 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_ANY_WIDGET_OBSERVER_SINGLETON_H_ +#define UI_VIEWS_WIDGET_ANY_WIDGET_OBSERVER_SINGLETON_H_ + +#include "base/no_destructor.h" +#include "base/observer_list.h" + +namespace views { + +class AnyWidgetObserver; +class Widget; + +namespace internal { + +// This is not the class you want - go look at AnyWidgetObserver. + +// This class serves as the "thing being observed" by AnyWidgetObservers, +// since there is no relevant singleton for Widgets. Every Widget notifies the +// singleton instance of this class of its creation, and it handles notifying +// all AnyWidgetObservers of that. +class AnyWidgetObserverSingleton { + public: + static AnyWidgetObserverSingleton* GetInstance(); + + void OnAnyWidgetInitialized(Widget* widget); + void OnAnyWidgetShown(Widget* widget); + void OnAnyWidgetHidden(Widget* widget); + void OnAnyWidgetClosing(Widget* widget); + + void AddObserver(AnyWidgetObserver* observer); + void RemoveObserver(AnyWidgetObserver* observer); + + private: + friend class base::NoDestructor<AnyWidgetObserverSingleton>; + + AnyWidgetObserverSingleton(); + ~AnyWidgetObserverSingleton(); + + base::ObserverList<AnyWidgetObserver> observers_; +}; + +} // namespace internal +} // namespace views + +#endif // UI_VIEWS_WIDGET_ANY_WIDGET_OBSERVER_SINGLETON_H_ diff --git a/chromium/ui/views/widget/any_widget_observer_unittest.cc b/chromium/ui/views/widget/any_widget_observer_unittest.cc new file mode 100644 index 00000000000..4a1bf692f57 --- /dev/null +++ b/chromium/ui/views/widget/any_widget_observer_unittest.cc @@ -0,0 +1,122 @@ +// 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/any_widget_observer.h" + +#include <string> +#include <utility> + +#include "base/bind.h" +#include "base/test/bind_test_util.h" +#include "base/threading/thread_task_runner_handle.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/views/test/native_widget_factory.h" +#include "ui/views/test/widget_test.h" + +namespace { + +using views::Widget; + +using AnyWidgetObserverTest = views::test::WidgetTest; + +TEST_F(AnyWidgetObserverTest, ObservesInitialize) { + views::AnyWidgetObserver observer(views::test::AnyWidgetTestPasskey{}); + + bool initialized = false; + + observer.set_initialized_callback( + base::BindLambdaForTesting([&](Widget*) { initialized = true; })); + + EXPECT_FALSE(initialized); + WidgetAutoclosePtr w0(WidgetTest::CreateTopLevelPlatformWidget()); + EXPECT_TRUE(initialized); +} + +TEST_F(AnyWidgetObserverTest, ObservesClose) { + views::AnyWidgetObserver observer(views::test::AnyWidgetTestPasskey{}); + + bool closing = false; + + observer.set_closing_callback( + base::BindLambdaForTesting([&](Widget*) { closing = true; })); + + EXPECT_FALSE(closing); + { WidgetAutoclosePtr w0(WidgetTest::CreateTopLevelPlatformWidget()); } + EXPECT_TRUE(closing); +} + +TEST_F(AnyWidgetObserverTest, ObservesShow) { + views::AnyWidgetObserver observer(views::test::AnyWidgetTestPasskey{}); + + bool shown = false; + + observer.set_shown_callback( + base::BindLambdaForTesting([&](Widget*) { shown = true; })); + + EXPECT_FALSE(shown); + WidgetAutoclosePtr w0(WidgetTest::CreateTopLevelPlatformWidget()); + w0->Show(); + EXPECT_TRUE(shown); +} + +TEST_F(AnyWidgetObserverTest, ObservesHide) { + views::AnyWidgetObserver observer(views::test::AnyWidgetTestPasskey{}); + + bool hidden = false; + + observer.set_hidden_callback( + base::BindLambdaForTesting([&](Widget*) { hidden = true; })); + + EXPECT_FALSE(hidden); + WidgetAutoclosePtr w0(WidgetTest::CreateTopLevelPlatformWidget()); + w0->Hide(); + EXPECT_TRUE(hidden); +} + +class NamedWidgetShownWaiterTest : public views::test::WidgetTest { + public: + NamedWidgetShownWaiterTest() = default; + ~NamedWidgetShownWaiterTest() override = default; + + views::Widget* CreateNamedWidget(const std::string& name) { + Widget* widget = new Widget; + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); + params.native_widget = views::test::CreatePlatformNativeWidgetImpl( + params, widget, views::test::kStubCapture, nullptr); + params.name = name; + widget->Init(std::move(params)); + return widget; + } +}; + +TEST_F(NamedWidgetShownWaiterTest, ShownAfterWait) { + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + "TestWidget"); + + WidgetAutoclosePtr w0(CreateNamedWidget("TestWidget")); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce([](views::Widget* widget) { widget->Show(); }, + base::Unretained(w0.get()))); + EXPECT_EQ(waiter.WaitIfNeededAndGet(), w0.get()); +} + +TEST_F(NamedWidgetShownWaiterTest, ShownBeforeWait) { + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + "TestWidget"); + WidgetAutoclosePtr w0(CreateNamedWidget("TestWidget")); + w0->Show(); + EXPECT_EQ(waiter.WaitIfNeededAndGet(), w0.get()); +} + +TEST_F(NamedWidgetShownWaiterTest, OtherWidgetShown) { + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + "TestWidget"); + WidgetAutoclosePtr w0(CreateNamedWidget("NotTestWidget")); + WidgetAutoclosePtr w1(CreateNamedWidget("TestWidget")); + w0->Show(); + w1->Show(); + EXPECT_EQ(waiter.WaitIfNeededAndGet(), w1.get()); +} + +} // namespace 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 c6c77c8af54..faf79e0e6c7 100644 --- a/chromium/ui/views/widget/ax_native_widget_mac_unittest.mm +++ b/chromium/ui/views/widget/ax_native_widget_mac_unittest.mm @@ -7,7 +7,6 @@ #import <Cocoa/Cocoa.h> #include "base/mac/mac_util.h" -#import "base/mac/sdk_forward_declarations.h" #include "base/strings/stringprintf.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" diff --git a/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc b/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc index 4b6586cc54b..d437e382af5 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc @@ -53,8 +53,7 @@ void DesktopCaptureClient::SetCapture(aura::Window* new_capture_window) { // We should only ever be told to capture a child of |root_|. Otherwise // things are going to be really confused. - DCHECK(!new_capture_window || - (new_capture_window->GetRootWindow() == root_)); + DCHECK(!new_capture_window || (new_capture_window->GetRootWindow() == root_)); DCHECK(!capture_window_ || capture_window_->GetRootWindow()); aura::Window* old_capture_window = capture_window_; 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 d0a6ce719b3..707f2b4aa33 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 @@ -7,8 +7,8 @@ #include <stddef.h> #include <stdint.h> -#include "base/bind.h" -#include "base/lazy_instance.h" +#include <utility> + #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" @@ -18,168 +18,30 @@ #include "ui/aura/client/drag_drop_delegate.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" -#include "ui/base/clipboard/clipboard_constants.h" #include "ui/base/dragdrop/drop_target_event.h" #include "ui/base/dragdrop/os_exchange_data.h" #include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h" #include "ui/base/layout.h" +#include "ui/base/mojom/cursor_type.mojom-shared.h" #include "ui/base/x/selection_utils.h" +#include "ui/base/x/x11_drag_context.h" +#include "ui/base/x/x11_util.h" #include "ui/display/screen.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" -#include "ui/events/platform/platform_event_source.h" -#include "ui/events/platform_event.h" -#include "ui/events/x/x11_window_event_manager.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/x/x11.h" -#include "ui/gfx/x/x11_atom_cache.h" #include "ui/views/controls/image_view.h" #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h" #include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h" #include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h" #include "ui/views/widget/widget.h" -// Reading recommended for understanding the implementation in this file: -// -// * The X Window System Concepts section in The X New Developer’s Guide -// * The X Selection Mechanism paper by Keith Packard -// * The Peer-to-Peer Communication by Means of Selections section in the -// ICCCM (X Consortium's Inter-Client Communication Conventions Manual) -// * The XDND specification, Drag-and-Drop Protocol for the X Window System -// * The XDS specification, The Direct Save Protocol for the X Window System -// -// All the readings are freely available online. - using aura::client::DragDropDelegate; using ui::OSExchangeData; namespace { -// The lowest XDND protocol version that we understand. -// -// The XDND protocol specification says that we must support all versions -// between 3 and the version we advertise in the XDndAware property. -constexpr int kMinXdndVersion = 3; - -// The value used in the XdndAware property. -// -// The XDND protocol version used between two windows will be the minimum -// between the two versions advertised in the XDndAware property. -constexpr int kMaxXdndVersion = 5; - -constexpr int kWillAcceptDrop = 1; -constexpr int kWantFurtherPosEvents = 2; - -// These actions have the same meaning as in the W3C Drag and Drop spec. -const char kXdndActionCopy[] = "XdndActionCopy"; -const char kXdndActionMove[] = "XdndActionMove"; -const char kXdndActionLink[] = "XdndActionLink"; - -// Triggers the XDS protocol. -const char kXdndActionDirectSave[] = "XdndActionDirectSave"; - -// Window property that will receive the drag and drop selection data. -const char kChromiumDragReciever[] = "_CHROMIUM_DRAG_RECEIVER"; - -// Window property that contains the possible actions that will be presented to -// the user when the drag and drop action is kXdndActionAsk. -const char kXdndActionList[] = "XdndActionList"; - -// Window property that tells other applications the window understands XDND. -const char kXdndAware[] = "XdndAware"; - -// Window property on the source window and message used by the XDS protocol. -// This atom name intentionally includes the XDS protocol version (0). -// After the source sends the XdndDrop message, this property stores the -// (path-less) name of the file to be saved, and has the type text/plain, with -// an optional charset attribute. -// When receiving an XdndDrop event, the target needs to check for the -// XdndDirectSave property on the source window. The target then modifies the -// XdndDirectSave on the source window, and sends an XdndDirectSave message to -// the source. -// After the target sends the XdndDirectSave message, this property stores an -// URL indicating the location where the source should save the file. -const char kXdndDirectSave0[] = "XdndDirectSave0"; - -// Window property pointing to a proxy window to receive XDND target messages. -// The XDND source must check the proxy window must for the XdndAware property, -// and must send all XDND messages to the proxy instead of the target. However, -// the target field in the messages must still represent the original target -// window (the window pointed to by the cursor). -const char kXdndProxy[] = "XdndProxy"; - -// Window property that holds the supported drag and drop data types. -// This property is set on the XDND source window when the drag and drop data -// can be converted to more than 3 types. -const char kXdndTypeList[] = "XdndTypeList"; - -// Selection used by the XDND protocol to transfer data between applications. -const char kXdndSelection[] = "XdndSelection"; - -// Message sent from an XDND source to the target when the user confirms the -// drag and drop operation. -const char kXdndDrop[] = "XdndDrop"; - -// Message sent from an XDND source to the target to start the XDND protocol. -// The target must wait for an XDndPosition event before querying the data. -const char kXdndEnter[] = "XdndEnter"; - -// Message sent from an XDND target to the source in respose to an XdndDrop. -// The message must be sent whether the target acceepts the drop or not. -const char kXdndFinished[] = "XdndFinished"; - -// Message sent from an XDND source to the target when the user cancels the drag -// and drop operation. -const char kXdndLeave[] = "XdndLeave"; - -// Message sent by the XDND source when the cursor position changes. -// The source will also send an XdndPosition event right after the XdndEnter -// event, to tell the target about the initial cursor position and the desired -// drop action. -// The time stamp in the XdndPosition must be used when requesting selection -// information. -// After the target optionally acquires selection information, it must tell the -// source if it can accept the drop via an XdndStatus message. -const char kXdndPosition[] = "XdndPosition"; - -// Message sent by the XDND target in response to an XdndPosition message. -// The message informs the source if the target will accept the drop, and what -// action will be taken if the drop is accepted. -const char kXdndStatus[] = "XdndStatus"; - -int XGetModifiers() { - XDisplay* display = gfx::GetXDisplay(); - - XID root, child; - int root_x, root_y, win_x, win_y; - unsigned int mask; - XQueryPointer(display, - DefaultRootWindow(display), - &root, - &child, - &root_x, - &root_y, - &win_x, - &win_y, - &mask); - int modifiers = ui::EF_NONE; - if (mask & ShiftMask) - modifiers |= ui::EF_SHIFT_DOWN; - if (mask & ControlMask) - modifiers |= ui::EF_CONTROL_DOWN; - if (mask & Mod1Mask) - modifiers |= ui::EF_ALT_DOWN; - if (mask & Mod4Mask) - modifiers |= ui::EF_COMMAND_DOWN; - if (mask & Button1Mask) - modifiers |= ui::EF_LEFT_MOUSE_BUTTON; - if (mask & Button2Mask) - modifiers |= ui::EF_MIDDLE_MOUSE_BUTTON; - if (mask & Button3Mask) - modifiers |= ui::EF_RIGHT_MOUSE_BUTTON; - return modifiers; -} - // The minimum alpha before we declare a pixel transparent when searching in // our source image. constexpr uint32_t kMinAlpha = 32; @@ -187,578 +49,111 @@ constexpr uint32_t kMinAlpha = 32; // |drag_widget_|'s opacity. constexpr float kDragWidgetOpacity = .75f; -static base::LazyInstance< - std::map<::Window, views::DesktopDragDropClientAuraX11*> >::Leaky - g_live_client_map = LAZY_INSTANCE_INITIALIZER; - -} // namespace - -namespace views { - -DesktopDragDropClientAuraX11* - DesktopDragDropClientAuraX11::g_current_drag_drop_client = nullptr; - -class DesktopDragDropClientAuraX11::X11DragContext - : public ui::PlatformEventDispatcher { - public: - X11DragContext(::Window local_window, const XClientMessageEvent& event); - ~X11DragContext() override; - - // When we receive an XdndPosition message, we need to have all the data - // copied from the other window before we process the XdndPosition - // message. If we have that data already, dispatch immediately. Otherwise, - // delay dispatching until we do. - void OnXdndPositionMessage(DesktopDragDropClientAuraX11* client, - ::Atom suggested_action, - ::Window source_window, - ::Time time_stamp, - const gfx::Point& screen_point); - - // Called when XSelection data has been copied to our process. - void OnSelectionNotify(const XSelectionEvent& xselection); - - // Clones the fetched targets. - const ui::SelectionFormatMap& fetched_targets() { return fetched_targets_; } - - // Reads the kXdndActionList property from |source_window| and copies it - // into |actions|. - void ReadActions(); - - // Creates a ui::DragDropTypes::DragOperation representation of the current - // action list. - int GetDragOperation() const; - - DesktopDragDropClientAuraX11* source_client() { return source_client_; } - - private: - // Called to request the next target from the source window. This is only - // done on the first XdndPosition; after that, we cache the data offered by - // the source window. - void RequestNextTarget(); - - // Masks the X11 atom |xdnd_operation|'s views representation onto - // |drag_operation|. - void MaskOperation(::Atom xdnd_operation, int* drag_operation) const; - - // ui::PlatformEventDispatcher: - bool CanDispatchEvent(const ui::PlatformEvent& event) override; - uint32_t DispatchEvent(const ui::PlatformEvent& event) override; - - // The XID of our chrome local aura window handling our events. - ::Window local_window_; - - // The XID of the window that's initiated the drag. - unsigned long source_window_; - - // Events that we have selected on |source_window_|. - std::unique_ptr<ui::XScopedEventSelector> source_window_events_; - - // The DesktopDragDropClientAuraX11 for |source_window_| if |source_window_| - // belongs to a Chrome window. - DesktopDragDropClientAuraX11* source_client_; - - // The client we inform once we're done with requesting data. - DesktopDragDropClientAuraX11* drag_drop_client_ = nullptr; - - // Whether we're blocking the handling of an XdndPosition message by waiting - // for |unfetched_targets_| to be fetched. - bool waiting_to_handle_position_ = false; - - // Where the cursor is on screen. - gfx::Point screen_point_; - - // The time stamp of the last XdndPosition event we received. The XDND - // specification mandates that we use this time stamp when querying the source - // about the drag and drop data. - ::Time position_time_stamp_; - - // A SelectionFormatMap of data that we have in our process. - ui::SelectionFormatMap fetched_targets_; - - // The names of various data types offered by the other window that we - // haven't fetched and put in |fetched_targets_| yet. - std::vector<::Atom> unfetched_targets_; - - // XdndPosition messages have a suggested action. Qt applications exclusively - // use this, instead of the XdndActionList which is backed by |actions_|. - ::Atom suggested_action_ = x11::None; - - // Possible actions. - std::vector<::Atom> actions_; - - DISALLOW_COPY_AND_ASSIGN(X11DragContext); -}; - -DesktopDragDropClientAuraX11::X11DragContext::X11DragContext( - ::Window local_window, - const XClientMessageEvent& event) - : local_window_(local_window), - source_window_(event.data.l[0]), - source_client_( - DesktopDragDropClientAuraX11::GetForWindow(source_window_)) { - if (!source_client_) { - bool get_types_from_property = ((event.data.l[1] & 1) != 0); - - if (get_types_from_property) { - if (!ui::GetAtomArrayProperty(source_window_, kXdndTypeList, - &unfetched_targets_)) { - return; - } - } else { - // data.l[2,3,4] contain the first three types. Unused slots can be None. - for (size_t i = 2; i < 5; ++i) { - if (event.data.l[i] != x11::None) - unfetched_targets_.push_back(event.data.l[i]); - } - } - -#if DCHECK_IS_ON() - DVLOG(1) << "XdndEnter has " << unfetched_targets_.size() << " data types"; - for (::Atom target : unfetched_targets_) - DVLOG(1) << "XdndEnter data type: " << target; -#endif // DCHECK_IS_ON() - - // The window doesn't have a DesktopDragDropClientAuraX11, that means it's - // created by some other process. Listen for messages on it. - ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); - source_window_events_ = std::make_unique<ui::XScopedEventSelector>( - source_window_, PropertyChangeMask); - - // We must perform a full sync here because we could be racing - // |source_window_|. - XSync(gfx::GetXDisplay(), x11::False); - } else { - // This drag originates from an aura window within our process. This means - // that we can shortcut the X11 server and ask the owning SelectionOwner - // for the data it's offering. - fetched_targets_ = source_client_->GetFormatMap(); - } - - ReadActions(); -} - -DesktopDragDropClientAuraX11::X11DragContext::~X11DragContext() { - if (!source_client_) { - // Unsubscribe from message events. - ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); - } -} - -void DesktopDragDropClientAuraX11::X11DragContext::OnXdndPositionMessage( - DesktopDragDropClientAuraX11* client, - ::Atom suggested_action, - ::Window source_window, - ::Time time_stamp, - const gfx::Point& screen_point) { - DCHECK_EQ(source_window_, source_window); - suggested_action_ = suggested_action; - - if (!unfetched_targets_.empty()) { - // We have unfetched targets. That means we need to pause the handling of - // the position message and ask the other window for its data. - screen_point_ = screen_point; - drag_drop_client_ = client; - position_time_stamp_ = time_stamp; - waiting_to_handle_position_ = true; - - fetched_targets_ = ui::SelectionFormatMap(); - RequestNextTarget(); - } else { - client->CompleteXdndPosition(source_window, screen_point); - } -} - -void DesktopDragDropClientAuraX11::X11DragContext::RequestNextTarget() { - DCHECK(!unfetched_targets_.empty()); - DCHECK(drag_drop_client_); - DCHECK(waiting_to_handle_position_); - - ::Atom target = unfetched_targets_.back(); - unfetched_targets_.pop_back(); - - XConvertSelection(gfx::GetXDisplay(), gfx::GetAtom(kXdndSelection), target, - gfx::GetAtom(kChromiumDragReciever), local_window_, - position_time_stamp_); -} - -void DesktopDragDropClientAuraX11::X11DragContext::OnSelectionNotify( - const XSelectionEvent& event) { - if (!waiting_to_handle_position_) { - // A misbehaved window may send SelectionNotify without us requesting data - // via XConvertSelection(). - return; - } - DCHECK(drag_drop_client_); - - DVLOG(1) << "SelectionNotify, format " << event.target; +// Returns true if |image| has any visible regions (defined as having a pixel +// with alpha > 32). +bool IsValidDragImage(const gfx::ImageSkia& image) { + if (image.isNull()) + return false; - if (event.property != x11::None) { - DCHECK_EQ(event.property, gfx::GetAtom(kChromiumDragReciever)); + // 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); - scoped_refptr<base::RefCountedMemory> data; - ::Atom type = x11::None; - if (ui::GetRawBytesOfProperty(local_window_, event.property, &data, nullptr, - &type)) { - fetched_targets_.Insert(event.target, data); + for (int x = 0; x < in_bitmap->width(); ++x) { + if (SkColorGetA(in_row[x]) > kMinAlpha) + return true; } - } else { - // The source failed to convert the drop data to the format (target in X11 - // parlance) that we asked for. This happens, even though we only ask for - // the formats advertised by the source. http://crbug.com/628099 - LOG(ERROR) << "XConvertSelection failed for source-advertised target " - << event.target; } - if (!unfetched_targets_.empty()) { - RequestNextTarget(); - } else { - waiting_to_handle_position_ = false; - drag_drop_client_->CompleteXdndPosition(source_window_, screen_point_); - drag_drop_client_ = nullptr; - } + return false; } -void DesktopDragDropClientAuraX11::X11DragContext::ReadActions() { - if (!source_client_) { - std::vector<::Atom> atom_array; - if (!ui::GetAtomArrayProperty(source_window_, kXdndActionList, - &atom_array)) { - actions_.clear(); - } else { - actions_.swap(atom_array); - } - } else { - // We have a property notify set up for other windows in case they change - // their action list. Thankfully, the views interface is static and you - // can't change the action list after you enter StartDragAndDrop(). - actions_ = source_client_->GetOfferedDragOperations(); - } -} +std::unique_ptr<views::Widget> CreateDragWidget( + 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); + if (ui::IsCompositingManagerPresent()) + params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent; + else + params.opacity = views::Widget::InitParams::WindowOpacity::kOpaque; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.accept_events = false; -int DesktopDragDropClientAuraX11::X11DragContext::GetDragOperation() const { - int drag_operation = ui::DragDropTypes::DRAG_NONE; - for (const auto& action : actions_) - MaskOperation(action, &drag_operation); + gfx::Point location = + display::Screen::GetScreen()->GetCursorScreenPoint() - 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)); + if (params.opacity == views::Widget::InitParams::WindowOpacity::kTranslucent) + widget->SetOpacity(kDragWidgetOpacity); + widget->GetNativeWindow()->SetName("DragWindow"); - MaskOperation(suggested_action_, &drag_operation); + views::ImageView* image_view = new views::ImageView(); + image_view->SetImage(image); + image_view->SetBoundsRect(gfx::Rect(image.size())); + widget->SetContentsView(image_view); + widget->Show(); + widget->GetNativeWindow()->layer()->SetFillsBoundsOpaquely(false); - return drag_operation; + return widget; } -void DesktopDragDropClientAuraX11::X11DragContext::MaskOperation( - ::Atom xdnd_operation, - int* drag_operation) const { - if (xdnd_operation == gfx::GetAtom(kXdndActionCopy)) - *drag_operation |= ui::DragDropTypes::DRAG_COPY; - else if (xdnd_operation == gfx::GetAtom(kXdndActionMove)) - *drag_operation |= ui::DragDropTypes::DRAG_MOVE; - else if (xdnd_operation == gfx::GetAtom(kXdndActionLink)) - *drag_operation |= ui::DragDropTypes::DRAG_LINK; -} +} // namespace -bool DesktopDragDropClientAuraX11::X11DragContext::CanDispatchEvent( - const ui::PlatformEvent& event) { - return event->xany.window == source_window_; -} +namespace views { -uint32_t DesktopDragDropClientAuraX11::X11DragContext::DispatchEvent( - const ui::PlatformEvent& event) { - if (event->type == PropertyNotify && - event->xproperty.atom == gfx::GetAtom(kXdndActionList)) { - ReadActions(); - return ui::POST_DISPATCH_STOP_PROPAGATION; - } - return ui::POST_DISPATCH_NONE; -} +DesktopDragDropClientAuraX11* + DesktopDragDropClientAuraX11::g_current_drag_drop_client = nullptr; /////////////////////////////////////////////////////////////////////////////// DesktopDragDropClientAuraX11::DesktopDragDropClientAuraX11( aura::Window* root_window, views::DesktopNativeCursorManager* cursor_manager, - ::Display* xdisplay, - ::Window xwindow) - : root_window_(root_window), - cursor_manager_(cursor_manager), - xdisplay_(xdisplay), - xwindow_(xwindow) { - // Some tests change the DesktopDragDropClientAuraX11 associated with an - // |xwindow|. - g_live_client_map.Get()[xwindow] = this; - - // Mark that we are aware of drag and drop concepts. - unsigned long xdnd_version = kMaxXdndVersion; - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom(kXdndAware), XA_ATOM, 32, - PropModeReplace, - reinterpret_cast<unsigned char*>(&xdnd_version), 1); -} + ::Display* display, + XID window) + : XDragDropClient(this, display, window), + root_window_(root_window), + cursor_manager_(cursor_manager) {} DesktopDragDropClientAuraX11::~DesktopDragDropClientAuraX11() { // This is necessary when the parent native widget gets destroyed while a drag // operation is in progress. move_loop_->EndMoveLoop(); NotifyDragLeave(); - - g_live_client_map.Get().erase(xwindow_); -} - -// static -DesktopDragDropClientAuraX11* DesktopDragDropClientAuraX11::GetForWindow( - ::Window window) { - std::map<::Window, DesktopDragDropClientAuraX11*>::const_iterator it = - g_live_client_map.Get().find(window); - if (it == g_live_client_map.Get().end()) - return nullptr; - return it->second; + ResetDragContext(); } void DesktopDragDropClientAuraX11::Init() { move_loop_ = CreateMoveLoop(this); } -void DesktopDragDropClientAuraX11::OnXdndEnter( - const XClientMessageEvent& event) { - int version = (event.data.l[1] & 0xff000000) >> 24; - DVLOG(1) << "OnXdndEnter, version " << version; - - if (version < kMinXdndVersion) { - // This protocol version is not documented in the XDND standard (last - // revised in 1999), so we don't support it. Since don't understand the - // protocol spoken by the source, we can't tell it that we can't talk to it. - LOG(ERROR) << "XdndEnter message discarded because its version is too old."; - return; - } - if (version > kMaxXdndVersion) { - // The XDND version used should be the minimum between the versions - // advertised by the source and the target. We advertise kMaxXdndVersion, so - // this should never happen when talking to an XDND-compliant application. - LOG(ERROR) << "XdndEnter message discarded because its version is too new."; - return; - } - - // Make sure that we've run ~X11DragContext() before creating another one. - target_current_context_.reset(); - target_current_context_ = std::make_unique<X11DragContext>(xwindow_, event); - - // In the Windows implementation, we immediately call DesktopDropTargetWin:: - // Translate(). The XDND specification demands that we wait until we receive - // an XdndPosition message before we use XConvertSelection or send an - // XdndStatus message. -} - -void DesktopDragDropClientAuraX11::OnXdndLeave( - const XClientMessageEvent& event) { - DVLOG(1) << "OnXdndLeave"; - NotifyDragLeave(); - target_current_context_.reset(); -} - -void DesktopDragDropClientAuraX11::OnXdndPosition( - const XClientMessageEvent& event) { - DVLOG(1) << "OnXdndPosition"; - - unsigned long source_window = event.data.l[0]; - int x_root_window = event.data.l[2] >> 16; - int y_root_window = event.data.l[2] & 0xffff; - ::Time time_stamp = event.data.l[3]; - ::Atom suggested_action = event.data.l[4]; - - if (!target_current_context_.get()) { - NOTREACHED(); - return; - } - - target_current_context_->OnXdndPositionMessage( - this, suggested_action, source_window, time_stamp, - gfx::Point(x_root_window, y_root_window)); -} - -void DesktopDragDropClientAuraX11::OnXdndStatus( - const XClientMessageEvent& event) { - DVLOG(1) << "OnXdndStatus"; - - unsigned long source_window = event.data.l[0]; - - if (source_window != source_current_window_) - return; - - if (source_state_ != SourceState::kPendingDrop && - source_state_ != SourceState::kOther) { - return; - } - - waiting_on_status_ = false; - status_received_since_enter_ = true; - - if (event.data.l[1] & 1) { - ::Atom atom_operation = event.data.l[4]; - negotiated_operation_ = AtomToDragOperation(atom_operation); - } else { - negotiated_operation_ = ui::DragDropTypes::DRAG_NONE; - } - - if (source_state_ == SourceState::kPendingDrop) { - // We were waiting on the status message so we could send the XdndDrop. - if (negotiated_operation_ == ui::DragDropTypes::DRAG_NONE) { - move_loop_->EndMoveLoop(); - return; - } - source_state_ = SourceState::kDropped; - SendXdndDrop(source_window); - return; - } - - ui::CursorType cursor_type = ui::CursorType::kNull; - switch (negotiated_operation_) { - case ui::DragDropTypes::DRAG_NONE: - cursor_type = ui::CursorType::kDndNone; - break; - case ui::DragDropTypes::DRAG_MOVE: - cursor_type = ui::CursorType::kDndMove; - break; - case ui::DragDropTypes::DRAG_COPY: - cursor_type = ui::CursorType::kDndCopy; - break; - case ui::DragDropTypes::DRAG_LINK: - cursor_type = ui::CursorType::kDndLink; - break; - } - move_loop_->UpdateCursor(cursor_manager_->GetInitializedCursor(cursor_type)); - - // Note: event.data.[2,3] specify a rectangle. It is a request by the other - // window to not send further XdndPosition messages while the cursor is - // within it. However, it is considered advisory and (at least according to - // the spec) the other side must handle further position messages within - // it. GTK+ doesn't bother with this, so neither should we. - - if (next_position_message_.get()) { - // We were waiting on the status message so we could send off the next - // position message we queued up. - gfx::Point p = next_position_message_->first; - unsigned long event_time = next_position_message_->second; - next_position_message_.reset(); - - SendXdndPosition(source_window, p, event_time); - } -} - -void DesktopDragDropClientAuraX11::OnXdndFinished( - const XClientMessageEvent& event) { - DVLOG(1) << "OnXdndFinished"; - unsigned long source_window = event.data.l[0]; - if (source_current_window_ != source_window) - return; - - // Clear |negotiated_operation_| if the drag was rejected. - if ((event.data.l[1] & 1) == 0) - negotiated_operation_ = ui::DragDropTypes::DRAG_NONE; - - // Clear |source_current_window_| to avoid sending XdndLeave upon ending the - // move loop. - source_current_window_ = x11::None; - move_loop_->EndMoveLoop(); -} - -void DesktopDragDropClientAuraX11::OnXdndDrop( - const XClientMessageEvent& event) { - DVLOG(1) << "OnXdndDrop"; - - unsigned long source_window = event.data.l[0]; - - int drag_operation = ui::DragDropTypes::DRAG_NONE; - if (target_window_) { - aura::client::DragDropDelegate* delegate = - aura::client::GetDragDropDelegate(target_window_); - if (delegate) { - auto data(std::make_unique<ui::OSExchangeData>( - std::make_unique<ui::OSExchangeDataProviderAuraX11>( - xwindow_, target_current_context_->fetched_targets()))); - - ui::DropTargetEvent drop_event( - *data.get(), gfx::PointF(target_window_location_), - gfx::PointF(target_window_root_location_), - target_current_context_->GetDragOperation()); - if (target_current_context_->source_client()) { - drop_event.set_flags( - target_current_context_->source_client()->current_modifier_state()); - } else { - drop_event.set_flags(XGetModifiers()); - } - - if (!IsDragDropInProgress()) { - UMA_HISTOGRAM_COUNTS_1M("Event.DragDrop.ExternalOriginDrop", 1); - } - - drag_operation = delegate->OnPerformDrop(drop_event, std::move(data)); - } - - target_window_->RemoveObserver(this); - target_window_ = nullptr; - } - - XEvent xev; - xev.xclient.type = ClientMessage; - xev.xclient.message_type = gfx::GetAtom(kXdndFinished); - xev.xclient.format = 32; - xev.xclient.window = source_window; - xev.xclient.data.l[0] = xwindow_; - xev.xclient.data.l[1] = (drag_operation != 0) ? 1 : 0; - xev.xclient.data.l[2] = DragOperationToAtom(drag_operation); - - SendXClientEvent(source_window, &xev); -} - -void DesktopDragDropClientAuraX11::OnSelectionNotify( - const XSelectionEvent& xselection) { - DVLOG(1) << "OnSelectionNotify"; - if (target_current_context_) - target_current_context_->OnSelectionNotify(xselection); - - // ICCCM requires us to delete the property passed into SelectionNotify. - if (xselection.property != x11::None) - XDeleteProperty(xdisplay_, xwindow_, xselection.property); -} - int DesktopDragDropClientAuraX11::StartDragAndDrop( std::unique_ptr<ui::OSExchangeData> data, aura::Window* root_window, aura::Window* source_window, - const gfx::Point& screen_location, + const gfx::Point& /*screen_location*/, int operation, ui::DragDropTypes::DragEventSource source) { UMA_HISTOGRAM_ENUMERATION("Event.DragDrop.Start", source, ui::DragDropTypes::DRAG_EVENT_SOURCE_COUNT); - source_current_window_ = x11::None; DCHECK(!g_current_drag_drop_client); g_current_drag_drop_client = this; - waiting_on_status_ = false; - next_position_message_.reset(); - status_received_since_enter_ = false; - source_state_ = SourceState::kOther; - drag_operation_ = operation; - negotiated_operation_ = ui::DragDropTypes::DRAG_NONE; - - const ui::OSExchangeData::Provider* provider = &data->provider(); - source_provider_ = static_cast<const ui::OSExchangeDataProviderAuraX11*>( - provider); - - source_provider_->TakeOwnershipOfSelection(); - - std::vector<::Atom> actions = GetOfferedDragOperations(); - if (!source_provider_->file_contents_name().empty()) { - actions.push_back(gfx::GetAtom(kXdndActionDirectSave)); - ui::SetStringProperty( - xwindow_, gfx::GetAtom(kXdndDirectSave0), - gfx::GetAtom(ui::kMimeTypeText), - source_provider_->file_contents_name().AsUTF8Unsafe()); - } - ui::SetAtomArrayProperty(xwindow_, kXdndActionList, "ATOM", actions); - gfx::ImageSkia drag_image = source_provider_->GetDragImage(); + InitDrag(operation, data.get()); + + DCHECK(source_provider()); + gfx::ImageSkia drag_image = source_provider()->GetDragImage(); if (IsValidDragImage(drag_image)) { - CreateDragWidget(drag_image); - drag_widget_offset_ = source_provider_->GetDragImageOffset(); + drag_image_size_ = drag_image.size(); + drag_widget_offset_ = source_provider()->GetDragImageOffset(); + drag_widget_ = CreateDragWidget(drag_image, drag_widget_offset_); } // Chrome expects starting drag and drop to release capture. @@ -777,10 +172,11 @@ int DesktopDragDropClientAuraX11::StartDragAndDrop( // 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. move_loop_->RunMoveLoop(source_window, cursor_manager_->GetInitializedCursor( - ui::CursorType::kGrabbing)); + ui::mojom::CursorType::kGrabbing)); if (alive) { - if (negotiated_operation_ == ui::DragDropTypes::DRAG_NONE) { + 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 { @@ -788,14 +184,9 @@ int DesktopDragDropClientAuraX11::StartDragAndDrop( ui::DragDropTypes::DRAG_EVENT_SOURCE_COUNT); } drag_widget_.reset(); - - source_provider_ = nullptr; g_current_drag_drop_client = nullptr; - drag_operation_ = 0; - XDeleteProperty(xdisplay_, xwindow_, gfx::GetAtom(kXdndActionList)); - XDeleteProperty(xdisplay_, xwindow_, gfx::GetAtom(kXdndDirectSave0)); - - return negotiated_operation_; + CleanupDrag(); + return resulting_operation; } UMA_HISTOGRAM_ENUMERATION("Event.DragDrop.Cancel", source, ui::DragDropTypes::DRAG_EVENT_SOURCE_COUNT); @@ -820,6 +211,14 @@ void DesktopDragDropClientAuraX11::RemoveObserver( NOTIMPLEMENTED(); } +bool DesktopDragDropClientAuraX11::DispatchXEvent(XEvent* event) { + if (!target_current_context() || + event->xany.window != target_current_context()->source_window()) { + return false; + } + return target_current_context()->DispatchXEvent(event); +} + void DesktopDragDropClientAuraX11::OnWindowDestroyed(aura::Window* window) { DCHECK_EQ(target_window_, window); target_window_ = nullptr; @@ -838,72 +237,15 @@ void DesktopDragDropClientAuraX11::OnMouseMovement( gfx::Rect(scaled_point - drag_widget_offset_, drag_image_size_)); drag_widget_->StackAtTop(); } - - const int kModifiers = ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | - ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN | - ui::EF_LEFT_MOUSE_BUTTON | - ui::EF_MIDDLE_MOUSE_BUTTON | - ui::EF_RIGHT_MOUSE_BUTTON; - current_modifier_state_ = flags & kModifiers; - - repeat_mouse_move_timer_.Stop(); - ProcessMouseMove(screen_point, - (event_time - base::TimeTicks()).InMilliseconds()); + HandleMouseMovement(screen_point, flags, event_time); } void DesktopDragDropClientAuraX11::OnMouseReleased() { - repeat_mouse_move_timer_.Stop(); - - if (source_state_ != SourceState::kOther) { - // The user has previously released the mouse and is clicking in - // frustration. - move_loop_->EndMoveLoop(); - return; - } - - if (source_current_window_ != x11::None) { - if (waiting_on_status_) { - if (status_received_since_enter_) { - // If we are waiting for an XdndStatus message, we need to wait for it - // to complete. - source_state_ = SourceState::kPendingDrop; - - // Start timer to end the move loop if the target takes too long to send - // the XdndStatus and XdndFinished messages. - StartEndMoveLoopTimer(); - return; - } - - move_loop_->EndMoveLoop(); - return; - } - - if (negotiated_operation_ != ui::DragDropTypes::DRAG_NONE) { - // Start timer to end the move loop if the target takes too long to send - // an XdndFinished message. It is important that StartEndMoveLoopTimer() - // is called before SendXdndDrop() because SendXdndDrop() - // sends XdndFinished synchronously if the drop target is a Chrome - // window. - StartEndMoveLoopTimer(); - - // We have negotiated an action with the other end. - source_state_ = SourceState::kDropped; - SendXdndDrop(source_current_window_); - return; - } - } - - move_loop_->EndMoveLoop(); + XDragDropClient::HandleMouseReleased(); } void DesktopDragDropClientAuraX11::OnMoveLoopEnded() { - if (source_current_window_ != x11::None) { - SendXdndLeave(source_current_window_); - source_current_window_ = x11::None; - } - target_current_context_.reset(); - repeat_mouse_move_timer_.Stop(); - end_move_loop_timer_.Stop(); + XDragDropClient::HandleMoveLoopEnded(); } std::unique_ptr<X11MoveLoop> DesktopDragDropClientAuraX11::CreateMoveLoop( @@ -911,115 +253,6 @@ std::unique_ptr<X11MoveLoop> DesktopDragDropClientAuraX11::CreateMoveLoop( return base::WrapUnique(new X11WholeScreenMoveLoop(this)); } -XID DesktopDragDropClientAuraX11::FindWindowFor( - const gfx::Point& screen_point) { - views::X11TopmostWindowFinder finder; - ::Window target = finder.FindWindowAt(screen_point); - - if (target == x11::None) - return x11::None; - - // TODO(crbug/651775): The proxy window should be reported separately from the - // target window. XDND messages should be sent to the proxy, and their - // window field should point to the target. - - // Figure out which window we should test as XdndAware. If |target| has - // XdndProxy, it will set that proxy on target, and if not, |target|'s - // original value will remain. - ui::GetXIDProperty(target, kXdndProxy, &target); - - int version; - if (ui::GetIntProperty(target, kXdndAware, &version) && - version >= kMaxXdndVersion) { - return target; - } - return x11::None; -} - -void DesktopDragDropClientAuraX11::SendXClientEvent(::Window xid, - XEvent* xev) { - DCHECK_EQ(ClientMessage, xev->type); - - // Don't send messages to the X11 message queue if we can help it. - DesktopDragDropClientAuraX11* short_circuit = GetForWindow(xid); - if (short_circuit) { - Atom message_type = xev->xclient.message_type; - if (message_type == gfx::GetAtom(kXdndEnter)) { - short_circuit->OnXdndEnter(xev->xclient); - return; - } else if (message_type == gfx::GetAtom(kXdndLeave)) { - short_circuit->OnXdndLeave(xev->xclient); - return; - } else if (message_type == gfx::GetAtom(kXdndPosition)) { - short_circuit->OnXdndPosition(xev->xclient); - return; - } else if (message_type == gfx::GetAtom(kXdndStatus)) { - short_circuit->OnXdndStatus(xev->xclient); - return; - } else if (message_type == gfx::GetAtom(kXdndFinished)) { - short_circuit->OnXdndFinished(xev->xclient); - return; - } else if (message_type == gfx::GetAtom(kXdndDrop)) { - short_circuit->OnXdndDrop(xev->xclient); - return; - } - } - - // I don't understand why the GTK+ code is doing what it's doing here. It - // goes out of its way to send the XEvent so that it receives a callback on - // success or failure, and when it fails, it then sends an internal - // GdkEvent about the failed drag. (And sending this message doesn't appear - // to go through normal xlib machinery, but instead passes through the low - // level xProto (the x11 wire format) that I don't understand. - // - // I'm unsure if I have to jump through those hoops, or if XSendEvent is - // sufficient. - XSendEvent(xdisplay_, xid, x11::False, 0, xev); -} - -void DesktopDragDropClientAuraX11::ProcessMouseMove( - const gfx::Point& screen_point, - unsigned long event_time) { - if (source_state_ != SourceState::kOther) - return; - - // Find the current window the cursor is over. - ::Window dest_window = FindWindowFor(screen_point); - - if (source_current_window_ != dest_window) { - if (source_current_window_ != x11::None) - SendXdndLeave(source_current_window_); - - source_current_window_ = dest_window; - waiting_on_status_ = false; - next_position_message_.reset(); - status_received_since_enter_ = false; - negotiated_operation_ = ui::DragDropTypes::DRAG_NONE; - - if (source_current_window_ != x11::None) - SendXdndEnter(source_current_window_); - } - - if (source_current_window_ != x11::None) { - if (waiting_on_status_) { - next_position_message_ = - std::make_unique<std::pair<gfx::Point, unsigned long>>(screen_point, - event_time); - } else { - SendXdndPosition(dest_window, screen_point, event_time); - } - } -} - -void DesktopDragDropClientAuraX11::StartEndMoveLoopTimer() { - end_move_loop_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(1000), - this, &DesktopDragDropClientAuraX11::EndMoveLoop); -} - -void DesktopDragDropClientAuraX11::EndMoveLoop() { - move_loop_->EndMoveLoop(); -} - void DesktopDragDropClientAuraX11::DragTranslate( const gfx::Point& root_window_location, std::unique_ptr<ui::OSExchangeData>* data, @@ -1045,16 +278,17 @@ void DesktopDragDropClientAuraX11::DragTranslate( if (!*delegate) return; + DCHECK(target_current_context()); *data = std::make_unique<OSExchangeData>( std::make_unique<ui::OSExchangeDataProviderAuraX11>( - xwindow_, target_current_context_->fetched_targets())); + xwindow(), target_current_context()->fetched_targets())); gfx::Point location = root_location; aura::Window::ConvertPointToTarget(root_window_, target_window_, &location); target_window_location_ = location; target_window_root_location_ = root_location; - int drag_op = target_current_context_->GetDragOperation(); + int drag_op = target_current_context()->GetDragOperation(); // KDE-based file browsers such as Dolphin change the drag operation depending // on whether alt/ctrl/shift was pressed. However once Chromium gets control // over the X11 events, the source application does no longer receive X11 @@ -1069,11 +303,11 @@ void DesktopDragDropClientAuraX11::DragTranslate( *event = std::make_unique<ui::DropTargetEvent>( *(data->get()), gfx::PointF(location), gfx::PointF(root_location), drag_op); - if (target_current_context_->source_client()) { + if (target_current_context()->source_client()) { (*event)->set_flags( - target_current_context_->source_client()->current_modifier_state()); + target_current_context()->source_client()->current_modifier_state()); } else { - (*event)->set_flags(XGetModifiers()); + (*event)->set_flags(ui::XGetMaskAsEventFlags()); } if (target_window_changed) (*delegate)->OnDragEntered(*event->get()); @@ -1090,213 +324,106 @@ void DesktopDragDropClientAuraX11::NotifyDragLeave() { target_window_ = nullptr; } -::Atom DesktopDragDropClientAuraX11::DragOperationToAtom( - int drag_operation) { - if (drag_operation & ui::DragDropTypes::DRAG_COPY) - return gfx::GetAtom(kXdndActionCopy); - if (drag_operation & ui::DragDropTypes::DRAG_MOVE) - return gfx::GetAtom(kXdndActionMove); - if (drag_operation & ui::DragDropTypes::DRAG_LINK) - return gfx::GetAtom(kXdndActionLink); - - return x11::None; +std::unique_ptr<ui::XTopmostWindowFinder> +DesktopDragDropClientAuraX11::CreateWindowFinder() { + return std::make_unique<X11TopmostWindowFinder>(); } -ui::DragDropTypes::DragOperation -DesktopDragDropClientAuraX11::AtomToDragOperation(::Atom atom) { - if (atom == gfx::GetAtom(kXdndActionCopy)) - return ui::DragDropTypes::DRAG_COPY; - if (atom == gfx::GetAtom(kXdndActionMove)) - return ui::DragDropTypes::DRAG_MOVE; - if (atom == gfx::GetAtom(kXdndActionLink)) - return ui::DragDropTypes::DRAG_LINK; - - return ui::DragDropTypes::DRAG_NONE; -} - -std::vector<::Atom> DesktopDragDropClientAuraX11::GetOfferedDragOperations() { - std::vector<::Atom> operations; - if (drag_operation_ & ui::DragDropTypes::DRAG_COPY) - operations.push_back(gfx::GetAtom(kXdndActionCopy)); - if (drag_operation_ & ui::DragDropTypes::DRAG_MOVE) - operations.push_back(gfx::GetAtom(kXdndActionMove)); - if (drag_operation_ & ui::DragDropTypes::DRAG_LINK) - operations.push_back(gfx::GetAtom(kXdndActionLink)); - return operations; -} - -ui::SelectionFormatMap DesktopDragDropClientAuraX11::GetFormatMap() const { - return source_provider_ ? source_provider_->GetFormatMap() : - ui::SelectionFormatMap(); -} - -void DesktopDragDropClientAuraX11::CompleteXdndPosition( - ::Window source_window, - const gfx::Point& screen_point) { - int drag_operation = ui::DragDropTypes::DRAG_NONE; +int DesktopDragDropClientAuraX11::UpdateDrag(const gfx::Point& screen_point) { + // The drop target event holds a reference to data, that's why we have to hold + // the data until the event is handled. std::unique_ptr<ui::OSExchangeData> data; std::unique_ptr<ui::DropTargetEvent> drop_target_event; DragDropDelegate* delegate = nullptr; DragTranslate(screen_point, &data, &drop_target_event, &delegate); - if (delegate) - drag_operation = delegate->OnDragUpdated(*drop_target_event); + 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); - // Sends an XdndStatus message back to the source_window. l[2,3] - // theoretically represent an area in the window where the current action is - // the same as what we're returning, but I can't find any implementation that - // actually making use of this. A client can return (0, 0) and/or set the - // first bit of l[1] to disable the feature, and it appears that gtk neither - // sets this nor respects it if set. - XEvent xev; - xev.xclient.type = ClientMessage; - xev.xclient.message_type = gfx::GetAtom(kXdndStatus); - xev.xclient.format = 32; - xev.xclient.window = source_window; - xev.xclient.data.l[0] = xwindow_; - xev.xclient.data.l[1] = (drag_operation != 0) ? - (kWantFurtherPosEvents | kWillAcceptDrop) : 0; - xev.xclient.data.l[2] = 0; - xev.xclient.data.l[3] = 0; - xev.xclient.data.l[4] = DragOperationToAtom(drag_operation); - - SendXClientEvent(source_window, &xev); + return drag_operation; } -void DesktopDragDropClientAuraX11::SendXdndEnter(::Window dest_window) { - XEvent xev; - xev.xclient.type = ClientMessage; - xev.xclient.message_type = gfx::GetAtom(kXdndEnter); - xev.xclient.format = 32; - xev.xclient.window = dest_window; - xev.xclient.data.l[0] = xwindow_; - xev.xclient.data.l[1] = (kMaxXdndVersion << 24); // The version number. - xev.xclient.data.l[2] = 0; - xev.xclient.data.l[3] = 0; - xev.xclient.data.l[4] = 0; - - std::vector<Atom> targets; - source_provider_->RetrieveTargets(&targets); - - if (targets.size() > 3) { - xev.xclient.data.l[1] |= 1; - ui::SetAtomArrayProperty(xwindow_, kXdndTypeList, "ATOM", targets); - } else { - // Pack the targets into the enter message. - for (size_t i = 0; i < targets.size(); ++i) - xev.xclient.data.l[2 + i] = targets[i]; +void DesktopDragDropClientAuraX11::UpdateCursor( + ui::DragDropTypes::DragOperation negotiated_operation) { + ui::mojom::CursorType cursor_type = ui::mojom::CursorType::kNull; + switch (negotiated_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; } - - SendXClientEvent(dest_window, &xev); + move_loop_->UpdateCursor(cursor_manager_->GetInitializedCursor(cursor_type)); } -void DesktopDragDropClientAuraX11::SendXdndLeave(::Window dest_window) { - XEvent xev; - xev.xclient.type = ClientMessage; - xev.xclient.message_type = gfx::GetAtom(kXdndLeave); - xev.xclient.format = 32; - xev.xclient.window = dest_window; - xev.xclient.data.l[0] = xwindow_; - xev.xclient.data.l[1] = 0; - xev.xclient.data.l[2] = 0; - xev.xclient.data.l[3] = 0; - xev.xclient.data.l[4] = 0; - SendXClientEvent(dest_window, &xev); +void DesktopDragDropClientAuraX11::OnBeginForeignDrag(XID window) { + DCHECK(target_current_context()); + DCHECK(!target_current_context()->source_client()); + + ui::X11EventSource::GetInstance()->AddXEventDispatcher(this); + source_window_events_ = + std::make_unique<ui::XScopedEventSelector>(window, PropertyChangeMask); } -void DesktopDragDropClientAuraX11::SendXdndPosition( - ::Window dest_window, - const gfx::Point& screen_point, - unsigned long event_time) { - waiting_on_status_ = true; - - XEvent xev; - xev.xclient.type = ClientMessage; - xev.xclient.message_type = gfx::GetAtom(kXdndPosition); - xev.xclient.format = 32; - xev.xclient.window = dest_window; - xev.xclient.data.l[0] = xwindow_; - xev.xclient.data.l[1] = 0; - xev.xclient.data.l[2] = (screen_point.x() << 16) | screen_point.y(); - xev.xclient.data.l[3] = event_time; - xev.xclient.data.l[4] = DragOperationToAtom(drag_operation_); - SendXClientEvent(dest_window, &xev); - - // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html and - // the Xdnd protocol both recommend that drag events should be sent - // periodically. - repeat_mouse_move_timer_.Start( - FROM_HERE, base::TimeDelta::FromMilliseconds(350), - base::BindOnce(&DesktopDragDropClientAuraX11::ProcessMouseMove, - base::Unretained(this), screen_point, event_time)); +void DesktopDragDropClientAuraX11::OnEndForeignDrag() { + DCHECK(target_current_context()); + DCHECK(!target_current_context()->source_client()); + + ui::X11EventSource::GetInstance()->RemoveXEventDispatcher(this); } -void DesktopDragDropClientAuraX11::SendXdndDrop(::Window dest_window) { - XEvent xev; - xev.xclient.type = ClientMessage; - xev.xclient.message_type = gfx::GetAtom(kXdndDrop); - xev.xclient.format = 32; - xev.xclient.window = dest_window; - xev.xclient.data.l[0] = xwindow_; - xev.xclient.data.l[1] = 0; - xev.xclient.data.l[2] = x11::CurrentTime; - xev.xclient.data.l[3] = x11::None; - xev.xclient.data.l[4] = x11::None; - SendXClientEvent(dest_window, &xev); +void DesktopDragDropClientAuraX11::OnBeforeDragLeave() { + NotifyDragLeave(); } -void DesktopDragDropClientAuraX11::CreateDragWidget( - const gfx::ImageSkia& image) { - Widget* widget = new Widget; - Widget::InitParams params(Widget::InitParams::TYPE_DRAG); - if (ui::IsCompositingManagerPresent()) - params.opacity = Widget::InitParams::WindowOpacity::kTranslucent; - else - params.opacity = Widget::InitParams::WindowOpacity::kOpaque; - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.accept_events = false; +int DesktopDragDropClientAuraX11::PerformDrop() { + DCHECK(target_current_context()); - gfx::Point location = display::Screen::GetScreen()->GetCursorScreenPoint() - - drag_widget_offset_; - params.bounds = gfx::Rect(location, image.size()); - widget->set_focus_on_creation(false); - widget->set_frame_type(Widget::FrameType::kForceNative); - widget->Init(std::move(params)); - if (params.opacity == Widget::InitParams::WindowOpacity::kTranslucent) - widget->SetOpacity(kDragWidgetOpacity); - widget->GetNativeWindow()->SetName("DragWindow"); - - drag_image_size_ = image.size(); - ImageView* image_view = new ImageView(); - image_view->SetImage(image); - image_view->SetBoundsRect(gfx::Rect(drag_image_size_)); - widget->SetContentsView(image_view); - widget->Show(); - widget->GetNativeWindow()->layer()->SetFillsBoundsOpaquely(false); - - drag_widget_.reset(widget); -} + int drag_operation = ui::DragDropTypes::DRAG_NONE; + if (target_window_) { + aura::client::DragDropDelegate* delegate = + aura::client::GetDragDropDelegate(target_window_); + if (delegate) { + auto data(std::make_unique<ui::OSExchangeData>( + std::make_unique<ui::OSExchangeDataProviderAuraX11>( + xwindow(), target_current_context()->fetched_targets()))); -bool DesktopDragDropClientAuraX11::IsValidDragImage( - const gfx::ImageSkia& image) { - if (image.isNull()) - return false; + ui::DropTargetEvent drop_event( + *data.get(), gfx::PointF(target_window_location_), + gfx::PointF(target_window_root_location_), + target_current_context()->GetDragOperation()); + if (target_current_context()->source_client()) { + drop_event.set_flags(target_current_context() + ->source_client() + ->current_modifier_state()); + } else { + drop_event.set_flags(ui::XGetMaskAsEventFlags()); + } - // 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); + if (!IsDragDropInProgress()) { + UMA_HISTOGRAM_COUNTS_1M("Event.DragDrop.ExternalOriginDrop", 1); + } - for (int x = 0; x < in_bitmap->width(); ++x) { - if (SkColorGetA(in_row[x]) > kMinAlpha) - return true; + drag_operation = delegate->OnPerformDrop(drop_event, std::move(data)); } + + target_window_->RemoveObserver(this); + target_window_ = nullptr; } + return drag_operation; +} - return false; +void DesktopDragDropClientAuraX11::EndMoveLoop() { + move_loop_->EndMoveLoop(); } } // namespace views 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 f719b1ad8db..7ae53151b9e 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 @@ -9,15 +9,16 @@ #include <set> #include <vector> -#include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/timer/timer.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/drag_drop_types.h" +#include "ui/base/x/x11_drag_drop_client.h" #include "ui/events/event_constants.h" +#include "ui/events/platform/x11/x11_event_source.h" +#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/x11.h" @@ -28,20 +29,18 @@ namespace aura { namespace client { class DragDropClientObserver; class DragDropDelegate; -} -} +} // namespace client +} // namespace aura namespace gfx { -class ImageSkia; class Point; } namespace ui { class DropTargetEvent; class OSExchangeData; -class OSExchangeDataProviderAuraX11; -class SelectionFormatMap; -} +class XTopmostWindowFinder; +} // namespace ui namespace views { class DesktopNativeCursorManager; @@ -52,36 +51,23 @@ class X11MoveLoop; // X11 events forwarded from DesktopWindowTreeHostLinux, while on the other, it // handles the views drag events. class VIEWS_EXPORT DesktopDragDropClientAuraX11 - : public aura::client::DragDropClient, + : public ui::XDragDropClient, + public ui::XDragDropClient::Delegate, + public aura::client::DragDropClient, + public ui::XEventDispatcher, public aura::WindowObserver, public X11MoveLoopDelegate { public: DesktopDragDropClientAuraX11( aura::Window* root_window, views::DesktopNativeCursorManager* cursor_manager, - ::Display* xdisplay, - ::Window xwindow); + Display* xdisplay, + XID xwindow); ~DesktopDragDropClientAuraX11() override; - // We maintain a mapping of live DesktopDragDropClientAuraX11 objects to - // their ::Windows. We do this so that we're able to short circuit sending - // X11 messages to windows in our process. - static DesktopDragDropClientAuraX11* GetForWindow(::Window window); - void Init(); - // These methods handle the various X11 client messages from the platform. - void OnXdndEnter(const XClientMessageEvent& event); - void OnXdndLeave(const XClientMessageEvent& event); - void OnXdndPosition(const XClientMessageEvent& event); - void OnXdndStatus(const XClientMessageEvent& event); - void OnXdndFinished(const XClientMessageEvent& event); - void OnXdndDrop(const XClientMessageEvent& event); - - // Called when XSelection data has been copied to our process. - void OnSelectionNotify(const XSelectionEvent& xselection); - - // Overridden from aura::client::DragDropClient: + // aura::client::DragDropClient: int StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data, aura::Window* root_window, aura::Window* source_window, @@ -93,10 +79,13 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11 void AddObserver(aura::client::DragDropClientObserver* observer) override; void RemoveObserver(aura::client::DragDropClientObserver* observer) override; - // Overridden from aura::WindowObserver: + // XEventDispatcher: + bool DispatchXEvent(XEvent* event) override; + + // aura::WindowObserver: void OnWindowDestroyed(aura::Window* window) override; - // Overridden from X11WholeScreenMoveLoopDelegate: + // X11MoveLoopDelegate: void OnMouseMovement(const gfx::Point& screen_point, int flags, base::TimeTicks event_time) override; @@ -104,51 +93,15 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11 void OnMoveLoopEnded() override; protected: - // The following methods are virtual for the sake of testing. + // Getter for tests. + Widget* drag_widget() { return drag_widget_.get(); } - // Creates a move loop. + // Creates a move loop. Virtual for testing. virtual std::unique_ptr<X11MoveLoop> CreateMoveLoop( X11MoveLoopDelegate* delegate); - // Finds the topmost X11 window at |screen_point| and returns it if it is - // Xdnd aware. Returns NULL otherwise. - virtual ::Window FindWindowFor(const gfx::Point& screen_point); - - // Sends |xev| to |xid|, optionally short circuiting the round trip to the X - // server. - virtual void SendXClientEvent(::Window xid, XEvent* xev); - - protected: - Widget* drag_widget() { return drag_widget_.get(); } - private: - enum class SourceState { - // |source_current_window_| will receive a drop once we receive an - // XdndStatus from it. - kPendingDrop, - - // The move looped will be ended once we receive XdndFinished from - // |source_current_window_|. We should not send XdndPosition to - // |source_current_window_| while in this state. - kDropped, - - // There is no drag in progress or there is a drag in progress and the - // user has not yet released the mouse. - kOther, - }; - - // Processes a mouse move at |screen_point|. - void ProcessMouseMove(const gfx::Point& screen_point, - unsigned long event_time); - - // Start timer to end the move loop if the target is too slow to respond after - // the mouse is released. - void StartEndMoveLoopTimer(); - - // Ends the move loop. - void EndMoveLoop(); - - // When we receive an position x11 message, we need to translate that into + // When we receive a position X11 message, we need to translate that into // the underlying aura::Window representation, as moves internal to the X11 // window can cause internal drag leave and enter messages. void DragTranslate(const gfx::Point& root_window_location, @@ -156,52 +109,20 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11 std::unique_ptr<ui::DropTargetEvent>* event, aura::client::DragDropDelegate** delegate); - // Called when we need to notify the current aura::Window that we're no - // longer dragging over it. + // Notifies |target_window_|'s drag delegate that we're no longer dragging, + // then unsubscribes |target_window_| from ourselves and forgets it. void NotifyDragLeave(); - // Converts our bitfield of actions into an Atom that represents what action - // we're most likely to take on drop. - ::Atom DragOperationToAtom(int drag_operation); - - // Converts a single action atom to a drag operation. - ui::DragDropTypes::DragOperation AtomToDragOperation(::Atom atom); - - // During the blocking StartDragAndDrop() call, this converts the views-style - // |drag_operation_| bitfield into a vector of Atoms to offer to other - // processes. - std::vector< ::Atom> GetOfferedDragOperations(); - - // This returns a representation of the data we're offering in this - // drag. This is done to bypass an asynchronous roundtrip with the X11 - // server. - ui::SelectionFormatMap GetFormatMap() const; - - // Returns the modifier state for the most recent mouse move. This is done to - // bypass an asynchronous roundtrip with the X11 server. - int current_modifier_state() const { - return current_modifier_state_; - } - - // Handling XdndPosition can be paused while waiting for more data; this is - // called either synchronously from OnXdndPosition, or asynchronously after - // we've received data requested from the other window. - void CompleteXdndPosition(::Window source_window, - const gfx::Point& screen_point); - - void SendXdndEnter(::Window dest_window); - void SendXdndLeave(::Window dest_window); - void SendXdndPosition(::Window dest_window, - const gfx::Point& screen_point, - unsigned long event_time); - void SendXdndDrop(::Window dest_window); - - // Creates a widget for the user to drag around. - void CreateDragWidget(const gfx::ImageSkia& image); - - // Returns true if |image| has any visible regions (defined as having a pixel - // with alpha > 32). - bool IsValidDragImage(const gfx::ImageSkia& image); + // ui::XDragDropClient::Delegate + std::unique_ptr<ui::XTopmostWindowFinder> CreateWindowFinder() override; + int UpdateDrag(const gfx::Point& screen_point) override; + void UpdateCursor( + ui::DragDropTypes::DragOperation negotiated_operation) override; + void OnBeginForeignDrag(XID window) override; + void OnEndForeignDrag() override; + void OnBeforeDragLeave() override; + int PerformDrop() override; + void EndMoveLoop() override; // A nested run loop that notifies this object of events through the // X11MoveLoopDelegate interface. @@ -211,15 +132,8 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11 DesktopNativeCursorManager* cursor_manager_; - ::Display* xdisplay_; - ::Window xwindow_; - - // Target side information. - class X11DragContext; - std::unique_ptr<X11DragContext> target_current_context_; - - // The modifier state for the most recent mouse move. - int current_modifier_state_ = ui::EF_NONE; + // Events that we have selected on |source_window_|. + std::unique_ptr<ui::XScopedEventSelector> source_window_events_; // The Aura window that is currently under the cursor. We need to manually // keep track of this because Windows will only call our drag enter method @@ -234,50 +148,12 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11 gfx::Point target_window_location_; gfx::Point target_window_root_location_; - // In the Xdnd protocol, we aren't supposed to send another XdndPosition - // message until we have received a confirming XdndStatus message. - bool waiting_on_status_ = false; - - // If we would send an XdndPosition message while we're waiting for an - // XdndStatus response, we need to cache the latest details we'd send. - std::unique_ptr<std::pair<gfx::Point, unsigned long>> next_position_message_; - - // Reprocesses the most recent mouse move event if the mouse has not moved - // in a while in case the window stacking order has changed and - // |source_current_window_| needs to be updated. - base::OneShotTimer repeat_mouse_move_timer_; - - // When the mouse is released, we need to wait for the last XdndStatus message - // only if we have previously received a status message from - // |source_current_window_|. - bool status_received_since_enter_ = false; - - // Source side information. - ui::OSExchangeDataProviderAuraX11 const* source_provider_ = nullptr; - ::Window source_current_window_ = x11::None; - SourceState source_state_ = SourceState::kOther; - // The current drag-drop client that has an active operation. Since we have // multiple root windows and multiple DesktopDragDropClientAuraX11 instances // it is important to maintain only one drag and drop operation at any time. static DesktopDragDropClientAuraX11* g_current_drag_drop_client; - // The operation bitfield as requested by StartDragAndDrop. - int drag_operation_ = 0; - - // We offer the other window a list of possible operations, - // XdndActionsList. This is the requested action from the other window. This - // is DRAG_NONE if we haven't sent out an XdndPosition message yet, haven't - // yet received an XdndStatus or if the other window has told us that there's - // no action that we can agree on. - ui::DragDropTypes::DragOperation negotiated_operation_ = - ui::DragDropTypes::DRAG_NONE; - - // Ends the move loop if the target is too slow to respond after the mouse is - // released. - base::OneShotTimer end_move_loop_timer_; - - // Widget that the user drags around. May be NULL. + // Widget that the user drags around. May be nullptr. std::unique_ptr<Widget> drag_widget_; // The size of drag image. 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 e81a78ca57b..b188e6c9a40 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 @@ -4,12 +4,9 @@ #include <map> #include <memory> +#include <utility> #include <vector> -// Include views_test_base.h first because the definition of None in X.h -// conflicts with the definition of None in gtest-type-util.h -#include "ui/views/test/views_test_base.h" - #include "base/bind.h" #include "base/location.h" #include "base/macros.h" @@ -28,6 +25,7 @@ #include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11_atom_cache.h" #include "ui/gfx/x/x11_types.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" @@ -48,9 +46,7 @@ class ClientMessageEventCollector { virtual ~ClientMessageEventCollector(); // Returns true if |events_| is non-empty. - bool HasEvents() const { - return !events_.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 @@ -140,16 +136,13 @@ class TestDragDropClient : public SimpleTestDragDropClient { ~TestDragDropClient() override; // Returns the XID of the window which initiated the drag. - ::Window source_xwindow() { - return source_xid_; - } + ::Window source_xwindow() { return source_xid_; } // Returns the Atom with |name|. 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 XClientMessageEvent& event, const char* type); // Sets |collector| to collect XClientMessageEvents which would otherwise // have been sent to the drop target window. @@ -181,7 +174,7 @@ class TestDragDropClient : public SimpleTestDragDropClient { // Map of ::Windows to the collector which intercepts XClientMessageEvents // for that window. - std::map< ::Window, ClientMessageEventCollector*> collectors_; + std::map<::Window, ClientMessageEventCollector*> collectors_; DISALLOW_COPY_AND_ASSIGN(TestDragDropClient); }; @@ -192,8 +185,7 @@ class TestDragDropClient : public SimpleTestDragDropClient { ClientMessageEventCollector::ClientMessageEventCollector( ::Window xid, TestDragDropClient* client) - : xid_(xid), - client_(client) { + : xid_(xid), client_(client) { client->SetEventCollectorFor(xid, this); } @@ -224,9 +216,7 @@ bool TestMoveLoop::IsRunning() const { return is_running_; } -bool TestMoveLoop::RunMoveLoop( - aura::Window* window, - gfx::NativeCursor cursor) { +bool TestMoveLoop::RunMoveLoop(aura::Window* window, gfx::NativeCursor cursor) { is_running_ = true; base::RunLoop run_loop; quit_closure_ = run_loop.QuitClosure(); @@ -234,8 +224,7 @@ bool TestMoveLoop::RunMoveLoop( return true; } -void TestMoveLoop::UpdateCursor(gfx::NativeCursor cursor) { -} +void TestMoveLoop::UpdateCursor(gfx::NativeCursor cursor) {} void TestMoveLoop::EndMoveLoop() { if (is_running_) { @@ -397,9 +386,7 @@ class DesktopDragDropClientAuraX11Test : public ViewsTestBase { ViewsTestBase::TearDown(); } - TestDragDropClient* client() { - return client_.get(); - } + TestDragDropClient* client() { return client_.get(); } private: std::unique_ptr<TestDragDropClient> client_; @@ -425,17 +412,15 @@ void BasicStep2(TestDragDropClient* client, XID toplevel) { 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(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 long kCoords = + 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"), @@ -450,8 +435,7 @@ void BasicStep2(TestDragDropClient* client, XID toplevel) { 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])); + 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 @@ -793,9 +777,7 @@ class TestDragDropDelegate : public aura::client::DragDropDelegate { return ui::DragDropTypes::DRAG_COPY; } - void OnDragExited() override { - ++num_exits_; - } + void OnDragExited() override { ++num_exits_; } int OnPerformDrop(const ui::DropTargetEvent& event, std::unique_ptr<OSExchangeData> data) override { @@ -864,9 +846,7 @@ class DesktopDragDropClientAuraX11ChromeSourceTargetTest ViewsTestBase::TearDown(); } - SimpleTestDragDropClient* client() { - return client_.get(); - } + SimpleTestDragDropClient* client() { return client_.get(); } private: std::unique_ptr<SimpleTestDragDropClient> client_; 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 7f08e6a6141..1ed740d20ce 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 @@ -5,6 +5,7 @@ #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h" #include <memory> +#include <utility> #include "base/bind.h" #include "base/run_loop.h" @@ -20,6 +21,7 @@ #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/mojom/cursor_type.mojom-shared.h" #include "ui/platform_window/platform_window_delegate.h" #include "ui/platform_window/platform_window_handler/wm_drag_handler.h" #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h" @@ -78,7 +80,7 @@ int DesktopDragDropClientOzone::StartDragAndDrop( initial_cursor_ = source_window->GetHost()->last_cursor(); drag_operation_ = operation; cursor_client->SetCursor( - cursor_manager_->GetInitializedCursor(ui::CursorType::kGrabbing)); + cursor_manager_->GetInitializedCursor(ui::mojom::CursorType::kGrabbing)); drag_handler_->StartDrag( *data.get(), operation, cursor_client->GetCursor(), 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 984d4098eff..806e4a883a0 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 @@ -4,6 +4,8 @@ #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h" +#include <memory> + #include "base/metrics/histogram_macros.h" #include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/dragdrop/drag_source_win.h" 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 9e6208cb096..74c40adff7e 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 @@ -7,6 +7,8 @@ #include <wrl/client.h> +#include <memory> + #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/ref_counted.h" 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 052d82cbea1..a1703ed51c4 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 @@ -4,6 +4,8 @@ #include "ui/views/widget/desktop_aura/desktop_drop_target_win.h" +#include <utility> + #include "base/metrics/histogram_macros.h" #include "base/win/win_util.h" #include "ui/aura/client/drag_drop_client.h" @@ -22,8 +24,7 @@ using ui::OSExchangeDataProviderWin; namespace { -int ConvertKeyStateToAuraEventFlags(DWORD key_state) -{ +int ConvertKeyStateToAuraEventFlags(DWORD key_state) { int flags = 0; if (key_state & MK_CONTROL) diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.h b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.h index f13016028f1..88b92c66cc1 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.h @@ -15,12 +15,12 @@ namespace aura { namespace client { class DragDropDelegate; } -} +} // namespace aura namespace ui { class DropTargetEvent; class OSExchangeData; -} +} // namespace ui namespace views { diff --git a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc index ec25062629a..22339eed132 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc @@ -51,7 +51,7 @@ bool DesktopFocusRules::IsWindowConsideredVisibleForActivation( // |content_window_| is initially hidden and made visible from Show(). Even in // this state we still want it to be activatable. return BaseFocusRules::IsWindowConsideredVisibleForActivation(window) || - (window == content_window_); + (window == content_window_); } const aura::Window* DesktopFocusRules::GetToplevelWindow( diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc index d33e3209023..478b16bc606 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc @@ -9,6 +9,7 @@ #include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_tree_host.h" #include "ui/base/cursor/cursor_loader.h" +#include "ui/base/mojom/cursor_type.mojom-shared.h" namespace views { @@ -18,7 +19,7 @@ DesktopNativeCursorManager::DesktopNativeCursorManager() DesktopNativeCursorManager::~DesktopNativeCursorManager() = default; gfx::NativeCursor DesktopNativeCursorManager::GetInitializedCursor( - ui::CursorType type) { + ui::mojom::CursorType type) { gfx::NativeCursor cursor(type); cursor_loader_->SetPlatformCursor(&cursor); return cursor; @@ -63,7 +64,7 @@ void DesktopNativeCursorManager::SetVisibility( if (visible) { SetCursor(delegate->GetCursor(), delegate); } else { - gfx::NativeCursor invisible_cursor(ui::CursorType::kNone); + gfx::NativeCursor invisible_cursor(ui::mojom::CursorType::kNone); cursor_loader_->SetPlatformCursor(&invisible_cursor); for (auto* host : hosts_) host->SetCursor(invisible_cursor); diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h index 31cf5781ab5..fdb5d86b797 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h @@ -10,6 +10,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" +#include "ui/base/mojom/cursor_type.mojom-forward.h" #include "ui/views/views_export.h" #include "ui/wm/core/native_cursor_manager.h" @@ -30,15 +31,14 @@ namespace views { // A NativeCursorManager that performs the desktop-specific setting of cursor // state. Similar to NativeCursorManagerAsh, it also communicates these changes // to all root windows. -class VIEWS_EXPORT DesktopNativeCursorManager - : public wm::NativeCursorManager { +class VIEWS_EXPORT DesktopNativeCursorManager : public wm::NativeCursorManager { public: DesktopNativeCursorManager(); ~DesktopNativeCursorManager() override; // Builds a cursor and sets the internal platform representation. The return // value should not be cached. - gfx::NativeCursor GetInitializedCursor(ui::CursorType type); + gfx::NativeCursor GetInitializedCursor(ui::mojom::CursorType type); // Adds |host| to the set |hosts_|. void AddHost(aura::WindowTreeHost* host); diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc index 541a8197e4c..7578eef4f53 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc @@ -5,6 +5,7 @@ #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" #include <memory> +#include <utility> #include "base/auto_reset.h" #include "base/bind.h" @@ -110,9 +111,8 @@ class DesktopNativeWidgetTopLevelHandler : public aura::WindowObserver { init_params.bounds = bounds; init_params.ownership = Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET; init_params.layer_type = ui::LAYER_NOT_DRAWN; - init_params.activatable = full_screen ? - Widget::InitParams::ACTIVATABLE_YES : - Widget::InitParams::ACTIVATABLE_NO; + init_params.activatable = full_screen ? Widget::InitParams::ACTIVATABLE_YES + : Widget::InitParams::ACTIVATABLE_NO; init_params.z_order = root_z_order; // This widget instance will get deleted when the window is @@ -143,8 +143,7 @@ class DesktopNativeWidgetTopLevelHandler : public aura::WindowObserver { // If the widget is being destroyed by the OS then we should not try and // destroy it again. - if (top_level_widget_ && - window == top_level_widget_->GetNativeView()) { + if (top_level_widget_ && window == top_level_widget_->GetNativeView()) { top_level_widget_ = nullptr; return; } @@ -199,7 +198,7 @@ class DesktopNativeWidgetAuraWindowParentingClient aura::Window* GetDefaultParent(aura::Window* window, const gfx::Rect& bounds) override { bool is_fullscreen = window->GetProperty(aura::client::kShowStateKey) == - ui::SHOW_STATE_FULLSCREEN; + ui::SHOW_STATE_FULLSCREEN; bool is_menu = window->type() == aura::client::WINDOW_TYPE_MENU; if (is_fullscreen || is_menu) { @@ -226,7 +225,7 @@ class DesktopNativeWidgetAuraWindowParentingClient class RootWindowDestructionObserver : public aura::WindowObserver { public: explicit RootWindowDestructionObserver(DesktopNativeWidgetAura* parent) - : parent_(parent) {} + : parent_(parent) {} ~RootWindowDestructionObserver() override = default; private: @@ -482,7 +481,7 @@ void DesktopNativeWidgetAura::InitNativeWidget(Widget::InitParams params) { } host_.reset(desktop_window_tree_host_->AsWindowTreeHost()); } - desktop_window_tree_host_->Init(std::move(params)); + desktop_window_tree_host_->Init(params); host_->window()->AddChild(content_window_); host_->window()->SetProperty(kDesktopNativeWidgetAuraKey, this); @@ -540,8 +539,8 @@ void DesktopNativeWidgetAura::InitNativeWidget(Widget::InitParams params) { position_client_ = desktop_window_tree_host_->CreateScreenPositionClient(); - drag_drop_client_ = desktop_window_tree_host_->CreateDragDropClient( - native_cursor_manager_); + drag_drop_client_ = + desktop_window_tree_host_->CreateDragDropClient(native_cursor_manager_); // Mus returns null from CreateDragDropClient(). if (drag_drop_client_) aura::client::SetDragDropClient(host_->window(), drag_drop_client_.get()); @@ -686,7 +685,7 @@ void DesktopNativeWidgetAura::ReleaseCapture() { bool DesktopNativeWidgetAura::HasCapture() const { return content_window_ && content_window_->HasCapture() && - desktop_window_tree_host_->HasCapture(); + desktop_window_tree_host_->HasCapture(); } ui::InputMethod* DesktopNativeWidgetAura::GetInputMethod() { @@ -699,8 +698,8 @@ void DesktopNativeWidgetAura::CenterWindow(const gfx::Size& size) { } void DesktopNativeWidgetAura::GetWindowPlacement( - gfx::Rect* bounds, - ui::WindowShowState* maximized) const { + gfx::Rect* bounds, + ui::WindowShowState* maximized) const { if (content_window_) desktop_window_tree_host_->GetWindowPlacement(bounds, maximized); } @@ -728,23 +727,24 @@ void DesktopNativeWidgetAura::InitModalType(ui::ModalType modal_type) { } gfx::Rect DesktopNativeWidgetAura::GetWindowBoundsInScreen() const { - return content_window_ ? - desktop_window_tree_host_->GetWindowBoundsInScreen() : gfx::Rect(); + return content_window_ ? desktop_window_tree_host_->GetWindowBoundsInScreen() + : gfx::Rect(); } gfx::Rect DesktopNativeWidgetAura::GetClientAreaBoundsInScreen() const { - return content_window_ ? - desktop_window_tree_host_->GetClientAreaBoundsInScreen() : gfx::Rect(); + return content_window_ + ? desktop_window_tree_host_->GetClientAreaBoundsInScreen() + : gfx::Rect(); } gfx::Rect DesktopNativeWidgetAura::GetRestoredBounds() const { - return content_window_ ? - desktop_window_tree_host_->GetRestoredBounds() : gfx::Rect(); + return content_window_ ? desktop_window_tree_host_->GetRestoredBounds() + : gfx::Rect(); } std::string DesktopNativeWidgetAura::GetWorkspace() const { - return content_window_ ? - desktop_window_tree_host_->GetWorkspace() : std::string(); + return content_window_ ? desktop_window_tree_host_->GetWorkspace() + : std::string(); } void DesktopNativeWidgetAura::SetBounds(const gfx::Rect& bounds) { @@ -963,14 +963,15 @@ void DesktopNativeWidgetAura::ClearNativeFocus() { desktop_window_tree_host_->ClearNativeFocus(); if (ShouldActivate()) { - aura::client::GetFocusClient(content_window_)-> - ResetFocusWithinActiveWindow(content_window_); + aura::client::GetFocusClient(content_window_) + ->ResetFocusWithinActiveWindow(content_window_); } } gfx::Rect DesktopNativeWidgetAura::GetWorkAreaBoundsInScreen() const { - return desktop_window_tree_host_ ? - desktop_window_tree_host_->GetWorkAreaBoundsInScreen() : gfx::Rect(); + return desktop_window_tree_host_ + ? desktop_window_tree_host_->GetWorkAreaBoundsInScreen() + : gfx::Rect(); } Widget::MoveLoopResult DesktopNativeWidgetAura::RunMoveLoop( @@ -1021,7 +1022,7 @@ void DesktopNativeWidgetAura::SetVisibilityAnimationTransition( bool DesktopNativeWidgetAura::IsTranslucentWindowOpacitySupported() const { return content_window_ && - desktop_window_tree_host_->IsTranslucentWindowOpacitySupported(); + desktop_window_tree_host_->IsTranslucentWindowOpacitySupported(); } ui::GestureRecognizer* DesktopNativeWidgetAura::GetGestureRecognizer() { @@ -1034,6 +1035,10 @@ void DesktopNativeWidgetAura::OnSizeConstraintsChanged() { desktop_window_tree_host_->SizeConstraintsChanged(); } +void DesktopNativeWidgetAura::OnNativeViewHierarchyWillChange() {} + +void DesktopNativeWidgetAura::OnNativeViewHierarchyChanged() {} + std::string DesktopNativeWidgetAura::GetName() const { return name_; } @@ -1059,8 +1064,8 @@ int DesktopNativeWidgetAura::GetNonClientComponent( } bool DesktopNativeWidgetAura::ShouldDescendIntoChildForEventHandling( - aura::Window* child, - const gfx::Point& location) { + aura::Window* child, + const gfx::Point& location) { return native_widget_delegate_->ShouldDescendIntoChildForEventHandling( content_window_->layer(), child, child->layer(), location); } @@ -1091,8 +1096,7 @@ void DesktopNativeWidgetAura::OnWindowDestroyed(aura::Window* window) { // here. } -void DesktopNativeWidgetAura::OnWindowTargetVisibilityChanged(bool visible) { -} +void DesktopNativeWidgetAura::OnWindowTargetVisibilityChanged(bool visible) {} bool DesktopNativeWidgetAura::HasHitTestMask() const { return native_widget_delegate_->HasHitTestMask(); @@ -1205,14 +1209,14 @@ void DesktopNativeWidgetAura::OnWindowFocused(aura::Window* gained_focus, void DesktopNativeWidgetAura::OnDragEntered(const ui::DropTargetEvent& event) { DCHECK(drop_helper_.get() != nullptr); - last_drop_operation_ = drop_helper_->OnDragOver(event.data(), - event.location(), event.source_operations()); + last_drop_operation_ = drop_helper_->OnDragOver( + event.data(), event.location(), event.source_operations()); } int DesktopNativeWidgetAura::OnDragUpdated(const ui::DropTargetEvent& event) { DCHECK(drop_helper_.get() != nullptr); - last_drop_operation_ = drop_helper_->OnDragOver(event.data(), - event.location(), event.source_operations()); + last_drop_operation_ = drop_helper_->OnDragOver( + event.data(), event.location(), event.source_operations()); return last_drop_operation_; } @@ -1228,7 +1232,7 @@ int DesktopNativeWidgetAura::OnPerformDrop( if (ShouldActivate()) Activate(); return drop_helper_->OnDrop(event.data(), event.location(), - last_drop_operation_); + last_drop_operation_); } //////////////////////////////////////////////////////////////////////////////// diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h index 4e47c9230f8..89f7d22cbcb 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h @@ -5,6 +5,7 @@ #ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_NATIVE_WIDGET_AURA_H_ #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_NATIVE_WIDGET_AURA_H_ +#include <memory> #include <string> #include "base/macros.h" @@ -26,8 +27,8 @@ namespace client { class DragDropClient; class ScreenPositionClient; class WindowParentingClient; -} -} +} // namespace client +} // namespace aura namespace wm { class CompoundEventFilter; @@ -36,7 +37,7 @@ class FocusController; class ShadowController; class VisibilityController; class WindowModalityController; -} +} // namespace wm namespace views { namespace corewm { @@ -87,9 +88,7 @@ class VIEWS_EXPORT DesktopNativeWidgetAura wm::CompoundEventFilter* root_window_event_filter() { return root_window_event_filter_.get(); } - aura::WindowTreeHost* host() { - return host_.get(); - } + aura::WindowTreeHost* host() { return host_.get(); } aura::Window* content_window() { return content_window_; } @@ -107,7 +106,7 @@ class VIEWS_EXPORT DesktopNativeWidgetAura void UpdateWindowTransparency(); protected: - // Overridden from internal::NativeWidgetPrivate: + // internal::NativeWidgetPrivate: void InitNativeWidget(Widget::InitParams params) override; void OnWidgetInitDone() override; NonClientFrameView* CreateNonClientFrameView() override; @@ -195,9 +194,11 @@ class VIEWS_EXPORT DesktopNativeWidgetAura bool IsTranslucentWindowOpacitySupported() const override; ui::GestureRecognizer* GetGestureRecognizer() override; void OnSizeConstraintsChanged() override; + void OnNativeViewHierarchyWillChange() override; + void OnNativeViewHierarchyChanged() override; std::string GetName() const override; - // Overridden from aura::WindowDelegate: + // aura::WindowDelegate: gfx::Size GetMinimumSize() const override; gfx::Size GetMaximumSize() const override; void OnBoundsChanged(const gfx::Rect& old_bounds, @@ -219,32 +220,32 @@ class VIEWS_EXPORT DesktopNativeWidgetAura void GetHitTestMask(SkPath* mask) const override; void UpdateVisualState() override; - // Overridden from ui::EventHandler: + // ui::EventHandler: void OnKeyEvent(ui::KeyEvent* event) override; void OnMouseEvent(ui::MouseEvent* event) override; void OnScrollEvent(ui::ScrollEvent* event) override; void OnGestureEvent(ui::GestureEvent* event) override; - // Overridden from wm::ActivationDelegate: + // wm::ActivationDelegate: bool ShouldActivate() const override; - // Overridden from wm::ActivationChangeObserver: + // wm::ActivationChangeObserver: void OnWindowActivated(wm::ActivationChangeObserver::ActivationReason reason, aura::Window* gained_active, aura::Window* lost_active) override; - // Overridden from aura::client::FocusChangeObserver: + // aura::client::FocusChangeObserver: void OnWindowFocused(aura::Window* gained_focus, aura::Window* lost_focus) override; - // Overridden from aura::client::DragDropDelegate: + // ura::client::DragDropDelegate: void OnDragEntered(const ui::DropTargetEvent& event) override; int OnDragUpdated(const ui::DropTargetEvent& event) override; void OnDragExited() override; int OnPerformDrop(const ui::DropTargetEvent& event, std::unique_ptr<ui::OSExchangeData> data) override; - // Overridden from aura::WindowTreeHostObserver: + // aura::WindowTreeHostObserver: void OnHostCloseRequested(aura::WindowTreeHost* host) override; void OnHostResized(aura::WindowTreeHost* host) override; void OnHostWorkspaceChanged(aura::WindowTreeHost* host) override; diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc index e3bfa420e30..a28f778d4a5 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc @@ -4,6 +4,9 @@ #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" +#include <memory> +#include <utility> + #include "base/bind.h" #include "base/macros.h" #include "base/run_loop.h" @@ -19,6 +22,7 @@ #include "ui/aura/test/window_occlusion_tracker_test_api.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" +#include "ui/base/mojom/cursor_type.mojom-shared.h" #include "ui/display/screen.h" #include "ui/events/event_processor.h" #include "ui/events/event_utils.h" @@ -66,8 +70,7 @@ TEST_F(DesktopNativeWidgetAuraTest, DesktopAuraWindowSizeTest) { // On Linux we test this with popup windows because the WM may ignore the size // suggestion for normal windows. #if defined(OS_LINUX) - Widget::InitParams init_params = - CreateParams(Widget::InitParams::TYPE_POPUP); + Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); #else Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); @@ -220,14 +223,14 @@ TEST_F(DesktopNativeWidgetAuraTest, MAYBE_GlobalCursorState) { // Verify that setting the cursor using one cursor client // will set it for all root windows. - EXPECT_EQ(ui::CursorType::kNone, cursor_client_a->GetCursor().native_type()); - EXPECT_EQ(ui::CursorType::kNone, cursor_client_b->GetCursor().native_type()); + EXPECT_EQ(ui::mojom::CursorType::kNone, cursor_client_a->GetCursor().type()); + EXPECT_EQ(ui::mojom::CursorType::kNone, cursor_client_b->GetCursor().type()); - cursor_client_b->SetCursor(ui::CursorType::kPointer); - EXPECT_EQ(ui::CursorType::kPointer, - cursor_client_a->GetCursor().native_type()); - EXPECT_EQ(ui::CursorType::kPointer, - cursor_client_b->GetCursor().native_type()); + cursor_client_b->SetCursor(ui::mojom::CursorType::kPointer); + EXPECT_EQ(ui::mojom::CursorType::kPointer, + cursor_client_a->GetCursor().type()); + EXPECT_EQ(ui::mojom::CursorType::kPointer, + cursor_client_b->GetCursor().type()); // Verify that hiding the cursor using one cursor client will // hide it for all root windows. Note that hiding the cursor @@ -405,8 +408,7 @@ class DesktopAuraTopLevelWindowTest : public aura::WindowObserver { } owned_window_->Init(ui::LAYER_TEXTURED); aura::client::ParentWindowWithContext( - owned_window_, - widget_.GetNativeView()->GetRootWindow(), + owned_window_, widget_.GetNativeView()->GetRootWindow(), gfx::Rect(0, 0, 1900, 1600)); owned_window_->Show(); owned_window_->AddObserver(this); @@ -447,17 +449,11 @@ class DesktopAuraTopLevelWindowTest : public aura::WindowObserver { } } - aura::Window* owned_window() { - return owned_window_; - } + aura::Window* owned_window() { return owned_window_; } - views::Widget* top_level_widget() { - return top_level_widget_; - } + views::Widget* top_level_widget() { return top_level_widget_; } - void set_use_async_mode(bool async_mode) { - use_async_mode_ = async_mode; - } + void set_use_async_mode(bool async_mode) { use_async_mode_ = async_mode; } private: views::Widget widget_; @@ -477,8 +473,8 @@ using DesktopAuraWidgetTest = DesktopWidgetTest; TEST_F(DesktopAuraWidgetTest, FullscreenWindowDestroyedBeforeOwnerTest) { DesktopAuraTopLevelWindowTest fullscreen_window; - ASSERT_NO_FATAL_FAILURE(fullscreen_window.CreateTopLevelWindow( - gfx::Rect(0, 0, 200, 200), true)); + ASSERT_NO_FATAL_FAILURE( + fullscreen_window.CreateTopLevelWindow(gfx::Rect(0, 0, 200, 200), true)); RunPendingMessages(); ASSERT_NO_FATAL_FAILURE(fullscreen_window.DestroyOwnedWindow()); @@ -487,8 +483,8 @@ TEST_F(DesktopAuraWidgetTest, FullscreenWindowDestroyedBeforeOwnerTest) { TEST_F(DesktopAuraWidgetTest, FullscreenWindowOwnerDestroyed) { DesktopAuraTopLevelWindowTest fullscreen_window; - ASSERT_NO_FATAL_FAILURE(fullscreen_window.CreateTopLevelWindow( - gfx::Rect(0, 0, 200, 200), true)); + ASSERT_NO_FATAL_FAILURE( + fullscreen_window.CreateTopLevelWindow(gfx::Rect(0, 0, 200, 200), true)); RunPendingMessages(); ASSERT_NO_FATAL_FAILURE(fullscreen_window.DestroyOwnerWindow()); @@ -497,8 +493,8 @@ TEST_F(DesktopAuraWidgetTest, FullscreenWindowOwnerDestroyed) { TEST_F(DesktopAuraWidgetTest, TopLevelOwnedPopupTest) { DesktopAuraTopLevelWindowTest popup_window; - ASSERT_NO_FATAL_FAILURE(popup_window.CreateTopLevelWindow( - gfx::Rect(0, 0, 200, 200), false)); + ASSERT_NO_FATAL_FAILURE( + popup_window.CreateTopLevelWindow(gfx::Rect(0, 0, 200, 200), false)); RunPendingMessages(); ASSERT_NO_FATAL_FAILURE(popup_window.DestroyOwnedWindow()); @@ -512,8 +508,8 @@ TEST_F(DesktopAuraWidgetTest, TopLevelOwnedPopupResizeTest) { popup_window.set_use_async_mode(false); - ASSERT_NO_FATAL_FAILURE(popup_window.CreateTopLevelWindow( - gfx::Rect(0, 0, 200, 200), false)); + ASSERT_NO_FATAL_FAILURE( + popup_window.CreateTopLevelWindow(gfx::Rect(0, 0, 200, 200), false)); gfx::Rect new_size(0, 0, 400, 400); popup_window.owned_window()->SetBounds(new_size); @@ -531,8 +527,8 @@ TEST_F(DesktopAuraWidgetTest, TopLevelOwnedPopupRepositionTest) { popup_window.set_use_async_mode(false); - ASSERT_NO_FATAL_FAILURE(popup_window.CreateTopLevelWindow( - gfx::Rect(0, 0, 200, 200), false)); + ASSERT_NO_FATAL_FAILURE( + popup_window.CreateTopLevelWindow(gfx::Rect(0, 0, 200, 200), false)); gfx::Rect new_pos(10, 10, 400, 400); popup_window.owned_window()->SetBoundsInScreen( @@ -733,9 +729,7 @@ TEST_F(DesktopWidgetTest, WindowModalityActivationTest) { EXPECT_TRUE(modal_dialog_widget->IsVisible()); LRESULT activate_result = ::SendMessage( - win32_window, - WM_MOUSEACTIVATE, - reinterpret_cast<WPARAM>(win32_window), + win32_window, WM_MOUSEACTIVATE, reinterpret_cast<WPARAM>(win32_window), MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT)); EXPECT_EQ(activate_result, MA_ACTIVATE); diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc index b889969ec97..2406d29e9b4 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc @@ -22,15 +22,7 @@ bool PositionWindowInScreenCoordinates(aura::Window* window) { } // namespace -DesktopScreenPositionClient::DesktopScreenPositionClient( - aura::Window* root_window) - : root_window_(root_window) { - aura::client::SetScreenPositionClient(root_window_, this); -} - -DesktopScreenPositionClient::~DesktopScreenPositionClient() { - aura::client::SetScreenPositionClient(root_window_, nullptr); -} +DesktopScreenPositionClient::~DesktopScreenPositionClient() = default; void DesktopScreenPositionClient::SetBounds(aura::Window* window, const gfx::Rect& bounds, diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.h b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.h index 33fbdc2ef8d..586ac072643 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.h @@ -16,7 +16,7 @@ namespace views { class VIEWS_EXPORT DesktopScreenPositionClient : public wm::DefaultScreenPositionClient { public: - explicit DesktopScreenPositionClient(aura::Window* root_window); + using DefaultScreenPositionClient::DefaultScreenPositionClient; ~DesktopScreenPositionClient() override; // aura::client::DefaultScreenPositionClient: @@ -25,8 +25,6 @@ class VIEWS_EXPORT DesktopScreenPositionClient const display::Display& display) override; private: - aura::Window* root_window_; - DISALLOW_COPY_AND_ASSIGN(DesktopScreenPositionClient); }; 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 87299feba93..e17fe7611d7 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h @@ -12,7 +12,7 @@ namespace views { class VIEWS_EXPORT DesktopScreenWin : public display::win::ScreenWin { -public: + public: DesktopScreenWin(); ~DesktopScreenWin() override; 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 6ca1be4cc9e..0ffdc450043 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc @@ -4,6 +4,8 @@ #include "ui/views/widget/desktop_aura/desktop_screen_x11.h" +#include <vector> + #include "base/command_line.h" #include "base/trace_event/trace_event.h" #include "ui/aura/window.h" @@ -15,72 +17,41 @@ #include "ui/display/display.h" #include "ui/display/display_finder.h" #include "ui/display/util/display_util.h" -#include "ui/events/platform/platform_event_source.h" -#include "ui/events/platform/x11/x11_event_source.h" #include "ui/gfx/font_render_params.h" #include "ui/gfx/geometry/dip_util.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/switches.h" -#include "ui/views/linux_ui/linux_ui.h" #include "ui/views/widget/desktop_aura/desktop_screen.h" #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h" #include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h" -namespace { - -float GetDeviceScaleFactor() { - float device_scale_factor = 1.0f; - if (views::LinuxUI::instance()) { - device_scale_factor = views::LinuxUI::instance()->GetDeviceScaleFactor(); - } else if (display::Display::HasForceDeviceScaleFactor()) { - device_scale_factor = display::Display::GetForcedDeviceScaleFactor(); - } - return device_scale_factor; -} - -} // namespace - namespace views { -//////////////////////////////////////////////////////////////////////////////// -// DesktopScreenX11, public: - -DesktopScreenX11::DesktopScreenX11() - : x11_display_manager_(std::make_unique<ui::XDisplayManager>(this)) { - if (auto* linux_ui = views::LinuxUI::instance()) - linux_ui->AddDeviceScaleFactorObserver(this); +DesktopScreenX11::DesktopScreenX11() { + if (LinuxUI::instance()) + display_scale_factor_observer_.Add(LinuxUI::instance()); } -DesktopScreenX11::~DesktopScreenX11() { - if (auto* linux_ui = views::LinuxUI::instance()) - linux_ui->RemoveDeviceScaleFactorObserver(this); - if (x11_display_manager_->IsXrandrAvailable() && - ui::PlatformEventSource::GetInstance()) { - ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); - } -} +DesktopScreenX11::~DesktopScreenX11() = default; void DesktopScreenX11::Init() { if (x11_display_manager_->IsXrandrAvailable() && - ui::PlatformEventSource::GetInstance()) { - ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); - } + ui::X11EventSource::HasInstance()) + event_source_observer_.Add(ui::X11EventSource::GetInstance()); x11_display_manager_->Init(); } -//////////////////////////////////////////////////////////////////////////////// -// DesktopScreenX11, display::Screen implementation: - gfx::Point DesktopScreenX11::GetCursorScreenPoint() { TRACE_EVENT0("views", "DesktopScreenX11::GetCursorScreenPoint()"); - if (auto* event_source = ui::X11EventSource::GetInstance()) { - auto point = event_source->GetRootCursorLocationFromCurrentEvent(); - if (point) - return gfx::ConvertPointToDIP(GetDeviceScaleFactor(), point.value()); - } - return gfx::ConvertPointToDIP(GetDeviceScaleFactor(), - x11_display_manager_->GetCursorLocation()); + base::Optional<gfx::Point> point; + if (const auto* const event_source = ui::X11EventSource::GetInstance()) + point = event_source->GetRootCursorLocationFromCurrentEvent(); + return gfx::ConvertPointToDIP( + GetXDisplayScaleFactor(), + // NB: Do NOT call value_or() here, since that would defeat the purpose of + // caching |point|. + point ? point.value() : x11_display_manager_->GetCursorLocation()); } bool DesktopScreenX11::IsWindowUnderCursor(gfx::NativeWindow window) { @@ -89,13 +60,12 @@ bool DesktopScreenX11::IsWindowUnderCursor(gfx::NativeWindow window) { gfx::NativeWindow DesktopScreenX11::GetWindowAtScreenPoint( const gfx::Point& point) { - X11TopmostWindowFinder finder; - return finder.FindLocalProcessWindowAt( - gfx::ConvertPointToPixel(GetDeviceScaleFactor(), point), {}); + return X11TopmostWindowFinder().FindLocalProcessWindowAt( + gfx::ConvertPointToPixel(GetXDisplayScaleFactor(), point), {}); } int DesktopScreenX11::GetNumDisplays() const { - return x11_display_manager_->displays().size(); + return int{x11_display_manager_->displays().size()}; } const std::vector<display::Display>& DesktopScreenX11::GetAllDisplays() const { @@ -104,9 +74,6 @@ const std::vector<display::Display>& DesktopScreenX11::GetAllDisplays() const { display::Display DesktopScreenX11::GetDisplayNearestWindow( gfx::NativeView window) const { - if (!window) - return GetPrimaryDisplay(); - // Getting screen bounds here safely is hard. // // You'd think we'd be able to just call window->GetBoundsInScreen(), but we @@ -116,15 +83,14 @@ display::Display DesktopScreenX11::GetDisplayNearestWindow( // created before we create the aura::WindowEventDispatcher. So we ask what // the DRWHX11 believes the window bounds are instead of going through the // aura::Window's screen bounds. - aura::WindowTreeHost* host = window->GetHost(); - if (host) { - auto* rwh = DesktopWindowTreeHostLinux::GetHostForWidget( - host->GetAcceleratedWidget()); - if (rwh) { - const gfx::Rect pixel_rect = rwh->GetBoundsInPixels(); - const gfx::Rect dip_rect = - gfx::ConvertRectToDIP(GetDeviceScaleFactor(), pixel_rect); - return GetDisplayMatching(dip_rect); + if (aura::WindowTreeHost* host = window ? window->GetHost() : nullptr) { + const auto* const desktop_host = + DesktopWindowTreeHostLinux::GetHostForWidget( + host->GetAcceleratedWidget()); + if (desktop_host) { + const gfx::Rect pixel_rect = desktop_host->GetBoundsInPixels(); + return GetDisplayMatching( + gfx::ConvertRectToDIP(GetXDisplayScaleFactor(), pixel_rect)); } } @@ -133,16 +99,15 @@ display::Display DesktopScreenX11::GetDisplayNearestWindow( display::Display DesktopScreenX11::GetDisplayNearestPoint( const gfx::Point& point) const { - if (GetNumDisplays() <= 1) - return GetPrimaryDisplay(); - return *FindDisplayNearestPoint(GetAllDisplays(), point); + return (GetNumDisplays() <= 1) + ? GetPrimaryDisplay() + : *FindDisplayNearestPoint(GetAllDisplays(), point); } display::Display DesktopScreenX11::GetDisplayMatching( const gfx::Rect& match_rect) const { - const display::Display* matching = + const display::Display* const matching = display::FindDisplayWithBiggestIntersection(GetAllDisplays(), match_rect); - // Fallback to the primary display if there is no matching display. return matching ? *matching : GetPrimaryDisplay(); } @@ -158,13 +123,13 @@ void DesktopScreenX11::RemoveObserver(display::DisplayObserver* observer) { x11_display_manager_->RemoveObserver(observer); } -bool DesktopScreenX11::CanDispatchEvent(const ui::PlatformEvent& event) { - return x11_display_manager_->CanProcessEvent(*event); +std::string DesktopScreenX11::GetCurrentWorkspace() { + return x11_display_manager_->GetCurrentWorkspace(); } -uint32_t DesktopScreenX11::DispatchEvent(const ui::PlatformEvent& event) { - ignore_result(x11_display_manager_->ProcessEvent(event)); - return ui::POST_DISPATCH_NONE; +bool DesktopScreenX11::DispatchXEvent(XEvent* event) { + return x11_display_manager_->CanProcessEvent(*event) && + x11_display_manager_->ProcessEvent(event); } void DesktopScreenX11::OnDeviceScaleFactorChanged() { @@ -173,21 +138,21 @@ void DesktopScreenX11::OnDeviceScaleFactorChanged() { // static void DesktopScreenX11::UpdateDeviceScaleFactorForTest() { - DesktopScreenX11* screen = - static_cast<DesktopScreenX11*>(display::Screen::GetScreen()); + auto* screen = static_cast<DesktopScreenX11*>(display::Screen::GetScreen()); screen->x11_display_manager_->UpdateDisplayList(); } -//////////////////////////////////////////////////////////////////////////////// -// DesktopScreenX11, private: - void DesktopScreenX11::OnXDisplayListUpdated() { gfx::SetFontRenderParamsDeviceScaleFactor( GetPrimaryDisplay().device_scale_factor()); } -float DesktopScreenX11::GetXDisplayScaleFactor() { - return GetDeviceScaleFactor(); +float DesktopScreenX11::GetXDisplayScaleFactor() const { + if (LinuxUI::instance()) + return LinuxUI::instance()->GetDeviceScaleFactor(); + return display::Display::HasForceDeviceScaleFactor() + ? display::Display::GetForcedDeviceScaleFactor() + : 1.0f; } //////////////////////////////////////////////////////////////////////////////// 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 9a5814ce14f..dcf3e0f725e 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h @@ -5,15 +5,15 @@ #ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_X11_H_ #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_X11_H_ -#include <stdint.h> - #include <memory> +#include <vector> -#include "base/macros.h" +#include "base/scoped_observer.h" #include "ui/base/x/x11_display_manager.h" #include "ui/display/screen.h" -#include "ui/events/platform/platform_event_dispatcher.h" +#include "ui/events/platform/x11/x11_event_source.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" namespace views { @@ -25,9 +25,9 @@ class DesktopScreenX11TestApi; // Screen implementation that talks to XRandR class VIEWS_EXPORT DesktopScreenX11 : public display::Screen, - public ui::PlatformEventDispatcher, + public ui::XEventDispatcher, public ui::XDisplayManager::Delegate, - public views::DeviceScaleFactorObserver { + public DeviceScaleFactorObserver { public: DesktopScreenX11(); ~DesktopScreenX11() override; @@ -36,7 +36,7 @@ class VIEWS_EXPORT DesktopScreenX11 : public display::Screen, // fetching might not be desirable in some scenarios (e.g: unit tests) void Init(); - // Overridden from display::Screen: + // display::Screen: gfx::Point GetCursorScreenPoint() override; bool IsWindowUnderCursor(gfx::NativeWindow window) override; gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) override; @@ -51,12 +51,12 @@ class VIEWS_EXPORT DesktopScreenX11 : public display::Screen, display::Display GetPrimaryDisplay() const override; void AddObserver(display::DisplayObserver* observer) override; void RemoveObserver(display::DisplayObserver* observer) override; + std::string GetCurrentWorkspace() override; - // ui::PlatformEventDispatcher: - bool CanDispatchEvent(const ui::PlatformEvent& event) override; - uint32_t DispatchEvent(const ui::PlatformEvent& event) override; + // ui::XEventDispatcher: + bool DispatchXEvent(XEvent* event) override; - // views::DeviceScaleFactorObserver: + // DeviceScaleFactorObserver: void OnDeviceScaleFactorChanged() override; static void UpdateDeviceScaleFactorForTest(); @@ -65,13 +65,22 @@ class VIEWS_EXPORT DesktopScreenX11 : public display::Screen, friend class DesktopScreenX11Test; friend class test::DesktopScreenX11TestApi; - // ui::XDisplayManager::Delegate + // ui::XDisplayManager::Delegate: void OnXDisplayListUpdated() override; - float GetXDisplayScaleFactor() override; - - std::unique_ptr<ui::XDisplayManager> x11_display_manager_; - - DISALLOW_COPY_AND_ASSIGN(DesktopScreenX11); + float GetXDisplayScaleFactor() const override; + + std::unique_ptr<ui::XDisplayManager> x11_display_manager_ = + std::make_unique<ui::XDisplayManager>(this); + ScopedObserver<LinuxUI, + DeviceScaleFactorObserver, + &LinuxUI::AddDeviceScaleFactorObserver, + &LinuxUI::RemoveDeviceScaleFactorObserver> + display_scale_factor_observer_{this}; + ScopedObserver<ui::X11EventSource, + XEventDispatcher, + &ui::X11EventSource::AddXEventDispatcher, + &ui::X11EventSource::RemoveXEventDispatcher> + event_source_observer_{this}; }; } // namespace views diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc index b5183989b5e..d284138d2a9 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc @@ -7,6 +7,7 @@ #include <stdint.h> #include <memory> +#include <utility> #include <vector> #include "base/macros.h" diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h index da8caf2e499..9e15a572258 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h @@ -6,6 +6,7 @@ #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_H_ #include <memory> +#include <string> #include "ui/aura/window_event_dispatcher.h" #include "ui/base/ui_base_types.h" 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 7705e7b4135..91cfaf77bb3 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 @@ -4,6 +4,12 @@ #include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h" +#include <algorithm> +#include <list> +#include <memory> +#include <string> +#include <vector> + #include "ui/aura/null_window_targeter.h" #include "ui/aura/scoped_window_targeter.h" #include "ui/aura/window.h" @@ -119,10 +125,6 @@ void DesktopWindowTreeHostLinux::CleanUpWindowList( open_windows_ = nullptr; } -void DesktopWindowTreeHostLinux::SetPendingXVisualId(int x_visual_id) { - pending_x_visual_id_ = x_visual_id; -} - gfx::Rect DesktopWindowTreeHostLinux::GetXRootWindowOuterBounds() const { // TODO(msisov): must be removed as soon as all X11 low-level bits are moved // to Ozone. @@ -291,6 +293,14 @@ void DesktopWindowTreeHostLinux::OnActivationChanged(bool active) { DesktopWindowTreeHostPlatform::OnActivationChanged(active); } +ui::X11Extension* DesktopWindowTreeHostLinux::GetX11Extension() { + return ui::GetX11Extension(*(platform_window())); +} + +const ui::X11Extension* DesktopWindowTreeHostLinux::GetX11Extension() const { + return ui::GetX11Extension(*(platform_window())); +} + #if BUILDFLAG(USE_ATK) bool DesktopWindowTreeHostLinux::OnAtkKeyEvent(AtkKeyEventStruct* atk_event) { if (!IsActive() && !HasCapture()) @@ -300,6 +310,11 @@ bool DesktopWindowTreeHostLinux::OnAtkKeyEvent(AtkKeyEventStruct* atk_event) { } #endif +bool DesktopWindowTreeHostLinux::IsOverrideRedirect() const { + // BrowserDesktopWindowTreeHostLinux implements this for browser windows. + return false; +} + void DesktopWindowTreeHostLinux::AddAdditionalInitProperties( const Widget::InitParams& params, ui::PlatformWindowInitProperties* properties) { @@ -333,8 +348,6 @@ void DesktopWindowTreeHostLinux::AddAdditionalInitProperties( properties->wm_class_class = params.wm_class_class; properties->wm_role_name = params.wm_role_name; - properties->x_visual_id = pending_x_visual_id_; - DCHECK(!properties->x11_extension_delegate); properties->x11_extension_delegate = this; } @@ -355,10 +368,6 @@ void DesktopWindowTreeHostLinux::DestroyNonClientEventFilter() { non_client_window_event_filter_.reset(); } -void DesktopWindowTreeHostLinux::OnXWindowMapped() {} - -void DesktopWindowTreeHostLinux::OnXWindowUnmapped() {} - void DesktopWindowTreeHostLinux::GetWindowMask(const gfx::Size& size, SkPath* window_mask) { DCHECK(window_mask); @@ -380,14 +389,6 @@ void DesktopWindowTreeHostLinux::EnableEventListening() { targeter_for_modal_.reset(); } -ui::X11Extension* DesktopWindowTreeHostLinux::GetX11Extension() { - return ui::GetX11Extension(*(platform_window())); -} - -const ui::X11Extension* DesktopWindowTreeHostLinux::GetX11Extension() const { - return ui::GetX11Extension(*(platform_window())); -} - std::list<gfx::AcceleratedWidget>& DesktopWindowTreeHostLinux::open_windows() { if (!open_windows_) open_windows_ = new std::list<gfx::AcceleratedWidget>(); 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 99cc4190f27..1351c2a66c4 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 @@ -5,6 +5,11 @@ #ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_LINUX_H_ #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_LINUX_H_ +#include <list> +#include <memory> +#include <string> +#include <vector> + #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "ui/aura/scoped_window_targeter.h" @@ -55,10 +60,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostLinux // internal list of open windows. static void CleanUpWindowList(void (*func)(aura::Window* window)); - // This must be called before the window is created, because the visual cannot - // be changed after. Useful for X11. Not in use for Wayland. - void SetPendingXVisualId(int x_visual_id); - // Returns the current bounds in terms of the X11 Root Window including the // borders provided by the window manager (if any). Not in use for Wayland. gfx::Rect GetXRootWindowOuterBounds() const; @@ -88,7 +89,11 @@ class VIEWS_EXPORT DesktopWindowTreeHostLinux void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) override; void OnActivationChanged(bool active) override; + ui::X11Extension* GetX11Extension(); + const ui::X11Extension* GetX11Extension() const; + private: + friend class DesktopWindowTreeHostX11Test; FRIEND_TEST_ALL_PREFIXES(DesktopWindowTreeHostLinuxTest, HitTest); // Overridden from display::DisplayObserver via aura::WindowTreeHost: @@ -107,20 +112,16 @@ class VIEWS_EXPORT DesktopWindowTreeHostLinux void DestroyNonClientEventFilter(); // X11ExtensionDelegate overrides: - void OnXWindowMapped() override; - void OnXWindowUnmapped() override; void GetWindowMask(const gfx::Size& size, SkPath* window_mask) override; void OnLostMouseGrab() override; #if BUILDFLAG(USE_ATK) bool OnAtkKeyEvent(AtkKeyEventStruct* atk_key_event) override; #endif + bool IsOverrideRedirect() const override; // Enables event listening after closing |dialog|. void EnableEventListening(); - ui::X11Extension* GetX11Extension(); - const ui::X11Extension* GetX11Extension() const; - // See comment for variable open_windows_. static std::list<gfx::AcceleratedWidget>& open_windows(); @@ -129,11 +130,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostLinux // other consumer handled them. std::unique_ptr<WindowEventFilterLinux> non_client_window_event_filter_; - // X11 may set set a visual id for the system tray icon before the host is - // initialized. This value will be passed down to PlatformWindow during - // initialization of the host. - base::Optional<int> pending_x_visual_id_; - std::unique_ptr<CompositorObserver> compositor_observer_; std::unique_ptr<aura::ScopedWindowTargeter> targeter_for_modal_; diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc index 2eb29b2909d..0b2ab7e4538 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc @@ -115,9 +115,9 @@ class HitTestNonClientFrameView : public NativeFrameView { }; // This is used to return HitTestNonClientFrameView on create call. -class HitTestWidgetDelegate : public views::WidgetDelegate { +class HitTestWidgetDelegate : public WidgetDelegate { public: - explicit HitTestWidgetDelegate(views::Widget* widget) : widget_(widget) {} + explicit HitTestWidgetDelegate(Widget* widget) : widget_(widget) {} ~HitTestWidgetDelegate() override = default; void set_can_resize(bool can_resize) { @@ -127,11 +127,11 @@ class HitTestWidgetDelegate : public views::WidgetDelegate { HitTestNonClientFrameView* frame_view() { return frame_view_; } - // views::WidgetDelegate: + // WidgetDelegate: bool CanResize() const override { return can_resize_; } - views::Widget* GetWidget() override { return widget_; } - views::Widget* GetWidget() const override { return widget_; } - views::NonClientFrameView* CreateNonClientFrameView(Widget* widget) override { + Widget* GetWidget() override { return widget_; } + Widget* GetWidget() const override { return widget_; } + NonClientFrameView* CreateNonClientFrameView(Widget* widget) override { DCHECK(widget_ == widget); if (!frame_view_) frame_view_ = new HitTestNonClientFrameView(widget); @@ -140,7 +140,7 @@ class HitTestWidgetDelegate : public views::WidgetDelegate { void DeleteDelegate() override { delete this; } private: - views::Widget* const widget_; + Widget* const widget_; HitTestNonClientFrameView* frame_view_ = nullptr; bool can_resize_ = false; @@ -191,7 +191,7 @@ class DesktopWindowTreeHostLinuxTest : public ViewsInteractiveUITestBase { delegate_ = new HitTestWidgetDelegate(toplevel); Widget::InitParams toplevel_params = CreateParams(Widget::InitParams::TYPE_WINDOW); - auto* native_widget = new views::DesktopNativeWidgetAura(toplevel); + auto* native_widget = new DesktopNativeWidgetAura(toplevel); toplevel_params.native_widget = native_widget; host_ = new TestDesktopWindowTreeHostLinux(toplevel, native_widget); toplevel_params.desktop_window_tree_host = host_; diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_observer_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_observer_x11.h deleted file mode 100644 index 544f20527aa..00000000000 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_observer_x11.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2013 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_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_OBSERVER_X11_H_ -#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_OBSERVER_X11_H_ - -#include "ui/views/views_export.h" - -namespace views { - -// Allows for the observation of lower level window events. -class VIEWS_EXPORT DesktopWindowTreeHostObserverX11 { - public: - virtual ~DesktopWindowTreeHostObserverX11() {} - - // Called after we receive a MapNotify event (the X11 server has allocated - // resources for it). - virtual void OnWindowMapped(unsigned long xid) = 0; - - // Called after we receive an UnmapNotify event (the X11 server has freed - // resources for it). - virtual void OnWindowUnmapped(unsigned long xid) = 0; -}; - -} // namespace views - -#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_OBSERVER_X11_H_ - diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc index 30e99b6183f..f3a3175c6c3 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc @@ -4,6 +4,10 @@ #include "ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h" +#include <memory> +#include <string> +#include <utility> + #include "base/bind.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" @@ -42,36 +46,43 @@ bool DetermineInactivity(ui::WindowShowState show_state) { return show_state == ui::SHOW_STATE_INACTIVE; } -ui::PlatformWindowInitProperties ConvertWidgetInitParamsToInitProperties( - const Widget::InitParams& params) { - ui::PlatformWindowInitProperties properties; +ui::PlatformWindowOpacity GetPlatformWindowOpacity( + Widget::InitParams::WindowOpacity opacity) { + switch (opacity) { + case Widget::InitParams::WindowOpacity::kInferred: + return ui::PlatformWindowOpacity::kInferOpacity; + case Widget::InitParams::WindowOpacity::kOpaque: + return ui::PlatformWindowOpacity::kOpaqueWindow; + case Widget::InitParams::WindowOpacity::kTranslucent: + return ui::PlatformWindowOpacity::kTranslucentWindow; + } + return ui::PlatformWindowOpacity::kOpaqueWindow; +} - switch (params.type) { +ui::PlatformWindowType GetPlatformWindowType( + Widget::InitParams::Type window_type) { + switch (window_type) { case Widget::InitParams::TYPE_WINDOW: - properties.type = ui::PlatformWindowType::kWindow; - break; - + return ui::PlatformWindowType::kWindow; case Widget::InitParams::TYPE_MENU: - properties.type = ui::PlatformWindowType::kMenu; - break; - + return ui::PlatformWindowType::kMenu; case Widget::InitParams::TYPE_TOOLTIP: - properties.type = ui::PlatformWindowType::kTooltip; - break; - + return ui::PlatformWindowType::kTooltip; case Widget::InitParams::TYPE_DRAG: - properties.type = ui::PlatformWindowType::kDrag; - break; - + return ui::PlatformWindowType::kDrag; case Widget::InitParams::TYPE_BUBBLE: - properties.type = ui::PlatformWindowType::kBubble; - break; - + return ui::PlatformWindowType::kBubble; default: - properties.type = ui::PlatformWindowType::kPopup; - break; + return ui::PlatformWindowType::kPopup; } + NOTREACHED(); + return ui::PlatformWindowType::kPopup; +} +ui::PlatformWindowInitProperties ConvertWidgetInitParamsToInitProperties( + const Widget::InitParams& params) { + ui::PlatformWindowInitProperties properties; + properties.type = GetPlatformWindowType(params.type); properties.activatable = params.activatable == Widget::InitParams::ACTIVATABLE_YES; properties.force_show_in_taskbar = params.force_show_in_taskbar; @@ -80,22 +91,11 @@ ui::PlatformWindowInitProperties ConvertWidgetInitParamsToInitProperties( properties.visible_on_all_workspaces = params.visible_on_all_workspaces; properties.remove_standard_frame = params.remove_standard_frame; properties.workspace = params.workspace; + properties.opacity = GetPlatformWindowOpacity(params.opacity); if (params.parent && params.parent->GetHost()) properties.parent_widget = params.parent->GetHost()->GetAcceleratedWidget(); - switch (params.opacity) { - case Widget::InitParams::WindowOpacity::kInferred: - properties.opacity = ui::PlatformWindowOpacity::kInferOpacity; - break; - case Widget::InitParams::WindowOpacity::kOpaque: - properties.opacity = ui::PlatformWindowOpacity::kOpaqueWindow; - break; - case Widget::InitParams::WindowOpacity::kTranslucent: - properties.opacity = ui::PlatformWindowOpacity::kTranslucentWindow; - break; - } - return properties; } @@ -215,7 +215,7 @@ void DesktopWindowTreeHostPlatform::Close() { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&DesktopWindowTreeHostPlatform::CloseNow, close_widget_factory_.GetWeakPtr())); -} // namespace views +} void DesktopWindowTreeHostPlatform::CloseNow() { if (!platform_window()) @@ -504,13 +504,13 @@ Widget::MoveLoopResult DesktopWindowTreeHostPlatform::RunMoveLoop( const gfx::Vector2d& drag_offset, Widget::MoveLoopSource source, Widget::MoveLoopEscapeBehavior escape_behavior) { - // TODO: needs PlatformWindow support. + // TODO(crbug.com/896640): needs PlatformWindow support. NOTIMPLEMENTED_LOG_ONCE(); return Widget::MOVE_LOOP_CANCELED; } void DesktopWindowTreeHostPlatform::EndMoveLoop() { - // TODO: needs PlatformWindow support. + // TODO(crbug.com/896640): needs PlatformWindow support. NOTIMPLEMENTED_LOG_ONCE(); } @@ -560,7 +560,7 @@ void DesktopWindowTreeHostPlatform::SetFullscreen(bool fullscreen) { DCHECK_EQ(fullscreen, IsFullscreen()); if (IsFullscreen() == fullscreen) - Relayout(); + ScheduleRelayout(); // Else: the widget will be relaid out either when the window bounds change // or when |platform_window|'s fullscreen state changes. } @@ -673,7 +673,7 @@ void DesktopWindowTreeHostPlatform::OnWindowStateChanged( // Now that we have different window properties, we may need to relayout the // window. (The windows code doesn't need this because their window change is // synchronous.) - Relayout(); + ScheduleRelayout(); } void DesktopWindowTreeHostPlatform::OnCloseRequest() { @@ -681,9 +681,12 @@ void DesktopWindowTreeHostPlatform::OnCloseRequest() { } void DesktopWindowTreeHostPlatform::OnActivationChanged(bool active) { + if (is_active_ == active) + return; is_active_ = active; aura::WindowTreeHostPlatform::OnActivationChanged(active); desktop_native_widget_aura_->HandleActivationChanged(active); + ScheduleRelayout(); } base::Optional<gfx::Size> @@ -716,7 +719,7 @@ gfx::Rect DesktopWindowTreeHostPlatform::ToPixelRect( return gfx::ToEnclosingRect(rect_in_pixels); } -void DesktopWindowTreeHostPlatform::Relayout() { +void DesktopWindowTreeHostPlatform::ScheduleRelayout() { Widget* widget = native_widget_delegate_->AsWidget(); NonClientView* non_client_view = widget->non_client_view(); // non_client_view may be NULL, especially during creation. diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h index 89beb8d2245..24a5fa974dd 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h @@ -5,7 +5,9 @@ #ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_PLATFORM_H_ #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_PLATFORM_H_ +#include <memory> #include <set> +#include <string> #include <vector> #include "base/memory/weak_ptr.h" @@ -129,7 +131,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform gfx::Rect ToPixelRect(const gfx::Rect& rect_in_dip) const; private: - void Relayout(); + void ScheduleRelayout(); Widget* GetWidget(); const Widget* GetWidget() const; 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 d14c81e31d4..62e2a8fd5ab 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 @@ -3,6 +3,10 @@ // found in the LICENSE file. #include "ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h" + +#include <memory> +#include <utility> + #include "base/run_loop.h" #include "ui/views/test/views_test_base.h" #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" 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 b43ff29b2bc..6f576d95707 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 @@ -4,6 +4,10 @@ #include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h" +#include <algorithm> +#include <utility> +#include <vector> + #include "base/bind.h" #include "base/containers/flat_set.h" #include "base/memory/ptr_util.h" @@ -169,8 +173,7 @@ void DesktopWindowTreeHostWin::OnWidgetInitDone() {} std::unique_ptr<corewm::Tooltip> DesktopWindowTreeHostWin::CreateTooltip() { bool force_legacy_tooltips = (base::win::GetVersion() < base::win::Version::WIN8); - if (base::FeatureList::IsEnabled(features::kEnableAuraTooltipsOnWindows) && - !force_legacy_tooltips) + if (!force_legacy_tooltips) return std::make_unique<corewm::TooltipAura>(); DCHECK(!tooltip_); @@ -230,8 +233,8 @@ bool DesktopWindowTreeHostWin::IsVisible() const { } void DesktopWindowTreeHostWin::SetSize(const gfx::Size& size) { - gfx::Size size_in_pixels = display::win::ScreenWin::DIPToScreenSize(GetHWND(), - size); + gfx::Size size_in_pixels = + display::win::ScreenWin::DIPToScreenSize(GetHWND(), size); gfx::Size expanded = GetExpandedWindowSize(message_handler_->is_translucent(), size_in_pixels); window_enlargement_ = @@ -251,8 +254,8 @@ void DesktopWindowTreeHostWin::StackAtTop() { } void DesktopWindowTreeHostWin::CenterWindow(const gfx::Size& size) { - gfx::Size size_in_pixels = display::win::ScreenWin::DIPToScreenSize(GetHWND(), - size); + gfx::Size size_in_pixels = + display::win::ScreenWin::DIPToScreenSize(GetHWND(), size); gfx::Size expanded_size; expanded_size = GetExpandedWindowSize(message_handler_->is_translucent(), size_in_pixels); @@ -295,9 +298,9 @@ std::string DesktopWindowTreeHostWin::GetWorkspace() const { gfx::Rect DesktopWindowTreeHostWin::GetWorkAreaBoundsInScreen() const { MONITORINFO monitor_info; monitor_info.cbSize = sizeof(monitor_info); - GetMonitorInfo(MonitorFromWindow(message_handler_->hwnd(), - MONITOR_DEFAULTTONEAREST), - &monitor_info); + GetMonitorInfo( + MonitorFromWindow(message_handler_->hwnd(), MONITOR_DEFAULTTONEAREST), + &monitor_info); gfx::Rect pixel_bounds = gfx::Rect(monitor_info.rcWork); return display::win::ScreenWin::ScreenToDIPRect(GetHWND(), pixel_bounds); } @@ -412,8 +415,9 @@ Widget::MoveLoopResult DesktopWindowTreeHostWin::RunMoveLoop( Widget::MoveLoopEscapeBehavior escape_behavior) { const bool hide_on_escape = escape_behavior == Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_HIDE; - return message_handler_->RunMoveLoop(drag_offset, hide_on_escape) ? - Widget::MOVE_LOOP_SUCCESSFUL : Widget::MOVE_LOOP_CANCELED; + return message_handler_->RunMoveLoop(drag_offset, hide_on_escape) + ? Widget::MOVE_LOOP_SUCCESSFUL + : Widget::MOVE_LOOP_CANCELED; } void DesktopWindowTreeHostWin::EndMoveLoop() { @@ -477,8 +481,8 @@ void DesktopWindowTreeHostWin::SetAspectRatio(const gfx::SizeF& aspect_ratio) { aspect_ratio.height()); } -void DesktopWindowTreeHostWin::SetWindowIcons( - const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) { +void DesktopWindowTreeHostWin::SetWindowIcons(const gfx::ImageSkia& window_icon, + const gfx::ImageSkia& app_icon) { message_handler_->SetWindowIcons(window_icon, app_icon); } @@ -729,8 +733,8 @@ bool DesktopWindowTreeHostWin::WillProcessWorkAreaChange() const { int DesktopWindowTreeHostWin::GetNonClientComponent( const gfx::Point& point) const { - gfx::Point dip_position = display::win::ScreenWin::ClientToDIPPoint(GetHWND(), - point); + gfx::Point dip_position = + display::win::ScreenWin::ClientToDIPPoint(GetHWND(), point); return native_widget_delegate_->GetNonClientComponent(dip_position); } @@ -794,11 +798,11 @@ void DesktopWindowTreeHostWin::HandleActivationChanged(bool active) { desktop_native_widget_aura_->HandleActivationChanged(active); } -bool DesktopWindowTreeHostWin::HandleAppCommand(short command) { +bool DesktopWindowTreeHostWin::HandleAppCommand(int command) { // We treat APPCOMMAND ids as an extension of our command namespace, and just // let the delegate figure out what to do... return GetWidget()->widget_delegate() && - GetWidget()->widget_delegate()->ExecuteWindowsCommand(command); + GetWidget()->widget_delegate()->ExecuteWindowsCommand(command); } void DesktopWindowTreeHostWin::HandleCancelMode() { @@ -1025,8 +1029,7 @@ bool DesktopWindowTreeHostWin::PreHandleMSG(UINT message, void DesktopWindowTreeHostWin::PostHandleMSG(UINT message, WPARAM w_param, - LPARAM l_param) { -} + LPARAM l_param) {} bool DesktopWindowTreeHostWin::HandleScrollEvent(ui::ScrollEvent* event) { SendEventToSink(event); 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 b195b582fe5..4b217541512 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 @@ -19,8 +19,8 @@ namespace aura { namespace client { class DragDropClient; class FocusClient; -} -} +} // namespace client +} // namespace aura namespace ui { enum class DomCode; @@ -181,7 +181,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin void ResetWindowControls() override; gfx::NativeViewAccessible GetNativeViewAccessible() override; void HandleActivationChanged(bool active) override; - bool HandleAppCommand(short command) override; + bool HandleAppCommand(int command) override; void HandleCancelMode() override; void HandleCaptureLost() override; void HandleClose() override; diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win_unittest.cc index cb045d8b402..4f4d95a5014 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win_unittest.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win_unittest.cc @@ -7,6 +7,8 @@ #include <oleacc.h> #include <windows.h> +#include <utility> + #include "base/command_line.h" #include "ui/accessibility/accessibility_switches.h" #include "ui/accessibility/platform/ax_platform_node_win.h" 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 34c798b2367..2c94941cf27 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 @@ -16,6 +16,7 @@ #include "base/command_line.h" #include "base/containers/flat_set.h" #include "base/location.h" +#include "base/memory/ptr_util.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" @@ -41,7 +42,8 @@ #include "ui/events/devices/x11/device_list_cache_x11.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" -#include "ui/events/platform/platform_event_source.h" +#include "ui/events/keyboard_hook.h" +#include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/x/events_x_utils.h" #include "ui/events/x/x11_window_event_manager.h" #include "ui/gfx/geometry/size_conversions.h" @@ -55,8 +57,6 @@ #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/desktop_aura/desktop_window_tree_host_observer_x11.h" -#include "ui/views/widget/desktop_aura/x11_desktop_handler.h" #include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h" #include "ui/views/window/native_frame_view.h" #include "ui/wm/core/compound_event_filter.h" @@ -79,16 +79,6 @@ DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() { // also destroyes the dispatcher. } -void DesktopWindowTreeHostX11::AddObserver( - DesktopWindowTreeHostObserverX11* observer) { - observer_list_.AddObserver(observer); -} - -void DesktopWindowTreeHostX11::RemoveObserver( - DesktopWindowTreeHostObserverX11* observer) { - observer_list_.RemoveObserver(observer); -} - //////////////////////////////////////////////////////////////////////////////// // DesktopWindowTreeHostX11, DesktopWindowTreeHost implementation: @@ -106,10 +96,6 @@ void DesktopWindowTreeHostX11::Init(const Widget::InitParams& params) { void DesktopWindowTreeHostX11::OnNativeWidgetCreated( const Widget::InitParams& params) { - // Ensure that the X11DesktopHandler exists so that it tracks create/destroy - // notify events. - X11DesktopHandler::get(); - x11_window_move_client_ = std::make_unique<X11DesktopWindowMoveClient>(); wm::SetWindowMoveClient(window(), x11_window_move_client_.get()); @@ -131,7 +117,7 @@ Widget::MoveLoopResult DesktopWindowTreeHostX11::RunMoveLoop( Widget::MoveLoopSource source, Widget::MoveLoopEscapeBehavior escape_behavior) { wm::WindowMoveSource window_move_source = - source == Widget::MOVE_LOOP_SOURCE_MOUSE ? wm::WINDOW_MOVE_SOURCE_MOUSE + source == Widget::MoveLoopSource::kMouse ? wm::WINDOW_MOVE_SOURCE_MOUSE : wm::WINDOW_MOVE_SOURCE_TOUCH; if (x11_window_move_client_->RunMoveLoop(GetContentWindow(), drag_offset, window_move_source) == @@ -148,16 +134,6 @@ void DesktopWindowTreeHostX11::EndMoveLoop() { //////////////////////////////////////////////////////////////////////////////// // DesktopWindowTreeHostX11 implementation: -void DesktopWindowTreeHostX11::OnXWindowMapped() { - for (DesktopWindowTreeHostObserverX11& observer : observer_list_) - observer.OnWindowMapped(GetXWindow()->window()); -} - -void DesktopWindowTreeHostX11::OnXWindowUnmapped() { - for (DesktopWindowTreeHostObserverX11& observer : observer_list_) - observer.OnWindowUnmapped(GetXWindow()->window()); -} - void DesktopWindowTreeHostX11::OnXWindowSelectionEvent(XEvent* xev) { DCHECK(xev); DCHECK(drag_drop_client_); 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 9db2bb988a7..53da309c14d 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,7 +8,6 @@ #include <memory> #include "base/macros.h" -#include "base/observer_list.h" #include "ui/gfx/x/x11_types.h" #include "ui/platform_window/platform_window_delegate.h" #include "ui/platform_window/x11/x11_window.h" @@ -22,7 +21,6 @@ class X11Window; namespace views { class DesktopDragDropClientAuraX11; -class DesktopWindowTreeHostObserverX11; class X11DesktopWindowMoveClient; class VIEWS_EXPORT DesktopWindowTreeHostX11 : public DesktopWindowTreeHostLinux, @@ -33,9 +31,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11 : public DesktopWindowTreeHostLinux, DesktopNativeWidgetAura* desktop_native_widget_aura); ~DesktopWindowTreeHostX11() override; - void AddObserver(DesktopWindowTreeHostObserverX11* observer); - void RemoveObserver(DesktopWindowTreeHostObserverX11* observer); - protected: // Overridden from DesktopWindowTreeHost: void Init(const Widget::InitParams& params) override; @@ -51,14 +46,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11 : public DesktopWindowTreeHostLinux, private: friend class DesktopWindowTreeHostX11HighDPITest; - // X11ExtensionDelegate overrides: - // - // DWTHX11 temporarily overrides the X11ExtensionDelegate - // methods instead of underlying DWTHPlatform and WTHPlatform. Eventually, - // these will be removed from here as we progress in https://crbug.com/990756. - void OnXWindowMapped() override; - void OnXWindowUnmapped() override; - // Overridden from ui::XEventDelegate. void OnXWindowSelectionEvent(XEvent* xev) override; void OnXWindowDragDropEvent(XEvent* xev) override; @@ -73,9 +60,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11 : public DesktopWindowTreeHostLinux, std::unique_ptr<X11DesktopWindowMoveClient> x11_window_move_client_; - base::ObserverList<DesktopWindowTreeHostObserverX11>::Unchecked - observer_list_; - DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostX11); }; 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 8bd27d22979..7135ad984e3 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 @@ -14,7 +14,7 @@ #include "ui/base/x/x11_util.h" #include "ui/events/event_handler.h" #include "ui/events/platform/x11/x11_event_source.h" -#include "ui/events/platform/x11/x11_event_source_glib.h" +#include "ui/events/x/x11_event_translation.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11_atom_cache.h" @@ -32,14 +32,13 @@ class ActivationWaiter : public X11PropertyChangeWaiter { public: explicit ActivationWaiter(XID window) : X11PropertyChangeWaiter(ui::GetX11RootWindow(), "_NET_ACTIVE_WINDOW"), - window_(window) { - } + window_(window) {} ~ActivationWaiter() override = default; private: // X11PropertyChangeWaiter: - bool ShouldKeepOnWaiting(const ui::PlatformEvent& event) override { + bool ShouldKeepOnWaiting(XEvent* event) override { XID xid = 0; ui::GetXIDProperty(ui::GetX11RootWindow(), "_NET_ACTIVE_WINDOW", &xid); return xid != window_; @@ -62,9 +61,7 @@ class MouseMoveCounterHandler : public ui::EventHandler { ++count_; } - int num_mouse_moves() const { - return count_; - } + int num_mouse_moves() const { return count_; } private: int count_ = 0; @@ -84,18 +81,17 @@ std::unique_ptr<Widget> CreateWidget(const gfx::Rect& bounds) { return widget; } -// Dispatches an XMotionEvent targeted at |host|'s X window with location +// Dispatches a XMotionEvent targeted at |host|'s X window with location // |point_in_screen|. void DispatchMouseMotionEvent(DesktopWindowTreeHostX11* desktop_host, const gfx::Point& point_in_screen) { - aura::WindowTreeHost* host = static_cast<aura::WindowTreeHost*>(desktop_host); 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 = host->GetAcceleratedWidget(); + xev.xmotion.window = desktop_host->GetAcceleratedWidget(); xev.xmotion.root = DefaultRootWindow(display); xev.xmotion.subwindow = 0; xev.xmotion.time = x11::CurrentTime; @@ -107,8 +103,7 @@ void DispatchMouseMotionEvent(DesktopWindowTreeHostX11* desktop_host, xev.xmotion.is_hint = NotifyNormal; xev.xmotion.same_screen = x11::True; - static_cast<ui::X11EventSourceGlib*>(ui::PlatformEventSource::GetInstance()) - ->ProcessXEvent(&xev); + ui::X11EventSource::GetInstance()->ProcessXEvent(&xev); } } // namespace @@ -252,9 +247,12 @@ TEST_F(DesktopWindowTreeHostX11Test, InputMethodFocus) { // EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, // widget->GetInputMethod()->GetTextInputType()); - widget->Activate(); + // Waiter should be created before widget->Activate is called. Otherwise, + // there is a race, and waiter might not be able to set property changes mask + // on time and miss the events. ActivationWaiter waiter( widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget()); + widget->Activate(); waiter.Wait(); EXPECT_TRUE(widget->IsActive()); 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 index 8195a801561..88b625f1b59 100644 --- 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 @@ -3,7 +3,9 @@ // found in the LICENSE file. #include <stddef.h> + #include <memory> +#include <utility> #include <vector> #include "base/command_line.h" @@ -17,9 +19,10 @@ #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_glib.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" @@ -49,7 +52,7 @@ class WMStateWaiter : public X11PropertyChangeWaiter { private: // X11PropertyChangeWaiter: - bool ShouldKeepOnWaiting(const ui::PlatformEvent& event) override { + 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_; @@ -173,7 +176,7 @@ bool ShapeRectContainsPoint(const std::vector<gfx::Rect>& shape_rects, class DesktopWindowTreeHostX11Test : public ViewsTestBase { public: DesktopWindowTreeHostX11Test() - : event_source_(ui::PlatformEventSource::GetInstance()) {} + : event_source_(ui::X11EventSource::GetInstance()) {} ~DesktopWindowTreeHostX11Test() override = default; void SetUp() override { @@ -195,17 +198,17 @@ class DesktopWindowTreeHostX11Test : public ViewsTestBase { ViewsTestBase::TearDown(); } - void DispatchSingleEventToWidget(XEvent* event, Widget* widget) { - DCHECK_EQ(GenericEvent, event->type); + void DispatchSingleEventToWidget(XEvent* xev, Widget* widget) { + DCHECK_EQ(GenericEvent, xev->type); XIDeviceEvent* device_event = - static_cast<XIDeviceEvent*>(event->xcookie.data); + static_cast<XIDeviceEvent*>(xev->xcookie.data); device_event->event = widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget(); - event_source_.Dispatch(event); + event_source_->ProcessXEvent(xev); } private: - ui::test::PlatformEventSourceTestAPI event_source_; + ui::X11EventSource* event_source_; DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostX11Test); }; diff --git a/chromium/ui/views/widget/desktop_aura/window_event_filter_linux.cc b/chromium/ui/views/widget/desktop_aura/window_event_filter_linux.cc index f1729e53d09..d69da05aa30 100644 --- a/chromium/ui/views/widget/desktop_aura/window_event_filter_linux.cc +++ b/chromium/ui/views/widget/desktop_aura/window_event_filter_linux.cc @@ -163,7 +163,7 @@ void WindowEventFilterLinux::MaybeDispatchHostWindowDragMovement( // interactive move/resize. auto bounds_in_px = desktop_window_tree_host_->AsWindowTreeHost()->GetBoundsInPixels(); - auto screen_point_in_px = event->root_location(); + auto screen_point_in_px = event->location(); screen_point_in_px.Offset(bounds_in_px.x(), bounds_in_px.y()); handler_->DispatchHostWindowDragMovement(hittest, screen_point_in_px); event->StopPropagation(); diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc deleted file mode 100644 index cfe62d62144..00000000000 --- a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) 2012 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/x11_desktop_handler.h" - -#include <memory> - -#include "base/strings/string_number_conversions.h" -#include "ui/aura/env.h" -#include "ui/aura/window_event_dispatcher.h" -#include "ui/base/x/x11_menu_list.h" -#include "ui/base/x/x11_util.h" -#include "ui/events/platform/platform_event_source.h" -#include "ui/events/x/x11_window_event_manager.h" -#include "ui/gfx/x/x11.h" -#include "ui/gfx/x/x11_atom_cache.h" -#include "ui/gfx/x/x11_error_tracker.h" -#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h" - -namespace { - -// Our global instance. Deleted when our Env() is deleted. -views::X11DesktopHandler* g_handler = nullptr; - -} // namespace - -namespace views { - -// static -X11DesktopHandler* X11DesktopHandler::get() { - if (!g_handler) - g_handler = new X11DesktopHandler; - - return g_handler; -} - -// static -X11DesktopHandler* X11DesktopHandler::get_dont_create() { - return g_handler; -} - -X11DesktopHandler::X11DesktopHandler() - : xdisplay_(gfx::GetXDisplay()), - x_root_window_(DefaultRootWindow(xdisplay_)) { - if (ui::PlatformEventSource::GetInstance()) - ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); - aura::Env::GetInstance()->AddObserver(this); - - x_root_window_events_ = std::make_unique<ui::XScopedEventSelector>( - x_root_window_, - PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask); -} - -X11DesktopHandler::~X11DesktopHandler() { - aura::Env::GetInstance()->RemoveObserver(this); - if (ui::PlatformEventSource::GetInstance()) - ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); -} - -void X11DesktopHandler::AddObserver(X11DesktopHandlerObserver* observer) { - observers_.AddObserver(observer); -} - -void X11DesktopHandler::RemoveObserver(X11DesktopHandlerObserver* observer) { - observers_.RemoveObserver(observer); -} - -std::string X11DesktopHandler::GetWorkspace() { - if (workspace_.empty()) - UpdateWorkspace(); - return workspace_; -} - -bool X11DesktopHandler::UpdateWorkspace() { - int desktop; - if (ui::GetCurrentDesktop(&desktop)) { - workspace_ = base::NumberToString(desktop); - return true; - } - return false; -} - -bool X11DesktopHandler::CanDispatchEvent(const ui::PlatformEvent& event) { - return event->type == CreateNotify || event->type == DestroyNotify || - (event->type == PropertyNotify && - event->xproperty.window == x_root_window_); -} - -uint32_t X11DesktopHandler::DispatchEvent(const ui::PlatformEvent& event) { - switch (event->type) { - case PropertyNotify: { - if (event->xproperty.atom == gfx::GetAtom("_NET_CURRENT_DESKTOP")) { - if (UpdateWorkspace()) { - for (views::X11DesktopHandlerObserver& observer : observers_) - observer.OnWorkspaceChanged(workspace_); - } - } - break; - } - case CreateNotify: - OnWindowCreatedOrDestroyed(event->type, event->xcreatewindow.window); - break; - case DestroyNotify: - OnWindowCreatedOrDestroyed(event->type, event->xdestroywindow.window); - break; - default: - NOTREACHED(); - } - - return ui::POST_DISPATCH_NONE; -} - -void X11DesktopHandler::OnWindowInitialized(aura::Window* window) { -} - -void X11DesktopHandler::OnWillDestroyEnv() { - g_handler = nullptr; - delete this; -} - -void X11DesktopHandler::OnWindowCreatedOrDestroyed(int event_type, - XID window) { - // Menus created by Chrome can be drag and drop targets. Since they are - // direct children of the screen root window and have override_redirect - // we cannot use regular _NET_CLIENT_LIST_STACKING property to find them - // and use a separate cache to keep track of them. - // TODO(varkha): Implement caching of all top level X windows and their - // coordinates and stacking order to eliminate repeated calls to the X server - // during mouse movement, drag and shaping events. - if (event_type == CreateNotify) { - // The window might be destroyed if the message pump did not get a chance to - // run but we can safely ignore the X error. - gfx::X11ErrorTracker error_tracker; - ui::XMenuList::GetInstance()->MaybeRegisterMenu(window); - } else { - ui::XMenuList::GetInstance()->MaybeUnregisterMenu(window); - } -} - -} // namespace views diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h deleted file mode 100644 index bcf36736232..00000000000 --- a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2012 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_DESKTOP_AURA_X11_DESKTOP_HANDLER_H_ -#define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_DESKTOP_HANDLER_H_ - -#include <stdint.h> - -#include <vector> - -#include "base/macros.h" -#include "base/observer_list.h" -#include "ui/aura/env_observer.h" -#include "ui/events/platform/platform_event_dispatcher.h" -#include "ui/events/platform/x11/x11_event_source.h" -#include "ui/gfx/x/x11.h" -#include "ui/gfx/x/x11_types.h" -#include "ui/views/views_export.h" -#include "ui/views/widget/desktop_aura/x11_desktop_handler_observer.h" - -namespace base { -template <typename T> struct DefaultSingletonTraits; -} - -namespace ui { -class XScopedEventSelector; -} - -namespace views { - -// A singleton that owns global objects related to the desktop and listens for -// X11 events on the X11 root window. Destroys itself when aura::Env is -// deleted. -class VIEWS_EXPORT X11DesktopHandler : public ui::PlatformEventDispatcher, - public aura::EnvObserver { - public: - // Returns the singleton handler. Creates one if one has not - // already been created. - static X11DesktopHandler* get(); - - // Returns the singleton handler, or nullptr if one has not already - // been created. - static X11DesktopHandler* get_dont_create(); - - // Adds/removes X11DesktopHandlerObservers. - void AddObserver(X11DesktopHandlerObserver* observer); - void RemoveObserver(X11DesktopHandlerObserver* observer); - - // Gets the current workspace ID. - std::string GetWorkspace(); - - // ui::PlatformEventDispatcher - bool CanDispatchEvent(const ui::PlatformEvent& event) override; - uint32_t DispatchEvent(const ui::PlatformEvent& event) override; - - // Overridden from aura::EnvObserver: - void OnWindowInitialized(aura::Window* window) override; - void OnWillDestroyEnv() override; - - private: - X11DesktopHandler(); - ~X11DesktopHandler() override; - - // Called when |window| has been created or destroyed. |window| may not be - // managed by Chrome. - void OnWindowCreatedOrDestroyed(int event_type, XID window); - - // Makes a round trip to the X server to get the current workspace. - bool UpdateWorkspace(); - - // The display and the native X window hosting the root window. - XDisplay* xdisplay_; - - // The native root window. - ::Window x_root_window_; - - // Events selected on x_root_window_. - std::unique_ptr<ui::XScopedEventSelector> x_root_window_events_; - - base::ObserverList<X11DesktopHandlerObserver>::Unchecked observers_; - - std::string workspace_; - - DISALLOW_COPY_AND_ASSIGN(X11DesktopHandler); -}; - -} // namespace views - -#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_X11_DESKTOP_HANDLER_H_ diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler_observer.h b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler_observer.h deleted file mode 100644 index 679d867a0b4..00000000000 --- a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler_observer.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_X11_DESKTOP_HANDLER_OBSERVER_H_ -#define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_DESKTOP_HANDLER_OBSERVER_H_ - -#include <string> - -#include "ui/views/views_export.h" - -namespace views { - -class VIEWS_EXPORT X11DesktopHandlerObserver { - public: - // Called when the (platform-specific) workspace ID changes to - // |new_workspace|. - virtual void OnWorkspaceChanged(const std::string& new_workspace) = 0; - - protected: - virtual ~X11DesktopHandlerObserver() {} -}; - -} // namespace views - -#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_X11_DESKTOP_HANDLER_OBSERVER_H_ diff --git a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc index 670b2e179ca..9acc365e582 100644 --- a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc +++ b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc @@ -6,6 +6,8 @@ #include <stddef.h> +#include <vector> + #include "ui/aura/client/screen_position_client.h" #include "ui/aura/window.h" #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h" diff --git a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.h b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.h index 31ed462855c..0d9e535153a 100644 --- a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.h +++ b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.h @@ -8,6 +8,7 @@ #include <set> #include "base/macros.h" +#include "ui/base/x/x11_topmost_window_finder.h" #include "ui/base/x/x11_util.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/x/x11.h" @@ -20,8 +21,8 @@ class Window; namespace views { // Utility class for finding the topmost window at a given screen position. -class VIEWS_EXPORT X11TopmostWindowFinder - : public ui::EnumerateWindowsDelegate { +class VIEWS_EXPORT X11TopmostWindowFinder : public ui::EnumerateWindowsDelegate, + public ui::XTopmostWindowFinder { public: X11TopmostWindowFinder(); ~X11TopmostWindowFinder() override; @@ -33,7 +34,7 @@ class VIEWS_EXPORT X11TopmostWindowFinder const std::set<aura::Window*>& ignore); // Returns the topmost window at |screen_loc_in_pixels|. - XID FindWindowAt(const gfx::Point& screen_loc_in_pixels); + XID FindWindowAt(const gfx::Point& screen_loc_in_pixels) override; private: // ui::EnumerateWindowsDelegate: 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 ad283d52268..ce5c9ef430d 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 @@ -21,7 +21,6 @@ #include "ui/views/test/views_interactive_ui_test_base.h" #include "ui/views/test/x11_property_change_waiter.h" #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" -#include "ui/views/widget/desktop_aura/x11_desktop_handler.h" #include "ui/views/widget/widget.h" namespace views { @@ -38,7 +37,7 @@ class MinimizeWaiter : public X11PropertyChangeWaiter { private: // X11PropertyChangeWaiter: - bool ShouldKeepOnWaiting(const ui::PlatformEvent& event) override { + bool ShouldKeepOnWaiting(XEvent* event) override { std::vector<Atom> wm_states; if (ui::GetAtomArrayProperty(xwindow(), "_NET_WM_STATE", &wm_states)) { return !base::Contains(wm_states, gfx::GetAtom("_NET_WM_STATE_HIDDEN")); @@ -56,8 +55,7 @@ class StackingClientListWaiter : public X11PropertyChangeWaiter { StackingClientListWaiter(XID* expected_windows, size_t count) : X11PropertyChangeWaiter(ui::GetX11RootWindow(), "_NET_CLIENT_LIST_STACKING"), - expected_windows_(expected_windows, expected_windows + count) { - } + expected_windows_(expected_windows, expected_windows + count) {} ~StackingClientListWaiter() override = default; @@ -73,7 +71,7 @@ class StackingClientListWaiter : public X11PropertyChangeWaiter { private: // X11PropertyChangeWaiter: - bool ShouldKeepOnWaiting(const ui::PlatformEvent& event) override { + bool ShouldKeepOnWaiting(XEvent* event) override { std::vector<XID> stack; ui::GetXWindowStack(ui::GetX11RootWindow(), &stack); return !std::all_of( @@ -111,9 +109,7 @@ class X11TopmostWindowFinderTest : public ViewsInteractiveUITestBase { // 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, + XID xid = XCreateSimpleWindow(xdisplay(), root, 0, 0, 1, 1, 0, // border_width 0, // border 0); // background @@ -132,15 +128,10 @@ class X11TopmostWindowFinderTest : public ViewsInteractiveUITestBase { changes.y = bounds.y(); changes.width = bounds.width(); changes.height = bounds.height(); - XConfigureWindow(xdisplay(), - xid, - CWX | CWY | CWWidth | CWHeight, - &changes); + XConfigureWindow(xdisplay(), xid, CWX | CWY | CWWidth | CWHeight, &changes); } - Display* xdisplay() { - return gfx::GetXDisplay(); - } + Display* xdisplay() { return gfx::GetXDisplay(); } // Returns the topmost X window at the passed in screen position. XID FindTopmostXWindowAt(int screen_x, int screen_y) { @@ -177,10 +168,6 @@ class X11TopmostWindowFinderTest : public ViewsInteractiveUITestBase { // Make X11 synchronous for our display connection. This does not force the // window manager to behave synchronously. XSynchronize(xdisplay(), x11::True); - - // Ensure that the X11DesktopHandler exists. The X11DesktopHandler is - // necessary to properly track menu windows. - X11DesktopHandler::get(); } void TearDown() override { @@ -208,7 +195,7 @@ TEST_F(X11TopmostWindowFinderTest, Basic) { aura::Window* window3 = widget3->GetNativeWindow(); XID xid3 = window3->GetHost()->GetAcceleratedWidget(); - XID xids[] = { xid1, xid2, xid3 }; + XID xids[] = {xid1, xid2, xid3}; StackingClientListWaiter waiter(xids, base::size(xids)); waiter.Wait(); ui::X11EventSource::GetInstance()->DispatchXEvents(); @@ -251,7 +238,7 @@ TEST_F(X11TopmostWindowFinderTest, Minimized) { XID xid1 = window1->GetHost()->GetAcceleratedWidget(); XID xid2 = CreateAndShowXWindow(gfx::Rect(300, 100, 100, 100)); - XID xids[] = { xid1, xid2 }; + XID xids[] = {xid1, xid2}; StackingClientListWaiter stack_waiter(xids, base::size(xids)); stack_waiter.Wait(); ui::X11EventSource::GetInstance()->DispatchXEvents(); @@ -300,7 +287,7 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangular) { region2(gfx::CreateRegionFromSkRegion(skregion2)); XShapeCombineRegion(xdisplay(), xid2, ShapeBounding, 0, 0, region2.get(), false); - XID xids[] = { xid1, xid2 }; + XID xids[] = {xid1, xid2}; StackingClientListWaiter stack_waiter(xids, base::size(xids)); stack_waiter.Wait(); ui::X11EventSource::GetInstance()->DispatchXEvents(); @@ -331,7 +318,7 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangularEmptyShape) { // Widget takes ownership of |shape1|. widget1->SetShape(std::move(shape1)); - XID xids[] = { xid1 }; + XID xids[] = {xid1}; StackingClientListWaiter stack_waiter(xids, base::size(xids)); stack_waiter.Wait(); ui::X11EventSource::GetInstance()->DispatchXEvents(); @@ -354,7 +341,7 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangularNullShape) { // Remove the shape - this is now just a normal window. widget1->SetShape(nullptr); - XID xids[] = { xid1 }; + XID xids[] = {xid1}; StackingClientListWaiter stack_waiter(xids, base::size(xids)); stack_waiter.Wait(); ui::X11EventSource::GetInstance()->DispatchXEvents(); @@ -370,15 +357,12 @@ TEST_F(X11TopmostWindowFinderTest, Menu) { XID root = DefaultRootWindow(xdisplay()); XSetWindowAttributes swa; swa.override_redirect = x11::True; - XID menu_xid = XCreateWindow(xdisplay(), - root, - 0, 0, 1, 1, - 0, // border width - CopyFromParent, // depth + XID menu_xid = XCreateWindow(xdisplay(), root, 0, 0, 1, 1, + 0, // border width + CopyFromParent, // depth InputOutput, - CopyFromParent, // visual - CWOverrideRedirect, - &swa); + CopyFromParent, // visual + CWOverrideRedirect, &swa); { ui::SetAtomProperty(menu_xid, "_NET_WM_WINDOW_TYPE", "ATOM", gfx::GetAtom("_NET_WM_WINDOW_TYPE_MENU")); @@ -388,7 +372,7 @@ TEST_F(X11TopmostWindowFinderTest, Menu) { ui::X11EventSource::GetInstance()->DispatchXEvents(); // |menu_xid| is never added to _NET_CLIENT_LIST_STACKING. - XID xids[] = { xid }; + XID xids[] = {xid}; StackingClientListWaiter stack_waiter(xids, base::size(xids)); stack_waiter.Wait(); diff --git a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc index eb1de4a7e4b..01509c2d677 100644 --- a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc +++ b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc @@ -21,6 +21,7 @@ #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_tree_host.h" +#include "ui/base/mojom/cursor_type.mojom-shared.h" #include "ui/base/x/x11_pointer_grab.h" #include "ui/base/x/x11_util.h" #include "ui/events/event.h" @@ -29,27 +30,26 @@ #include "ui/events/platform/platform_event_source.h" #include "ui/events/platform/scoped_event_dispatcher.h" #include "ui/events/platform/x11/x11_event_source.h" +#include "ui/events/x/events_x_utils.h" #include "ui/events/x/x11_window_event_manager.h" #include "ui/gfx/x/x11.h" namespace views { // XGrabKey requires the modifier mask to explicitly be specified. -const unsigned int kModifiersMasks[] = { - 0, // No additional modifier. - Mod2Mask, // Num lock - LockMask, // Caps lock - Mod5Mask, // Scroll lock - Mod2Mask | LockMask, - Mod2Mask | Mod5Mask, - LockMask | Mod5Mask, - Mod2Mask | LockMask | Mod5Mask -}; +const unsigned int kModifiersMasks[] = {0, // No additional modifier. + Mod2Mask, // Num lock + LockMask, // Caps lock + Mod5Mask, // Scroll lock + Mod2Mask | LockMask, + Mod2Mask | Mod5Mask, + LockMask | Mod5Mask, + Mod2Mask | LockMask | Mod5Mask}; X11WholeScreenMoveLoop::X11WholeScreenMoveLoop(X11MoveLoopDelegate* delegate) : delegate_(delegate), in_move_loop_(false), - initial_cursor_(ui::CursorType::kNull), + initial_cursor_(ui::mojom::CursorType::kNull), should_reset_mouse_flags_(false), grab_input_window_(x11::None), grabbed_pointer_(false), @@ -60,12 +60,26 @@ X11WholeScreenMoveLoop::~X11WholeScreenMoveLoop() = default; void X11WholeScreenMoveLoop::DispatchMouseMovement() { if (!last_motion_in_screen_) return; - delegate_->OnMouseMovement(last_motion_in_screen_->location(), + delegate_->OnMouseMovement(last_motion_in_screen_->root_location(), last_motion_in_screen_->flags(), last_motion_in_screen_->time_stamp()); last_motion_in_screen_.reset(); } +void X11WholeScreenMoveLoop::PostDispatchIfNeeded(const ui::MouseEvent& event) { + bool dispatch_mouse_event = !last_motion_in_screen_; + last_motion_in_screen_ = std::make_unique<ui::MouseEvent>(event); + 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(&X11WholeScreenMoveLoop::DispatchMouseMovement, + weak_factory_.GetWeakPtr())); + } +} + //////////////////////////////////////////////////////////////////////////////// // DesktopWindowTreeHostLinux, ui::PlatformEventDispatcher implementation: @@ -80,32 +94,14 @@ uint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& event) { if (!in_move_loop_) return ui::POST_DISPATCH_PERFORM_DEFAULT; - XEvent* xev = event; - ui::EventType type = ui::EventTypeFromNative(xev); - switch (type) { + switch (event->type()) { case ui::ET_MOUSE_MOVED: case ui::ET_MOUSE_DRAGGED: { - bool dispatch_mouse_event = !last_motion_in_screen_.get(); - last_motion_in_screen_.reset( - ui::EventFromNative(xev).release()->AsMouseEvent()); - last_motion_in_screen_->set_location( - ui::EventSystemLocationFromNative(xev)); - 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(&X11WholeScreenMoveLoop::DispatchMouseMovement, - weak_factory_.GetWeakPtr())); - } + PostDispatchIfNeeded(*event->AsMouseEvent()); return ui::POST_DISPATCH_NONE; } case ui::ET_MOUSE_RELEASED: { - int button = (xev->type == ButtonRelease) - ? xev->xbutton.button - : ui::EventButtonFromNative(xev); - if (button == Button1) { + if (event->AsMouseEvent()->IsLeftMouseButton()) { // Assume that drags are being done with the left mouse button. Only // break the drag if the left mouse button was released. DispatchMouseMovement(); @@ -121,7 +117,7 @@ uint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& event) { return ui::POST_DISPATCH_NONE; } case ui::ET_KEY_PRESSED: - if (ui::KeyboardCodeFromXKeyEvent(xev) == ui::VKEY_ESCAPE) { + if (event->AsKeyEvent()->key_code() == ui::VKEY_ESCAPE) { canceled_ = true; EndMoveLoop(); return ui::POST_DISPATCH_NONE; @@ -167,7 +163,7 @@ bool X11WholeScreenMoveLoop::RunMoveLoop(aura::Window* source, std::unique_ptr<ui::ScopedEventDispatcher> old_dispatcher = std::move(nested_dispatcher_); nested_dispatcher_ = - ui::PlatformEventSource::GetInstance()->OverrideDispatcher(this); + ui::PlatformEventSource::GetInstance()->OverrideDispatcher(this); // We are handling a mouse drag outside of the aura::Window system. We must // manually make aura think that the mouse button is pressed so that we don't @@ -261,13 +257,12 @@ void X11WholeScreenMoveLoop::GrabEscKey() { } void X11WholeScreenMoveLoop::CreateDragInputWindow(XDisplay* display) { - unsigned long attribute_mask = CWEventMask | CWOverrideRedirect; XSetWindowAttributes swa; memset(&swa, 0, sizeof(swa)); swa.override_redirect = x11::True; grab_input_window_ = XCreateWindow(display, DefaultRootWindow(display), -100, -100, 10, 10, 0, CopyFromParent, InputOnly, - CopyFromParent, attribute_mask, &swa); + CopyFromParent, CWOverrideRedirect, &swa); uint32_t event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask; diff --git a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h index 529cb62bac6..1fa5bbd5cca 100644 --- a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h +++ b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h @@ -7,6 +7,8 @@ #include <stdint.h> +#include <memory> + #include "base/callback.h" #include "base/compiler_specific.h" #include "base/macros.h" @@ -28,7 +30,7 @@ namespace ui { class MouseEvent; class ScopedEventDispatcher; class XScopedEventSelector; -} +} // namespace ui namespace views { @@ -62,6 +64,8 @@ class X11WholeScreenMoveLoop : public X11MoveLoop, // Dispatch mouse movement event to |delegate_| in a posted task. void DispatchMouseMovement(); + void PostDispatchIfNeeded(const ui::MouseEvent& event); + X11MoveLoopDelegate* delegate_; // Are we running a nested run loop from RunMoveLoop()? diff --git a/chromium/ui/views/widget/desktop_widget_unittest.cc b/chromium/ui/views/widget/desktop_widget_unittest.cc index 411a2ede663..6295852a6cb 100644 --- a/chromium/ui/views/widget/desktop_widget_unittest.cc +++ b/chromium/ui/views/widget/desktop_widget_unittest.cc @@ -51,16 +51,14 @@ TEST_F(DesktopScreenPositionClientTest, PositionControlWithNonRootParent) { // Create 3 windows. A root window, an arbitrary window parented to the root // but NOT positioned at (0,0) relative to the root, and then a third window // parented to the second, also not positioned at (0,0). - Widget::InitParams params1 = - CreateParams(Widget::InitParams::TYPE_WINDOW); + Widget::InitParams params1 = CreateParams(Widget::InitParams::TYPE_WINDOW); params1.bounds = gfx::Rect( origin + work_area.OffsetFromOrigin(), gfx::Size(700, work_area.height() - origin.y() - work_area.y())); params1.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; widget1.Init(std::move(params1)); - Widget::InitParams params2 = - CreateParams(Widget::InitParams::TYPE_WINDOW); + Widget::InitParams params2 = CreateParams(Widget::InitParams::TYPE_WINDOW); params2.bounds = gfx::Rect(origin, gfx::Size(600, work_area.height() - 100)); params2.parent = widget1.GetNativeView(); params2.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; @@ -69,8 +67,7 @@ TEST_F(DesktopScreenPositionClientTest, PositionControlWithNonRootParent) { params2, &widget2, test::kStubCapture, nullptr); widget2.Init(std::move(params2)); - Widget::InitParams params3 = - CreateParams(Widget::InitParams::TYPE_CONTROL); + Widget::InitParams params3 = CreateParams(Widget::InitParams::TYPE_CONTROL); params3.parent = widget2.GetNativeView(); params3.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params3.child = true; diff --git a/chromium/ui/views/widget/drop_helper.cc b/chromium/ui/views/widget/drop_helper.cc index 571361a64b4..445cd80b3e4 100644 --- a/chromium/ui/views/widget/drop_helper.cc +++ b/chromium/ui/views/widget/drop_helper.cc @@ -4,6 +4,8 @@ #include "ui/views/widget/drop_helper.h" +#include <set> + #include "base/callback.h" #include "base/no_destructor.h" #include "build/build_config.h" @@ -48,8 +50,8 @@ int DropHelper::OnDragOver(const OSExchangeData& data, const gfx::Point& root_view_location, int drag_operation) { const View* old_deepest_view = deepest_view_; - View* view = CalculateTargetViewImpl(root_view_location, data, true, - &deepest_view_); + View* view = + CalculateTargetViewImpl(root_view_location, data, true, &deepest_view_); if (view != target_view_) { // Target changed. Notify old drag exited, then new drag entered. @@ -96,19 +98,17 @@ int DropHelper::OnDrop(const OSExchangeData& data, return drop_view->OnPerformDrop(drop_event); } -View* DropHelper::CalculateTargetView( - const gfx::Point& root_view_location, - const OSExchangeData& data, - bool check_can_drop) { +View* DropHelper::CalculateTargetView(const gfx::Point& root_view_location, + const OSExchangeData& data, + bool check_can_drop) { return CalculateTargetViewImpl(root_view_location, data, check_can_drop, nullptr); } -View* DropHelper::CalculateTargetViewImpl( - const gfx::Point& root_view_location, - const OSExchangeData& data, - bool check_can_drop, - View** deepest_view) { +View* DropHelper::CalculateTargetViewImpl(const gfx::Point& root_view_location, + const OSExchangeData& data, + bool check_can_drop, + View** deepest_view) { View* view = root_view_->GetEventHandlerForPoint(root_view_location); if (view == deepest_view_) { // The view the mouse is over hasn't changed; reuse the target. @@ -116,9 +116,9 @@ View* DropHelper::CalculateTargetViewImpl( } if (deepest_view) *deepest_view = view; - // TODO(sky): for the time being these are separate. Once I port chrome menu - // I can switch to the #else implementation and nuke the OS_WIN - // implementation. + // TODO(sky): for the time being these are separate. Once I port chrome menu + // I can switch to the #else implementation and nuke the OS_WIN + // implementation. #if defined(OS_WIN) // View under mouse changed, which means a new view may want the drop. // Walk the tree, stopping at target_view_ as we know it'll accept the diff --git a/chromium/ui/views/widget/native_widget_aura.cc b/chromium/ui/views/widget/native_widget_aura.cc index a30e4d8264a..efd53803fa4 100644 --- a/chromium/ui/views/widget/native_widget_aura.cc +++ b/chromium/ui/views/widget/native_widget_aura.cc @@ -109,8 +109,8 @@ NativeWidgetAura::NativeWidgetAura(internal::NativeWidgetDelegate* delegate) // static void NativeWidgetAura::RegisterNativeWidgetForWindow( - internal::NativeWidgetPrivate* native_widget, - aura::Window* window) { + internal::NativeWidgetPrivate* native_widget, + aura::Window* window) { window->SetProperty(kNativeWidgetPrivateKey, native_widget); } @@ -230,8 +230,8 @@ void NativeWidgetAura::InitNativeWidget(Widget::InitParams params) { if (parent) { parent->AddChild(window_); } else { - aura::client::ParentWindowWithContext( - window_, context->GetRootWindow(), window_bounds); + aura::client::ParentWindowWithContext(window_, context->GetRootWindow(), + window_bounds); } window_->AddObserver(this); @@ -400,8 +400,7 @@ void NativeWidgetAura::CenterWindow(const gfx::Size& size) { gfx::Rect window_bounds( parent_bounds.x() + (parent_bounds.width() - size.width()) / 2, parent_bounds.y() + (parent_bounds.height() - size.height()) / 2, - size.width(), - size.height()); + size.width(), size.height()); // Don't size the window bigger than the parent, otherwise the user may not be // able to close or move it. window_bounds.AdjustToFit(parent_bounds); @@ -409,7 +408,7 @@ void NativeWidgetAura::CenterWindow(const gfx::Size& size) { // Convert the bounds back relative to the parent. gfx::Point origin = window_bounds.origin(); aura::Window::ConvertPointToTarget(window_->GetRootWindow(), - window_->parent(), &origin); + window_->parent(), &origin); window_bounds.set_origin(origin); window_->SetBounds(window_bounds); } @@ -419,8 +418,8 @@ void NativeWidgetAura::GetWindowPlacement( ui::WindowShowState* show_state) const { // The interface specifies returning restored bounds, not current bounds. *bounds = GetRestoredBounds(); - *show_state = window_ ? window_->GetProperty(aura::client::kShowStateKey) : - ui::SHOW_STATE_DEFAULT; + *show_state = window_ ? window_->GetProperty(aura::client::kShowStateKey) + : ui::SHOW_STATE_DEFAULT; } bool NativeWidgetAura::SetWindowTitle(const base::string16& title) { @@ -440,6 +439,10 @@ void NativeWidgetAura::SetWindowIcons(const gfx::ImageSkia& window_icon, void NativeWidgetAura::InitModalType(ui::ModalType modal_type) { if (modal_type != ui::MODAL_TYPE_NONE) window_->SetProperty(aura::client::kModalKey, modal_type); + if (modal_type == ui::MODAL_TYPE_WINDOW) { + wm::TransientWindowManager::GetOrCreate(window_) + ->set_parent_controls_visibility(true); + } } gfx::Rect NativeWidgetAura::GetWindowBoundsInScreen() const { @@ -644,12 +647,12 @@ void NativeWidgetAura::Minimize() { bool NativeWidgetAura::IsMaximized() const { return window_ && window_->GetProperty(aura::client::kShowStateKey) == - ui::SHOW_STATE_MAXIMIZED; + ui::SHOW_STATE_MAXIMIZED; } bool NativeWidgetAura::IsMinimized() const { return window_ && window_->GetProperty(aura::client::kShowStateKey) == - ui::SHOW_STATE_MINIMIZED; + ui::SHOW_STATE_MINIMIZED; } void NativeWidgetAura::Restore() { @@ -666,7 +669,7 @@ void NativeWidgetAura::SetFullscreen(bool fullscreen) { bool NativeWidgetAura::IsFullscreen() const { return window_ && window_->GetProperty(aura::client::kShowStateKey) == - ui::SHOW_STATE_FULLSCREEN; + ui::SHOW_STATE_FULLSCREEN; } void NativeWidgetAura::SetCanAppearInExistingFullscreenSpaces( @@ -761,7 +764,7 @@ Widget::MoveLoopResult NativeWidgetAura::RunMoveLoop( SetCapture(); wm::WindowMoveSource window_move_source = - source == Widget::MOVE_LOOP_SOURCE_MOUSE ? wm::WINDOW_MOVE_SOURCE_MOUSE + source == Widget::MoveLoopSource::kMouse ? wm::WINDOW_MOVE_SOURCE_MOUSE : wm::WINDOW_MOVE_SOURCE_TOUCH; if (move_client->RunMoveLoop(window_, drag_offset, window_move_source) == wm::MOVE_SUCCESSFUL) { @@ -821,6 +824,10 @@ void NativeWidgetAura::OnSizeConstraintsChanged() { SetResizeBehaviorFromDelegate(GetWidget()->widget_delegate(), window_); } +void NativeWidgetAura::OnNativeViewHierarchyWillChange() {} + +void NativeWidgetAura::OnNativeViewHierarchyChanged() {} + std::string NativeWidgetAura::GetName() const { return window_ ? window_->GetName() : std::string(); } @@ -860,8 +867,8 @@ int NativeWidgetAura::GetNonClientComponent(const gfx::Point& point) const { } bool NativeWidgetAura::ShouldDescendIntoChildForEventHandling( - aura::Window* child, - const gfx::Point& location) { + aura::Window* child, + const gfx::Point& location) { return delegate_->ShouldDescendIntoChildForEventHandling( window_->layer(), child, child->layer(), location); } @@ -1018,14 +1025,14 @@ void NativeWidgetAura::OnWindowFocused(aura::Window* gained_focus, void NativeWidgetAura::OnDragEntered(const ui::DropTargetEvent& event) { DCHECK(drop_helper_.get() != nullptr); - last_drop_operation_ = drop_helper_->OnDragOver(event.data(), - event.location(), event.source_operations()); + last_drop_operation_ = drop_helper_->OnDragOver( + event.data(), event.location(), event.source_operations()); } int NativeWidgetAura::OnDragUpdated(const ui::DropTargetEvent& event) { DCHECK(drop_helper_.get() != nullptr); - last_drop_operation_ = drop_helper_->OnDragOver(event.data(), - event.location(), event.source_operations()); + last_drop_operation_ = drop_helper_->OnDragOver( + event.data(), event.location(), event.source_operations()); return last_drop_operation_; } @@ -1038,7 +1045,7 @@ int NativeWidgetAura::OnPerformDrop(const ui::DropTargetEvent& event, std::unique_ptr<ui::OSExchangeData> data) { DCHECK(drop_helper_.get() != nullptr); return drop_helper_->OnDrop(event.data(), event.location(), - last_drop_operation_); + last_drop_operation_); } //////////////////////////////////////////////////////////////////////////////// @@ -1215,8 +1222,8 @@ void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView native_view, // matches our previous behaviour; the global stacking client would almost // always reattach the window to the same RootWindow. aura::Window* root_window = native_view->GetRootWindow(); - aura::client::ParentWindowWithContext( - native_view, root_window, root_window->GetBoundsInScreen()); + aura::client::ParentWindowWithContext(native_view, root_window, + root_window->GetBoundsInScreen()); } // And now, notify them that they have a brand new parent. diff --git a/chromium/ui/views/widget/native_widget_aura.h b/chromium/ui/views/widget/native_widget_aura.h index b31bef115e8..df9c3d83096 100644 --- a/chromium/ui/views/widget/native_widget_aura.h +++ b/chromium/ui/views/widget/native_widget_aura.h @@ -5,6 +5,7 @@ #ifndef UI_VIEWS_WIDGET_NATIVE_WIDGET_AURA_H_ #define UI_VIEWS_WIDGET_NATIVE_WIDGET_AURA_H_ +#include <memory> #include <string> #include "base/macros.h" @@ -67,7 +68,7 @@ class VIEWS_EXPORT NativeWidgetAura : public internal::NativeWidgetPrivate, static void SetResizeBehaviorFromDelegate(WidgetDelegate* delegate, aura::Window* window); - // Overridden from internal::NativeWidgetPrivate: + // internal::NativeWidgetPrivate: void InitNativeWidget(Widget::InitParams params) override; void OnWidgetInitDone() override; NonClientFrameView* CreateNonClientFrameView() override; @@ -156,9 +157,11 @@ class VIEWS_EXPORT NativeWidgetAura : public internal::NativeWidgetPrivate, bool IsTranslucentWindowOpacitySupported() const override; ui::GestureRecognizer* GetGestureRecognizer() override; void OnSizeConstraintsChanged() override; + void OnNativeViewHierarchyWillChange() override; + void OnNativeViewHierarchyChanged() override; std::string GetName() const override; - // Overridden from aura::WindowDelegate: + // aura::WindowDelegate: gfx::Size GetMinimumSize() const override; gfx::Size GetMaximumSize() const override; void OnBoundsChanged(const gfx::Rect& old_bounds, @@ -180,32 +183,32 @@ class VIEWS_EXPORT NativeWidgetAura : public internal::NativeWidgetPrivate, void GetHitTestMask(SkPath* mask) const override; void UpdateVisualState() override; - // Overridden from aura::WindowObserver: + // aura::WindowObserver: void OnWindowPropertyChanged(aura::Window* window, const void* key, intptr_t old) override; void OnResizeLoopStarted(aura::Window* window) override; void OnResizeLoopEnded(aura::Window* window) override; - // Overridden from ui::EventHandler: + // ui::EventHandler: void OnKeyEvent(ui::KeyEvent* event) override; void OnMouseEvent(ui::MouseEvent* event) override; void OnScrollEvent(ui::ScrollEvent* event) override; void OnGestureEvent(ui::GestureEvent* event) override; - // Overridden from wm::ActivationDelegate: + // wm::ActivationDelegate: bool ShouldActivate() const override; - // Overridden from wm::ActivationChangeObserver: + // wm::ActivationChangeObserver: void OnWindowActivated(wm::ActivationChangeObserver::ActivationReason reason, aura::Window* gained_active, aura::Window* lost_active) override; - // Overridden from aura::client::FocusChangeObserver: + // aura::client::FocusChangeObserver: void OnWindowFocused(aura::Window* gained_focus, aura::Window* lost_focus) override; - // Overridden from aura::client::DragDropDelegate: + // aura::client::DragDropDelegate: void OnDragEntered(const ui::DropTargetEvent& event) override; int OnDragUpdated(const ui::DropTargetEvent& event) override; void OnDragExited() override; diff --git a/chromium/ui/views/widget/native_widget_aura_unittest.cc b/chromium/ui/views/widget/native_widget_aura_unittest.cc index 4ddad6d7a06..5bd2526da57 100644 --- a/chromium/ui/views/widget/native_widget_aura_unittest.cc +++ b/chromium/ui/views/widget/native_widget_aura_unittest.cc @@ -5,6 +5,7 @@ #include "ui/views/widget/native_widget_aura.h" #include <memory> +#include <utility> #include "base/command_line.h" #include "base/macros.h" @@ -33,7 +34,7 @@ namespace { NativeWidgetAura* Init(aura::Window* parent, Widget* widget) { Widget::InitParams params(Widget::InitParams::TYPE_POPUP); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.parent = parent; widget->Init(std::move(params)); return static_cast<NativeWidgetAura*>(widget->native_widget()); @@ -97,9 +98,7 @@ TEST_F(NativeWidgetAuraTest, CenterWindowLargeParent) { NativeWidgetAura* window = Init(parent.get(), widget.get()); window->CenterWindow(gfx::Size(100, 100)); - EXPECT_EQ(gfx::Rect((640 - 100) / 2, - (480 - 100) / 2, - 100, 100), + EXPECT_EQ(gfx::Rect((640 - 100) / 2, (480 - 100) / 2, 100, 100), window->GetNativeWindow()->bounds()); widget->CloseNow(); } @@ -114,9 +113,7 @@ TEST_F(NativeWidgetAuraTest, CenterWindowSmallParent) { NativeWidgetAura* window = Init(parent.get(), widget.get()); window->CenterWindow(gfx::Size(100, 100)); - EXPECT_EQ(gfx::Rect((480 - 100) / 2, - (320 - 100) / 2, - 100, 100), + EXPECT_EQ(gfx::Rect((480 - 100) / 2, (320 - 100) / 2, 100, 100), window->GetNativeWindow()->bounds()); widget->CloseNow(); } @@ -158,9 +155,7 @@ class TestWindowObserver : public aura::WindowObserver { explicit TestWindowObserver(gfx::NativeWindow window) : window_(window) { window_->AddObserver(this); } - ~TestWindowObserver() override { - window_->RemoveObserver(this); - } + ~TestWindowObserver() override { window_->RemoveObserver(this); } // aura::WindowObserver: void OnWindowPropertyChanged(aura::Window* window, @@ -181,7 +176,7 @@ class TestWindowObserver : public aura::WindowObserver { int count_ = 0; ui::WindowShowState state_ = ui::WindowShowState::SHOW_STATE_DEFAULT; - DISALLOW_COPY_AND_ASSIGN(TestWindowObserver); + DISALLOW_COPY_AND_ASSIGN(TestWindowObserver); }; // Tests that window transitions from normal to minimized and back do not @@ -255,7 +250,7 @@ class MaximizeLayoutManager : public TestLayoutManagerBase { // This simulates BrowserView, which creates a custom RootView so that // OnNativeWidgetSizeChanged that is invoked during Init matters. -class TestWidget : public views::Widget { +class TestWidget : public Widget { public: TestWidget() = default; @@ -289,7 +284,7 @@ TEST_F(NativeWidgetAuraTest, ShowMaximizedDoesntBounceAround) { root_window()->SetLayoutManager(new MaximizeLayoutManager); std::unique_ptr<TestWidget> widget(new TestWidget()); Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.parent = nullptr; params.context = root_window(); params.show_state = ui::SHOW_STATE_MAXIMIZED; @@ -321,13 +316,13 @@ class PropertyTestLayoutManager : public TestLayoutManagerBase { DISALLOW_COPY_AND_ASSIGN(PropertyTestLayoutManager); }; -class PropertyTestWidgetDelegate : public views::WidgetDelegate { +class PropertyTestWidgetDelegate : public WidgetDelegate { public: explicit PropertyTestWidgetDelegate(Widget* widget) : widget_(widget) {} ~PropertyTestWidgetDelegate() override = default; private: - // views::WidgetDelegate: + // WidgetDelegate: bool CanMaximize() const override { return true; } bool CanMinimize() const override { return true; } bool CanResize() const override { return true; } @@ -346,7 +341,7 @@ TEST_F(NativeWidgetAuraTest, TestPropertiesWhenAddedToLayout) { root_window()->SetLayoutManager(layout_manager); std::unique_ptr<TestWidget> widget(new TestWidget()); Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.delegate = new PropertyTestWidgetDelegate(widget.get()); params.parent = nullptr; params.context = root_window(); @@ -358,7 +353,7 @@ TEST_F(NativeWidgetAuraTest, TestPropertiesWhenAddedToLayout) { TEST_F(NativeWidgetAuraTest, GetClientAreaScreenBounds) { // Create a widget. Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.context = root_window(); params.bounds.SetRect(10, 20, 300, 400); std::unique_ptr<Widget> widget(new Widget()); @@ -373,20 +368,14 @@ TEST_F(NativeWidgetAuraTest, GetClientAreaScreenBounds) { } // View subclass that tracks whether it has gotten a gesture event. -class GestureTrackingView : public views::View { +class GestureTrackingView : public View { public: GestureTrackingView() = default; - void set_consume_gesture_event(bool value) { - consume_gesture_event_ = value; - } + void set_consume_gesture_event(bool value) { consume_gesture_event_ = value; } - void clear_got_gesture_event() { - got_gesture_event_ = false; - } - bool got_gesture_event() const { - return got_gesture_event_; - } + void clear_got_gesture_event() { got_gesture_event_ = false; } + bool got_gesture_event() const { return got_gesture_event_; } // View overrides: void OnGestureEvent(ui::GestureEvent* event) override { @@ -417,7 +406,7 @@ TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) { view->AddChildView(child); std::unique_ptr<TestWidget> widget(new TestWidget()); Widget::InitParams params(Widget::InitParams::TYPE_WINDOW_FRAMELESS); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + 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)); @@ -447,20 +436,15 @@ TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) { EXPECT_TRUE(view->got_gesture_event()); EXPECT_FALSE(child->got_gesture_event()); view->clear_got_gesture_event(); - - // Work around for bug in NativeWidgetAura. - // TODO: fix bug and remove this. - widget->Close(); } // 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|. - views::View* parent_root = new views::View; + View* parent_root = new View; std::unique_ptr<Widget> parent(new Widget()); Widget::InitParams parent_params(Widget::InitParams::TYPE_WINDOW_FRAMELESS); - parent_params.ownership = - views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; parent_params.context = root_window(); parent->Init(std::move(parent_params)); parent->SetContentsView(parent_root); @@ -469,51 +453,46 @@ TEST_F(NativeWidgetAuraTest, PreferViewLayersToChildWindows) { std::unique_ptr<Widget> child(new Widget()); Widget::InitParams child_params(Widget::InitParams::TYPE_CONTROL); - child_params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; child_params.parent = parent->GetNativeWindow(); child->Init(std::move(child_params)); child->SetBounds(gfx::Rect(0, 0, 200, 200)); child->Show(); // Point is over |child|. - EXPECT_EQ(child->GetNativeWindow(), - parent->GetNativeWindow()->GetEventHandlerForPoint( - gfx::Point(50, 50))); + EXPECT_EQ( + child->GetNativeWindow(), + parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(50, 50))); // Create a view with a layer and stack it at the bottom (below |child|). - views::View* view_with_layer = new views::View; + View* view_with_layer = new View; parent_root->AddChildView(view_with_layer); view_with_layer->SetBounds(0, 0, 50, 50); view_with_layer->SetPaintToLayer(); // Make sure that |child| still gets the event. - EXPECT_EQ(child->GetNativeWindow(), - parent->GetNativeWindow()->GetEventHandlerForPoint( - gfx::Point(20, 20))); + EXPECT_EQ( + child->GetNativeWindow(), + parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(20, 20))); // Move |view_with_layer| to the top and make sure it gets the // event when the point is within |view_with_layer|'s bounds. - view_with_layer->layer()->parent()->StackAtTop( - view_with_layer->layer()); - EXPECT_EQ(parent->GetNativeWindow(), - parent->GetNativeWindow()->GetEventHandlerForPoint( - gfx::Point(20, 20))); + view_with_layer->layer()->parent()->StackAtTop(view_with_layer->layer()); + EXPECT_EQ( + parent->GetNativeWindow(), + parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(20, 20))); // Point is over |child|, it should get the event. - EXPECT_EQ(child->GetNativeWindow(), - parent->GetNativeWindow()->GetEventHandlerForPoint( - gfx::Point(70, 70))); + EXPECT_EQ( + child->GetNativeWindow(), + parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(70, 70))); delete view_with_layer; view_with_layer = nullptr; - EXPECT_EQ(child->GetNativeWindow(), - parent->GetNativeWindow()->GetEventHandlerForPoint( - gfx::Point(20, 20))); - - // Work around for bug in NativeWidgetAura. - // TODO: fix bug and remove this. - parent->Close(); + EXPECT_EQ( + child->GetNativeWindow(), + parent->GetNativeWindow()->GetEventHandlerForPoint(gfx::Point(20, 20))); } // Verifies views with layers are targeted for events properly. @@ -570,7 +549,7 @@ TEST_F(NativeWidgetAuraTest, FlashFrame) { std::unique_ptr<Widget> widget(new Widget()); Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); params.context = root_window(); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; widget->Init(std::move(params)); aura::Window* window = widget->GetNativeWindow(); EXPECT_FALSE(window->GetProperty(aura::client::kDrawAttentionKey)); @@ -621,14 +600,12 @@ class MoveTestWidgetDelegate : public WidgetDelegateView { TEST_F(NativeWidgetAuraTest, OnWidgetMovedInvokedAfterAcquireLayer) { // |delegate| deletes itself when the widget is destroyed. MoveTestWidgetDelegate* delegate = new MoveTestWidgetDelegate; - Widget* widget = - Widget::CreateWindowWithContextAndBounds(delegate, - root_window(), - gfx::Rect(10, 10, 100, 200)); + Widget* widget = Widget::CreateWindowWithContext(delegate, root_window(), + gfx::Rect(10, 10, 100, 200)); widget->Show(); delegate->ClearGotMove(); // Simulate a maximize with animation. - delete widget->GetNativeView()->RecreateLayer().release(); + widget->GetNativeView()->RecreateLayer(); widget->SetBounds(gfx::Rect(0, 0, 500, 500)); EXPECT_TRUE(delegate->got_move()); widget->CloseNow(); @@ -639,12 +616,12 @@ TEST_F(NativeWidgetAuraTest, OnWidgetMovedInvokedAfterAcquireLayer) { // can not be activated. TEST_F(NativeWidgetAuraTest, PreventFocusOnNonActivableWindow) { test_focus_rules()->set_can_activate(false); - views::test::TestInitialFocusWidgetDelegate delegate(root_window()); + test::TestInitialFocusWidgetDelegate delegate(root_window()); delegate.GetWidget()->Show(); EXPECT_FALSE(delegate.view()->HasFocus()); test_focus_rules()->set_can_activate(true); - views::test::TestInitialFocusWidgetDelegate delegate2(root_window()); + test::TestInitialFocusWidgetDelegate delegate2(root_window()); delegate2.GetWidget()->Show(); EXPECT_TRUE(delegate2.view()->HasFocus()); } @@ -683,5 +660,65 @@ TEST_F(NativeWidgetAuraTest, VisibilityOfChildBubbleWindow) { EXPECT_TRUE(child.IsVisible()); } +class ModalWidgetDelegate : public WidgetDelegate { + public: + explicit ModalWidgetDelegate(Widget* widget) : widget_(widget) {} + ~ModalWidgetDelegate() override = default; + + // WidgetDelegate: + void DeleteDelegate() override { delete this; } + Widget* GetWidget() override { return widget_; } + const Widget* GetWidget() const override { return widget_; } + ui::ModalType GetModalType() const override { + return ui::ModalType::MODAL_TYPE_WINDOW; + } + + private: + Widget* widget_; + + DISALLOW_COPY_AND_ASSIGN(ModalWidgetDelegate); +}; + +// Tests that for a child transient window, if its modal type is +// ui::MODAL_TYPE_WINDOW, then its visibility is controlled by its transient +// parent's visibility. +TEST_F(NativeWidgetAuraTest, TransientChildModalWindowVisibility) { + // Create a parent window. + Widget parent; + Widget::InitParams parent_params(Widget::InitParams::TYPE_WINDOW); + parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + parent_params.context = root_window(); + parent.Init(std::move(parent_params)); + parent.SetBounds(gfx::Rect(0, 0, 400, 400)); + parent.Show(); + EXPECT_TRUE(parent.IsVisible()); + + // Create a ui::MODAL_TYPE_WINDOW modal type transient child window. + Widget child; + Widget::InitParams child_params(Widget::InitParams::TYPE_WINDOW); + child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + child_params.parent = parent.GetNativeWindow(); + child_params.delegate = new ModalWidgetDelegate(&child); + child.Init(std::move(child_params)); + child.SetBounds(gfx::Rect(0, 0, 200, 200)); + child.Show(); + EXPECT_TRUE(parent.IsVisible()); + EXPECT_TRUE(child.IsVisible()); + + // Hide the parent window should also hide the child window. + parent.Hide(); + EXPECT_FALSE(parent.IsVisible()); + EXPECT_FALSE(child.IsVisible()); + + // The child window can't be shown if the parent window is hidden. + child.Show(); + EXPECT_FALSE(parent.IsVisible()); + EXPECT_FALSE(child.IsVisible()); + + parent.Show(); + EXPECT_TRUE(parent.IsVisible()); + EXPECT_TRUE(child.IsVisible()); +} + } // namespace } // namespace views diff --git a/chromium/ui/views/widget/native_widget_delegate.h b/chromium/ui/views/widget/native_widget_delegate.h index ea5da66b67f..d8ed38d2de5 100644 --- a/chromium/ui/views/widget/native_widget_delegate.h +++ b/chromium/ui/views/widget/native_widget_delegate.h @@ -14,7 +14,7 @@ class SkPath; namespace gfx { class Point; class Size; -} +} // namespace gfx namespace ui { class GestureEvent; @@ -23,7 +23,7 @@ class Layer; class MouseEvent; class PaintContext; class ScrollEvent; -} +} // namespace ui namespace views { class Widget; diff --git a/chromium/ui/views/widget/native_widget_mac.h b/chromium/ui/views/widget/native_widget_mac.h index dd64370ab98..24b98636751 100644 --- a/chromium/ui/views/widget/native_widget_mac.h +++ b/chromium/ui/views/widget/native_widget_mac.h @@ -5,7 +5,11 @@ #ifndef UI_VIEWS_WIDGET_NATIVE_WIDGET_MAC_H_ #define UI_VIEWS_WIDGET_NATIVE_WIDGET_MAC_H_ +#include <memory> +#include <string> + #include "base/macros.h" +#include "ui/base/ime/input_method_delegate.h" #include "ui/base/window_open_disposition.h" #include "ui/gfx/native_widget_types.h" #include "ui/views/widget/native_widget_private.h" @@ -31,10 +35,12 @@ namespace test { class HitTestNativeWidgetMac; class MockNativeWidgetMac; class WidgetTest; -} +} // namespace test class NativeWidgetMacNSWindowHost; -class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate { +class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate, + public FocusChangeListener, + public ui::internal::InputMethodDelegate { public: explicit NativeWidgetMac(internal::NativeWidgetDelegate* delegate); ~NativeWidgetMac() override; @@ -49,6 +55,9 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate { // destroyed. void WindowDestroyed(); + // Called when the backing NSWindow gains or loses key status. + void OnWindowKeyStatusChanged(bool is_key, bool is_content_first_responder); + // The vertical position from which sheets should be anchored, from the top // of the content view. virtual int32_t SheetOffsetY(); @@ -174,6 +183,8 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate { bool IsTranslucentWindowOpacitySupported() const override; ui::GestureRecognizer* GetGestureRecognizer() override; void OnSizeConstraintsChanged() override; + void OnNativeViewHierarchyWillChange() override; + void OnNativeViewHierarchyChanged() override; std::string GetName() const override; // Calls |callback| with the newly created NativeWidget whenever a @@ -182,6 +193,11 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate { base::RepeatingCallback<void(NativeWidgetMac*)> callback); protected: + // The argument to SetBounds is sometimes in screen coordinates and sometimes + // in parent window coordinates. This function will take that bounds argument + // and convert it to screen coordinates if needed. + gfx::Rect ConvertBoundsToScreenIfNeeded(const gfx::Rect& bounds) const; + virtual void PopulateCreateWindowParams( const Widget::InitParams& widget_params, remote_cocoa::mojom::CreateWindowParams* params) {} @@ -220,13 +236,22 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate { return ns_window_host_.get(); } + // Unregister focus listeners from previous focus manager, and register them + // with the |new_focus_manager|. Updates |focus_manager_|. + void SetFocusManager(FocusManager* new_focus_manager); + + // FocusChangeListener: + void OnWillChangeFocus(View* focused_before, View* focused_now) override; + void OnDidChangeFocus(View* focused_before, View* focused_now) override; + + // ui::internal::InputMethodDelegate: + ui::EventDispatchDetails DispatchKeyEventPostIME(ui::KeyEvent* key) override; + private: friend class test::MockNativeWidgetMac; friend class test::HitTestNativeWidgetMac; friend class views::test::WidgetTest; - class ZoomFocusMonitor; - std::unique_ptr<ZoomFocusMonitor> zoom_focus_monitor_; internal::NativeWidgetDelegate* delegate_; std::unique_ptr<NativeWidgetMacNSWindowHost> ns_window_host_; @@ -240,6 +265,14 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate { Widget::InitParams::Type type_; + // Weak pointer to the FocusManager with with |zoom_focus_monitor_| and + // |ns_window_host_| are registered. + FocusManager* focus_manager_ = nullptr; + std::unique_ptr<ui::InputMethod> input_method_; + std::unique_ptr<ZoomFocusMonitor> zoom_focus_monitor_; + // Held while this widget is active if it's a child. + std::unique_ptr<Widget::PaintAsActiveLock> parent_key_lock_; + DISALLOW_COPY_AND_ASSIGN(NativeWidgetMac); }; diff --git a/chromium/ui/views/widget/native_widget_mac.mm b/chromium/ui/views/widget/native_widget_mac.mm index 670250dfa9c..22e0bd3b5ce 100644 --- a/chromium/ui/views/widget/native_widget_mac.mm +++ b/chromium/ui/views/widget/native_widget_mac.mm @@ -23,6 +23,8 @@ #import "components/remote_cocoa/app_shim/views_nswindow_delegate.h" #import "ui/base/cocoa/constrained_window/constrained_window_animation.h" #import "ui/base/cocoa/window_size_constants.h" +#include "ui/base/ime/init/input_method_factory.h" +#include "ui/base/ime/input_method.h" #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/events/gestures/gesture_recognizer_impl_mac.h" @@ -32,7 +34,9 @@ #include "ui/native_theme/native_theme_mac.h" #import "ui/views/cocoa/drag_drop_client_mac.h" #import "ui/views/cocoa/native_widget_mac_ns_window_host.h" +#include "ui/views/cocoa/text_input_host.h" #include "ui/views/widget/drop_helper.h" +#include "ui/views/widget/widget_aura_utils.h" #include "ui/views/widget/widget_delegate.h" #include "ui/views/window/native_frame_view.h" @@ -107,11 +111,10 @@ class NativeWidgetMac::ZoomFocusMonitor : public FocusChangeListener { }; //////////////////////////////////////////////////////////////////////////////// -// NativeWidgetMac, public: +// NativeWidgetMac: NativeWidgetMac::NativeWidgetMac(internal::NativeWidgetDelegate* delegate) - : zoom_focus_monitor_(std::make_unique<ZoomFocusMonitor>()), - delegate_(delegate), + : delegate_(delegate), ns_window_host_(new NativeWidgetMacNSWindowHost(this)), ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET) {} @@ -123,14 +126,13 @@ NativeWidgetMac::~NativeWidgetMac() { } void NativeWidgetMac::WindowDestroying() { - if (auto* focus_manager = GetWidget()->GetFocusManager()) - focus_manager->RemoveFocusChangeListener(zoom_focus_monitor_.get()); OnWindowDestroying(GetNativeWindow()); delegate_->OnNativeWidgetDestroying(); } void NativeWidgetMac::WindowDestroyed() { DCHECK(GetNSWindowMojo()); + SetFocusManager(nullptr); ns_window_host_.reset(); // |OnNativeWidgetDestroyed| may delete |this| if the object does not own // itself. @@ -141,6 +143,35 @@ void NativeWidgetMac::WindowDestroyed() { delete this; } +void NativeWidgetMac::OnWindowKeyStatusChanged( + bool is_key, + bool is_content_first_responder) { + Widget* widget = GetWidget(); + if (!widget->OnNativeWidgetActivationChanged(is_key)) + return; + // The contentView is the BridgedContentView hosting the views::RootView. The + // focus manager will already know if a native subview has focus. + if (!is_content_first_responder) + return; + + if (is_key) { + widget->OnNativeFocus(); + widget->GetFocusManager()->RestoreFocusedView(); + if (NativeWidgetMacNSWindowHost* parent_host = ns_window_host_->parent()) { + // Unclear under what circumstances this would be null, but speculatively + // working around https://crbug/1050430 + if (Widget* top_widget = + parent_host->native_widget_mac()->GetTopLevelWidget()) { + parent_key_lock_ = top_widget->LockPaintAsActive(); + } + } + } else { + widget->OnNativeBlur(); + widget->GetFocusManager()->StoreFocusedView(true); + parent_key_lock_.reset(); + } +} + int32_t NativeWidgetMac::SheetOffsetY() { return 0; } @@ -161,9 +192,6 @@ bool NativeWidgetMac::ExecuteCommand( return false; } -//////////////////////////////////////////////////////////////////////////////// -// NativeWidgetMac, internal::NativeWidgetPrivate implementation: - void NativeWidgetMac::InitNativeWidget(Widget::InitParams params) { ownership_ = params.ownership; name_ = params.name; @@ -194,7 +222,8 @@ void NativeWidgetMac::InitNativeWidget(Widget::InitParams params) { ns_window_host_->CreateInProcessNSWindowBridge(std::move(window)); } ns_window_host_->SetParent(parent_host); - ns_window_host_->InitWindow(params); + ns_window_host_->InitWindow(params, + ConvertBoundsToScreenIfNeeded(params.bounds)); OnWindowInitialized(); // Only set the z-order here if it is non-default since setting it may affect @@ -212,12 +241,12 @@ void NativeWidgetMac::InitNativeWidget(Widget::InitParams params) { GetWidget()->GetRootView()->bounds()); if (auto* focus_manager = GetWidget()->GetFocusManager()) { GetNSWindowMojo()->MakeFirstResponder(); - ns_window_host_->SetFocusManager(focus_manager); - // Non-top-level widgets use the the top level widget's focus manager. - if (GetWidget() == GetTopLevelWidget()) - focus_manager->AddFocusChangeListener(zoom_focus_monitor_.get()); + // Only one ZoomFocusMonitor is needed per FocusManager, so create one only + // for top-level widgets. + if (GetWidget()->is_top_level()) + zoom_focus_monitor_ = std::make_unique<ZoomFocusMonitor>(); + SetFocusManager(focus_manager); } - ns_window_host_->CreateCompositor(params); if (g_init_native_widget_callback) @@ -328,7 +357,13 @@ bool NativeWidgetMac::HasCapture() const { } ui::InputMethod* NativeWidgetMac::GetInputMethod() { - return ns_window_host_ ? ns_window_host_->GetInputMethod() : nullptr; + if (!input_method_) { + input_method_ = ui::CreateInputMethod(this, gfx::kNullAcceleratedWidget); + // For now, use always-focused mode on Mac for the input method. + // TODO(tapted): Move this to OnWindowKeyStatusChangedTo() and balance. + input_method_->OnFocus(); + } + return input_method_.get(); } void NativeWidgetMac::CenterWindow(const gfx::Size& size) { @@ -395,9 +430,35 @@ std::string NativeWidgetMac::GetWorkspace() const { : std::string(); } +gfx::Rect NativeWidgetMac::ConvertBoundsToScreenIfNeeded( + const gfx::Rect& bounds) const { + // If there isn't a parent widget, then bounds cannot be relative to the + // parent. + if (!ns_window_host_ || !ns_window_host_->parent() || !GetWidget()) + return bounds; + + // Replicate the logic in desktop_aura/desktop_screen_position_client.cc. + if (GetAuraWindowTypeForWidgetType(type_) == + aura::client::WINDOW_TYPE_POPUP || + GetWidget()->is_top_level()) { + return bounds; + } + + // Empty bounds are only allowed to be specified at initialization and are + // expected not to be translated. + if (bounds.IsEmpty()) + return bounds; + + gfx::Rect bounds_in_screen = bounds; + bounds_in_screen.Offset( + ns_window_host_->parent()->GetWindowBoundsInScreen().OffsetFromOrigin()); + return bounds_in_screen; +} + void NativeWidgetMac::SetBounds(const gfx::Rect& bounds) { - if (ns_window_host_) - ns_window_host_->SetBounds(bounds); + if (!ns_window_host_) + return; + ns_window_host_->SetBoundsInScreen(ConvertBoundsToScreenIfNeeded(bounds)); } void NativeWidgetMac::SetBoundsConstrained(const gfx::Rect& bounds) { @@ -414,9 +475,12 @@ void NativeWidgetMac::SetBoundsConstrained(const gfx::Rect& bounds) { } void NativeWidgetMac::SetSize(const gfx::Size& size) { + if (!ns_window_host_) + return; // Ensure the top-left corner stays in-place (rather than the bottom-left, // which -[NSWindow setContentSize:] would do). - SetBounds(gfx::Rect(GetWindowBoundsInScreen().origin(), size)); + ns_window_host_->SetBoundsInScreen( + gfx::Rect(GetWindowBoundsInScreen().origin(), size)); } void NativeWidgetMac::StackAbove(gfx::NativeView native_view) { @@ -740,6 +804,19 @@ void NativeWidgetMac::OnSizeConstraintsChanged() { widget->widget_delegate()->CanMaximize()); } +void NativeWidgetMac::OnNativeViewHierarchyWillChange() { + // If this is not top-level, then the FocusManager may change, so remove our + // listeners. + if (!GetWidget()->is_top_level()) + SetFocusManager(nullptr); + parent_key_lock_.reset(); +} + +void NativeWidgetMac::OnNativeViewHierarchyChanged() { + if (!GetWidget()->is_top_level()) + SetFocusManager(GetWidget()->GetFocusManager()); +} + std::string NativeWidgetMac::GetName() const { return name_; } @@ -759,9 +836,6 @@ void NativeWidgetMac::SetInitNativeWidgetCallback( new base::RepeatingCallback<void(NativeWidgetMac*)>(std::move(callback)); } -//////////////////////////////////////////////////////////////////////////////// -// NativeWidgetMac, protected: - NativeWidgetMacNSWindow* NativeWidgetMac::CreateNSWindow( const remote_cocoa::mojom::CreateWindowParams* params) { return remote_cocoa::NativeWidgetNSWindowBridge::CreateNSWindow(params) @@ -784,8 +858,56 @@ NativeWidgetMac::GetInProcessNSWindowBridge() const { : nullptr; } +void NativeWidgetMac::SetFocusManager(FocusManager* new_focus_manager) { + if (focus_manager_) { + if (View* old_focus = focus_manager_->GetFocusedView()) + OnDidChangeFocus(old_focus, nullptr); + focus_manager_->RemoveFocusChangeListener(this); + if (zoom_focus_monitor_) + focus_manager_->RemoveFocusChangeListener(zoom_focus_monitor_.get()); + } + focus_manager_ = new_focus_manager; + if (focus_manager_) { + if (View* new_focus = focus_manager_->GetFocusedView()) + OnDidChangeFocus(nullptr, new_focus); + focus_manager_->AddFocusChangeListener(this); + if (zoom_focus_monitor_) + focus_manager_->AddFocusChangeListener(zoom_focus_monitor_.get()); + } +} + +void NativeWidgetMac::OnWillChangeFocus(View* focused_before, + View* focused_now) {} + +void NativeWidgetMac::OnDidChangeFocus(View* focused_before, + View* focused_now) { + ui::InputMethod* input_method = GetWidget()->GetInputMethod(); + if (!input_method) + return; + + ui::TextInputClient* new_text_input_client = + input_method->GetTextInputClient(); + // Sanity check: When focus moves away from the widget (i.e. |focused_now| + // is nil), then the textInputClient will be cleared. + DCHECK(!!focused_now || !new_text_input_client); + if (ns_window_host_) { + ns_window_host_->text_input_host()->SetTextInputClient( + new_text_input_client); + } +} + +ui::EventDispatchDetails NativeWidgetMac::DispatchKeyEventPostIME( + ui::KeyEvent* key) { + DCHECK(focus_manager_); + if (!focus_manager_->OnKeyEvent(*key)) + key->StopPropagation(); + else + GetWidget()->OnKeyEvent(key); + return ui::EventDispatchDetails(); +} + //////////////////////////////////////////////////////////////////////////////// -// Widget, public: +// Widget: // static void Widget::CloseAllSecondaryWidgets() { @@ -821,7 +943,7 @@ const ui::NativeTheme* Widget::GetNativeTheme() const { namespace internal { //////////////////////////////////////////////////////////////////////////////// -// internal::NativeWidgetPrivate, public: +// internal::NativeWidgetPrivate: // static NativeWidgetPrivate* NativeWidgetPrivate::CreateNativeWidget( @@ -921,74 +1043,49 @@ void NativeWidgetPrivate::GetAllOwnedWidgets(gfx::NativeView native_view, } // static -void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView native_view, +void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView child, gfx::NativeView new_parent) { - DCHECK_NE(native_view, new_parent); + DCHECK_NE(child, new_parent); DCHECK([new_parent.GetNativeNSView() window]); - if (!new_parent || [native_view.GetNativeNSView() superview] == - new_parent.GetNativeNSView()) { + if (!new_parent || + [child.GetNativeNSView() superview] == new_parent.GetNativeNSView()) { NOTREACHED(); return; } - NativeWidgetMacNSWindowHost* window_host = - NativeWidgetMacNSWindowHost::GetFromNativeView(native_view); - DCHECK(window_host); - gfx::NativeView bridge_view = - window_host->native_widget_mac()->GetNativeView(); - gfx::NativeWindow bridge_window = - window_host->native_widget_mac()->GetNativeWindow(); - bool bridge_is_top_level = - window_host->native_widget_mac()->GetWidget()->is_top_level(); - DCHECK([native_view.GetNativeNSView() - isDescendantOf:bridge_view.GetNativeNSView()]); - DCHECK(bridge_window && ![bridge_window.GetNativeNSWindow() isSheet]); + NativeWidgetMacNSWindowHost* child_window_host = + NativeWidgetMacNSWindowHost::GetFromNativeView(child); + DCHECK(child_window_host); + gfx::NativeView widget_view = + child_window_host->native_widget_mac()->GetNativeView(); + DCHECK_EQ(child, widget_view); + gfx::NativeWindow widget_window = + child_window_host->native_widget_mac()->GetNativeWindow(); + DCHECK( + [child.GetNativeNSView() isDescendantOf:widget_view.GetNativeNSView()]); + DCHECK(widget_window && ![widget_window.GetNativeNSWindow() isSheet]); NativeWidgetMacNSWindowHost* parent_window_host = NativeWidgetMacNSWindowHost::GetFromNativeView(new_parent); // Early out for no-op changes. - if (native_view == bridge_view && bridge_is_top_level && - window_host->parent() == parent_window_host) { + if (child == widget_view && + child_window_host->parent() == parent_window_host) { return; } // First notify all the widgets that they are being disassociated from their // previous parent. Widget::Widgets widgets; - GetAllChildWidgets(native_view, &widgets); - for (auto* child : widgets) - child->NotifyNativeViewHierarchyWillChange(); - - // Update |bridge_host|'s parent only if - // NativeWidgetNSWindowBridge::ReparentNativeView will. - if (native_view == bridge_view) { - window_host->SetParent(parent_window_host); - if (!bridge_is_top_level) { - // Make |window_host|'s NSView be a child of |new_parent| by adding it as - // a subview. Note that this will have the effect of removing - // |window_host|'s NSView from its NSWindow. The |NSWindow| must remain - // visible because it controls the bounds and visibility of the ui::Layer, - // so just hide it by setting alpha value to zero. - // TODO(ccameron): This path likely violates assumptions. Verify that this - // path is unused and remove it. - LOG(ERROR) << "Reparenting a non-top-level BridgedNativeWidget. This is " - "likely unsupported."; - [new_parent.GetNativeNSView() addSubview:native_view.GetNativeNSView()]; - [bridge_window.GetNativeNSWindow() setAlphaValue:0]; - [bridge_window.GetNativeNSWindow() setIgnoresMouseEvents:YES]; - } - } else { - // TODO(ccameron): This path likely violates assumptions. Verify that this - // path is unused and remove it. - LOG(ERROR) << "Reparenting with a non-root BridgedNativeWidget NSView. " - "This is likely unsupported."; - [new_parent.GetNativeNSView() addSubview:native_view.GetNativeNSView()]; - } + GetAllChildWidgets(child, &widgets); + for (auto* widget : widgets) + widget->NotifyNativeViewHierarchyWillChange(); + + child_window_host->SetParent(parent_window_host); // And now, notify them that they have a brand new parent. - for (auto* child : widgets) - child->NotifyNativeViewHierarchyChanged(); + for (auto* widget : widgets) + widget->NotifyNativeViewHierarchyChanged(); } // static diff --git a/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm b/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm index f8cf2390153..77a8c22c22a 100644 --- a/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm +++ b/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm @@ -199,15 +199,21 @@ TEST_F(NativeWidgetMacInteractiveUITest, ParentWindowTrafficLights) { EXPECT_TRUE(button); NSData* active_button_image = ViewAsTIFF(button); EXPECT_TRUE(active_button_image); - - // Pop open a bubble on the parent Widget. When the visibility of Bubbles with - // an anchor View changes, BubbleDialogDelegateView::HandleVisibilityChanged() - // updates Widget::ShouldPaintAsActive() accordingly. - ShowKeyWindow(BubbleDialogDelegateView::CreateBubble( - new TestBubbleView(parent_widget))); + EXPECT_TRUE(parent_widget->ShouldPaintAsActive()); + + // If a child widget is key, the parent should paint as active. + Widget* child_widget = new Widget; + Widget::InitParams params = + CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); + params.parent = parent_widget->GetNativeView(); + child_widget->Init(std::move(params)); + child_widget->SetContentsView(new View); + child_widget->Show(); + NSWindow* child = child_widget->GetNativeWindow().GetNativeNSWindow(); // Ensure the button instance is still valid. EXPECT_EQ(button, [parent standardWindowButton:NSWindowCloseButton]); + EXPECT_TRUE(parent_widget->ShouldPaintAsActive()); // Parent window should still be main, and have its traffic lights active. EXPECT_TRUE([parent isMainWindow]); @@ -226,10 +232,18 @@ TEST_F(NativeWidgetMacInteractiveUITest, ParentWindowTrafficLights) { ShowKeyWindow(other_widget); EXPECT_FALSE([parent isMainWindow]); EXPECT_FALSE([parent isKeyWindow]); + EXPECT_FALSE(parent_widget->ShouldPaintAsActive()); EXPECT_TRUE([button isEnabled]); NSData* inactive_button_image = ViewAsTIFF(button); EXPECT_FALSE([active_button_image isEqualToData:inactive_button_image]); + // Focus the child again and assert the parent once again paints as active. + [child makeKeyWindow]; + EXPECT_TRUE(parent_widget->ShouldPaintAsActive()); + EXPECT_TRUE([child isKeyWindow]); + EXPECT_FALSE([parent isKeyWindow]); + + child_widget->CloseNow(); other_widget->CloseNow(); parent_widget->CloseNow(); } diff --git a/chromium/ui/views/widget/native_widget_mac_unittest.mm b/chromium/ui/views/widget/native_widget_mac_unittest.mm index f7a9964d6d8..90c111179a7 100644 --- a/chromium/ui/views/widget/native_widget_mac_unittest.mm +++ b/chromium/ui/views/widget/native_widget_mac_unittest.mm @@ -69,10 +69,10 @@ @interface MockBridgedView : NSView { @private // Number of times -[NSView drawRect:] has been called. - NSUInteger drawRectCount_; + NSUInteger _drawRectCount; // The dirtyRect parameter passed to last invocation of drawRect:. - NSRect lastDirtyRect_; + NSRect _lastDirtyRect; } @property(assign, nonatomic) NSUInteger drawRectCount; @@ -1108,18 +1108,16 @@ class ModalDialogDelegate : public DialogDelegateView { explicit ModalDialogDelegate(ui::ModalType modal_type) : modal_type_(modal_type) {} - void set_can_close(bool value) { can_close_ = value; } - void set_buttons(int buttons) { buttons_ = buttons; } + void SetButtons(int buttons) { + DialogDelegate::SetButtons(buttons); + DialogModelChanged(); + } // DialogDelegateView: - int GetDialogButtons() const override { return buttons_; } ui::ModalType GetModalType() const override { return modal_type_; } - bool Close() override { return can_close_; } private: const ui::ModalType modal_type_; - bool can_close_ = true; - int buttons_ = ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL; DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate); }; @@ -2081,46 +2079,6 @@ TEST_F(NativeWidgetMacTest, ChangeFocusOnChangeFirstResponder) { widget->CloseNow(); } -// Ensure reparented native view has correct bounds. -TEST_F(NativeWidgetMacTest, ReparentNativeViewBounds) { - Widget* parent = CreateTopLevelFramelessPlatformWidget(); - gfx::Rect parent_rect(100, 100, 300, 200); - parent->SetBounds(parent_rect); - - Widget::InitParams params(Widget::InitParams::TYPE_CONTROL); - params.parent = parent->GetNativeView(); - Widget* widget = new Widget; - widget->Init(std::move(params)); - widget->SetContentsView(new View); - - NSView* child_view = widget->GetNativeView().GetNativeNSView(); - Widget::ReparentNativeView(child_view, parent->GetNativeView()); - - // Reparented content view has the size of the Widget that created it. - gfx::Rect widget_rect(0, 0, 200, 100); - widget->SetBounds(widget_rect); - EXPECT_EQ(200, NSWidth([child_view frame])); - EXPECT_EQ(100, NSHeight([child_view frame])); - - // Reparented widget has bounds relative to the native parent - NSRect native_parent_rect = NSMakeRect(50, 100, 200, 70); - base::scoped_nsobject<NSView> native_parent( - [[NSView alloc] initWithFrame:native_parent_rect]); - [parent->GetNativeView().GetNativeNSView() addSubview:native_parent]; - - gfx::Rect screen_rect = widget->GetWindowBoundsInScreen(); - EXPECT_EQ(100, screen_rect.x()); - EXPECT_EQ(100, screen_rect.y()); - - Widget::ReparentNativeView(child_view, native_parent.get()); - widget->SetBounds(widget_rect); - screen_rect = widget->GetWindowBoundsInScreen(); - EXPECT_EQ(150, screen_rect.x()); - EXPECT_EQ(130, screen_rect.y()); - - parent->CloseNow(); -} - // Test two kinds of widgets to re-parent. TEST_F(NativeWidgetMacTest, ReparentNativeViewTypes) { std::unique_ptr<Widget> toplevel1(new Widget); @@ -2141,16 +2099,13 @@ TEST_F(NativeWidgetMacTest, ReparentNativeViewTypes) { Widget::ReparentNativeView(child->GetNativeView(), toplevel1->GetNativeView()); - EXPECT_EQ([child->GetNativeView().GetNativeNSView() window], + EXPECT_EQ([child->GetNativeWindow().GetNativeNSWindow() parentWindow], [toplevel1->GetNativeView().GetNativeNSView() window]); - EXPECT_EQ(0, [child->GetNativeWindow().GetNativeNSWindow() alphaValue]); Widget::ReparentNativeView(child->GetNativeView(), toplevel2->GetNativeView()); - EXPECT_EQ([child->GetNativeView().GetNativeNSView() window], + EXPECT_EQ([child->GetNativeWindow().GetNativeNSWindow() parentWindow], [toplevel2->GetNativeView().GetNativeNSView() window]); - EXPECT_EQ(0, [child->GetNativeWindow().GetNativeNSWindow() alphaValue]); - EXPECT_NE(0, [toplevel1->GetNativeWindow().GetNativeNSWindow() alphaValue]); Widget::ReparentNativeView(toplevel2->GetNativeView(), toplevel1->GetNativeView()); @@ -2188,6 +2143,61 @@ class NativeWidgetMacFullKeyboardAccessTest : public NativeWidgetMacTest { ui::test::ScopedFakeFullKeyboardAccess* fake_full_keyboard_access_ = nullptr; }; +// Ensure that calling SetSize doesn't change the origin. +TEST_F(NativeWidgetMacTest, SetSizeDoesntChangeOrigin) { + Widget* parent = CreateTopLevelFramelessPlatformWidget(); + gfx::Rect parent_rect(100, 100, 400, 200); + parent->SetBounds(parent_rect); + + // Popup children specify their bounds relative to their parent window. + Widget* child_control = new Widget; + gfx::Rect child_control_rect(50, 70, 300, 100); + { + Widget::InitParams params(Widget::InitParams::TYPE_CONTROL); + params.parent = parent->GetNativeView(); + params.bounds = child_control_rect; + child_control->Init(std::move(params)); + child_control->SetContentsView(new View); + } + + // Window children specify their bounds in screen coords. + Widget* child_window = new Widget; + gfx::Rect child_window_rect(110, 90, 200, 50); + { + Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); + params.parent = parent->GetNativeView(); + params.bounds = child_window_rect; + child_window->Init(std::move(params)); + } + + // Sanity-check the initial bounds. Note that the CONTROL should be offset by + // the parent's origin. + EXPECT_EQ(parent->GetWindowBoundsInScreen(), parent_rect); + EXPECT_EQ( + child_control->GetWindowBoundsInScreen(), + gfx::Rect(child_control_rect.origin() + parent_rect.OffsetFromOrigin(), + child_control_rect.size())); + EXPECT_EQ(child_window->GetWindowBoundsInScreen(), child_window_rect); + + // Update the size, but not the origin. + parent_rect.set_size(gfx::Size(505, 310)); + parent->SetSize(parent_rect.size()); + child_control_rect.set_size(gfx::Size(256, 102)); + child_control->SetSize(child_control_rect.size()); + child_window_rect.set_size(gfx::Size(172, 96)); + child_window->SetSize(child_window_rect.size()); + + // Ensure that the origin didn't change. + EXPECT_EQ(parent->GetWindowBoundsInScreen(), parent_rect); + EXPECT_EQ( + child_control->GetWindowBoundsInScreen(), + gfx::Rect(child_control_rect.origin() + parent_rect.OffsetFromOrigin(), + child_control_rect.size())); + EXPECT_EQ(child_window->GetWindowBoundsInScreen(), child_window_rect); + + parent->CloseNow(); +} + // Test that updateFullKeyboardAccess method on BridgedContentView correctly // sets the keyboard accessibility mode on the associated focus manager. TEST_F(NativeWidgetMacFullKeyboardAccessTest, FullKeyboardToggle) { @@ -2348,19 +2358,6 @@ TEST_F(NativeWidgetMacViewsOrderTest, UnassociatedViewsIsAbove) { ]])); } -// Test -[NSWindowDelegate windowShouldClose:]. -TEST_F(NativeWidgetMacTest, CanClose) { - ModalDialogDelegate* delegate = new ModalDialogDelegate(ui::MODAL_TYPE_NONE); - Widget* widget = - views::DialogDelegate::CreateDialogWidget(delegate, nullptr, nullptr); - NSWindow* window = widget->GetNativeWindow().GetNativeNSWindow(); - delegate->set_can_close(false); - EXPECT_FALSE([[window delegate] windowShouldClose:window]); - delegate->set_can_close(true); - EXPECT_TRUE([[window delegate] windowShouldClose:window]); - widget->CloseNow(); -} - namespace { // Returns an array of NSTouchBarItemIdentifier (i.e. NSString), extracted from @@ -2427,7 +2424,7 @@ TEST_F(NativeWidgetMacTest, TouchBar) { } // Remove the cancel button. - delegate->set_buttons(ui::DIALOG_BUTTON_OK); + delegate->SetButtons(ui::DIALOG_BUTTON_OK); delegate->DialogModelChanged(); EXPECT_TRUE(delegate->GetOkButton()); EXPECT_FALSE(delegate->GetCancelButton()); @@ -2479,37 +2476,37 @@ TEST_F(NativeWidgetMacTest, InitCallback) { @implementation NativeWidgetMacTestWindow -@synthesize invalidateShadowCount = invalidateShadowCount_; -@synthesize fakeOnInactiveSpace = fakeOnInactiveSpace_; -@synthesize deallocFlag = deallocFlag_; +@synthesize invalidateShadowCount = _invalidateShadowCount; +@synthesize fakeOnInactiveSpace = _fakeOnInactiveSpace; +@synthesize deallocFlag = _deallocFlag; - (void)dealloc { - if (deallocFlag_) { - DCHECK(!*deallocFlag_); - *deallocFlag_ = true; + if (_deallocFlag) { + DCHECK(!*_deallocFlag); + *_deallocFlag = true; } [super dealloc]; } - (void)invalidateShadow { - ++invalidateShadowCount_; + ++_invalidateShadowCount; [super invalidateShadow]; } - (BOOL)isOnActiveSpace { - return !fakeOnInactiveSpace_; + return !_fakeOnInactiveSpace; } @end @implementation MockBridgedView -@synthesize drawRectCount = drawRectCount_; -@synthesize lastDirtyRect = lastDirtyRect_; +@synthesize drawRectCount = _drawRectCount; +@synthesize lastDirtyRect = _lastDirtyRect; - (void)drawRect:(NSRect)dirtyRect { - ++drawRectCount_; - lastDirtyRect_ = dirtyRect; + ++_drawRectCount; + _lastDirtyRect = dirtyRect; } @end diff --git a/chromium/ui/views/widget/native_widget_private.h b/chromium/ui/views/widget/native_widget_private.h index 4aa5fd12c5c..1ef89be9ec0 100644 --- a/chromium/ui/views/widget/native_widget_private.h +++ b/chromium/ui/views/widget/native_widget_private.h @@ -17,13 +17,13 @@ namespace gfx { class ImageSkia; class Rect; -} +} // namespace gfx namespace ui { class InputMethod; class GestureRecognizer; class OSExchangeData; -} +} // namespace ui namespace views { class TooltipManager; @@ -149,9 +149,8 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget { // Retrieves the window's current restored bounds and "show" state, for // persisting. - virtual void GetWindowPlacement( - gfx::Rect* bounds, - ui::WindowShowState* show_state) const = 0; + virtual void GetWindowPlacement(gfx::Rect* bounds, + ui::WindowShowState* show_state) const = 0; // Sets the NativeWindow title. Returns true if the title changed. virtual bool SetWindowTitle(const base::string16& title) = 0; @@ -230,6 +229,9 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget { virtual bool IsTranslucentWindowOpacitySupported() const = 0; virtual ui::GestureRecognizer* GetGestureRecognizer() = 0; virtual void OnSizeConstraintsChanged() = 0; + // Called before and after re-parenting of this or an ancestor widget. + virtual void OnNativeViewHierarchyWillChange() = 0; + virtual void OnNativeViewHierarchyChanged() = 0; // Returns an internal name that matches the name of the associated Widget. virtual std::string GetName() const = 0; diff --git a/chromium/ui/views/widget/native_widget_unittest.cc b/chromium/ui/views/widget/native_widget_unittest.cc index 5167fabefcb..9196b811137 100644 --- a/chromium/ui/views/widget/native_widget_unittest.cc +++ b/chromium/ui/views/widget/native_widget_unittest.cc @@ -15,17 +15,14 @@ namespace views { class ScopedTestWidget { public: explicit ScopedTestWidget(internal::NativeWidgetPrivate* native_widget) - : native_widget_(native_widget) { - } + : native_widget_(native_widget) {} ~ScopedTestWidget() { // |CloseNow| deletes both |native_widget_| and its associated // |Widget|. native_widget_->GetWidget()->CloseNow(); } - internal::NativeWidgetPrivate* operator->() const { - return native_widget_; - } + internal::NativeWidgetPrivate* operator->() const { return native_widget_; } internal::NativeWidgetPrivate* get() const { return native_widget_; } private: diff --git a/chromium/ui/views/widget/root_view.cc b/chromium/ui/views/widget/root_view.cc index 0a709e59d39..a88f7849e6b 100644 --- a/chromium/ui/views/widget/root_view.cc +++ b/chromium/ui/views/widget/root_view.cc @@ -5,6 +5,7 @@ #include "ui/views/widget/root_view.h" #include <algorithm> +#include <memory> #include "base/logging.h" #include "base/macros.h" @@ -39,8 +40,7 @@ class MouseEnterExitEvent : public ui::MouseEvent { : ui::MouseEvent(event, static_cast<View*>(nullptr), static_cast<View*>(nullptr)) { - DCHECK(type == ui::ET_MOUSE_ENTERED || - type == ui::ET_MOUSE_EXITED); + DCHECK(type == ui::ET_MOUSE_ENTERED || type == ui::ET_MOUSE_EXITED); SetType(type); } @@ -85,8 +85,7 @@ class AnnounceTextView : public View { // - Shows keyboard-triggered context menus. class PreEventDispatchHandler : public ui::EventHandler { public: - explicit PreEventDispatchHandler(View* owner) - : owner_(owner) { + explicit PreEventDispatchHandler(View* owner) : owner_(owner) { owner_->AddPreTargetHandler(this); } ~PreEventDispatchHandler() override { owner_->RemovePreTargetHandler(this); } @@ -132,8 +131,7 @@ class PreEventDispatchHandler : public ui::EventHandler { class PostEventDispatchHandler : public ui::EventHandler { public: PostEventDispatchHandler() - : touch_dnd_enabled_(::switches::IsTouchDragDropEnabled()) { - } + : touch_dnd_enabled_(::switches::IsTouchDragDropEnabled()) {} ~PostEventDispatchHandler() override = default; private: @@ -144,14 +142,14 @@ class PostEventDispatchHandler : public ui::EventHandler { return; View* target = static_cast<View*>(event->target()); + gfx::Point location = event->location(); - if (touch_dnd_enabled_ && - event->type() == ui::ET_GESTURE_LONG_PRESS && + if (touch_dnd_enabled_ && event->type() == ui::ET_GESTURE_LONG_PRESS && (!target->drag_controller() || - target->drag_controller()->CanStartDragForView( - target, location, location))) { + target->drag_controller()->CanStartDragForView(target, location, + location))) { if (target->DoDrag(*event, location, - ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH)) { + ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH)) { event->StopPropagation(); return; } @@ -210,8 +208,8 @@ RootView::~RootView() { // Tree operations ------------------------------------------------------------- void RootView::SetContentsView(View* contents_view) { - DCHECK(contents_view && GetWidget()->native_widget()) << - "Can't be called until after the native widget is created!"; + DCHECK(contents_view && GetWidget()->native_widget()) + << "Can't be called until after the native widget is created!"; // The ContentsView must be set up _after_ the window is created so that its // Widget pointer is valid. SetLayoutManager(std::make_unique<FillLayout>()); @@ -269,8 +267,12 @@ void RootView::AnnounceText(const base::string16& text) { NOTREACHED(); #else DCHECK(GetWidget()); - if (!announce_view_) + DCHECK(GetContentsView()); + if (!announce_view_) { announce_view_ = AddChildView(std::make_unique<AnnounceTextView>()); + static_cast<FillLayout*>(GetLayoutManager()) + ->SetChildViewIgnoredByLayout(announce_view_, true); + } announce_view_->Announce(text); #endif } @@ -317,8 +319,7 @@ void RootView::OnEventProcessingStarted(ui::Event* event) { // removal of the final touch point or if no gesture handler has already // been set. if (gesture_event->type() == ui::ET_GESTURE_END && - (gesture_event->details().touch_points() > 1 || - !gesture_handler_)) { + (gesture_event->details().touch_points() > 1 || !gesture_handler_)) { event->SetHandled(); return; } @@ -340,8 +341,7 @@ void RootView::OnEventProcessingFinished(ui::Event* event) { // If |event| was not handled and |gesture_handler_| was not set by the // dispatch of a previous gesture event, then no default gesture handler // should be set prior to the next gesture event being received. - if (event->IsGestureEvent() && - !event->handled() && + if (event->IsGestureEvent() && !event->handled() && !gesture_handler_set_before_processing_) { gesture_handler_ = nullptr; } @@ -381,18 +381,14 @@ bool RootView::OnMousePressed(const ui::MouseEvent& event) { } DCHECK(!explicit_mouse_handler_); - bool hit_disabled_view = false; - // Walk up the tree until we find a view that wants the mouse event. + // Walk up the tree from the target until we find a view that wants + // the mouse event. for (mouse_pressed_handler_ = GetEventHandlerForPoint(event.location()); mouse_pressed_handler_ && (mouse_pressed_handler_ != this); mouse_pressed_handler_ = mouse_pressed_handler_->parent()) { DVLOG(1) << "OnMousePressed testing " - << mouse_pressed_handler_->GetClassName(); - if (!mouse_pressed_handler_->GetEnabled()) { - // Disabled views should eat events instead of propagating them upwards. - hit_disabled_view = true; - break; - } + << mouse_pressed_handler_->GetClassName(); + DCHECK(mouse_pressed_handler_->GetEnabled()); // See if this view wants to handle the mouse press. ui::MouseEvent mouse_pressed_event(event, static_cast<View*>(this), @@ -425,7 +421,7 @@ bool RootView::OnMousePressed(const ui::MouseEvent& event) { if (mouse_pressed_event.handled()) { last_click_handler_ = mouse_pressed_handler_; DVLOG(1) << "OnMousePressed handled by " - << mouse_pressed_handler_->GetClassName(); + << mouse_pressed_handler_->GetClassName(); return true; } } @@ -433,15 +429,14 @@ bool RootView::OnMousePressed(const ui::MouseEvent& event) { // Reset mouse_pressed_handler_ to indicate that no processing is occurring. mouse_pressed_handler_ = nullptr; + const bool last_click_was_handled = (last_click_handler_ != nullptr); + last_click_handler_ = nullptr; + // In the event that a double-click is not handled after traversing the // entire hierarchy (even as a single-click when sent to a different view), // it must be marked as handled to avoid anything happening from default // processing if it the first click-part was handled by us. - if (last_click_handler_ && (event.flags() & ui::EF_IS_DOUBLE_CLICK)) - hit_disabled_view = true; - - last_click_handler_ = nullptr; - return hit_disabled_view; + return last_click_was_handled && (event.flags() & ui::EF_IS_DOUBLE_CLICK); } bool RootView::OnMouseDragged(const ui::MouseEvent& event) { @@ -476,8 +471,6 @@ void RootView::OnMouseReleased(const ui::MouseEvent& event) { } void RootView::OnMouseCaptureLost() { - // TODO: this likely needs to reset touch handler too. - if (mouse_pressed_handler_ || gesture_handler_) { // Synthesize a release event for UpdateCursor. if (mouse_pressed_handler_) { @@ -502,12 +495,14 @@ void RootView::OnMouseCaptureLost() { void RootView::OnMouseMoved(const ui::MouseEvent& event) { View* v = GetEventHandlerForPoint(event.location()); - // Find the first enabled view, or the existing move handler, whichever comes - // first. The check for the existing handler is because if a view becomes - // disabled while handling moves, it's wrong to suddenly send ET_MOUSE_EXITED - // and ET_MOUSE_ENTERED events, because the mouse hasn't actually exited yet. - while (v && !v->GetEnabled() && (v != mouse_move_handler_)) - v = v->parent(); + // Check for a disabled move handler. If the move handler became + // disabled while handling moves, it's wrong to suddenly send + // ET_MOUSE_EXITED and ET_MOUSE_ENTERED events, because the mouse + // hasn't actually exited yet. + if (mouse_move_handler_ && !mouse_move_handler_->GetEnabled() && + v->Contains(mouse_move_handler_)) + v = mouse_move_handler_; + if (v && v != this) { if (v != mouse_move_handler_) { if (mouse_move_handler_ != nullptr && @@ -638,8 +633,12 @@ void RootView::SetMouseHandler(View* new_mh) { } void RootView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->SetName(widget_->widget_delegate()->GetAccessibleWindowTitle()); - node_data->role = widget_->widget_delegate()->GetAccessibleWindowRole(); + DCHECK(GetWidget()); + auto* widget_delegate = GetWidget()->widget_delegate(); + if (!widget_delegate) + return; + node_data->SetName(widget_delegate->GetAccessibleWindowTitle()); + node_data->role = widget_delegate->GetAccessibleWindowRole(); } void RootView::UpdateParentLayer() { @@ -647,14 +646,6 @@ void RootView::UpdateParentLayer() { ReparentLayer(widget_->GetLayer()); } -void RootView::Layout() { - View::Layout(); - // TODO(crbug.com/1026461): when FillLayout derives from LayoutManagerBase, - // just ignore the announce view instead of forcing it to zero size. - if (announce_view_) - announce_view_->SetSize({0, 0}); -} - //////////////////////////////////////////////////////////////////////////////// // RootView, protected: @@ -717,8 +708,6 @@ View::DragInfo* RootView::GetDragInfo() { //////////////////////////////////////////////////////////////////////////////// // RootView, private: -// Input ----------------------------------------------------------------------- - void RootView::UpdateCursor(const ui::MouseEvent& event) { if (!(event.flags() & ui::EF_IS_NON_CLIENT)) { View* v = GetEventHandlerForPoint(event.location()); @@ -771,12 +760,6 @@ ui::EventDispatchDetails RootView::PreDispatchEvent(ui::EventTarget* target, // |gesture_handler_| to detect if the view has been // removed from the tree. gesture_handler_ = view; - - // Disabled views are permitted to be targets of gesture events, but - // gesture events should never actually be dispatched to them. Prevent - // dispatch by marking the event as handled. - if (!view->GetEnabled()) - event->SetHandled(); } old_dispatch_target_ = event_dispatch_target_; diff --git a/chromium/ui/views/widget/root_view.h b/chromium/ui/views/widget/root_view.h index f003b6e6289..c72230774d9 100644 --- a/chromium/ui/views/widget/root_view.h +++ b/chromium/ui/views/widget/root_view.h @@ -5,6 +5,7 @@ #ifndef UI_VIEWS_WIDGET_ROOT_VIEW_H_ #define UI_VIEWS_WIDGET_ROOT_VIEW_H_ +#include <memory> #include <string> #include "base/macros.h" @@ -20,7 +21,7 @@ namespace views { namespace test { class ViewTargeterTest; class WidgetTest; -} +} // namespace test class RootViewTargeter; class Widget; @@ -34,19 +35,19 @@ class PreEventDispatchHandler; //////////////////////////////////////////////////////////////////////////////// // RootView class // -// The RootView is the root of a View hierarchy. A RootView is attached to a -// Widget. The Widget is responsible for receiving events from the host -// environment, converting them to views-compatible events and then forwarding -// them to the RootView for propagation into the View hierarchy. +// The RootView is the root of a View hierarchy. A RootView is attached to a +// Widget. The Widget is responsible for receiving events from the host +// environment, converting them to views-compatible events and then forwarding +// them to the RootView for propagation into the View hierarchy. // -// A RootView can have only one child, called its "Contents View" which is -// sized to fill the bounds of the RootView (and hence the client area of the -// Widget). Call SetContentsView() after the associated Widget has been -// initialized to attach the contents view to the RootView. -// TODO(beng): Enforce no other callers to AddChildView/tree functions by -// overriding those methods as private here. -// TODO(beng): Clean up API further, make Widget a friend. -// TODO(sky): We don't really want to export this class. +// A RootView can have only one child, called its "Contents View" which is +// sized to fill the bounds of the RootView (and hence the client area of the +// Widget). Call SetContentsView() after the associated Widget has been +// initialized to attach the contents view to the RootView. +// TODO(beng): Enforce no other callers to AddChildView/tree functions by +// overriding those methods as private here. +// TODO(beng): Clean up API further, make Widget a friend. +// TODO(sky): We don't really want to export this class. // class VIEWS_EXPORT RootView : public View, public ViewTargeterDelegate, @@ -98,18 +99,18 @@ class VIEWS_EXPORT RootView : public View, // Make an announcement through the screen reader, if present. void AnnounceText(const base::string16& text); - // Overridden from FocusTraversable: + // FocusTraversable: FocusSearch* GetFocusSearch() override; FocusTraversable* GetFocusTraversableParent() override; View* GetFocusTraversableParentView() override; - // Overridden from ui::EventProcessor: + // ui::EventProcessor: ui::EventTarget* GetRootForEvent(ui::Event* event) override; ui::EventTargeter* GetDefaultEventTargeter() override; void OnEventProcessingStarted(ui::Event* event) override; void OnEventProcessingFinished(ui::Event* event) override; - // Overridden from View: + // View: const Widget* GetWidget() const override; Widget* GetWidget() override; bool IsDrawn() const override; @@ -123,10 +124,9 @@ class VIEWS_EXPORT RootView : public View, void SetMouseHandler(View* new_mouse_handler) override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; void UpdateParentLayer() override; - void Layout() override; protected: - // Overridden from View: + // View: void ViewHierarchyChanged( const ViewHierarchyChangedDetails& details) override; void VisibilityChanged(View* starting_from, bool is_visible) override; @@ -166,7 +166,7 @@ class VIEWS_EXPORT RootView : public View, View* view, View* sibling) WARN_UNUSED_RESULT; - // Overridden from ui::EventDispatcherDelegate: + // ui::EventDispatcherDelegate: bool CanDispatchToTarget(ui::EventTarget* target) override; ui::EventDispatchDetails PreDispatchEvent(ui::EventTarget* target, ui::Event* event) override; diff --git a/chromium/ui/views/widget/root_view_targeter.cc b/chromium/ui/views/widget/root_view_targeter.cc index 1871da4ccb1..22e00035817 100644 --- a/chromium/ui/views/widget/root_view_targeter.cc +++ b/chromium/ui/views/widget/root_view_targeter.cc @@ -14,8 +14,7 @@ namespace views { RootViewTargeter::RootViewTargeter(ViewTargeterDelegate* delegate, internal::RootView* root_view) - : ViewTargeter(delegate), root_view_(root_view) { -} + : ViewTargeter(delegate), root_view_(root_view) {} RootViewTargeter::~RootViewTargeter() = default; diff --git a/chromium/ui/views/widget/root_view_unittest.cc b/chromium/ui/views/widget/root_view_unittest.cc index 343ca41b540..a0640142341 100644 --- a/chromium/ui/views/widget/root_view_unittest.cc +++ b/chromium/ui/views/widget/root_view_unittest.cc @@ -4,15 +4,20 @@ #include "ui/views/widget/root_view.h" +#include <memory> +#include <utility> + #include "base/macros.h" #include "base/memory/ptr_util.h" #include "build/build_config.h" +#include "ui/accessibility/ax_enums.mojom.h" +#include "ui/accessibility/ax_node_data.h" #include "ui/events/event_utils.h" #include "ui/events/keycodes/dom/dom_code.h" #include "ui/views/context_menu_controller.h" +#include "ui/views/test/test_views.h" #include "ui/views/test/views_test_base.h" #include "ui/views/view_targeter.h" -#include "ui/views/widget/root_view.h" #include "ui/views/widget/widget_deletion_observer.h" #include "ui/views/window/dialog_delegate.h" @@ -109,10 +114,8 @@ class TestContextMenuController : public ContextMenuController { // Tests that context menus are shown for certain key events (Shift+F10 // and VKEY_APPS) by the pre-target handler installed on RootView. TEST_F(RootViewTest, ContextMenuFromKeyEvent) { -#if defined(OS_MACOSX) // This behavior is intentionally unsupported on macOS. - return; -#endif +#if !defined(OS_MACOSX) Widget widget; Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); @@ -142,8 +145,8 @@ TEST_F(RootViewTest, ContextMenuFromKeyEvent) { controller.Reset(); // A context menu should be shown for a keypress of Shift+F10. - ui::KeyEvent menu_key_event( - ui::ET_KEY_PRESSED, ui::VKEY_F10, ui::EF_SHIFT_DOWN); + ui::KeyEvent menu_key_event(ui::ET_KEY_PRESSED, ui::VKEY_F10, + ui::EF_SHIFT_DOWN); details = root_view->OnEventFromSource(&menu_key_event); EXPECT_FALSE(details.target_destroyed); EXPECT_FALSE(details.dispatcher_destroyed); @@ -161,6 +164,7 @@ TEST_F(RootViewTest, ContextMenuFromKeyEvent) { EXPECT_EQ(focused_view, controller.menu_source_view()); EXPECT_EQ(ui::MENU_SOURCE_KEYBOARD, controller.menu_source_type()); controller.Reset(); +#endif } // View which handles all gesture events. @@ -181,8 +185,7 @@ class GestureHandlingView : public View { // show a context menu. TEST_F(RootViewTest, ContextMenuFromLongPress) { Widget widget; - Widget::InitParams init_params = - CreateParams(Widget::InitParams::TYPE_POPUP); + Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; init_params.bounds = gfx::Rect(100, 100); widget.Init(std::move(init_params)); @@ -255,8 +258,7 @@ TEST_F(RootViewTest, ContextMenuFromLongPress) { // Tests that context menus are not shown for disabled views on a long press. TEST_F(RootViewTest, ContextMenuFromLongPressOnDisabledView) { Widget widget; - Widget::InitParams init_params = - CreateParams(Widget::InitParams::TYPE_POPUP); + Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; init_params.bounds = gfx::Rect(100, 100); widget.Init(std::move(init_params)); @@ -337,9 +339,7 @@ class DeleteViewOnEvent : public View { DeleteViewOnEvent(ui::EventType delete_event_type, bool* was_destroyed) : delete_event_type_(delete_event_type), was_destroyed_(was_destroyed) {} - ~DeleteViewOnEvent() override { - *was_destroyed_ = true; - } + ~DeleteViewOnEvent() override { *was_destroyed_ = true; } void OnEvent(ui::Event* event) override { if (event->type() == delete_event_type_) @@ -408,8 +408,7 @@ class NestedEventOnEvent : public View { // Verifies deleting a View in OnMouseExited() doesn't crash. TEST_F(RootViewTest, DeleteViewOnMouseExitDispatch) { Widget widget; - Widget::InitParams init_params = - CreateParams(Widget::InitParams::TYPE_POPUP); + Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; widget.Init(std::move(init_params)); widget.SetBounds(gfx::Rect(10, 10, 500, 500)); @@ -428,8 +427,7 @@ TEST_F(RootViewTest, DeleteViewOnMouseExitDispatch) { // Generate a mouse move event which ensures that |mouse_moved_handler_| // is set in the RootView class. ui::MouseEvent moved_event(ui::ET_MOUSE_MOVED, gfx::Point(15, 15), - gfx::Point(15, 15), ui::EventTimeForNow(), 0, - 0); + gfx::Point(15, 15), ui::EventTimeForNow(), 0, 0); root_view->OnMouseMoved(moved_event); ASSERT_FALSE(view_destroyed); @@ -447,8 +445,7 @@ TEST_F(RootViewTest, DeleteViewOnMouseExitDispatch) { // Verifies deleting a View in OnMouseEntered() doesn't crash. TEST_F(RootViewTest, DeleteViewOnMouseEnterDispatch) { Widget widget; - Widget::InitParams init_params = - CreateParams(Widget::InitParams::TYPE_POPUP); + Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; widget.Init(std::move(init_params)); widget.SetBounds(gfx::Rect(10, 10, 500, 500)); @@ -468,8 +465,7 @@ TEST_F(RootViewTest, DeleteViewOnMouseEnterDispatch) { // Move the mouse within |widget| but outside of |child|. ui::MouseEvent moved_event(ui::ET_MOUSE_MOVED, gfx::Point(15, 15), - gfx::Point(15, 15), ui::EventTimeForNow(), 0, - 0); + gfx::Point(15, 15), ui::EventTimeForNow(), 0, 0); root_view->OnMouseMoved(moved_event); ASSERT_FALSE(view_destroyed); @@ -637,15 +633,11 @@ namespace { // View class which deletes its owning Widget when it gets a mouse exit event. class DeleteWidgetOnMouseExit : public View { public: - explicit DeleteWidgetOnMouseExit(Widget* widget) - : widget_(widget) { - } + explicit DeleteWidgetOnMouseExit(Widget* widget) : widget_(widget) {} ~DeleteWidgetOnMouseExit() override = default; - void OnMouseExited(const ui::MouseEvent& event) override { - delete widget_; - } + void OnMouseExited(const ui::MouseEvent& event) override { delete widget_; } private: Widget* widget_; @@ -659,8 +651,7 @@ class DeleteWidgetOnMouseExit : public View { // View::OnMouseExited(). TEST_F(RootViewTest, DeleteWidgetOnMouseExitDispatch) { Widget* widget = new Widget; - Widget::InitParams init_params = - CreateParams(Widget::InitParams::TYPE_POPUP); + Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; widget->Init(std::move(init_params)); widget->SetBounds(gfx::Rect(10, 10, 500, 500)); @@ -679,8 +670,7 @@ TEST_F(RootViewTest, DeleteWidgetOnMouseExitDispatch) { // Move the mouse within |child|. ui::MouseEvent moved_event(ui::ET_MOUSE_MOVED, gfx::Point(115, 115), - gfx::Point(115, 115), ui::EventTimeForNow(), 0, - 0); + gfx::Point(115, 115), ui::EventTimeForNow(), 0, 0); root_view->OnMouseMoved(moved_event); ASSERT_TRUE(widget_deletion_observer.IsWidgetAlive()); @@ -697,8 +687,7 @@ TEST_F(RootViewTest, DeleteWidgetOnMouseExitDispatch) { // of a mouse exited event which was propagated from one of its children. TEST_F(RootViewTest, DeleteWidgetOnMouseExitDispatchFromChild) { Widget* widget = new Widget; - Widget::InitParams init_params = - CreateParams(Widget::InitParams::TYPE_POPUP); + Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; widget->Init(std::move(init_params)); widget->SetBounds(gfx::Rect(10, 10, 500, 500)); @@ -740,7 +729,11 @@ TEST_F(RootViewTest, DeleteWidgetOnMouseExitDispatchFromChild) { namespace { class RootViewTestDialogDelegate : public DialogDelegateView { public: - RootViewTestDialogDelegate() = default; + RootViewTestDialogDelegate() { + // Ensure that buttons don't influence the layout. + DialogDelegate::SetButtons(ui::DIALOG_BUTTON_NONE); + } + ~RootViewTestDialogDelegate() override = default; int layout_count() const { return layout_count_; } @@ -750,9 +743,6 @@ class RootViewTestDialogDelegate : public DialogDelegateView { EXPECT_EQ(size(), preferred_size_); ++layout_count_; } - int GetDialogButtons() const override { - return ui::DIALOG_BUTTON_NONE; // Ensure buttons do not influence size. - } private: const gfx::Size preferred_size_ = gfx::Size(111, 111); @@ -784,5 +774,144 @@ TEST_F(RootViewDesktopNativeWidgetTest, SingleLayoutDuringInit) { widget->CloseNow(); } +#if !defined(OS_MACOSX) + +// Tests that AnnounceText sets up the correct text value on the hidden view, +// and that the resulting hidden view actually stays hidden. +TEST_F(RootViewTest, AnnounceTextTest) { + Widget widget; + Widget::InitParams init_params = + CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + init_params.bounds = {100, 100, 100, 100}; + widget.Init(std::move(init_params)); + widget.Show(); + internal::RootView* root_view = + static_cast<internal::RootView*>(widget.GetRootView()); + root_view->SetContentsView(new View()); + + EXPECT_EQ(1U, root_view->children().size()); + const base::string16 kText = base::ASCIIToUTF16("Text"); + root_view->AnnounceText(kText); + EXPECT_EQ(2U, root_view->children().size()); + root_view->Layout(); + EXPECT_FALSE(root_view->children()[0]->size().IsEmpty()); + EXPECT_TRUE(root_view->children()[1]->size().IsEmpty()); + View* const hidden_view = root_view->children()[1]; + ui::AXNodeData node_data; + hidden_view->GetAccessibleNodeData(&node_data); + EXPECT_EQ(kText, + node_data.GetString16Attribute(ax::mojom::StringAttribute::kName)); +} + +#endif // !defined(OS_MACOSX) + +TEST_F(RootViewTest, MouseEventDispatchedToClosestEnabledView) { + Widget widget; + Widget::InitParams init_params = + CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + init_params.bounds = {100, 100, 100, 100}; + widget.Init(std::move(init_params)); + widget.Show(); + internal::RootView* root_view = + static_cast<internal::RootView*>(widget.GetRootView()); + root_view->SetContentsView(new View()); + + View* const contents_view = root_view->GetContentsView(); + EventCountView* const v1 = + contents_view->AddChildView(std::make_unique<EventCountView>()); + EventCountView* const v2 = + v1->AddChildView(std::make_unique<EventCountView>()); + EventCountView* const v3 = + v2->AddChildView(std::make_unique<EventCountView>()); + + contents_view->SetBoundsRect(gfx::Rect(0, 0, 10, 10)); + v1->SetBoundsRect(gfx::Rect(0, 0, 10, 10)); + v2->SetBoundsRect(gfx::Rect(0, 0, 10, 10)); + v3->SetBoundsRect(gfx::Rect(0, 0, 10, 10)); + + v1->set_handle_mode(EventCountView::CONSUME_EVENTS); + v2->set_handle_mode(EventCountView::CONSUME_EVENTS); + v3->set_handle_mode(EventCountView::CONSUME_EVENTS); + + ui::MouseEvent pressed_event(ui::ET_MOUSE_PRESSED, gfx::Point(5, 5), + gfx::Point(5, 5), ui::EventTimeForNow(), 0, 0); + ui::MouseEvent released_event(ui::ET_MOUSE_RELEASED, gfx::Point(5, 5), + gfx::Point(5, 5), ui::EventTimeForNow(), 0, 0); + root_view->OnMousePressed(pressed_event); + root_view->OnMouseReleased(released_event); + EXPECT_EQ(0, v1->GetEventCount(ui::ET_MOUSE_PRESSED)); + EXPECT_EQ(0, v2->GetEventCount(ui::ET_MOUSE_PRESSED)); + EXPECT_EQ(1, v3->GetEventCount(ui::ET_MOUSE_PRESSED)); + + v3->SetEnabled(false); + root_view->OnMousePressed(pressed_event); + root_view->OnMouseReleased(released_event); + EXPECT_EQ(0, v1->GetEventCount(ui::ET_MOUSE_PRESSED)); + EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_PRESSED)); + EXPECT_EQ(1, v3->GetEventCount(ui::ET_MOUSE_PRESSED)); + + v3->SetEnabled(true); + v2->SetEnabled(false); + root_view->OnMousePressed(pressed_event); + root_view->OnMouseReleased(released_event); + EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_PRESSED)); + EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_PRESSED)); + EXPECT_EQ(1, v3->GetEventCount(ui::ET_MOUSE_PRESSED)); +} + +// If RootView::OnMousePressed() receives a double-click event that isn't +// handled by any views, it should still report it as handled if the first click +// was handled. However, it should *not* if the first click was unhandled. +// Regression test for https://crbug.com/1055674. +TEST_F(RootViewTest, DoubleClickHandledIffFirstClickHandled) { + Widget widget; + Widget::InitParams init_params = + CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + init_params.bounds = {100, 100, 100, 100}; + widget.Init(std::move(init_params)); + widget.Show(); + internal::RootView* root_view = + static_cast<internal::RootView*>(widget.GetRootView()); + root_view->SetContentsView(new View()); + + View* const contents_view = root_view->GetContentsView(); + EventCountView* const v1 = + contents_view->AddChildView(std::make_unique<EventCountView>()); + + contents_view->SetBoundsRect(gfx::Rect(0, 0, 10, 10)); + v1->SetBoundsRect(gfx::Rect(0, 0, 10, 10)); + + ui::MouseEvent pressed_event(ui::ET_MOUSE_PRESSED, gfx::Point(5, 5), + gfx::Point(5, 5), ui::EventTimeForNow(), 0, 0); + ui::MouseEvent released_event(ui::ET_MOUSE_RELEASED, gfx::Point(5, 5), + gfx::Point(5, 5), ui::EventTimeForNow(), 0, 0); + + // First click handled, second click unhandled. + v1->set_handle_mode(EventCountView::CONSUME_EVENTS); + pressed_event.SetClickCount(1); + released_event.SetClickCount(1); + EXPECT_TRUE(root_view->OnMousePressed(pressed_event)); + root_view->OnMouseReleased(released_event); + v1->set_handle_mode(EventCountView::PROPAGATE_EVENTS); + pressed_event.SetClickCount(2); + released_event.SetClickCount(2); + EXPECT_TRUE(root_view->OnMousePressed(pressed_event)); + root_view->OnMouseReleased(released_event); + + // Both clicks unhandled. + v1->set_handle_mode(EventCountView::PROPAGATE_EVENTS); + pressed_event.SetClickCount(1); + released_event.SetClickCount(1); + EXPECT_FALSE(root_view->OnMousePressed(pressed_event)); + root_view->OnMouseReleased(released_event); + pressed_event.SetClickCount(2); + released_event.SetClickCount(2); + EXPECT_FALSE(root_view->OnMousePressed(pressed_event)); + root_view->OnMouseReleased(released_event); +} + } // namespace test } // namespace views diff --git a/chromium/ui/views/widget/tooltip_manager_aura.cc b/chromium/ui/views/widget/tooltip_manager_aura.cc index 3c4a4c11ed9..ca24a4c51b5 100644 --- a/chromium/ui/views/widget/tooltip_manager_aura.cc +++ b/chromium/ui/views/widget/tooltip_manager_aura.cc @@ -101,7 +101,7 @@ void TooltipManagerAura::UpdateTooltip() { } } -void TooltipManagerAura::TooltipTextChanged(View* view) { +void TooltipManagerAura::TooltipTextChanged(View* view) { aura::Window* root_window = GetWindow()->GetRootWindow(); if (wm::GetTooltipClient(root_window)) { gfx::Point view_point = diff --git a/chromium/ui/views/widget/widget.cc b/chromium/ui/views/widget/widget.cc index af72459e158..6472b4210a0 100644 --- a/chromium/ui/views/widget/widget.cc +++ b/chromium/ui/views/widget/widget.cc @@ -15,7 +15,6 @@ #include "base/trace_event/trace_event.h" #include "ui/base/cursor/cursor.h" #include "ui/base/default_style.h" -#include "ui/base/default_theme_provider.h" #include "ui/base/hit_test.h" #include "ui/base/ime/input_method.h" #include "ui/base/l10n/l10n_font_util.h" @@ -32,6 +31,7 @@ #include "ui/views/focus/focus_manager_factory.h" #include "ui/views/focus/widget_focus_manager.h" #include "ui/views/views_delegate.h" +#include "ui/views/widget/any_widget_observer_singleton.h" #include "ui/views/widget/native_widget_private.h" #include "ui/views/widget/root_view.h" #include "ui/views/widget/tooltip_manager.h" @@ -92,11 +92,10 @@ bool Widget::g_disable_activation_change_handling_ = false; // WidgetDelegate is supplied. class DefaultWidgetDelegate : public WidgetDelegate { public: - explicit DefaultWidgetDelegate(Widget* widget) : widget_(widget) { - } + explicit DefaultWidgetDelegate(Widget* widget) : widget_(widget) {} ~DefaultWidgetDelegate() override = default; - // Overridden from WidgetDelegate: + // WidgetDelegate: void DeleteDelegate() override { delete this; } Widget* GetWidget() override { return widget_; } const Widget* GetWidget() const override { return widget_; } @@ -177,6 +176,10 @@ ui::ZOrderLevel Widget::InitParams::EffectiveZOrderLevel() const { Widget::Widget() = default; +Widget::Widget(InitParams params) { + Init(std::move(params)); +} + Widget::~Widget() { DestroyRootView(); if (ownership_ == InitParams::WIDGET_OWNS_NATIVE_WIDGET) { @@ -191,40 +194,24 @@ Widget::~Widget() { // static Widget* Widget::CreateWindowWithParent(WidgetDelegate* delegate, - gfx::NativeView parent) { - return CreateWindowWithParentAndBounds(delegate, parent, gfx::Rect()); -} - -// static -Widget* Widget::CreateWindowWithParentAndBounds(WidgetDelegate* delegate, - gfx::NativeView parent, - const gfx::Rect& bounds) { - Widget* widget = new Widget; + gfx::NativeView parent, + const gfx::Rect& bounds) { Widget::InitParams params; params.delegate = delegate; params.parent = parent; params.bounds = bounds; - widget->Init(std::move(params)); - return widget; + return new Widget(std::move(params)); } // static Widget* Widget::CreateWindowWithContext(WidgetDelegate* delegate, - gfx::NativeWindow context) { - return CreateWindowWithContextAndBounds(delegate, context, gfx::Rect()); -} - -// static -Widget* Widget::CreateWindowWithContextAndBounds(WidgetDelegate* delegate, - gfx::NativeWindow context, - const gfx::Rect& bounds) { - Widget* widget = new Widget; + gfx::NativeWindow context, + const gfx::Rect& bounds) { Widget::InitParams params; params.delegate = delegate; params.context = context; params.bounds = bounds; - widget->Init(std::move(params)); - return widget; + return new Widget(std::move(params)); } // static @@ -256,8 +243,7 @@ void Widget::GetAllChildWidgets(gfx::NativeView native_view, } // static -void Widget::GetAllOwnedWidgets(gfx::NativeView native_view, - Widgets* owned) { +void Widget::GetAllOwnedWidgets(gfx::NativeView native_view, Widgets* owned) { internal::NativeWidgetPrivate::GetAllOwnedWidgets(native_view, owned); } @@ -290,8 +276,7 @@ gfx::Size Widget::GetLocalizedContentsSize(int col_resource_id, // static bool Widget::RequiresNonClientView(InitParams::Type type) { - return type == InitParams::TYPE_WINDOW || - type == InitParams::TYPE_BUBBLE; + return type == InitParams::TYPE_WINDOW || type == InitParams::TYPE_BUBBLE; } void Widget::Init(InitParams params) { @@ -342,7 +327,6 @@ void Widget::Init(InitParams params) { ownership_ = params.ownership; native_widget_ = CreateNativeWidget(params, this)->AsNativeWidgetPrivate(); root_view_.reset(CreateRootView()); - default_theme_provider_ = std::make_unique<ui::DefaultThemeProvider>(); // Copy the elements of params that will be used after it is moved. const InitParams::Type type = params.type; @@ -389,19 +373,16 @@ void Widget::Init(InitParams params) { SetContentsView(delegate->GetContentsView()); SetInitialBoundsForFramelessWindow(bounds); } - // TODO(https://crbug.com/953978): Use GetNativeTheme() for all platforms. -#if defined(OS_MACOSX) || defined(OS_WIN) - ui::NativeTheme* native_theme = ui::NativeTheme::GetInstanceForNativeUi(); - if (native_theme) - observer_manager_.Add(native_theme); -#else + observer_manager_.Add(GetNativeTheme()); -#endif native_widget_initialized_ = true; native_widget_->OnWidgetInitDone(); if (delegate) delegate->OnWidgetInitialized(); + + internal::AnyWidgetObserverSingleton::GetInstance()->OnAnyWidgetInitialized( + this); } void Widget::ShowEmojiPanel() { @@ -460,14 +441,17 @@ void Widget::ViewHierarchyChanged(const ViewHierarchyChangedDetails& details) { } void Widget::NotifyNativeViewHierarchyWillChange() { - FocusManager* focus_manager = GetFocusManager(); - // We are being removed from a window hierarchy. Treat this as - // the root_view_ being removed. - if (focus_manager) - focus_manager->ViewRemoved(root_view_.get()); + // During tear-down the top-level focus manager becomes unavailable to + // GTK tabbed panes and their children, so normal deregistration via + // |FocusManager::ViewRemoved()| calls are fouled. We clear focus here + // to avoid these redundant steps and to avoid accessing deleted views + // that may have been in focus. + ClearFocusFromWidget(); + native_widget_->OnNativeViewHierarchyChanged(); } void Widget::NotifyNativeViewHierarchyChanged() { + native_widget_->OnNativeViewHierarchyWillChange(); root_view_->NotifyNativeViewHierarchyChanged(); } @@ -613,18 +597,16 @@ void Widget::CloseWithReason(ClosedReason closed_reason) { widget_closed_ = true; closed_reason_ = closed_reason; SaveWindowPlacement(); - - // During tear-down the top-level focus manager becomes unavailable to - // GTK tabbed panes and their children, so normal deregistration via - // |FocusManager::ViewRemoved()| calls are fouled. We clear focus here - // to avoid these redundant steps and to avoid accessing deleted views - // that may have been in focus. - if (is_top_level() && focus_manager_) - focus_manager_->SetFocusedView(nullptr); + ClearFocusFromWidget(); for (WidgetObserver& observer : observers_) observer.OnWidgetClosing(this); + internal::AnyWidgetObserverSingleton::GetInstance()->OnAnyWidgetClosing(this); + + if (widget_delegate_) + widget_delegate_->WindowWillClose(); + native_widget_->Close(); } @@ -635,6 +617,7 @@ void Widget::Close() { void Widget::CloseNow() { for (WidgetObserver& observer : observers_) observer.OnWidgetClosing(this); + internal::AnyWidgetObserverSingleton::GetInstance()->OnAnyWidgetClosing(this); native_widget_->CloseNow(); } @@ -653,8 +636,7 @@ void Widget::Show() { // widget gets shown. In that case we stay in full screen mode, regardless // of the |saved_show_state_| member. if (saved_show_state_ == ui::SHOW_STATE_MAXIMIZED && - !initial_restored_bounds_.IsEmpty() && - !IsFullscreen()) { + !initial_restored_bounds_.IsEmpty() && !IsFullscreen()) { native_widget_->Show(ui::SHOW_STATE_MAXIMIZED, initial_restored_bounds_); } else { native_widget_->Show( @@ -668,10 +650,12 @@ void Widget::Show() { } else { native_widget_->Show(preferred_show_state, gfx::Rect()); } + internal::AnyWidgetObserverSingleton::GetInstance()->OnAnyWidgetShown(this); } void Widget::Hide() { native_widget_->Hide(); + internal::AnyWidgetObserverSingleton::GetInstance()->OnAnyWidgetHidden(this); } void Widget::ShowInactive() { @@ -784,18 +768,8 @@ bool Widget::IsVisible() const { const ui::ThemeProvider* Widget::GetThemeProvider() const { const Widget* root_widget = GetTopLevelWidget(); - if (root_widget && root_widget != this) { - // Attempt to get the theme provider, and fall back to the default theme - // provider if not found. - const ui::ThemeProvider* provider = root_widget->GetThemeProvider(); - if (provider) - return provider; - - provider = root_widget->default_theme_provider_.get(); - if (provider) - return provider; - } - return default_theme_provider_.get(); + return (root_widget && root_widget != this) ? root_widget->GetThemeProvider() + : &default_theme_provider_; } FocusManager* Widget::GetFocusManager() { @@ -1041,9 +1015,8 @@ void Widget::SynthesizeMouseMoveEvent() { // Convert: screen coordinate -> widget coordinate. View::ConvertPointFromScreen(root_view_.get(), &mouse_location); last_mouse_event_was_move_ = false; - ui::MouseEvent mouse_event(ui::ET_MOUSE_MOVED, mouse_location, - mouse_location, ui::EventTimeForNow(), - ui::EF_IS_SYNTHESIZED, 0); + ui::MouseEvent mouse_event(ui::ET_MOUSE_MOVED, mouse_location, mouse_location, + ui::EventTimeForNow(), ui::EF_IS_SYNTHESIZED, 0); root_view_->OnMouseMoved(mouse_event); } @@ -1077,6 +1050,10 @@ std::unique_ptr<Widget::PaintAsActiveLock> Widget::LockPaintAsActive() { weak_ptr_factory_.GetWeakPtr()); } +base::WeakPtr<Widget> Widget::GetWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); +} + bool Widget::ShouldPaintAsActive() const { return native_widget_active_ || paint_as_active_refcount_; } @@ -1233,9 +1210,8 @@ void Widget::OnNativeWidgetPaint(const ui::PaintContext& context) { } int Widget::GetNonClientComponent(const gfx::Point& point) { - int component = non_client_view_ ? - non_client_view_->NonClientHitTest(point) : - HTNOWHERE; + int component = + non_client_view_ ? non_client_view_->NonClientHitTest(point) : HTNOWHERE; if (movement_disabled_ && (component == HTCAPTION || component == HTSYSMENU)) return HTNOWHERE; @@ -1333,7 +1309,7 @@ void Widget::OnMouseEvent(ui::MouseEvent* event) { case ui::ET_MOUSEWHEEL: if (root_view && root_view->OnMouseWheel( - static_cast<const ui::MouseWheelEvent&>(*event))) + static_cast<const ui::MouseWheelEvent&>(*event))) event->SetHandled(); return; @@ -1393,12 +1369,14 @@ const Widget* Widget::AsWidget() const { bool Widget::SetInitialFocus(ui::WindowShowState show_state) { FocusManager* focus_manager = GetFocusManager(); + if (!focus_manager) + return false; View* v = widget_delegate_->GetInitiallyFocusedView(); if (!focus_on_creation_ || show_state == ui::SHOW_STATE_INACTIVE || show_state == ui::SHOW_STATE_MINIMIZED) { // If not focusing the window now, tell the focus manager which view to // focus when the window is restored. - if (v && focus_manager) + if (v) focus_manager->SetStoredFocusView(v); return true; } @@ -1407,10 +1385,8 @@ bool Widget::SetInitialFocus(ui::WindowShowState show_state) { // If the Widget is active (thus allowing its child Views to receive focus), // but the request for focus was unsuccessful, fall back to using the first // focusable View instead. - if (focus_manager && focus_manager->GetFocusedView() == nullptr && - IsActive()) { + if (focus_manager->GetFocusedView() == nullptr && IsActive()) focus_manager->AdvanceFocus(false); - } } return !!focus_manager->GetFocusedView(); } @@ -1525,8 +1501,7 @@ internal::RootView* Widget::CreateRootView() { } void Widget::DestroyRootView() { - if (is_top_level() && focus_manager_) - focus_manager_->SetFocusedView(nullptr); + ClearFocusFromWidget(); NotifyWillRemoveView(root_view_.get()); non_client_view_ = nullptr; // Remove all children before the unique_ptr reset so that @@ -1658,8 +1633,17 @@ void Widget::UnlockPaintAsActive() { void Widget::UpdatePaintAsActiveState(bool paint_as_active) { if (non_client_view_) non_client_view_->frame_view()->PaintAsActiveChanged(paint_as_active); - if (widget_delegate()) - widget_delegate()->OnPaintAsActiveChanged(paint_as_active); + + for (WidgetObserver& observer : observers_) + observer.OnWidgetPaintAsActiveChanged(this, paint_as_active); +} + +void Widget::ClearFocusFromWidget() { + FocusManager* focus_manager = GetFocusManager(); + // We are being removed from a window hierarchy. Treat this as + // the root_view_ being removed. + if (focus_manager) + focus_manager->ViewRemoved(root_view_.get()); } namespace internal { diff --git a/chromium/ui/views/widget/widget.h b/chromium/ui/views/widget/widget.h index 88cb98ff914..105fc39ed5e 100644 --- a/chromium/ui/views/widget/widget.h +++ b/chromium/ui/views/widget/widget.h @@ -16,6 +16,7 @@ #include "base/optional.h" #include "base/scoped_observer.h" #include "build/build_config.h" +#include "ui/base/default_theme_provider.h" #include "ui/base/ui_base_types.h" #include "ui/events/event_source.h" #include "ui/gfx/geometry/rect.h" @@ -34,12 +35,11 @@ class TimeDelta; namespace gfx { class Point; class Rect; -} +} // namespace gfx namespace ui { class Accelerator; class Compositor; -class DefaultThemeProvider; class GestureRecognizer; class InputMethod; class Layer; @@ -61,7 +61,7 @@ class WidgetRemovalsObserver; namespace internal { class NativeWidgetPrivate; class RootView; -} +} // namespace internal //////////////////////////////////////////////////////////////////////////////// // Widget class @@ -112,9 +112,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, }; // Source that initiated the move loop. - enum MoveLoopSource { - MOVE_LOOP_SOURCE_MOUSE, - MOVE_LOOP_SOURCE_TOUCH, + enum class MoveLoopSource { + kMouse, + kTouch, }; // Behavior when escape is pressed during a move loop. @@ -153,18 +153,17 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, struct VIEWS_EXPORT InitParams { enum Type { - TYPE_WINDOW, // A decorated Window, like a frame window. - // Widgets of TYPE_WINDOW will have a NonClientView. - TYPE_WINDOW_FRAMELESS, - // An undecorated Window. - TYPE_CONTROL, // A control, like a button. - TYPE_POPUP, // An undecorated Window, with transient properties. - TYPE_MENU, // An undecorated Window, with transient properties - // specialized to menus. + TYPE_WINDOW, // A decorated Window, like a frame window. + // Widgets of TYPE_WINDOW will have a NonClientView. + TYPE_WINDOW_FRAMELESS, // An undecorated Window. + TYPE_CONTROL, // A control, like a button. + TYPE_POPUP, // An undecorated Window, with transient properties. + TYPE_MENU, // An undecorated Window, with transient properties + // specialized to menus. TYPE_TOOLTIP, TYPE_BUBBLE, - TYPE_DRAG, // An undecorated Window, used during a drag-and-drop to - // show the drag image. + TYPE_DRAG, // An undecorated Window, used during a drag-and-drop to + // show the drag image. }; enum class WindowOpacity { @@ -236,6 +235,11 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // Internal name. Propagated to the NativeWidget. Useful for debugging. std::string name; + // False if this widget behaves like a top-level widget, true otherwise. A + // top-level widget has its own focus and IME state, independent of any + // other widget. A widget for which child is true should have a parent; if + // it doesn't, it will not handle keyboard events or IME input at all. + // TODO(https://crbug.com/1057758): DCHECK(parent || !child) bool child = false; // If kTranslucent, the widget may be fully or partially transparent. @@ -281,6 +285,31 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // Whether the widget should be maximized or minimized. ui::WindowShowState show_state = ui::SHOW_STATE_DEFAULT; + // The native *view* (not native *window*) to which this widget should be + // parented. If this widget has a parent, then: + // * If that parent closes, this widget is closed too + // * If that parent is hidden, this widget is hidden too + // * This widget is stacked above the parent widget (always on Mac, usually + // elsewhere) + // * This widget's initial bounds are constrained to the parent widget's + // bounds, which prevents window restoration from placing windows + // offscreen + // Note: on some platforms (Mac) this directly implies a parent-child + // relationship in the backing native windows, but on Aura platforms it does + // not necessarily. + // + // Windows with no parent window are permitted, although in Aura these + // windows instead need a "context". On Aura systems, if a widget has no + // parent set, its backing aura::Window is parented to the Aura root window. + // + // TODO(https://crbug.com/1057758): It makes no sense that this is a + // NativeView instead of a NativeWindow. On Aura, NativeView and + // NativeWindow are synonyms, and NativeWidgetAura immediately treats the + // provided NativeView as an aura::Window; on Mac, the NativeView is + // immediately converted to an NSWindow (ie a gfx::NativeWindow) and used + // that way throughout. This should simply be a NativeWindow - windows are + // parented to other windows, not to views, and it being a view confuses + // the concept with bubble anchoring a la BubbleDialogDelegateView. gfx::NativeView parent = nullptr; // Specifies the initial bounds of the Widget. Default is empty, which means @@ -356,25 +385,22 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, }; Widget(); + explicit Widget(InitParams params); ~Widget() override; // Creates a decorated window Widget with the specified properties. The // returned Widget is owned by its NativeWidget; see Widget class comment for // details. static Widget* CreateWindowWithParent(WidgetDelegate* delegate, - gfx::NativeView parent); - static Widget* CreateWindowWithParentAndBounds(WidgetDelegate* delegate, - gfx::NativeView parent, - const gfx::Rect& bounds); + gfx::NativeView parent, + const gfx::Rect& bounds = gfx::Rect()); // Creates a decorated window Widget in the same desktop context as |context|. // The returned Widget is owned by its NativeWidget; see Widget class comment // for details. static Widget* CreateWindowWithContext(WidgetDelegate* delegate, - gfx::NativeWindow context); - static Widget* CreateWindowWithContextAndBounds(WidgetDelegate* delegate, - gfx::NativeWindow context, - const gfx::Rect& bounds); + gfx::NativeWindow context, + const gfx::Rect& bounds = gfx::Rect()); // Closes all Widgets that aren't identified as "secondary widgets". Called // during application shutdown when the last non-secondary widget is closed. @@ -400,8 +426,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // Returns all Widgets owned by |native_view| (including child widgets, but // not including itself). - static void GetAllOwnedWidgets(gfx::NativeView native_view, - Widgets* owned); + static void GetAllOwnedWidgets(gfx::NativeView native_view, Widgets* owned); // Re-parent a NativeView and notify all Widgets in |native_view|'s hierarchy // of the change. @@ -763,9 +788,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, return const_cast<NonClientView*>( const_cast<const Widget*>(this)->non_client_view()); } - const NonClientView* non_client_view() const { - return non_client_view_; - } + const NonClientView* non_client_view() const { return non_client_view_; } ClientView* client_view() { return const_cast<ClientView*>( @@ -786,8 +809,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // Returns the widget's layer, if any. ui::Layer* GetLayer() { - return const_cast<ui::Layer*>( - const_cast<const Widget*>(this)->GetLayer()); + return const_cast<ui::Layer*>(const_cast<const Widget*>(this)->GetLayer()); } const ui::Layer* GetLayer() const; @@ -879,6 +901,8 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // returned lock can safely outlive the associated widget. std::unique_ptr<PaintAsActiveLock> LockPaintAsActive(); + base::WeakPtr<Widget> GetWeakPtr(); + // Overridden from NativeWidgetDelegate: bool IsModal() const override; bool IsDialogBox() const override; @@ -994,6 +1018,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // Notifies the window frame that the active rendering state has changed. void UpdatePaintAsActiveState(bool paint_as_active); + // If a descendent of |root_view_| is focused, then clear the focus. + void ClearFocusFromWidget(); + static bool g_disable_activation_change_handling_; internal::NativeWidgetPrivate* native_widget_ = nullptr; @@ -1024,7 +1051,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, std::unique_ptr<FocusManager> focus_manager_; // A theme provider to use when no other theme provider is specified. - std::unique_ptr<ui::DefaultThemeProvider> default_theme_provider_; + const ui::DefaultThemeProvider default_theme_provider_; // Valid for the lifetime of RunShellDrag(), indicates the view the drag // started from. diff --git a/chromium/ui/views/widget/widget_delegate.cc b/chromium/ui/views/widget/widget_delegate.cc index 1ffec627df2..1d7c735d497 100644 --- a/chromium/ui/views/widget/widget_delegate.cc +++ b/chromium/ui/views/widget/widget_delegate.cc @@ -29,21 +29,16 @@ void WidgetDelegate::SetCanActivate(bool can_activate) { can_activate_ = can_activate; } -void WidgetDelegate::OnWidgetMove() { -} +void WidgetDelegate::OnWidgetMove() {} -void WidgetDelegate::OnDisplayChanged() { -} +void WidgetDelegate::OnDisplayChanged() {} -void WidgetDelegate::OnWorkAreaChanged() { -} +void WidgetDelegate::OnWorkAreaChanged() {} bool WidgetDelegate::OnCloseRequested(Widget::ClosedReason close_reason) { return true; } -void WidgetDelegate::OnPaintAsActiveChanged(bool paint_as_active) {} - View* WidgetDelegate::GetInitiallyFocusedView() { return nullptr; } @@ -193,7 +188,6 @@ bool WidgetDelegate::ShouldDescendIntoChildForEventHandling( //////////////////////////////////////////////////////////////////////////////// // WidgetDelegateView: - WidgetDelegateView::WidgetDelegateView() { // A WidgetDelegate should be deleted on DeleteDelegate. set_owned_by_client(); diff --git a/chromium/ui/views/widget/widget_delegate.h b/chromium/ui/views/widget/widget_delegate.h index 82ad1562232..a3ec229f11c 100644 --- a/chromium/ui/views/widget/widget_delegate.h +++ b/chromium/ui/views/widget/widget_delegate.h @@ -17,7 +17,7 @@ namespace gfx { class ImageSkia; class Rect; -} +} // namespace gfx namespace views { class BubbleDialogDelegateView; @@ -56,10 +56,6 @@ class VIEWS_EXPORT WidgetDelegate { // ClientView. virtual bool OnCloseRequested(Widget::ClosedReason close_reason); - // Called when the widget transitions from a state in which it should render - // as active to one in which it should render as inactive or vice-versa. - virtual void OnPaintAsActiveChanged(bool paint_as_active); - // Returns the view that should have the focus when the widget is shown. If // NULL no view is focused. virtual View* GetInitiallyFocusedView(); @@ -136,13 +132,22 @@ class VIEWS_EXPORT WidgetDelegate { // Default is true. virtual bool ShouldRestoreWindowSize() const; - // Called when the window closes. The delegate MUST NOT delete itself during - // this call, since it can be called afterwards. See DeleteDelegate(). + // Hooks for the end of the Widget/Window lifecycle. As of this writing, these + // callbacks happen like so: + // 1. Client code calls Widget::CloseWithReason() + // 2. WidgetDelegate::WindowWillClose() is called + // 3. NativeWidget teardown (maybe async) starts OR the operating system + // abruptly closes the backing native window + // 4. WidgetDelegate::WindowClosing() is called + // 5. NativeWidget teardown completes, Widget teardown starts + // 6. WidgetDelegate::DeleteDelegate() is called + // 7. Widget teardown finishes, Widget is deleted + // At step 3, the "maybe async" is controlled by whether the close is done via + // Close() or CloseNow(). + // Important note: for OS-initiated window closes, steps 1 and 2 don't happen + // - i.e, WindowWillClose() is never invoked. + virtual void WindowWillClose() {} virtual void WindowClosing() {} - - // Called when the window is destroyed. No events must be sent or received - // after this point. The delegate can use this opportunity to delete itself at - // this time if necessary. virtual void DeleteDelegate() {} // Called when the user begins/ends to change the bounds of the window. diff --git a/chromium/ui/views/widget/widget_interactive_uitest.cc b/chromium/ui/views/widget/widget_interactive_uitest.cc index 4639c1e4ccd..0f50819e3c4 100644 --- a/chromium/ui/views/widget/widget_interactive_uitest.cc +++ b/chromium/ui/views/widget/widget_interactive_uitest.cc @@ -169,11 +169,13 @@ class NestedLoopCaptureView : public View { ui::WindowShowState GetWidgetShowState(const Widget* widget) { // Use IsMaximized/IsMinimized/IsFullScreen instead of GetWindowPlacement // because the former is implemented on all platforms but the latter is not. - return widget->IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN : - widget->IsMaximized() ? ui::SHOW_STATE_MAXIMIZED : - widget->IsMinimized() ? ui::SHOW_STATE_MINIMIZED : - widget->IsActive() ? ui::SHOW_STATE_NORMAL : - ui::SHOW_STATE_INACTIVE; + if (widget->IsFullscreen()) + return ui::SHOW_STATE_FULLSCREEN; + if (widget->IsMaximized()) + return ui::SHOW_STATE_MAXIMIZED; + if (widget->IsMinimized()) + return ui::SHOW_STATE_MINIMIZED; + return widget->IsActive() ? ui::SHOW_STATE_NORMAL : ui::SHOW_STATE_INACTIVE; } // Give the OS an opportunity to process messages for an activation change, when @@ -759,7 +761,7 @@ TEST_F(WidgetTestInteractive, ChildStackedRelativeToParent) { // Showing the parent again should raise it and its child above the popover. ShowSync(parent.get()); EXPECT_TRUE(IsWindowStackedAbove(child, parent.get())); - EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get())); + EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get())); // Test grandchildren. Widget* grandchild = CreateChildPlatformWidget(child->GetNativeView()); @@ -767,15 +769,15 @@ TEST_F(WidgetTestInteractive, ChildStackedRelativeToParent) { grandchild->ShowInactive(); EXPECT_TRUE(IsWindowStackedAbove(grandchild, child)); EXPECT_TRUE(IsWindowStackedAbove(child, parent.get())); - EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get())); + EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get())); ShowSync(popover.get()); - EXPECT_TRUE(IsWindowStackedAbove(popover.get(), grandchild)); + EXPECT_TRUE(IsWindowStackedAbove(popover.get(), grandchild)); EXPECT_TRUE(IsWindowStackedAbove(grandchild, child)); ShowSync(parent.get()); EXPECT_TRUE(IsWindowStackedAbove(grandchild, child)); - EXPECT_TRUE(IsWindowStackedAbove(child, popover.get())); + EXPECT_TRUE(IsWindowStackedAbove(child, popover.get())); // Test hiding and reshowing. parent->Hide(); @@ -784,7 +786,7 @@ TEST_F(WidgetTestInteractive, ChildStackedRelativeToParent) { EXPECT_TRUE(IsWindowStackedAbove(grandchild, child)); EXPECT_TRUE(IsWindowStackedAbove(child, parent.get())); - EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get())); + EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get())); grandchild->Hide(); EXPECT_FALSE(grandchild->IsVisible()); @@ -792,7 +794,7 @@ TEST_F(WidgetTestInteractive, ChildStackedRelativeToParent) { EXPECT_TRUE(IsWindowStackedAbove(grandchild, child)); EXPECT_TRUE(IsWindowStackedAbove(child, parent.get())); - EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get())); + EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get())); } #if defined(OS_WIN) @@ -902,8 +904,7 @@ TEST_F(WidgetTestInteractive, WidgetNotActivatedOnFakeActivationMessages) { // activation. This test verifies the same. TEST_F(WidgetTestInteractive, FullscreenBoundsReducedOnActivationLoss) { Widget widget1; - Widget::InitParams params = - CreateParams(Widget::InitParams::TYPE_WINDOW); + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); params.native_widget = new DesktopNativeWidgetAura(&widget1); params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; widget1.Init(std::move(params)); @@ -942,7 +943,8 @@ TEST_F(WidgetTestInteractive, FullscreenBoundsReducedOnActivationLoss) { // After deactivation loss the bounds of the fullscreen widget should be // reduced by 1px. EXPECT_EQ(fullscreen_bounds.height() - - fullscreen_bounds_after_activation_loss.height(), 1); + fullscreen_bounds_after_activation_loss.height(), + 1); widget1.Activate(); RunPendingMessages(); @@ -1097,7 +1099,7 @@ TEST_F(DesktopWidgetTestInteractive, WindowModalWindowDestroyedActivationTest) { // Investigate enabling for Chrome OS. It probably requires help from the window // service. #define MAYBE_SystemModalWindowReleasesCapture \ - DISABLED_SystemModalWindowReleasesCapture + DISABLED_SystemModalWindowReleasesCapture #else #define MAYBE_SystemModalWindowReleasesCapture SystemModalWindowReleasesCapture #endif @@ -1248,7 +1250,7 @@ TEST_F(WidgetTestInteractive, DisableViewDoesNotActivateWidget) { EXPECT_NE(view1, focus_manager1->GetFocusedView()); EXPECT_FALSE(widget1.IsActive()); EXPECT_TRUE(widget2.IsActive()); -} +} // namespace test TEST_F(WidgetTestInteractive, ShowCreatesActiveWindow) { Widget* widget = CreateTopLevelPlatformWidget(); @@ -1458,6 +1460,42 @@ TEST_F(DesktopWidgetTestInteractive, RestoreAndMinimizeVisibility) { EXPECT_TRUE(root_window->IsVisible()); widget->CloseNow(); } + +// Test that focus is restored to the widget after a minimized window +// is activated. +TEST_F(DesktopWidgetTestInteractive, MinimizeAndActivateFocus) { + Widget* widget = CreateWidget(); + aura::Window* root_window = GetRootWindow(widget); + auto* widget_window = widget->GetNativeWindow(); + ShowSync(widget); + ASSERT_FALSE(widget->IsMinimized()); + EXPECT_TRUE(root_window->IsVisible()); + widget_window->Focus(); + EXPECT_TRUE(widget_window->HasFocus()); + widget->GetContentsView()->SetFocusBehavior(View::FocusBehavior::ALWAYS); + widget->GetContentsView()->RequestFocus(); + EXPECT_TRUE(widget->GetContentsView()->HasFocus()); + + PropertyWaiter minimize_widget_waiter( + base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget)), + true); + widget->Minimize(); + EXPECT_TRUE(minimize_widget_waiter.Wait()); + EXPECT_TRUE(widget->IsVisible()); + EXPECT_FALSE(root_window->IsVisible()); + + PropertyWaiter restore_widget_waiter( + base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget)), + false); + widget->Activate(); + EXPECT_TRUE(widget->GetContentsView()->HasFocus()); + EXPECT_TRUE(restore_widget_waiter.Wait()); + EXPECT_TRUE(widget->IsVisible()); + EXPECT_TRUE(root_window->IsVisible()); + EXPECT_TRUE(widget_window->CanFocus()); + widget->CloseNow(); +} + #endif // defined(OS_WIN) #if BUILDFLAG(ENABLE_DESKTOP_AURA) || defined(OS_MACOSX) @@ -1834,7 +1872,6 @@ TEST_F(WidgetCaptureTest, SetCaptureToNonToplevel) { child->RemoveObserver(&observer); } - #if defined(OS_WIN) namespace { @@ -2085,12 +2122,10 @@ TEST_F(WidgetInputMethodInteractiveTest, AcceleratorInTextfield) { textfield->SetTextInputType(ui::TEXT_INPUT_TYPE_TEXT); textfield->RequestFocus(); - ui::KeyEvent key_event(ui::ET_KEY_PRESSED, - ui::VKEY_F, ui::EF_ALT_DOWN); + ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_F, ui::EF_ALT_DOWN); ui::Accelerator accelerator(key_event); widget->GetFocusManager()->RegisterAccelerator( - accelerator, ui::AcceleratorManager::kNormalPriority, - textfield); + accelerator, ui::AcceleratorManager::kNormalPriority, textfield); widget->OnKeyEvent(&key_event); EXPECT_TRUE(key_event.stopped_propagation()); diff --git a/chromium/ui/views/widget/widget_observer.h b/chromium/ui/views/widget/widget_observer.h index 51adacfee40..e1168897442 100644 --- a/chromium/ui/views/widget/widget_observer.h +++ b/chromium/ui/views/widget/widget_observer.h @@ -41,6 +41,11 @@ class VIEWS_EXPORT WidgetObserver : public base::CheckedObserver { virtual void OnWidgetDragWillStart(Widget* widget) {} virtual void OnWidgetDragComplete(Widget* widget) {} + // Called when the widget transitions from a state in which it should render + // as active to one in which it should render as inactive or vice-versa. + virtual void OnWidgetPaintAsActiveChanged(Widget* widget, + bool paint_as_active) {} + virtual void OnWidgetVisibilityChanging(Widget* widget, bool visible) {} virtual void OnWidgetVisibilityChanged(Widget* widget, bool visible) {} diff --git a/chromium/ui/views/widget/widget_unittest.cc b/chromium/ui/views/widget/widget_unittest.cc index 02a43cf961f..e932006a39a 100644 --- a/chromium/ui/views/widget/widget_unittest.cc +++ b/chromium/ui/views/widget/widget_unittest.cc @@ -129,7 +129,7 @@ class ScrollableEventCountView : public EventCountView { // A view that implements GetMinimumSize. class MinimumSizeFrameView : public NativeFrameView { public: - explicit MinimumSizeFrameView(Widget* frame): NativeFrameView(frame) {} + explicit MinimumSizeFrameView(Widget* frame) : NativeFrameView(frame) {} ~MinimumSizeFrameView() override = default; private: @@ -146,13 +146,9 @@ class EventCountHandler : public ui::EventHandler { EventCountHandler() = default; ~EventCountHandler() override = default; - int GetEventCount(ui::EventType type) { - return event_count_[type]; - } + int GetEventCount(ui::EventType type) { return event_count_[type]; } - void ResetCounts() { - event_count_.clear(); - } + void ResetCounts() { event_count_.clear(); } protected: // Overridden from ui::EventHandler: @@ -162,9 +158,7 @@ class EventCountHandler : public ui::EventHandler { } private: - void RecordEvent(const ui::Event& event) { - ++event_count_[event.type()]; - } + void RecordEvent(const ui::Event& event) { ++event_count_[event.type()]; } std::map<ui::EventType, int> event_count_; @@ -179,15 +173,20 @@ TEST_F(WidgetTest, WidgetInitParams) { // Tests that the internal name is propagated through widget initialization to // the native widget and back. -TEST_F(WidgetTest, GetName) { - Widget widget; - Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.name = "MyWidget"; - widget.Init(std::move(params)); +class WidgetNameTest : public WidgetTest { + public: + Widget::InitParams CreateParams(Widget::InitParams::Type type) override { + Widget::InitParams params = WidgetTest::CreateParams(type); + params.name = "MyWidget"; + return params; + } +}; + +TEST_F(WidgetNameTest, GetName) { + std::unique_ptr<Widget> widget = CreateTestWidget(); - EXPECT_EQ("MyWidget", widget.native_widget_private()->GetName()); - EXPECT_EQ("MyWidget", widget.GetName()); + EXPECT_EQ("MyWidget", widget->native_widget_private()->GetName()); + EXPECT_EQ("MyWidget", widget->GetName()); } TEST_F(WidgetTest, NativeWindowProperty) { @@ -349,11 +348,10 @@ class OwnershipTestWidget : public Widget { TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) { OwnershipTestState state; - std::unique_ptr<Widget> widget(new OwnershipTestWidget(&state)); - Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); + auto widget = std::make_unique<OwnershipTestWidget>(&state); + Widget::InitParams params = CreateParamsForTestWidget(); params.native_widget = CreatePlatformNativeWidgetImpl( params, widget.get(), kStubCapture, &state.native_widget_deleted); - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; widget->Init(std::move(params)); // Now delete the Widget, which should delete the NativeWidget. @@ -370,11 +368,10 @@ TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) { TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) { OwnershipTestState state; - std::unique_ptr<Widget> widget(new OwnershipTestWidget(&state)); - Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); + auto widget = std::make_unique<OwnershipTestWidget>(&state); + Widget::InitParams params = CreateParamsForTestWidget(); params.native_widget = CreatePlatformNativeWidgetImpl( params, widget.get(), kStubCapture, &state.native_widget_deleted); - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; widget->Init(std::move(params)); // Now delete the Widget, which should delete the NativeWidget. @@ -395,12 +392,11 @@ TEST_F(WidgetOwnershipTest, Widget* toplevel = CreateTopLevelPlatformWidget(); - std::unique_ptr<Widget> widget(new OwnershipTestWidget(&state)); - Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); + auto widget = std::make_unique<OwnershipTestWidget>(&state); + Widget::InitParams params = CreateParamsForTestWidget(); params.parent = toplevel->GetNativeView(); params.native_widget = CreatePlatformNativeWidgetImpl( params, widget.get(), kStubCapture, &state.native_widget_deleted); - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; widget->Init(std::move(params)); // Now close the toplevel, which deletes the view hierarchy. @@ -509,8 +505,7 @@ TEST_F(WidgetOwnershipTest, // NativeWidget owns its Widget, part 5: NativeWidget is a NativeWidget, // we close it directly. -TEST_F(WidgetOwnershipTest, - Ownership_ViewsNativeWidgetOwnsWidget_Close) { +TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget_Close) { OwnershipTestState state; Widget* toplevel = CreateTopLevelPlatformWidget(); @@ -541,11 +536,10 @@ TEST_F(WidgetOwnershipTest, WidgetDelegateView* delegate_view = new WidgetDelegateView; - std::unique_ptr<Widget> widget(new OwnershipTestWidget(&state)); - Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); + auto widget = std::make_unique<OwnershipTestWidget>(&state); + Widget::InitParams params = CreateParamsForTestWidget(); params.native_widget = CreatePlatformNativeWidgetImpl( params, widget.get(), kStubCapture, &state.native_widget_deleted); - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.delegate = delegate_view; widget->Init(std::move(params)); widget->SetContentsView(delegate_view); @@ -564,56 +558,53 @@ TEST_F(WidgetOwnershipTest, using WidgetWithDestroyedNativeViewTest = ViewsTestBaseWithNativeWidgetType; TEST_P(WidgetWithDestroyedNativeViewTest, Test) { - Widget widget; - Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - widget.Init(std::move(params)); - widget.Show(); + std::unique_ptr<Widget> widget = CreateTestWidget(); + widget->Show(); - widget.native_widget_private()->CloseNow(); - widget.GetNativeView(); - widget.GetNativeWindow(); + widget->native_widget_private()->CloseNow(); + widget->GetNativeView(); + widget->GetNativeWindow(); ui::Accelerator accelerator; - widget.GetAccelerator(0, &accelerator); - widget.GetTopLevelWidget(); - widget.GetWindowBoundsInScreen(); - widget.GetClientAreaBoundsInScreen(); - widget.SetBounds(gfx::Rect(0, 0, 100, 80)); - widget.SetSize(gfx::Size(10, 11)); - widget.SetBoundsConstrained(gfx::Rect(0, 0, 120, 140)); - widget.SetVisibilityChangedAnimationsEnabled(false); - widget.StackAtTop(); - widget.IsClosed(); - widget.Close(); - widget.Hide(); - widget.Activate(); - widget.Deactivate(); - widget.IsActive(); - widget.SetZOrderLevel(ui::ZOrderLevel::kNormal); - widget.GetZOrderLevel(); - widget.Maximize(); - widget.Minimize(); - widget.Restore(); - widget.IsMaximized(); - widget.IsFullscreen(); - widget.SetOpacity(0.f); - widget.FlashFrame(true); - widget.IsVisible(); - widget.GetThemeProvider(); - widget.GetNativeTheme(); - widget.GetFocusManager(); - widget.SchedulePaintInRect(gfx::Rect(0, 0, 1, 2)); - widget.IsMouseEventsEnabled(); - widget.SetNativeWindowProperty("xx", &widget); - widget.GetNativeWindowProperty("xx"); - widget.GetFocusTraversable(); - widget.GetLayer(); - widget.ReorderNativeViews(); - widget.SetCapture(widget.GetRootView()); - widget.ReleaseCapture(); - widget.HasCapture(); - widget.GetWorkAreaBoundsInScreen(); - widget.IsTranslucentWindowOpacitySupported(); + widget->GetAccelerator(0, &accelerator); + widget->GetTopLevelWidget(); + widget->GetWindowBoundsInScreen(); + widget->GetClientAreaBoundsInScreen(); + widget->SetBounds(gfx::Rect(0, 0, 100, 80)); + widget->SetSize(gfx::Size(10, 11)); + widget->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140)); + widget->SetVisibilityChangedAnimationsEnabled(false); + widget->StackAtTop(); + widget->IsClosed(); + widget->Close(); + widget->Hide(); + widget->Activate(); + widget->Deactivate(); + widget->IsActive(); + widget->SetZOrderLevel(ui::ZOrderLevel::kNormal); + widget->GetZOrderLevel(); + widget->Maximize(); + widget->Minimize(); + widget->Restore(); + widget->IsMaximized(); + widget->IsFullscreen(); + widget->SetOpacity(0.f); + widget->FlashFrame(true); + widget->IsVisible(); + widget->GetThemeProvider(); + widget->GetNativeTheme(); + widget->GetFocusManager(); + widget->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2)); + widget->IsMouseEventsEnabled(); + widget->SetNativeWindowProperty("xx", &widget); + widget->GetNativeWindowProperty("xx"); + widget->GetFocusTraversable(); + widget->GetLayer(); + widget->ReorderNativeViews(); + widget->SetCapture(widget->GetRootView()); + widget->ReleaseCapture(); + widget->HasCapture(); + widget->GetWorkAreaBoundsInScreen(); + widget->IsTranslucentWindowOpacitySupported(); } INSTANTIATE_TEST_SUITE_P( @@ -632,9 +623,7 @@ class WidgetObserverTest : public WidgetTest, public WidgetObserver { ~WidgetObserverTest() override = default; // Set a widget to Close() the next time the Widget being observed is hidden. - void CloseOnNextHide(Widget* widget) { - widget_to_close_on_hide_ = widget; - } + void CloseOnNextHide(Widget* widget) { widget_to_close_on_hide_ = widget; } // Overridden from WidgetObserver: void OnWidgetDestroying(Widget* widget) override { @@ -1026,11 +1015,11 @@ TEST_F(WidgetObserverTest, ClosingOnHiddenParent) { // Test behavior of NativeWidget*::GetWindowPlacement on the native desktop. #if defined(USE_X11) - // On desktop-Linux cheat and use non-desktop widgets. On X11, minimize is - // asynchronous. Also (harder) showing a window doesn't activate it without - // user interaction (or extra steps only done for interactive ui tests). - // Without that, show_state remains in ui::SHOW_STATE_INACTIVE throughout. - // TODO(tapted): Find a nice way to run this with desktop widgets on Linux. +// On desktop-Linux cheat and use non-desktop widgets. On X11, minimize is +// asynchronous. Also (harder) showing a window doesn't activate it without +// user interaction (or extra steps only done for interactive ui tests). +// Without that, show_state remains in ui::SHOW_STATE_INACTIVE throughout. +// TODO(tapted): Find a nice way to run this with desktop widgets on Linux. TEST_F(WidgetTest, GetWindowPlacement) { #else TEST_F(DesktopWidgetTest, GetWindowPlacement) { @@ -1126,8 +1115,9 @@ TEST_F(DesktopWidgetTest, MinimumSizeConstraints) { // The test environment may have dwm disabled on Windows. In this case, // CustomFrameView is used instead of the NativeFrameView, which will // provide a minimum size that includes frame decorations. - minimum_size = widget->non_client_view()->GetWindowBoundsForClientBounds( - gfx::Rect(minimum_size)).size(); + minimum_size = widget->non_client_view() + ->GetWindowBoundsForClientBounds(gfx::Rect(minimum_size)) + .size(); } EXPECT_EQ(minimum_size, widget->GetMinimumSize()); @@ -1238,8 +1228,7 @@ TEST_F(DesktopWidgetTest, MAYBE_GetRestoredBounds) { toplevel->SetFullscreen(true); RunPendingMessages(); - EXPECT_NE(toplevel->GetWindowBoundsInScreen(), - toplevel->GetRestoredBounds()); + EXPECT_NE(toplevel->GetWindowBoundsInScreen(), toplevel->GetRestoredBounds()); EXPECT_EQ(bounds, toplevel->GetRestoredBounds()); toplevel->SetFullscreen(false); @@ -1277,15 +1266,10 @@ TEST_F(DesktopWidgetTest, DISABLED_FocusChangesOnBubble) { // Create a widget, show and activate it and focus the contents view. View* contents_view = new View; contents_view->SetFocusBehavior(View::FocusBehavior::ALWAYS); - Widget widget; - Widget::InitParams init_params = - CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); - init_params.bounds = gfx::Rect(0, 0, 200, 200); - init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - widget.Init(std::move(init_params)); - widget.SetContentsView(contents_view); - widget.Show(); - widget.Activate(); + std::unique_ptr<Widget> widget = CreateTestWidget(); + widget->SetContentsView(contents_view); + widget->Show(); + widget->Activate(); contents_view->RequestFocus(); EXPECT_TRUE(contents_view->HasFocus()); @@ -1328,22 +1312,16 @@ TEST_F(WidgetTest, BubbleControlsResetOnInit) { // size while minimized. TEST_F(DesktopWidgetTest, TestViewWidthAfterMinimizingWidget) { // Create a widget. - Widget widget; - Widget::InitParams init_params = - CreateParams(Widget::InitParams::TYPE_WINDOW); - init_params.show_state = ui::SHOW_STATE_NORMAL; - gfx::Rect initial_bounds(0, 0, 300, 400); - init_params.bounds = initial_bounds; - init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - widget.Init(std::move(init_params)); - NonClientView* non_client_view = widget.non_client_view(); - NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget); + std::unique_ptr<Widget> widget = + CreateTestWidget(Widget::InitParams::TYPE_WINDOW); + NonClientView* non_client_view = widget->non_client_view(); + NonClientFrameView* frame_view = new MinimumSizeFrameView(widget.get()); non_client_view->SetFrameView(frame_view); // Setting the frame view doesn't do a layout, so force one. non_client_view->Layout(); - widget.Show(); + widget->Show(); EXPECT_NE(0, frame_view->width()); - widget.Minimize(); + widget->Minimize(); EXPECT_EQ(0, frame_view->width()); } #endif @@ -1354,16 +1332,12 @@ TEST_F(DesktopWidgetTest, TestViewWidthAfterMinimizingWidget) { // paints are expected. class DesktopAuraTestValidPaintWidget : public Widget, public WidgetObserver { public: - DesktopAuraTestValidPaintWidget() { AddObserver(this); } - - ~DesktopAuraTestValidPaintWidget() override { RemoveObserver(this); } + DesktopAuraTestValidPaintWidget() { observer_.Add(this); } - void InitForTest(Widget::InitParams create_params); + ~DesktopAuraTestValidPaintWidget() override = default; bool ReadReceivedPaintAndReset() { - bool result = received_paint_; - received_paint_ = false; - return result; + return std::exchange(received_paint_, false); } bool received_paint_while_hidden() const { @@ -1401,73 +1375,79 @@ class DesktopAuraTestValidPaintWidget : public Widget, public WidgetObserver { bool expect_paint_ = true; bool received_paint_while_hidden_ = false; base::OnceClosure quit_closure_; + ScopedObserver<Widget, WidgetObserver> observer_{this}; DISALLOW_COPY_AND_ASSIGN(DesktopAuraTestValidPaintWidget); }; -void DesktopAuraTestValidPaintWidget::InitForTest(InitParams init_params) { - init_params.bounds = gfx::Rect(0, 0, 200, 200); - init_params.ownership = InitParams::WIDGET_OWNS_NATIVE_WIDGET; - Init(std::move(init_params)); +class DesktopAuraPaintWidgetTest : public DesktopWidgetTest { + public: + std::unique_ptr<views::Widget> CreateTestWidget( + views::Widget::InitParams::Type type = + views::Widget::InitParams::TYPE_WINDOW_FRAMELESS) override { + Widget::InitParams params = CreateParamsForTestWidget(type); + auto widget = std::make_unique<DesktopAuraTestValidPaintWidget>(); + paint_widget_ = widget.get(); + widget->Init(std::move(params)); + + View* contents_view = new View; + contents_view->SetFocusBehavior(View::FocusBehavior::ALWAYS); + widget->SetContentsView(contents_view); - View* contents_view = new View; - contents_view->SetFocusBehavior(View::FocusBehavior::ALWAYS); - SetContentsView(contents_view); + widget->Show(); + widget->Activate(); - Show(); - Activate(); -} + return widget; + } + + DesktopAuraTestValidPaintWidget* paint_widget() { return paint_widget_; } + + private: + DesktopAuraTestValidPaintWidget* paint_widget_ = nullptr; +}; -TEST_F(DesktopWidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) { - DesktopAuraTestValidPaintWidget widget; - widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS)); - widget.WaitUntilPaint(); - EXPECT_TRUE(widget.ReadReceivedPaintAndReset()); - widget.SchedulePaintInRect(widget.GetRestoredBounds()); - widget.Close(); +TEST_F(DesktopAuraPaintWidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) { + std::unique_ptr<Widget> widget = CreateTestWidget(); + paint_widget()->WaitUntilPaint(); + EXPECT_TRUE(paint_widget()->ReadReceivedPaintAndReset()); + widget->SchedulePaintInRect(widget->GetRestoredBounds()); + widget->Close(); RunPendingMessages(); - EXPECT_FALSE(widget.ReadReceivedPaintAndReset()); - EXPECT_FALSE(widget.received_paint_while_hidden()); + EXPECT_FALSE(paint_widget()->ReadReceivedPaintAndReset()); + EXPECT_FALSE(paint_widget()->received_paint_while_hidden()); } -TEST_F(DesktopWidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) { - DesktopAuraTestValidPaintWidget widget; - widget.InitForTest(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS)); - widget.WaitUntilPaint(); - EXPECT_TRUE(widget.ReadReceivedPaintAndReset()); - widget.SchedulePaintInRect(widget.GetRestoredBounds()); - widget.Hide(); +TEST_F(DesktopAuraPaintWidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) { + std::unique_ptr<Widget> widget = CreateTestWidget(); + paint_widget()->WaitUntilPaint(); + EXPECT_TRUE(paint_widget()->ReadReceivedPaintAndReset()); + widget->SchedulePaintInRect(widget->GetRestoredBounds()); + widget->Hide(); RunPendingMessages(); - EXPECT_FALSE(widget.ReadReceivedPaintAndReset()); - EXPECT_FALSE(widget.received_paint_while_hidden()); - widget.Close(); + EXPECT_FALSE(paint_widget()->ReadReceivedPaintAndReset()); + EXPECT_FALSE(paint_widget()->received_paint_while_hidden()); + widget->Close(); } -// Test to ensure that the aura Window's visiblity state is set to visible if +// Test to ensure that the aura Window's visibility state is set to visible if // the underlying widget is hidden and then shown. TEST_F(DesktopWidgetTest, TestWindowVisibilityAfterHide) { // Create a widget. - Widget widget; - Widget::InitParams init_params = - CreateParams(Widget::InitParams::TYPE_WINDOW); - init_params.show_state = ui::SHOW_STATE_NORMAL; - gfx::Rect initial_bounds(0, 0, 300, 400); - init_params.bounds = initial_bounds; - init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - widget.Init(std::move(init_params)); - NonClientView* non_client_view = widget.non_client_view(); - NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget); + std::unique_ptr<Widget> widget = + CreateTestWidget(Widget::InitParams::TYPE_WINDOW); + NonClientView* non_client_view = widget->non_client_view(); + NonClientFrameView* frame_view = new MinimumSizeFrameView(widget.get()); non_client_view->SetFrameView(frame_view); - widget.Show(); - EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow())); - widget.Hide(); - EXPECT_FALSE(IsNativeWindowVisible(widget.GetNativeWindow())); - widget.Show(); - EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow())); + widget->Show(); + EXPECT_TRUE(IsNativeWindowVisible(widget->GetNativeWindow())); + widget->Hide(); + EXPECT_FALSE(IsNativeWindowVisible(widget->GetNativeWindow())); + widget->Show(); + EXPECT_TRUE(IsNativeWindowVisible(widget->GetNativeWindow())); } -// Tests that wheel events generated from scroll events are targetted to the +// Tests that wheel events generated from scroll events are targeted to the // views under the cursor when the focused view does not processed them. TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) { EventCountView* cursor_view = new EventCountView; @@ -1477,13 +1457,8 @@ TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) { widget->GetRootView()->AddChildView(cursor_view); // Generate a scroll event on the cursor view. - ui::ScrollEvent scroll(ui::ET_SCROLL, - gfx::Point(65, 5), - ui::EventTimeForNow(), - 0, - 0, 20, - 0, 20, - 2); + ui::ScrollEvent scroll(ui::ET_SCROLL, gfx::Point(65, 5), + ui::EventTimeForNow(), 0, 0, 20, 0, 20, 2); widget->OnScrollEvent(&scroll); EXPECT_EQ(1, cursor_view->GetEventCount(ui::ET_SCROLL)); @@ -1491,13 +1466,8 @@ TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) { cursor_view->ResetCounts(); - ui::ScrollEvent scroll2(ui::ET_SCROLL, - gfx::Point(5, 5), - ui::EventTimeForNow(), - 0, - 0, 20, - 0, 20, - 2); + ui::ScrollEvent scroll2(ui::ET_SCROLL, gfx::Point(5, 5), + ui::EventTimeForNow(), 0, 0, 20, 0, 20, 2); widget->OnScrollEvent(&scroll2); EXPECT_EQ(0, cursor_view->GetEventCount(ui::ET_SCROLL)); @@ -1576,13 +1546,8 @@ TEST_F(WidgetTest, EventHandlersOnRootView) { // Dispatch a ui::ET_SCROLL event. The event remains unhandled and should // bubble up the views hierarchy to be re-dispatched on the root view. - ui::ScrollEvent scroll(ui::ET_SCROLL, - gfx::Point(5, 5), - ui::EventTimeForNow(), - 0, - 0, 20, - 0, 20, - 2); + ui::ScrollEvent scroll(ui::ET_SCROLL, gfx::Point(5, 5), ui::EventTimeForNow(), + 0, 0, 20, 0, 20, 2); widget->OnScrollEvent(&scroll); EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL)); EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL)); @@ -1599,13 +1564,8 @@ TEST_F(WidgetTest, EventHandlersOnRootView) { // Dispatch a ui::ET_SCROLL_FLING_START event. The event remains unhandled and // should bubble up the views hierarchy to be re-dispatched on the root view. - ui::ScrollEvent fling(ui::ET_SCROLL_FLING_START, - gfx::Point(5, 5), - ui::EventTimeForNow(), - 0, - 0, 20, - 0, 20, - 2); + ui::ScrollEvent fling(ui::ET_SCROLL_FLING_START, gfx::Point(5, 5), + ui::EventTimeForNow(), 0, 0, 20, 0, 20, 2); widget->OnScrollEvent(&fling); EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL_FLING_START)); EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL_FLING_START)); @@ -1628,10 +1588,7 @@ TEST_F(WidgetTest, EventHandlersOnRootView) { // Dispatch a ui::ET_GESTURE_TAP_DOWN and a ui::ET_GESTURE_TAP_CANCEL event. // The events are handled at the target phase and should not reach the // post-target handler. - ui::GestureEvent tap_down(5, - 5, - 0, - ui::EventTimeForNow(), + ui::GestureEvent tap_down(5, 5, 0, ui::EventTimeForNow(), ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN)); widget->OnGestureEvent(&tap_down); EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_DOWN)); @@ -1639,10 +1596,7 @@ TEST_F(WidgetTest, EventHandlersOnRootView) { EXPECT_EQ(0, h2.GetEventCount(ui::ET_GESTURE_TAP_DOWN)); ui::GestureEvent tap_cancel( - 5, - 5, - 0, - ui::EventTimeForNow(), + 5, 5, 0, ui::EventTimeForNow(), ui::GestureEventDetails(ui::ET_GESTURE_TAP_CANCEL)); widget->OnGestureEvent(&tap_cancel); EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_TAP_CANCEL)); @@ -1655,13 +1609,8 @@ TEST_F(WidgetTest, EventHandlersOnRootView) { // Dispatch a ui::ET_SCROLL event. The event is handled at the target phase // and should not reach the post-target handler. - ui::ScrollEvent consumed_scroll(ui::ET_SCROLL, - gfx::Point(5, 5), - ui::EventTimeForNow(), - 0, - 0, 20, - 0, 20, - 2); + ui::ScrollEvent consumed_scroll(ui::ET_SCROLL, gfx::Point(5, 5), + ui::EventTimeForNow(), 0, 0, 20, 0, 20, 2); widget->OnScrollEvent(&consumed_scroll); EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL)); EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL)); @@ -1996,9 +1945,7 @@ void TestNativeWidgetDestroyedWidget::OnNativeWidgetDestroyed() { // crash in ASan. TEST_F(DesktopWidgetTest, WidgetDestroyedItselfDoesNotCrash) { TestDesktopWidgetDelegate delegate(new TestNativeWidgetDestroyedWidget); - Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - delegate.InitWidget(std::move(params)); + delegate.InitWidget(CreateParamsForTestWidget()); delegate.GetWidget()->Show(); delegate.GetWidget()->CloseNow(); } @@ -2270,6 +2217,7 @@ TEST_F(DesktopWidgetTest, CloseDestroys) { Widget::InitParams params = CreateParams(views::Widget::InitParams::TYPE_MENU); params.opacity = Widget::InitParams::WindowOpacity::kOpaque; + params.bounds = gfx::Rect(50, 50, 250, 250); widget->Init(std::move(params)); widget->Show(); widget->Hide(); @@ -2287,11 +2235,7 @@ TEST_F(DesktopWidgetTest, CloseDestroys) { // Tests that killing a widget while animating it does not crash. TEST_F(WidgetTest, CloseWidgetWhileAnimating) { - std::unique_ptr<Widget> widget(new Widget); - Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.bounds = gfx::Rect(50, 50, 250, 250); - widget->Init(std::move(params)); + std::unique_ptr<Widget> widget = CreateTestWidget(); AnimationEndObserver animation_observer; WidgetBoundsObserver widget_observer; gfx::Rect bounds(100, 100, 50, 50); @@ -2365,28 +2309,17 @@ TEST_F(DesktopWidgetTest, ValidDuringOnNativeWidgetDestroyingFromClose) { // Tests that we do not crash when a Widget is destroyed by going out of // scope (as opposed to being explicitly deleted by its NativeWidget). TEST_F(WidgetTest, NoCrashOnWidgetDelete) { - std::unique_ptr<Widget> widget(new Widget); - Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - widget->Init(std::move(params)); + CreateTestWidget(); } TEST_F(WidgetTest, NoCrashOnResizeConstraintsWindowTitleOnPopup) { - std::unique_ptr<Widget> widget(new Widget); - Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - widget->Init(std::move(params)); - widget->OnSizeConstraintsChanged(); + CreateTestWidget(Widget::InitParams::TYPE_POPUP)->OnSizeConstraintsChanged(); } // Tests that we do not crash when a Widget is destroyed before it finishes // processing of pending input events in the message loop. TEST_F(WidgetTest, NoCrashOnWidgetDeleteWithPendingEvents) { - std::unique_ptr<Widget> widget(new Widget); - Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); - params.bounds = gfx::Rect(0, 0, 200, 200); - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - widget->Init(std::move(params)); + std::unique_ptr<Widget> widget = CreateTestWidget(); widget->Show(); ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow()); @@ -2418,11 +2351,11 @@ class RootViewTestView : public View { // Checks if RootView::*_handler_ fields are unset when widget is hidden. // Fails on chromium.webkit Windows bot, see crbug.com/264872. #if defined(OS_WIN) -#define MAYBE_DisableTestRootViewHandlersWhenHidden\ - DISABLED_TestRootViewHandlersWhenHidden +#define MAYBE_DisableTestRootViewHandlersWhenHidden \ + DISABLED_TestRootViewHandlersWhenHidden #else -#define MAYBE_DisableTestRootViewHandlersWhenHidden\ - TestRootViewHandlersWhenHidden +#define MAYBE_DisableTestRootViewHandlersWhenHidden \ + TestRootViewHandlersWhenHidden #endif TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) { Widget* widget = CreateTopLevelNativeWidget(); @@ -2998,8 +2931,8 @@ TEST_F(WidgetTest, GestureEventLocationWhileBubbling) { // Define a GESTURE_TAP event located at (125, 105) in root view coordinates. // This event is contained within all of |v1|, |v2|, and |v3|. gfx::Point location_in_root(125, 105); - GestureEventForTest tap( - ui::ET_GESTURE_TAP, location_in_root.x(), location_in_root.y()); + GestureEventForTest tap(ui::ET_GESTURE_TAP, location_in_root.x(), + location_in_root.y()); // Calculate the location of the event in the local coordinate spaces // of each of the views. @@ -3031,125 +2964,6 @@ TEST_F(WidgetTest, GestureEventLocationWhileBubbling) { widget->Close(); } -// Verifies that disabled views are permitted to be set as the default gesture -// handler in RootView. Also verifies that gesture events targeted to a disabled -// view are not actually dispatched to the view, but are still marked as -// handled. -TEST_F(WidgetTest, DisabledGestureEventTarget) { - Widget* widget = CreateTopLevelNativeWidget(); - widget->SetBounds(gfx::Rect(0, 0, 300, 300)); - - // Define a hierarchy of four views (coordinates are in - // their parent coordinate space). - // v1 (0, 0, 300, 300) - // v2 (0, 0, 100, 100) - // v3 (0, 0, 50, 50) - // v4(0, 0, 10, 10) - EventCountView* v1 = new EventCountView(); - v1->SetBounds(0, 0, 300, 300); - EventCountView* v2 = new EventCountView(); - v2->SetBounds(0, 0, 100, 100); - EventCountView* v3 = new EventCountView(); - v3->SetBounds(0, 0, 50, 50); - EventCountView* v4 = new EventCountView(); - v4->SetBounds(0, 0, 10, 10); - internal::RootView* root_view = - static_cast<internal::RootView*>(widget->GetRootView()); - root_view->AddChildView(v1); - v1->AddChildView(v2); - v2->AddChildView(v3); - v3->AddChildView(v4); - - widget->Show(); - - // |v1|, |v2|, and |v3| all handle gesture events but |v3| is marked as - // disabled. - v1->set_handle_mode(EventCountView::CONSUME_EVENTS); - v2->set_handle_mode(EventCountView::CONSUME_EVENTS); - v3->set_handle_mode(EventCountView::CONSUME_EVENTS); - v3->SetEnabled(false); - - // No gesture handler is set in the root view. In this case the tap event - // should be dispatched only to |v4|, the gesture handler should be set to - // |v3|, and the event should be marked as handled. - GestureEventForTest tap(ui::ET_GESTURE_TAP, 5, 5); - widget->OnGestureEvent(&tap); - EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP)); - EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP)); - EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP)); - EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP)); - EXPECT_EQ(v3, GetGestureHandler(root_view)); - EXPECT_TRUE(tap.handled()); - v1->ResetCounts(); - v2->ResetCounts(); - v3->ResetCounts(); - v4->ResetCounts(); - - // A subsequent gesture event should be marked as handled but not dispatched. - tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5); - widget->OnGestureEvent(&tap); - EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP)); - EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP)); - EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP)); - EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_TAP)); - EXPECT_EQ(v3, GetGestureHandler(root_view)); - EXPECT_TRUE(tap.handled()); - v1->ResetCounts(); - v2->ResetCounts(); - v3->ResetCounts(); - v4->ResetCounts(); - - // A GESTURE_END should reset the default gesture handler to NULL. It should - // also not be dispatched to |v3| but still marked as handled. - GestureEventForTest end(ui::ET_GESTURE_END, 5, 5); - widget->OnGestureEvent(&end); - EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END)); - EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END)); - EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END)); - EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END)); - EXPECT_EQ(nullptr, GetGestureHandler(root_view)); - EXPECT_TRUE(end.handled()); - v1->ResetCounts(); - v2->ResetCounts(); - v3->ResetCounts(); - v4->ResetCounts(); - - // Change the handle mode of |v3| to indicate that it would no longer like - // to handle events which are dispatched to it. - v3->set_handle_mode(EventCountView::PROPAGATE_EVENTS); - - // No gesture handler is set in the root view. In this case the tap event - // should be dispatched only to |v4| and the event should be marked as - // handled. Furthermore, the gesture handler should be set to - // |v3|; even though |v3| does not explicitly handle events, it is a - // valid target for the tap event because it is disabled. - tap = GestureEventForTest(ui::ET_GESTURE_TAP, 5, 5); - widget->OnGestureEvent(&tap); - EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_TAP)); - EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_TAP)); - EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_TAP)); - EXPECT_EQ(1, v4->GetEventCount(ui::ET_GESTURE_TAP)); - EXPECT_EQ(v3, GetGestureHandler(root_view)); - EXPECT_TRUE(tap.handled()); - v1->ResetCounts(); - v2->ResetCounts(); - v3->ResetCounts(); - v4->ResetCounts(); - - // A GESTURE_END should reset the default gesture handler to NULL. It should - // also not be dispatched to |v3| but still marked as handled. - end = GestureEventForTest(ui::ET_GESTURE_END, 5, 5); - widget->OnGestureEvent(&end); - EXPECT_EQ(0, v1->GetEventCount(ui::ET_GESTURE_END)); - EXPECT_EQ(0, v2->GetEventCount(ui::ET_GESTURE_END)); - EXPECT_EQ(0, v3->GetEventCount(ui::ET_GESTURE_END)); - EXPECT_EQ(0, v4->GetEventCount(ui::ET_GESTURE_END)); - EXPECT_EQ(nullptr, GetGestureHandler(root_view)); - EXPECT_TRUE(end.handled()); - - widget->Close(); -} - // Test the result of Widget::GetAllChildWidgets(). TEST_F(WidgetTest, GetAllChildWidgets) { // Create the following widget hierarchy: @@ -3201,9 +3015,7 @@ class DestroyedTrackingView : public View { public: DestroyedTrackingView(const std::string& name, std::vector<std::string>* add_to) - : name_(name), - add_to_(add_to) { - } + : name_(name), add_to_(add_to) {} ~DestroyedTrackingView() override { add_to_->push_back(name_); } @@ -3285,35 +3097,19 @@ TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) { // Verifies nativeview visbility matches that of Widget visibility when // SetFullscreen is invoked. TEST_F(WidgetTest, FullscreenStatePropagated) { - Widget::InitParams init_params = - CreateParams(Widget::InitParams::TYPE_WINDOW); - init_params.show_state = ui::SHOW_STATE_NORMAL; - init_params.bounds = gfx::Rect(0, 0, 500, 500); - init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - - Widget top_level_widget; - top_level_widget.Init(std::move(init_params)); - top_level_widget.SetFullscreen(true); - EXPECT_EQ(top_level_widget.IsVisible(), - IsNativeWindowVisible(top_level_widget.GetNativeWindow())); - top_level_widget.CloseNow(); + std::unique_ptr<Widget> top_level_widget = CreateTestWidget(); + top_level_widget->SetFullscreen(true); + EXPECT_EQ(top_level_widget->IsVisible(), + IsNativeWindowVisible(top_level_widget->GetNativeWindow())); } // Verifies nativeview visbility matches that of Widget visibility when // SetFullscreen is invoked, for a widget provided with a desktop widget. TEST_F(DesktopWidgetTest, FullscreenStatePropagated_DesktopWidget) { - Widget::InitParams init_params = - CreateParams(Widget::InitParams::TYPE_WINDOW); - init_params.show_state = ui::SHOW_STATE_NORMAL; - init_params.bounds = gfx::Rect(0, 0, 500, 500); - init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - Widget top_level_widget; - - top_level_widget.Init(std::move(init_params)); - top_level_widget.SetFullscreen(true); - EXPECT_EQ(top_level_widget.IsVisible(), - IsNativeWindowVisible(top_level_widget.GetNativeWindow())); - top_level_widget.CloseNow(); + std::unique_ptr<Widget> top_level_widget = CreateTestWidget(); + top_level_widget->SetFullscreen(true); + EXPECT_EQ(top_level_widget->IsVisible(), + IsNativeWindowVisible(top_level_widget->GetNativeWindow())); } namespace { @@ -3390,28 +3186,38 @@ class IsActiveFromDestroyObserver : public WidgetObserver { } // namespace +class ChildDesktopWidgetTest : public DesktopWidgetTest { + public: + Widget::InitParams CreateParams(Widget::InitParams::Type type) override { + Widget::InitParams params = DesktopWidgetTest::CreateParams(type); + if (context_) + params.context = context_; + return params; + } + + std::unique_ptr<Widget> CreateChildWidget(gfx::NativeWindow context) { + context_ = context; + return CreateTestWidget(); + } + + private: + gfx::NativeWindow context_ = nullptr; +}; + // Verifies Widget::IsActive() invoked from // WidgetObserver::OnWidgetDestroying() in a child widget doesn't crash. -TEST_F(DesktopWidgetTest, IsActiveFromDestroy) { +TEST_F(ChildDesktopWidgetTest, IsActiveFromDestroy) { // Create two widgets, one a child of the other. IsActiveFromDestroyObserver observer; - Widget parent_widget; - Widget::InitParams parent_params = - CreateParams(Widget::InitParams::TYPE_POPUP); - 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_POPUP); - child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - child_params.context = parent_widget.GetNativeWindow(); - child_widget.Init(std::move(child_params)); - child_widget.AddObserver(&observer); - child_widget.Show(); - - parent_widget.CloseNow(); + std::unique_ptr<Widget> parent_widget = CreateTestWidget(); + parent_widget->Show(); + + std::unique_ptr<Widget> child_widget = + CreateChildWidget(parent_widget->GetNativeWindow()); + child_widget->AddObserver(&observer); + child_widget->Show(); + + parent_widget->CloseNow(); } // Tests that events propagate through from the dispatcher with the correct @@ -3506,8 +3312,7 @@ TEST_F(WidgetTest, NonClientWindowValidAfterInit) { class SubclassWindowHelper { public: explicit SubclassWindowHelper(HWND window) - : window_(window), - message_to_destroy_on_(0) { + : window_(window), message_to_destroy_on_(0) { EXPECT_EQ(instance_, nullptr); instance_ = this; EXPECT_TRUE(Subclass()); @@ -3523,9 +3328,7 @@ class SubclassWindowHelper { return (messages_.find(message) != messages_.end()); } - void Clear() { - messages_.clear(); - } + void Clear() { messages_.clear(); } void set_message_to_destroy_on(unsigned int message) { message_to_destroy_on_ = message; @@ -3533,16 +3336,13 @@ class SubclassWindowHelper { private: bool Subclass() { - old_proc_ = reinterpret_cast<WNDPROC>( - ::SetWindowLongPtr(window_, - GWLP_WNDPROC, - reinterpret_cast<LONG_PTR>(WndProc))); + old_proc_ = reinterpret_cast<WNDPROC>(::SetWindowLongPtr( + window_, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WndProc))); return old_proc_ != nullptr; } void Unsubclass() { - ::SetWindowLongPtr(window_, - GWLP_WNDPROC, + ::SetWindowLongPtr(window_, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(old_proc_)); } @@ -3585,15 +3385,12 @@ SubclassWindowHelper* SubclassWindowHelper::instance_ = nullptr; // Disabled because of flaky timeouts: http://crbug.com/592742 TEST_F(DesktopWidgetTest, DISABLED_SysCommandMoveOnNCLButtonDownOnCaptionAndMoveTest) { - Widget widget; - Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - widget.Init(std::move(params)); - widget.SetBounds(gfx::Rect(0, 0, 200, 200)); - widget.Show(); + std::unique_ptr<Widget> widget = + CreateTestWidget(Widget::InitParams::TYPE_WINDOW); + widget->Show(); ::SetCursorPos(500, 500); - HWND window = widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget(); + HWND window = widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget(); SubclassWindowHelper subclass_helper(window); @@ -3648,24 +3445,18 @@ TEST_F(DesktopWidgetTest, EXPECT_TRUE(subclass_helper.received_message(WM_NCLBUTTONDOWN)); EXPECT_TRUE(subclass_helper.received_message(WM_MOUSEMOVE)); EXPECT_TRUE(subclass_helper.received_message(WM_SYSCOMMAND)); - - widget.CloseNow(); } // This test validates that destroying the window in the context of the // WM_SYSCOMMAND message with SC_MOVE does not crash. // Disabled because of flaky timeouts: http://crbug.com/592742 TEST_F(DesktopWidgetTest, DISABLED_DestroyInSysCommandNCLButtonDownOnCaption) { - Widget widget; - Widget::InitParams params = - CreateParams(Widget::InitParams::TYPE_WINDOW); - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - widget.Init(std::move(params)); - widget.SetBounds(gfx::Rect(0, 0, 200, 200)); - widget.Show(); + std::unique_ptr<Widget> widget = + CreateTestWidget(Widget::InitParams::TYPE_WINDOW); + widget->Show(); ::SetCursorPos(500, 500); - HWND window = widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget(); + HWND window = widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget(); SubclassWindowHelper subclass_helper(window); @@ -3679,8 +3470,6 @@ TEST_F(DesktopWidgetTest, DISABLED_DestroyInSysCommandNCLButtonDownOnCaption) { EXPECT_TRUE(subclass_helper.received_message(WM_NCLBUTTONDOWN)); EXPECT_TRUE(subclass_helper.received_message(WM_SYSCOMMAND)); - - widget.CloseNow(); } #endif @@ -3875,22 +3664,19 @@ class LayoutCountingView : public View { using WidgetInvalidateLayoutTest = ViewsTestBaseWithNativeWidgetType; TEST_P(WidgetInvalidateLayoutTest, InvalidateLayout) { - Widget widget; - Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - widget.Init(std::move(params)); - widget.SetBounds(gfx::Rect(0, 0, 600, 600)); + std::unique_ptr<Widget> widget = + CreateTestWidget(Widget::InitParams::TYPE_WINDOW); LayoutCountingView* view = - widget.widget_delegate()->GetContentsView()->AddChildView( + widget->widget_delegate()->GetContentsView()->AddChildView( std::make_unique<LayoutCountingView>()); view->parent()->SetLayoutManager(std::make_unique<FillLayout>()); // Force an initial Layout(). // TODO(sky): this shouldn't be necessary, adding a child view should trigger // ScheduleLayout(). view->Layout(); - widget.Show(); + widget->Show(); - ui::Compositor* compositor = widget.GetCompositor(); + ui::Compositor* compositor = widget->GetCompositor(); ASSERT_TRUE(compositor); compositor->ScheduleDraw(); ui::DrawWaiterForTest::WaitForCompositingEnded(compositor); @@ -3902,14 +3688,14 @@ TEST_P(WidgetInvalidateLayoutTest, InvalidateLayout) { // wait for Layout() to be called. view->set_layout_closure(run_loop.QuitClosure()); EXPECT_FALSE(ViewTestApi(view).needs_layout()); - EXPECT_FALSE(ViewTestApi(widget.GetRootView()).needs_layout()); + EXPECT_FALSE(ViewTestApi(widget->GetRootView()).needs_layout()); view->InvalidateLayout(); EXPECT_TRUE(ViewTestApi(view).needs_layout()); - EXPECT_TRUE(ViewTestApi(widget.GetRootView()).needs_layout()); + EXPECT_TRUE(ViewTestApi(widget->GetRootView()).needs_layout()); run_loop.Run(); EXPECT_EQ(1u, view->GetAndClearLayoutCount()); EXPECT_FALSE(ViewTestApi(view).needs_layout()); - EXPECT_FALSE(ViewTestApi(widget.GetRootView()).needs_layout()); + EXPECT_FALSE(ViewTestApi(widget->GetRootView()).needs_layout()); } INSTANTIATE_TEST_SUITE_P( @@ -4068,14 +3854,14 @@ namespace { // Provides functionality to create a window modal dialog. class ModalDialogDelegate : public DialogDelegateView { -public: + public: explicit ModalDialogDelegate(ui::ModalType type) : type_(type) {} ~ModalDialogDelegate() override = default; // WidgetDelegate overrides. ui::ModalType GetModalType() const override { return type_; } -private: + private: const ui::ModalType type_; DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate); @@ -4088,18 +3874,10 @@ private: // remaining top-level windows should be re-enabled. TEST_F(DesktopWidgetTest, WindowModalOwnerDestroyedEnabledTest) { // top_level_widget owns owner_dialog_widget which owns owned_dialog_widget. - Widget top_level_widget; - Widget owner_dialog_widget; - Widget owned_dialog_widget; + // Create the top level widget. - Widget::InitParams init_params = - CreateParams(Widget::InitParams::TYPE_WINDOW); - init_params.show_state = ui::SHOW_STATE_NORMAL; - gfx::Rect initial_bounds(0, 0, 500, 500); - init_params.bounds = initial_bounds; - init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - top_level_widget.Init(std::move(init_params)); - top_level_widget.Show(); + std::unique_ptr<Widget> top_level_widget = CreateTestWidget(); + top_level_widget->Show(); // Create the owner modal dialog. // owner_dialog_delegate instance will be destroyed when the dialog @@ -4107,12 +3885,11 @@ TEST_F(DesktopWidgetTest, WindowModalOwnerDestroyedEnabledTest) { ModalDialogDelegate* owner_dialog_delegate = new ModalDialogDelegate(ui::MODAL_TYPE_WINDOW); - init_params = CreateParams(Widget::InitParams::TYPE_WINDOW); - init_params.show_state = ui::SHOW_STATE_NORMAL; - init_params.bounds = gfx::Rect(100, 100, 200, 200); - init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + Widget owner_dialog_widget; + Widget::InitParams init_params = + CreateParamsForTestWidget(Widget::InitParams::TYPE_WINDOW); init_params.delegate = owner_dialog_delegate; - init_params.parent = top_level_widget.GetNativeView(); + init_params.parent = top_level_widget->GetNativeView(); init_params.native_widget = new test::TestPlatformNativeWidget<DesktopNativeWidgetAura>( &owner_dialog_widget, false, nullptr); @@ -4128,10 +3905,7 @@ TEST_F(DesktopWidgetTest, WindowModalOwnerDestroyedEnabledTest) { ModalDialogDelegate* owned_dialog_delegate = new ModalDialogDelegate(ui::MODAL_TYPE_WINDOW); - init_params = CreateParams(Widget::InitParams::TYPE_WINDOW); - init_params.show_state = ui::SHOW_STATE_NORMAL; - init_params.bounds = gfx::Rect(150, 150, 250, 250); - init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + Widget owned_dialog_widget; init_params.delegate = owned_dialog_delegate; init_params.parent = owner_dialog_widget.GetNativeView(); init_params.native_widget = @@ -4144,7 +3918,7 @@ TEST_F(DesktopWidgetTest, WindowModalOwnerDestroyedEnabledTest) { owned_dialog_widget.Show(); RunPendingMessages(); - HWND top_hwnd = HWNDForWidget(&top_level_widget); + HWND top_hwnd = HWNDForWidget(top_level_widget.get()); EXPECT_FALSE(!!IsWindowEnabled(owner_hwnd)); EXPECT_FALSE(!!IsWindowEnabled(top_hwnd)); @@ -4157,7 +3931,7 @@ TEST_F(DesktopWidgetTest, WindowModalOwnerDestroyedEnabledTest) { EXPECT_FALSE(!!IsWindow(owned_hwnd)); EXPECT_TRUE(!!IsWindowEnabled(top_hwnd)); - top_level_widget.CloseNow(); + top_level_widget->CloseNow(); } #endif // defined(OS_WIN) @@ -4166,17 +3940,6 @@ TEST_F(DesktopWidgetTest, WindowModalOwnerDestroyedEnabledTest) { namespace { -void InitializeWidgetForOpacity( - Widget& widget, - Widget::InitParams init_params, - const Widget::InitParams::WindowOpacity opacity) { - init_params.opacity = opacity; - init_params.show_state = ui::SHOW_STATE_NORMAL; - init_params.bounds = gfx::Rect(0, 0, 500, 500); - init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - widget.Init(std::move(init_params)); -} - class CompositingWidgetTest : public DesktopWidgetTest { public: CompositingWidgetTest() @@ -4190,8 +3953,15 @@ class CompositingWidgetTest : public DesktopWidgetTest { Widget::InitParams::TYPE_DRAG} {} ~CompositingWidgetTest() override = default; + Widget::InitParams CreateParams(Widget::InitParams::Type type) override { + Widget::InitParams params = DesktopWidgetTest::CreateParams(type); + params.opacity = opacity_; + return params; + } + void CheckAllWidgetsForOpacity( const Widget::InitParams::WindowOpacity opacity) { + opacity_ = opacity; for (const auto& widget_type : widget_types_) { #if defined(OS_MACOSX) // Tooltips are native on Mac. See NativeWidgetNSWindowBridge::Init. @@ -4203,8 +3973,7 @@ class CompositingWidgetTest : public DesktopWidgetTest { if (widget_type != Widget::InitParams::TYPE_WINDOW) continue; #endif - Widget widget; - InitializeWidgetForOpacity(widget, CreateParams(widget_type), opacity); + std::unique_ptr<Widget> widget = CreateTestWidget(widget_type); // Use NativeWidgetAura directly. if (widget_type == Widget::InitParams::TYPE_WINDOW_FRAMELESS || @@ -4218,21 +3987,21 @@ class CompositingWidgetTest : public DesktopWidgetTest { // TestViewsDelegate::use_transparent_windows_ determines the result of // kInferOpacity: assume it is false. bool should_be_transparent = - opacity == Widget::InitParams::WindowOpacity::kTranslucent; + opacity_ == Widget::InitParams::WindowOpacity::kTranslucent; #else - bool should_be_transparent = widget.ShouldWindowContentsBeTransparent(); + bool should_be_transparent = widget->ShouldWindowContentsBeTransparent(); #endif - EXPECT_EQ(IsNativeWindowTransparent(widget.GetNativeWindow()), + EXPECT_EQ(IsNativeWindowTransparent(widget->GetNativeWindow()), should_be_transparent); #if defined(USE_X11) if (HasCompositingManager() && (widget_type == Widget::InitParams::TYPE_DRAG || widget_type == Widget::InitParams::TYPE_WINDOW)) { - EXPECT_TRUE(widget.IsTranslucentWindowOpacitySupported()); + EXPECT_TRUE(widget->IsTranslucentWindowOpacitySupported()); } else { - EXPECT_FALSE(widget.IsTranslucentWindowOpacitySupported()); + EXPECT_FALSE(widget->IsTranslucentWindowOpacitySupported()); } #endif } @@ -4240,6 +4009,8 @@ class CompositingWidgetTest : public DesktopWidgetTest { protected: const std::vector<Widget::InitParams::Type> widget_types_; + Widget::InitParams::WindowOpacity opacity_ = + Widget::InitParams::WindowOpacity::kInferred; DISALLOW_COPY_AND_ASSIGN(CompositingWidgetTest); }; diff --git a/chromium/ui/views/widget/window_reorderer.cc b/chromium/ui/views/widget/window_reorderer.cc index ce52ff296c5..b1ac11fc465 100644 --- a/chromium/ui/views/widget/window_reorderer.cc +++ b/chromium/ui/views/widget/window_reorderer.cc @@ -8,6 +8,7 @@ #include <algorithm> #include <map> +#include <set> #include <vector> #include "base/containers/adapters.h" @@ -87,8 +88,7 @@ class WindowReorderer::AssociationObserver : public aura::WindowObserver { WindowReorderer::AssociationObserver::AssociationObserver( WindowReorderer* reorderer) - : reorderer_(reorderer) { -} + : reorderer_(reorderer) {} WindowReorderer::AssociationObserver::~AssociationObserver() { while (!windows_.empty()) @@ -101,8 +101,7 @@ void WindowReorderer::AssociationObserver::StartObserving( window->AddObserver(this); } -void WindowReorderer::AssociationObserver::StopObserving( - aura::Window* window) { +void WindowReorderer::AssociationObserver::StopObserving(aura::Window* window) { windows_.erase(window); window->RemoveObserver(this); } @@ -121,8 +120,7 @@ void WindowReorderer::AssociationObserver::OnWindowDestroying( window->RemoveObserver(this); } -WindowReorderer::WindowReorderer(aura::Window* parent_window, - View* root_view) +WindowReorderer::WindowReorderer(aura::Window* parent_window, View* root_view) : parent_window_(parent_window), root_view_(root_view), association_observer_(new AssociationObserver(this)) { @@ -158,7 +156,7 @@ void WindowReorderer::ReorderChildWindows() { // with layers and views with associated windows in the view tree. std::vector<View*> view_with_layer_order; GetOrderOfViewsWithLayers(root_view_, parent_window_->layer(), hosted_windows, - &view_with_layer_order); + &view_with_layer_order); std::vector<ui::Layer*> children_layer_order; diff --git a/chromium/ui/views/widget/window_reorderer_unittest.cc b/chromium/ui/views/widget/window_reorderer_unittest.cc index 9ecebbc9dad..670cc0f1238 100644 --- a/chromium/ui/views/widget/window_reorderer_unittest.cc +++ b/chromium/ui/views/widget/window_reorderer_unittest.cc @@ -17,22 +17,10 @@ namespace views { namespace { -// Creates a control widget with the passed in parameters. -// The caller takes ownership of the returned widget. -Widget* CreateControlWidget(aura::Window* parent, const gfx::Rect& bounds) { - Widget::InitParams params(Widget::InitParams::TYPE_CONTROL); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.parent = parent; - params.bounds = bounds; - Widget* widget = new Widget(); - widget->Init(std::move(params)); - return widget; -} - // Sets the name of |window| and |window|'s layer to |name|. void SetWindowAndLayerName(aura::Window* window, const std::string& name) { window->SetName(name); - window->layer()->set_name(name); + window->layer()->SetName(name); } // Returns a string containing the name of each of the child windows (bottommost @@ -47,13 +35,27 @@ std::string ChildWindowNamesAsString(const aura::Window& parent) { return names; } -using WindowReordererTest = ViewsTestBase; +class WindowReordererTest : public ViewsTestBase { + public: + Widget::InitParams CreateParams(Widget::InitParams::Type type) override { + Widget::InitParams params = ViewsTestBase::CreateParams(type); + params.parent = parent_; + return params; + } + + std::unique_ptr<Widget> CreateControlWidget(aura::Window* parent) { + parent_ = parent; + return CreateTestWidget(Widget::InitParams::TYPE_CONTROL); + } + + private: + aura::Window* parent_ = nullptr; +}; // Test that views with layers and views with associated windows are reordered // according to the view hierarchy. TEST_F(WindowReordererTest, Basic) { - std::unique_ptr<Widget> parent( - CreateControlWidget(root_window(), gfx::Rect(0, 0, 100, 100))); + std::unique_ptr<Widget> parent = CreateControlWidget(root_window()); parent->Show(); aura::Window* parent_window = parent->GetNativeWindow(); @@ -65,15 +67,13 @@ TEST_F(WindowReordererTest, Basic) { // view. View* v = new View(); v->SetPaintToLayer(); - v->layer()->set_name("v"); + v->layer()->SetName("v"); contents_view->AddChildView(v); - std::unique_ptr<Widget> w1( - CreateControlWidget(parent_window, gfx::Rect(0, 1, 100, 101))); + std::unique_ptr<Widget> w1 = CreateControlWidget(parent_window); SetWindowAndLayerName(w1->GetNativeView(), "w1"); w1->Show(); - std::unique_ptr<Widget> w2( - CreateControlWidget(parent_window, gfx::Rect(0, 2, 100, 102))); + std::unique_ptr<Widget> w2 = CreateControlWidget(parent_window); SetWindowAndLayerName(w2->GetNativeView(), "w2"); w2->Show(); @@ -118,10 +118,6 @@ TEST_F(WindowReordererTest, Basic) { EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window)); EXPECT_EQ("w1 v w2", ui::test::ChildLayerNamesAsString(*parent_window->layer())); - - // Work around for bug in NativeWidgetAura. - // TODO: fix bug and remove this. - parent->Close(); } // Test that different orderings of: @@ -130,16 +126,15 @@ TEST_F(WindowReordererTest, Basic) { // - associating the "host" view and window // all correctly reorder the child windows and layers. TEST_F(WindowReordererTest, Association) { - std::unique_ptr<Widget> parent( - CreateControlWidget(root_window(), gfx::Rect(0, 0, 100, 100))); + std::unique_ptr<Widget> parent = CreateControlWidget(root_window()); parent->Show(); aura::Window* parent_window = parent->GetNativeWindow(); View* contents_view = new View(); parent->SetContentsView(contents_view); - aura::Window* w1 = aura::test::CreateTestWindowWithId(0, - parent->GetNativeWindow()); + aura::Window* w1 = + aura::test::CreateTestWindowWithId(0, parent->GetNativeWindow()); SetWindowAndLayerName(w1, "w1"); aura::Window* w2 = aura::test::CreateTestWindowWithId(0, nullptr); @@ -152,8 +147,7 @@ TEST_F(WindowReordererTest, Association) { contents_view->AddChildView(host_view2); w2->SetProperty(views::kHostViewKey, host_view2); EXPECT_EQ("w1", ChildWindowNamesAsString(*parent_window)); - EXPECT_EQ("w1", - ui::test::ChildLayerNamesAsString(*parent_window->layer())); + EXPECT_EQ("w1", ui::test::ChildLayerNamesAsString(*parent_window->layer())); parent_window->AddChild(w2); EXPECT_EQ("w2 w1", ChildWindowNamesAsString(*parent_window)); @@ -180,10 +174,6 @@ TEST_F(WindowReordererTest, Association) { EXPECT_EQ("w2 w1", ChildWindowNamesAsString(*parent_window)); EXPECT_EQ("w2 w1", ui::test::ChildLayerNamesAsString(*parent_window->layer())); - - // Work around for bug in NativeWidgetAura. - // TODO: fix bug and remove this. - parent->Close(); } // It is possible to associate a window to a view which has a parent layer @@ -191,8 +181,7 @@ TEST_F(WindowReordererTest, Association) { // view and the parent layer of the associated window are different. Test that // the layers and windows are properly reordered in this case. TEST_F(WindowReordererTest, HostViewParentHasLayer) { - std::unique_ptr<Widget> parent( - CreateControlWidget(root_window(), gfx::Rect(0, 0, 100, 100))); + std::unique_ptr<Widget> parent = CreateControlWidget(root_window()); parent->Show(); aura::Window* parent_window = parent->GetNativeWindow(); @@ -214,11 +203,10 @@ TEST_F(WindowReordererTest, HostViewParentHasLayer) { View* v11 = new View(); v11->SetPaintToLayer(); - v11->layer()->set_name("v11"); + v11->layer()->SetName("v11"); v1->AddChildView(v11); - std::unique_ptr<Widget> w( - CreateControlWidget(parent_window, gfx::Rect(0, 1, 100, 101))); + std::unique_ptr<Widget> w = CreateControlWidget(parent_window); SetWindowAndLayerName(w->GetNativeView(), "w"); w->Show(); @@ -228,12 +216,12 @@ TEST_F(WindowReordererTest, HostViewParentHasLayer) { View* v13 = new View(); v13->SetPaintToLayer(); - v13->layer()->set_name("v13"); + v13->layer()->SetName("v13"); v1->AddChildView(v13); View* v2 = new View(); v2->SetPaintToLayer(); - v2->layer()->set_name("v2"); + v2->layer()->SetName("v2"); contents_view->AddChildView(v2); // Test intial state. @@ -243,7 +231,7 @@ TEST_F(WindowReordererTest, HostViewParentHasLayer) { // |w|'s layer should be stacked above |v1|'s layer. v1->SetPaintToLayer(); - v1->layer()->set_name("v1"); + v1->layer()->SetName("v1"); EXPECT_EQ("w", ChildWindowNamesAsString(*parent_window)); EXPECT_EQ("v1 w v2", ui::test::ChildLayerNamesAsString(*parent_window->layer())); @@ -254,16 +242,11 @@ TEST_F(WindowReordererTest, HostViewParentHasLayer) { EXPECT_EQ("w", ChildWindowNamesAsString(*parent_window)); EXPECT_EQ("v1 v2 w", ui::test::ChildLayerNamesAsString(*parent_window->layer())); - - // Work around for bug in NativeWidgetAura. - // TODO: fix bug and remove this. - parent->Close(); } // Test that a layer added beneath a view is restacked correctly. TEST_F(WindowReordererTest, ViewWithLayerBeneath) { - std::unique_ptr<Widget> parent( - CreateControlWidget(root_window(), gfx::Rect(0, 0, 100, 100))); + std::unique_ptr<Widget> parent = CreateControlWidget(root_window()); parent->Show(); aura::Window* parent_window = parent->GetNativeWindow(); @@ -277,8 +260,8 @@ TEST_F(WindowReordererTest, ViewWithLayerBeneath) { view_with_layer_beneath->AddLayerBeneathView(&layer_beneath); ASSERT_NE(nullptr, view_with_layer_beneath->layer()); - view_with_layer_beneath->layer()->set_name("view"); - layer_beneath.set_name("beneath"); + view_with_layer_beneath->layer()->SetName("view"); + layer_beneath.SetName("beneath"); // Verify that the initial ordering is correct. EXPECT_EQ("beneath view", @@ -286,8 +269,7 @@ TEST_F(WindowReordererTest, ViewWithLayerBeneath) { // Add a hosted window to make WindowReorderer::ReorderChildWindows() restack // layers. - std::unique_ptr<Widget> child_widget( - CreateControlWidget(parent_window, gfx::Rect(gfx::Rect(0, 0, 50, 50)))); + std::unique_ptr<Widget> child_widget = CreateControlWidget(parent_window); SetWindowAndLayerName(child_widget->GetNativeView(), "child_widget"); child_widget->Show(); View* host_view = contents_view->AddChildView(std::make_unique<View>()); |