diff options
author | Daniel Playfair Cal | 2020-01-12 01:15:04 +1100 |
---|---|---|
committer | Daniel Playfair Cal | 2020-01-12 01:17:55 +1100 |
commit | 849fc03d9e5cf971762a366fcda21b8fba156864 (patch) | |
tree | 44b4fb65c1d3f4d22afcc288accbaa4810ec48a0 | |
parent | b26c568927542ce7d5084c654382c51fea251f75 (diff) | |
download | aur-849fc03d9e5cf971762a366fcda21b8fba156864.tar.gz |
80.0.3987.42
19 files changed, 6877 insertions, 380 deletions
@@ -1,6 +1,6 @@ pkgbase = chromium-ozone pkgdesc = Chromium built with patches for wayland support via Ozone - pkgver = 79.0.3945.117 + pkgver = 80.0.3987.42 pkgrel = 1 url = https://www.chromium.org/Home install = chromium.install @@ -35,7 +35,6 @@ pkgbase = chromium-ozone depends = desktop-file-utils depends = hicolor-icon-theme depends = icu - depends = libxml2 depends = fontconfig depends = harfbuzz depends = libjpeg @@ -56,30 +55,42 @@ pkgbase = chromium-ozone conflicts = chromium options = debug options = !strip - source = https://commondatastorage.googleapis.com/chromium-browser-official/chromium-79.0.3945.117.tar.xz + source = https://commondatastorage.googleapis.com/chromium-browser-official/chromium-80.0.3987.42.tar.xz source = chromium-launcher-6.tar.gz::https://github.com/foutrelis/chromium-launcher/archive/v6.tar.gz - source = launch_manager.h-uses-std-vector.patch - source = include-algorithm-to-use-std-lower_bound.patch source = 0001-Add-missing-algorithm-header-in-bitmap_cursor_factor.patch - source = 0001-ozone-wayland-Complete-submission-of-a-buffer-submit.patch - source = icu65.patch + source = 0001-cros-search-service-Include-cmath-for-std-pow.patch + source = 0001-BookmarkModelMerger-Move-RemoteTreeNode-declaration-.patch + source = 0001-ozone-wayland-Extract-ShellObjectFactory-to-a-separa.patch + source = 0002-ozone-Wayland-Add-WaylandWindow-factory-method.patch + source = 0003-ozone-Wayland-move-bounds-translation-util-to-utilit.patch + source = 0004-ozone-wayland-Fix-regression-with-hiding-nested-wind.patch + source = 0005-ozone-Wayland-extract-toplevel-surface-methods-into-.patch + source = 0006-ozone-wayland-extract-popup-methods-to-WaylandPopup.patch + source = 0007-ozone-wayland-Extract-subsurface-from-WaylandWindow.patch + source = 0008-ozone-wayland-Recreate-ShellSurface-and-ShellPopup-o.patch + source = 0009-ozone-wayland-window-state-change-must-be-synchronou.patch source = chromium-system-icu.patch source = chromium-system-zlib.patch - source = chromium-system-hb.patch source = fix-spammy-unique-font-matching-log.patch source = chromium-widevine.patch source = chromium-skia-harmony.patch - sha256sums = 4d960e8bd790cc1c8e7f0632790424957c4996a8a91b9d899eb572acec854ef1 + sha256sums = 160c02ed00d45a074246c8984144a35b092102e9b9a31e2bc9c2dad49f297945 sha256sums = 04917e3cd4307d8e31bfb0027a5dce6d086edb10ff8a716024fbb8bb0c7dccf1 - sha256sums = bd0fae907c451252e91c4cbf1ad301716bc9f8a4644ecc60e9590a64197477d3 - sha256sums = 1f906676563e866e2b59719679e76e0b2f7f082f48ef0593e86da0351a586c73 sha256sums = 716c28bed9f6e9c32e3617e125c1b04806700aef691763923cd4ed14b8d23279 - sha256sums = 9e9e5c66d4555c787736c5d5d5fcef8b5e14d913b138041c9c90d1976ee46845 - sha256sums = 1de9bdbfed482295dda45c7d4e323cee55a34e42f66b892da1c1a778682b7a41 + sha256sums = 4c892f046ab10df609aa39d9985248d368c77306783a64d335ff713dabad60b0 + sha256sums = a44ed59db5258221ee187dc2501040e5ebfc5c1353ac98d4313ac6a12ae32d1f + sha256sums = 01f7a6e098e105949ec6267d7293eef4b79a4f9d20ecbf3b53f5944cf64674db + sha256sums = 2f9fc85844350e86e8b8389a2b4d84cf7a49ae582ddb66d3248b308b46ed33a2 + sha256sums = d05d9dbb9ac53614365182cb04d473e906e20cba72225122b4ae1c03e7e19395 + sha256sums = 8577707001330b4da42828708da8cf85d122127c3c84b6531e60dcbe9c04c587 + sha256sums = 3909026200bb2b7d017da5a638bfa5785586a20445e24da846fe97878204a1c5 + sha256sums = 88153c36bc639bee8959721b5140b325178fe548e3d5bd5e3b4b57129a7a9a0e + sha256sums = ca681e32a34fea040357554bdded0aed82d61c10f07a2da5f23317f45f3295cf + sha256sums = 38a951ffe9a031241179163a71391c4aabbd31432c4fb6cbc35800b632bce747 + sha256sums = 7566c0690786bd2092736f6a7e6ad4c4304515e8a65814574d16f065c8a7d8f4 sha256sums = e73cc2ee8d3ea35aab18c478d76fdfc68ca4463e1e10306fa1e738c03b3f26b5 sha256sums = eb67eda4945a89c3b90473fa8dc20637511ca4dcb58879a8ed6bf403700ca9c8 - sha256sums = c0ad3fa426cb8fc1a237ddc6309a6b2dd4055bbe41dd07f50071ee61f969b81a - sha256sums = 6fbffe59b886195b92c9a55137cef83021c16593f49714acb20023633e3ebb19 + sha256sums = 71e63e2f4db01f7beecbbdc98f78134288429825dbef3412779506e51277fb80 sha256sums = 709e2fddba3c1f2ed4deb3a239fc0479bfa50c46e054e7f32db4fb1365fed070 sha256sums = 771292942c0901092a402cc60ee883877a99fb804cb54d568c8c6c94565a48e1 diff --git a/0001-BookmarkModelMerger-Move-RemoteTreeNode-declaration-.patch b/0001-BookmarkModelMerger-Move-RemoteTreeNode-declaration-.patch new file mode 100644 index 000000000000..ba57aca99be3 --- /dev/null +++ b/0001-BookmarkModelMerger-Move-RemoteTreeNode-declaration-.patch @@ -0,0 +1,240 @@ +From cdf3e81ff49b200213d67d65558f2919222b60ab Mon Sep 17 00:00:00 2001 +From: Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com> +Date: Mon, 16 Dec 2019 11:39:11 +0000 +Subject: [PATCH] BookmarkModelMerger: Move RemoteTreeNode declaration to + header. + +This fixes the build with libstdc++ after commit 8f5dad93e58 ("Fix CHECK +failure due to untracked local nodes"): + +/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/bits/stl_pair.h:215:11: error: field has incomplete type 'sync_bookmarks::BookmarkModelMerger::RemoteTreeNode' + _T2 second; /// @c second is a copy of the second object + ^ +/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/ext/aligned_buffer.h:91:28: note: in instantiation of template class 'std::pair<const std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode>' requested here + : std::aligned_storage<sizeof(_Tp), __alignof__(_Tp)> + ^ +/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/bits/hashtable_policy.h:233:43: note: in instantiation of template class '__gnu_cxx::__aligned_buffer<std::pair<const std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode> >' requested here + __gnu_cxx::__aligned_buffer<_Value> _M_storage; + ^ +/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/bits/hashtable_policy.h:264:39: note: in instantiation of template class 'std::__detail::_Hash_node_value_base<std::pair<const std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode> >' requested here + struct _Hash_node<_Value, true> : _Hash_node_value_base<_Value> + ^ +/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/bits/hashtable_policy.h:2028:25: note: in instantiation of template class 'std::__detail::_Hash_node<std::pair<const std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode>, true>' requested here + rebind_traits<typename __node_type::value_type>; + ^ +/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/bits/hashtable.h:184:15: note: in instantiation of template class 'std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<const std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode>, true> > > +' requested here + private __detail::_Hashtable_alloc< + ^ +/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/bits/unordered_map.h:105:18: note: in instantiation of template class 'std::_Hashtable<std::__cxx11::basic_string<char>, std::pair<const std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode>, std::allocator<std::pair<con +st std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode> >, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char> >, std::hash<std::string>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__deta +il::_Hashtable_traits<true, false, true> >' requested here + _Hashtable _M_h; + ^ +../../components/sync_bookmarks/bookmark_model_merger.h:146:22: note: in instantiation of template class 'std::unordered_map<std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode, std::hash<std::string>, std::equal_to<std::__cxx11::basic_string<char> >, std::allocator<std::pair<con +st std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode> > >' requested here + const RemoteForest remote_forest_; + ^ +../../components/sync_bookmarks/bookmark_model_merger.h:53:9: note: forward declaration of 'sync_bookmarks::BookmarkModelMerger::RemoteTreeNode' + class RemoteTreeNode; + ^ + +Essentially, the problem is that libstdc++'s std::unordered_map<T, U> +implementation requires both T and U to be fully declared. I raised the +problem in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92770, and GCC's +position is that we are relying on undefined behavior according to the C++ +standard (https://eel.is/c++draft/requirements#res.on.functions-2.5). + +Bug: 957519 +Change-Id: Ife7e435e516932a795bfbe05b2c910c3272878f0 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1960156 +Commit-Queue: Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com> +Reviewed-by: Mikel Astiz <mastiz@chromium.org> +Auto-Submit: Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com> +Cr-Commit-Position: refs/heads/master@{#725070} +--- + .../sync_bookmarks/bookmark_model_merger.cc | 89 +++++++------------ + .../sync_bookmarks/bookmark_model_merger.h | 48 +++++++++- + 2 files changed, 80 insertions(+), 57 deletions(-) + +diff --git a/components/sync_bookmarks/bookmark_model_merger.cc b/components/sync_bookmarks/bookmark_model_merger.cc +index eae153eff953..579848ee664e 100644 +--- a/components/sync_bookmarks/bookmark_model_merger.cc ++++ b/components/sync_bookmarks/bookmark_model_merger.cc +@@ -5,7 +5,6 @@ + #include "components/sync_bookmarks/bookmark_model_merger.h" + + #include <algorithm> +-#include <memory> + #include <set> + #include <string> + #include <utility> +@@ -205,66 +204,44 @@ UpdatesPerParentId GroupValidUpdatesByParentId( + + } // namespace + +-class BookmarkModelMerger::RemoteTreeNode final { +- public: +- // Constructs a tree given |update| as root and recursively all descendants by +- // traversing |*updates_per_parent_id|. |update| and |updates_per_parent_id| +- // must not be null. All updates |*updates_per_parent_id| must represent valid +- // updates. Updates corresponding from descendant nodes are moved away from +- // |*updates_per_parent_id|. +- static RemoteTreeNode BuildTree( +- std::unique_ptr<syncer::UpdateResponseData> update, +- UpdatesPerParentId* updates_per_parent_id); +- +- ~RemoteTreeNode() = default; +- +- // Allow moves, useful during construction. +- RemoteTreeNode(RemoteTreeNode&&) = default; +- RemoteTreeNode& operator=(RemoteTreeNode&&) = default; +- +- const syncer::EntityData& entity() const { return *update_->entity; } +- int64_t response_version() const { return update_->response_version; } +- +- // Direct children nodes, sorted by ascending unique position. These are +- // guaranteed to be valid updates (e.g. IsValidBookmarkSpecifics()). +- const std::vector<RemoteTreeNode>& children() const { return children_; } +- +- // Recursively emplaces all GUIDs (this node and descendants) into +- // |*guid_to_remote_node_map|, which must not be null. +- void EmplaceSelfAndDescendantsByGUID( +- std::unordered_map<std::string, const RemoteTreeNode*>* +- guid_to_remote_node_map) const { +- DCHECK(guid_to_remote_node_map); +- +- const std::string& guid = entity().specifics.bookmark().guid(); +- if (!guid.empty()) { +- DCHECK(base::IsValidGUID(guid)); +- +- // Duplicate GUIDs have been sorted out before. +- bool success = guid_to_remote_node_map->emplace(guid, this).second; +- DCHECK(success); +- } ++BookmarkModelMerger::RemoteTreeNode::RemoteTreeNode() = default; + +- for (const RemoteTreeNode& child : children_) { +- child.EmplaceSelfAndDescendantsByGUID(guid_to_remote_node_map); +- } +- } ++BookmarkModelMerger::RemoteTreeNode::~RemoteTreeNode() = default; ++ ++BookmarkModelMerger::RemoteTreeNode::RemoteTreeNode( ++ BookmarkModelMerger::RemoteTreeNode&&) = default; ++BookmarkModelMerger::RemoteTreeNode& BookmarkModelMerger::RemoteTreeNode:: ++operator=(BookmarkModelMerger::RemoteTreeNode&&) = default; ++ ++void BookmarkModelMerger::RemoteTreeNode::EmplaceSelfAndDescendantsByGUID( ++ std::unordered_map<std::string, const RemoteTreeNode*>* ++ guid_to_remote_node_map) const { ++ DCHECK(guid_to_remote_node_map); ++ ++ const std::string& guid = entity().specifics.bookmark().guid(); ++ if (!guid.empty()) { ++ DCHECK(base::IsValidGUID(guid)); + +- private: +- static bool UniquePositionLessThan(const RemoteTreeNode& lhs, +- const RemoteTreeNode& rhs) { +- const syncer::UniquePosition a_pos = +- syncer::UniquePosition::FromProto(lhs.entity().unique_position); +- const syncer::UniquePosition b_pos = +- syncer::UniquePosition::FromProto(rhs.entity().unique_position); +- return a_pos.LessThan(b_pos); ++ // Duplicate GUIDs have been sorted out before. ++ bool success = guid_to_remote_node_map->emplace(guid, this).second; ++ DCHECK(success); + } + +- RemoteTreeNode() = default; ++ for (const RemoteTreeNode& child : children_) { ++ child.EmplaceSelfAndDescendantsByGUID(guid_to_remote_node_map); ++ } ++} + +- std::unique_ptr<syncer::UpdateResponseData> update_; +- std::vector<RemoteTreeNode> children_; +-}; ++// static ++bool BookmarkModelMerger::RemoteTreeNode::UniquePositionLessThan( ++ const RemoteTreeNode& lhs, ++ const RemoteTreeNode& rhs) { ++ const syncer::UniquePosition a_pos = ++ syncer::UniquePosition::FromProto(lhs.entity().unique_position); ++ const syncer::UniquePosition b_pos = ++ syncer::UniquePosition::FromProto(rhs.entity().unique_position); ++ return a_pos.LessThan(b_pos); ++} + + // static + BookmarkModelMerger::RemoteTreeNode +diff --git a/components/sync_bookmarks/bookmark_model_merger.h b/components/sync_bookmarks/bookmark_model_merger.h +index 9b592000dc59..bf0783ecf8ee 100644 +--- a/components/sync_bookmarks/bookmark_model_merger.h ++++ b/components/sync_bookmarks/bookmark_model_merger.h +@@ -5,6 +5,7 @@ + #ifndef COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_MODEL_MERGER_H_ + #define COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_MODEL_MERGER_H_ + ++#include <memory> + #include <string> + #include <unordered_map> + #include <vector> +@@ -50,7 +51,52 @@ class BookmarkModelMerger { + + private: + // Internal representation of a remote tree, composed of nodes. +- class RemoteTreeNode; ++ class RemoteTreeNode final { ++ private: ++ using UpdatesPerParentId = ++ std::unordered_map<base::StringPiece, ++ syncer::UpdateResponseDataList, ++ base::StringPieceHash>; ++ ++ public: ++ // Constructs a tree given |update| as root and recursively all descendants ++ // by traversing |*updates_per_parent_id|. |update| and ++ // |updates_per_parent_id| must not be null. All updates ++ // |*updates_per_parent_id| must represent valid updates. Updates ++ // corresponding from descendant nodes are moved away from ++ // |*updates_per_parent_id|. ++ static RemoteTreeNode BuildTree( ++ std::unique_ptr<syncer::UpdateResponseData> update, ++ UpdatesPerParentId* updates_per_parent_id); ++ ++ ~RemoteTreeNode(); ++ ++ // Allow moves, useful during construction. ++ RemoteTreeNode(RemoteTreeNode&&); ++ RemoteTreeNode& operator=(RemoteTreeNode&&); ++ ++ const syncer::EntityData& entity() const { return *update_->entity; } ++ int64_t response_version() const { return update_->response_version; } ++ ++ // Direct children nodes, sorted by ascending unique position. These are ++ // guaranteed to be valid updates (e.g. IsValidBookmarkSpecifics()). ++ const std::vector<RemoteTreeNode>& children() const { return children_; } ++ ++ // Recursively emplaces all GUIDs (this node and descendants) into ++ // |*guid_to_remote_node_map|, which must not be null. ++ void EmplaceSelfAndDescendantsByGUID( ++ std::unordered_map<std::string, const RemoteTreeNode*>* ++ guid_to_remote_node_map) const; ++ ++ private: ++ static bool UniquePositionLessThan(const RemoteTreeNode& lhs, ++ const RemoteTreeNode& rhs); ++ ++ RemoteTreeNode(); ++ ++ std::unique_ptr<syncer::UpdateResponseData> update_; ++ std::vector<RemoteTreeNode> children_; ++ }; + + // A forest composed of multiple trees where the root of each tree represents + // a permanent node, keyed by server-defined unique tag of the root. +-- +2.24.1 + diff --git a/0001-Refactor-bookmark-GUID-matching-logic.patch b/0001-Refactor-bookmark-GUID-matching-logic.patch new file mode 100644 index 000000000000..3c0a732efc6e --- /dev/null +++ b/0001-Refactor-bookmark-GUID-matching-logic.patch @@ -0,0 +1,329 @@ +From afc8770181f528d391e74af41e9be125814e3009 Mon Sep 17 00:00:00 2001 +From: Mikel Astiz <mastiz@chromium.org> +Date: Mon, 25 Nov 2019 10:53:45 +0000 +Subject: [PATCH] Refactor bookmark GUID-matching logic + +Prior to this patch, the two existing functions to build GUID-keyed maps +were heavily coupled and there were fragile underlying assumptions that +made it work (e.g. there were potentially entries in +|guid_to_remote_node_map_| that didn't actually match any local GUID). + +Instead, let's centralize the matching logic into one single function, +and adopt a unified map to represent the matches. This simplifies the +code and enforces more strict invariants without the need for DCHECKs. + +Bug: 978430 +Change-Id: Ieea0db8d43376e204b793dcc64b2dc84d521b289 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1929216 +Commit-Queue: Mikel Astiz <mastiz@chromium.org> +Reviewed-by: Mohamed Amir Yosef <mamir@chromium.org> +Cr-Commit-Position: refs/heads/master@{#718580} +--- + .../sync_bookmarks/bookmark_model_merger.cc | 133 ++++++++---------- + .../sync_bookmarks/bookmark_model_merger.h | 40 ++---- + .../bookmark_specifics_conversions.cc | 6 + + 3 files changed, 81 insertions(+), 98 deletions(-) + +diff --git a/components/sync_bookmarks/bookmark_model_merger.cc b/components/sync_bookmarks/bookmark_model_merger.cc +index 861403dbe05a..dfd19a27a592 100644 +--- a/components/sync_bookmarks/bookmark_model_merger.cc ++++ b/components/sync_bookmarks/bookmark_model_merger.cc +@@ -237,9 +237,8 @@ BookmarkModelMerger::BookmarkModelMerger( + favicon_service_(favicon_service), + bookmark_tracker_(bookmark_tracker), + remote_forest_(BuildRemoteForest(std::move(updates))), +- guid_to_remote_node_map_(BuildGUIDToRemoteNodeMap(remote_forest_)), +- guid_to_local_node_map_( +- BuildGUIDToLocalNodeMap(bookmark_model_, guid_to_remote_node_map_)) { ++ guid_to_match_map_( ++ FindGuidMatchesOrReassignLocal(remote_forest_, bookmark_model_)) { + DCHECK(bookmark_tracker_->IsEmpty()); + DCHECK(favicon_service); + } +@@ -307,63 +306,62 @@ BookmarkModelMerger::RemoteForest BookmarkModelMerger::BuildRemoteForest( + } + + // static +-std::unordered_map<std::string, const BookmarkModelMerger::RemoteTreeNode*> +-BookmarkModelMerger::BuildGUIDToRemoteNodeMap( +- const RemoteForest& remote_forest) { ++std::unordered_map<std::string, BookmarkModelMerger::GuidMatch> ++BookmarkModelMerger::FindGuidMatchesOrReassignLocal( ++ const RemoteForest& remote_forest, ++ bookmarks::BookmarkModel* bookmark_model) { ++ DCHECK(bookmark_model); ++ + // TODO(crbug.com/978430): Handle potential duplicate GUIDs within remote + // updates. +- std::unordered_map<std::string, const RemoteTreeNode*> +- guid_to_remote_node_map; ++ + if (!base::FeatureList::IsEnabled(switches::kMergeBookmarksUsingGUIDs)) { +- return guid_to_remote_node_map; ++ return {}; + } + ++ // Build a temporary lookup table for remote GUIDs. ++ std::unordered_map<std::string, const RemoteTreeNode*> ++ guid_to_remote_node_map; + for (const auto& tree_tag_and_root : remote_forest) { + tree_tag_and_root.second.EmplaceSelfAndDescendantsByGUID( + &guid_to_remote_node_map); + } + +- return guid_to_remote_node_map; +-} +- +-// static +-std::unordered_map<std::string, const bookmarks::BookmarkNode*> +-BookmarkModelMerger::BuildGUIDToLocalNodeMap( +- bookmarks::BookmarkModel* bookmark_model, +- const std::unordered_map<std::string, const RemoteTreeNode*>& +- guid_to_remote_node_map) { +- DCHECK(bookmark_model); +- +- std::unordered_map<std::string, const bookmarks::BookmarkNode*> +- guid_to_local_node_map; +- if (!base::FeatureList::IsEnabled(switches::kMergeBookmarksUsingGUIDs)) { +- return guid_to_local_node_map; +- } +- ++ // Iterate through all local bookmarks to find matches by GUID. ++ std::unordered_map<std::string, BookmarkModelMerger::GuidMatch> ++ guid_to_match_map; + ui::TreeNodeIterator<const bookmarks::BookmarkNode> iterator( + bookmark_model->root_node()); + while (iterator.has_next()) { +- const bookmarks::BookmarkNode* node = iterator.Next(); ++ const bookmarks::BookmarkNode* const node = iterator.Next(); + DCHECK(base::IsValidGUID(node->guid())); ++ + if (node->is_permanent_node()) { + continue; + } ++ + const auto remote_it = guid_to_remote_node_map.find(node->guid()); + if (remote_it == guid_to_remote_node_map.end()) { + continue; + } +- // If local node and its remote node match are conflicting in node type or +- // URL, replace local GUID with a random GUID. +- const syncer::EntityData& remote_entity = remote_it->second->entity(); ++ ++ const RemoteTreeNode* const remote_node = remote_it->second; ++ const syncer::EntityData& remote_entity = remote_node->entity(); + if (node->is_folder() != remote_entity.is_folder || + (node->is_url() && + node->url() != remote_entity.specifics.bookmark().url())) { +- node = +- ReplaceBookmarkNodeGUID(node, base::GenerateGUID(), bookmark_model); ++ // If local node and its remote node match are conflicting in node type or ++ // URL, replace local GUID with a random GUID. ++ // TODO(crbug.com/978430): Local GUIDs should also be reassigned if they ++ // match a remote originator_item_id. ++ ReplaceBookmarkNodeGUID(node, base::GenerateGUID(), bookmark_model); ++ continue; + } +- guid_to_local_node_map.emplace(node->guid(), node); ++ ++ guid_to_match_map.emplace(node->guid(), GuidMatch{node, remote_node}); + } +- return guid_to_local_node_map; ++ ++ return guid_to_match_map; + } + + void BookmarkModelMerger::MergeSubtree( +@@ -422,25 +420,27 @@ const bookmarks::BookmarkNode* BookmarkModelMerger::FindMatchingLocalNode( + const bookmarks::BookmarkNode* local_parent, + size_t local_child_start_index) const { + // Try to match child by GUID. If we can't, try to match child by semantics. +- const bookmarks::BookmarkNode* matching_local_node = ++ const bookmarks::BookmarkNode* matching_local_node_by_guid = + FindMatchingLocalNodeByGUID(remote_child); +- if (!matching_local_node) { +- // All local nodes up to |remote_index-1| have processed already. Look for a +- // matching local node starting with the local node at position +- // |local_child_start_index|. FindMatchingChildBySemanticsStartingAt() +- // returns kInvalidIndex in the case where no semantics match was found or +- // the semantics match found is GUID-matchable to a different node. +- const size_t local_index = FindMatchingChildBySemanticsStartingAt( +- /*remote_node=*/remote_child, +- /*local_parent=*/local_parent, +- /*starting_child_index=*/local_child_start_index); +- if (local_index == kInvalidIndex) { +- // If no match found, return. +- return nullptr; +- } +- matching_local_node = local_parent->children()[local_index].get(); ++ if (matching_local_node_by_guid) { ++ return matching_local_node_by_guid; ++ } ++ ++ // All local nodes up to |remote_index-1| have processed already. Look for a ++ // matching local node starting with the local node at position ++ // |local_child_start_index|. FindMatchingChildBySemanticsStartingAt() ++ // returns kInvalidIndex in the case where no semantics match was found or ++ // the semantics match found is GUID-matchable to a different node. ++ const size_t local_index = FindMatchingChildBySemanticsStartingAt( ++ /*remote_node=*/remote_child, ++ /*local_parent=*/local_parent, ++ /*starting_child_index=*/local_child_start_index); ++ if (local_index == kInvalidIndex) { ++ // If no match found, return. ++ return nullptr; + } +- return matching_local_node; ++ ++ return local_parent->children()[local_index].get(); + } + + const bookmarks::BookmarkNode* +@@ -471,8 +471,6 @@ BookmarkModelMerger::UpdateBookmarkNodeFromSpecificsIncludingGUID( + return local_node; + } + DCHECK(base::IsValidGUID(specifics.guid())); +- // We do not update the GUID maps upon node replacement as per the comment +- // in bookmark_model_merger.h. + return ReplaceBookmarkNodeGUID(local_node, specifics.guid(), bookmark_model_); + } + +@@ -574,7 +572,7 @@ void BookmarkModelMerger::ProcessLocalCreation( + if (FindMatchingRemoteNodeByGUID(node->children()[i].get())) { + continue; + } +- ProcessLocalCreation(node, i); ++ ProcessLocalCreation(/*parent=*/node, i); + } + } + +@@ -612,36 +610,25 @@ const BookmarkModelMerger::RemoteTreeNode* + BookmarkModelMerger::FindMatchingRemoteNodeByGUID( + const bookmarks::BookmarkNode* local_node) const { + DCHECK(local_node); +- // Ensure matching nodes are of the same type and have the same URL, +- // guaranteed by BuildGUIDToLocalNodeMap(). +- const auto it = guid_to_remote_node_map_.find(local_node->guid()); +- if (it == guid_to_remote_node_map_.end()) { ++ ++ const auto it = guid_to_match_map_.find(local_node->guid()); ++ if (it == guid_to_match_map_.end()) { + return nullptr; + } + +- const RemoteTreeNode* const remote_node = it->second; +- DCHECK(remote_node); +- DCHECK_EQ(local_node->is_folder(), remote_node->entity().is_folder); +- DCHECK_EQ(local_node->url(), +- remote_node->entity().specifics.bookmark().url()); +- return remote_node; ++ return it->second.remote_node; + } + + const bookmarks::BookmarkNode* BookmarkModelMerger::FindMatchingLocalNodeByGUID( + const RemoteTreeNode& remote_node) const { + const syncer::EntityData& remote_entity = remote_node.entity(); + const auto it = +- guid_to_local_node_map_.find(remote_entity.specifics.bookmark().guid()); +- if (it == guid_to_local_node_map_.end()) { ++ guid_to_match_map_.find(remote_entity.specifics.bookmark().guid()); ++ if (it == guid_to_match_map_.end()) { + return nullptr; + } +- DCHECK(!remote_entity.specifics.bookmark().guid().empty()); +- const bookmarks::BookmarkNode* local_node = it->second; +- // Ensure matching nodes are of the same type and have the same URL, +- // guaranteed by BuildGUIDToLocalNodeMap(). +- DCHECK_EQ(local_node->is_folder(), remote_entity.is_folder); +- DCHECK_EQ(local_node->url(), remote_entity.specifics.bookmark().url()); +- return local_node; ++ ++ return it->second.local_node; + } + + } // namespace sync_bookmarks +diff --git a/components/sync_bookmarks/bookmark_model_merger.h b/components/sync_bookmarks/bookmark_model_merger.h +index 1a40fad2a074..18744920a1a4 100644 +--- a/components/sync_bookmarks/bookmark_model_merger.h ++++ b/components/sync_bookmarks/bookmark_model_merger.h +@@ -56,6 +56,14 @@ class BookmarkModelMerger { + // a permanent node, keyed by server-defined unique tag of the root. + using RemoteForest = std::unordered_map<std::string, RemoteTreeNode>; + ++ // Represents a pair of bookmarks, one local and one remote, that have been ++ // matched by GUID. They are guaranteed to have the same type and URL (if ++ // applicable). ++ struct GuidMatch { ++ const bookmarks::BookmarkNode* local_node; ++ const RemoteTreeNode* remote_node; ++ }; ++ + // Constructs the remote bookmark tree to be merged. Each entry in the + // returned map is a permanent node, identified (keyed) by the server-defined + // tag. All invalid updates are filtered out, including invalid bookmark +@@ -63,22 +71,12 @@ class BookmarkModelMerger { + // sends tombstones as part of the initial download. + static RemoteForest BuildRemoteForest(syncer::UpdateResponseDataList updates); + +- // Constructs a map from GUID to corresponding remote nodes, used in the merge +- // process to determine GUID-based node matches. +- static std::unordered_map<std::string, const RemoteTreeNode*> +- BuildGUIDToRemoteNodeMap(const RemoteForest& remote_forest); +- +- // Constructs a map from GUID to corresponding local node, used in the merge +- // process to determine GUID-based node matches. |bookmark_model| must not be +- // null. |guid_to_remote_node_map| is used to detect conflicting GUID matches +- // between local and remote bookmarks for the cases where they cannot be +- // merged (e.g. folder vs non-folder) and in such cases regenerate a random +- // GUID for the local bookmark. +- static std::unordered_map<std::string, const bookmarks::BookmarkNode*> +- BuildGUIDToLocalNodeMap( +- bookmarks::BookmarkModel* bookmark_model, +- const std::unordered_map<std::string, const RemoteTreeNode*>& +- guid_to_remote_node_map); ++ // Computes bookmark pairs that should be matched by GUID. Local bookmark ++ // GUIDs may be regenerated for the case where they collide with a remote GUID ++ // that is not compatible (e.g. folder vs non-folder). ++ static std::unordered_map<std::string, GuidMatch> ++ FindGuidMatchesOrReassignLocal(const RemoteForest& remote_forest, ++ bookmarks::BookmarkModel* bookmark_model); + + // Merges a local and a remote subtrees. The input nodes are two equivalent + // local and remote nodes. This method tries to recursively match their +@@ -151,15 +149,7 @@ class BookmarkModelMerger { + // Preprocessed remote nodes in the form a forest where each tree's root is a + // permanent node. Computed upon construction via BuildRemoteForest(). + const RemoteForest remote_forest_; +- // Maps GUIDs to their respective remote nodes. Used for GUID-based node +- // matching and is populated at the beginning of the merge process. +- const std::unordered_map<std::string, const RemoteTreeNode*> +- guid_to_remote_node_map_; +- // Maps GUIDs to their respective local nodes. Used for GUID-based +- // node matching and is populated at the beginning of the merge process. +- // Is not updated upon potential changes to the model during merge. +- const std::unordered_map<std::string, const bookmarks::BookmarkNode*> +- guid_to_local_node_map_; ++ std::unordered_map<std::string, GuidMatch> guid_to_match_map_; + + DISALLOW_COPY_AND_ASSIGN(BookmarkModelMerger); + }; +diff --git a/components/sync_bookmarks/bookmark_specifics_conversions.cc b/components/sync_bookmarks/bookmark_specifics_conversions.cc +index 98725dce2a61..74914f187509 100644 +--- a/components/sync_bookmarks/bookmark_specifics_conversions.cc ++++ b/components/sync_bookmarks/bookmark_specifics_conversions.cc +@@ -255,6 +255,12 @@ const bookmarks::BookmarkNode* ReplaceBookmarkNodeGUID( + } + const bookmarks::BookmarkNode* new_node; + DCHECK(base::IsValidGUID(guid)); ++ ++ if (node->guid() == guid) { ++ // Nothing to do. ++ return node; ++ } ++ + if (node->is_folder()) { + new_node = + model->AddFolder(node->parent(), node->parent()->GetIndexOf(node), +-- +2.24.1 + diff --git a/0001-cros-search-service-Include-cmath-for-std-pow.patch b/0001-cros-search-service-Include-cmath-for-std-pow.patch new file mode 100644 index 000000000000..5c620a79edf6 --- /dev/null +++ b/0001-cros-search-service-Include-cmath-for-std-pow.patch @@ -0,0 +1,38 @@ +From 8273f4d3130e06fd8b6bef87b07c936304b971d9 Mon Sep 17 00:00:00 2001 +From: Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com> +Date: Tue, 10 Dec 2019 20:59:57 +0000 +Subject: [PATCH] [cros search service]: Include <cmath> for std::pow() + +IWYU. Follow up to commit 2b2ea3c09b ("[cros search service] Move shared +string matching functions to //chrome"), which broke the libstdc++ build: + + ../../chrome/common/string_matching/fuzzy_tokenized_string_match.cc:199:14: error: no member named 'pow' in namespace 'std' + std::pow(partial_match_penalty_rate, long_start - current - 1); + ~~~~~^ + +Bug: 957519 +Change-Id: I66f61cb4f93cfa0bfa3d1b00ba391ddd8f31a7fb +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1960310 +Auto-Submit: Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com> +Reviewed-by: Jia Meng <jiameng@chromium.org> +Commit-Queue: Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com> +Cr-Commit-Position: refs/heads/master@{#723499} +--- + chrome/common/string_matching/fuzzy_tokenized_string_match.cc | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/chrome/common/string_matching/fuzzy_tokenized_string_match.cc b/chrome/common/string_matching/fuzzy_tokenized_string_match.cc +index 8351fa701e4d..884ef638c61c 100644 +--- a/chrome/common/string_matching/fuzzy_tokenized_string_match.cc ++++ b/chrome/common/string_matching/fuzzy_tokenized_string_match.cc +@@ -5,6 +5,7 @@ + #include "chrome/common/string_matching/fuzzy_tokenized_string_match.h" + + #include <algorithm> ++#include <cmath> + #include <iterator> + + #include "base/i18n/case_conversion.h" +-- +2.24.1 + diff --git a/0001-ozone-wayland-Complete-submission-of-a-buffer-submit.patch b/0001-ozone-wayland-Complete-submission-of-a-buffer-submit.patch deleted file mode 100644 index 53da1d5d3118..000000000000 --- a/0001-ozone-wayland-Complete-submission-of-a-buffer-submit.patch +++ /dev/null @@ -1,173 +0,0 @@ -Upstream-Status: Backport - -Backported from https://crrev.com/c/1946479 - -Signed-off-by: Maksim Sisov <msisov@igalia.com> ---- -From 4c9a7209005ee6c134692932d4c6d784d48ada34 Mon Sep 17 00:00:00 2001 -From: Maksim Sisov <msisov@igalia.com> -Date: Tue, 3 Dec 2019 08:23:42 +0000 -Subject: [PATCH] ozone/wayland: Complete submission of a buffer submitted more - than once - -This CL fixes a corner use case that was caught by one of the users -of Ozone/Wayland. - -The problem appeared when the Chromium compositor sent a next frame into -the same buffer that had just been submitted and a OnSubmission callback -had been sent to the viz process located WaylandBufferManager. This -happened only when the remote inspector was attached and the screencast -was enabled. - -In this case, Wayland compositor will not send an OnRelease callback -and we should not wait for that. Instead, we must complete the -submission immediately and set the |WaylandBuffer::released| -member to be false. Once another buffer is committed, Wayland compositor -will release the previous buffer. - -Bug: 1029777 -Change-Id: Ib74c16f41f128298998bc9699f8d9ded3697cd43 -Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1946479 -Commit-Queue: Maksim Sisov <msisov@igalia.com> -Reviewed-by: Robert Kroeger <rjkroege@chromium.org> -Cr-Commit-Position: refs/heads/master@{#720878} ---- - .../host/wayland_buffer_manager_host.cc | 22 ++++-- - .../wayland_buffer_manager_unittest.cc | 78 +++++++++++++++++++ - 2 files changed, 95 insertions(+), 5 deletions(-) - -diff --git a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc -index f360f916cae7..c7fc7094475a 100644 ---- a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc -+++ b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc -@@ -231,13 +231,20 @@ class WaylandBufferManagerHost::Surface { - DCHECK(buffer); - DCHECK(!pending_buffer_); - -- // Once the BufferRelease is called, the buffer will be released. -- DCHECK(buffer->released); -- buffer->released = false; -- - DCHECK(!submitted_buffer_); - submitted_buffer_ = buffer; - -+ // if the same buffer has been submitted again right after the client -+ // received OnSubmission for that buffer, just verify that the buffer has -+ // not been released by Wayland compositor, which is correct. -+ if (prev_submitted_buffer_ != submitted_buffer_) { -+ // Once the BufferRelease is called, the buffer will be released. -+ DCHECK(buffer->released); -+ buffer->released = false; -+ } else { -+ DCHECK(!buffer->released); -+ } -+ - AttachAndDamageBuffer(buffer); - - SetupFrameCallback(); -@@ -258,7 +265,12 @@ class WaylandBufferManagerHost::Surface { - // If it was the very first frame, the surface has not had a back buffer - // before, and Wayland won't release the front buffer until next buffer is - // attached. Thus, notify about successful submission immediately. -- if (!prev_submitted_buffer_) -+ // -+ // As said above, if the client submits the same buffer again, we must -+ // notify the client about the submission immediately as Wayland compositor -+ // is not going to send a release callback for a buffer committed more than -+ // once. -+ if (!prev_submitted_buffer_ || prev_submitted_buffer_ == submitted_buffer_) - CompleteSubmission(); - - return true; -diff --git a/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc b/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc -index 3908e2af629c..012e40f5a75a 100644 ---- a/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc -+++ b/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc -@@ -477,6 +477,84 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) { - Sync(); - } - -+// This test verifies that submitting the buffer more than once results in -+// OnSubmission callback as Wayland compositor is not supposed to release the -+// buffer committed twice. -+TEST_P(WaylandBufferManagerTest, SubmitSameBufferMultipleTimes) { -+ constexpr uint32_t kBufferId1 = 1; -+ constexpr uint32_t kBufferId2 = 2; -+ -+ const gfx::AcceleratedWidget widget = window_->GetWidget(); -+ const gfx::Rect bounds = window_->GetBounds(); -+ -+ MockSurfaceGpu mock_surface_gpu(buffer_manager_gpu_.get(), widget); -+ -+ auto* linux_dmabuf = server_.zwp_linux_dmabuf_v1(); -+ EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(2); -+ CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId1); -+ CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId2); -+ -+ Sync(); -+ -+ ProcessCreatedBufferResourcesWithExpectation(2u /* expected size */, -+ false /* fail */); -+ -+ // All the other expectations must come in order. -+ ::testing::InSequence sequence; -+ EXPECT_CALL(mock_surface_gpu, -+ OnSubmission(kBufferId1, gfx::SwapResult::SWAP_ACK)) -+ .Times(1); -+ ASSERT_TRUE(!connection_->presentation()); -+ EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1); -+ -+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds); -+ -+ Sync(); -+ -+ testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); -+ -+ auto* mock_surface = server_.GetObject<wl::MockSurface>(widget); -+ mock_surface->SendFrameCallback(); -+ -+ Sync(); -+ -+ // Commit second buffer now. -+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds); -+ -+ Sync(); -+ -+ EXPECT_CALL(mock_surface_gpu, -+ OnSubmission(kBufferId2, gfx::SwapResult::SWAP_ACK)) -+ .Times(1); -+ EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId2, _)).Times(1); -+ -+ mock_surface->ReleasePrevAttachedBuffer(); -+ mock_surface->SendFrameCallback(); -+ -+ Sync(); -+ -+ testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); -+ -+ // Now, commit the buffer with the |kBufferId2| again and make sure the -+ // manager manually sends the submission callback as long as the compositor is -+ // not going to release a buffer as it was the same buffer submitted more than -+ // once. -+ EXPECT_CALL(mock_surface_gpu, -+ OnSubmission(kBufferId2, gfx::SwapResult::SWAP_ACK)) -+ .Times(1); -+ EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId2, _)).Times(1); -+ -+ // Commit second buffer now. -+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds); -+ -+ Sync(); -+ -+ testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); -+ -+ DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/); -+ DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, false /*fail*/); -+} -+ - INSTANTIATE_TEST_SUITE_P(XdgVersionV5Test, - WaylandBufferManagerTest, - ::testing::Values(kXdgShellV5)); --- -2.20.1 - diff --git a/0001-ozone-wayland-Extract-ShellObjectFactory-to-a-separa.patch b/0001-ozone-wayland-Extract-ShellObjectFactory-to-a-separa.patch new file mode 100644 index 000000000000..ff7a44ce17c5 --- /dev/null +++ b/0001-ozone-wayland-Extract-ShellObjectFactory-to-a-separa.patch @@ -0,0 +1,788 @@ +From 40bbda2b7265437d6dea1ce9d3361f85147fedf1 Mon Sep 17 00:00:00 2001 +From: Maksim Sisov <msisov@igalia.com> +Date: Fri, 6 Dec 2019 19:35:16 +0000 +Subject: [PATCH 1/9] ozone/wayland: Extract ShellObjectFactory to a separate + file. + +This CL +1) extracts ShellObjectFactory into a separate file and keeps +the same creation and initialization logic of wrappers of shell objects, +2) extends ShellPopupWrapper and ShellSurfaceWrapper interfaces by adding +Initialize method so that it is more convenient to initialize +XdgPopupWrapperImpl XdgSurfaceWrapperImpl and let them handle initialization +based on the available xdg-shell version, +3) makes WaylandWindow use the extracted ShellObjectFactory, +4) makes InitializeStable and InitializeV6 methods of +XDGWrapper objects be private members. The decision on which +one to call is made in the main Initialize method now. +5) reconsiders the logging whether we need to keep pointers to +some objects or not. + +Bug: 1028919 +Change-Id: I87fd5fc0d0b35222f26c460c9174da6053dc320e +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1953708 +Reviewed-by: Michael Spang <spang@chromium.org> +Commit-Queue: Maksim Sisov <msisov@igalia.com> +Cr-Commit-Position: refs/heads/master@{#722572} +--- + ui/ozone/platform/wayland/BUILD.gn | 2 + + .../wayland/host/shell_object_factory.cc | 47 +++++ + .../wayland/host/shell_object_factory.h | 44 +++++ + .../wayland/host/shell_popup_wrapper.h | 6 + + .../wayland/host/shell_surface_wrapper.h | 4 + + .../platform/wayland/host/wayland_window.cc | 72 +------ + .../platform/wayland/host/wayland_window.h | 7 - + .../wayland/host/xdg_popup_wrapper_impl.cc | 48 ++--- + .../wayland/host/xdg_popup_wrapper_impl.h | 19 +- + .../wayland/host/xdg_surface_wrapper_impl.cc | 181 ++++++++++-------- + .../wayland/host/xdg_surface_wrapper_impl.h | 27 +-- + 11 files changed, 261 insertions(+), 196 deletions(-) + create mode 100644 ui/ozone/platform/wayland/host/shell_object_factory.cc + create mode 100644 ui/ozone/platform/wayland/host/shell_object_factory.h + +diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn +index 37e7ffb5d83c..9c2cbc52500b 100644 +--- a/ui/ozone/platform/wayland/BUILD.gn ++++ b/ui/ozone/platform/wayland/BUILD.gn +@@ -45,6 +45,8 @@ source_set("wayland") { + "host/internal/wayland_data_offer_base.h", + "host/internal/wayland_data_source_base.cc", + "host/internal/wayland_data_source_base.h", ++ "host/shell_object_factory.cc", ++ "host/shell_object_factory.h", + "host/shell_popup_wrapper.cc", + "host/shell_popup_wrapper.h", + "host/shell_surface_wrapper.cc", +diff --git a/ui/ozone/platform/wayland/host/shell_object_factory.cc b/ui/ozone/platform/wayland/host/shell_object_factory.cc +new file mode 100644 +index 000000000000..57383be20da5 +--- /dev/null ++++ b/ui/ozone/platform/wayland/host/shell_object_factory.cc +@@ -0,0 +1,47 @@ ++// Copyright 2019 The Chromium Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#include "ui/ozone/platform/wayland/host/shell_object_factory.h" ++ ++#include "ui/ozone/platform/wayland/host/wayland_connection.h" ++#include "ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h" ++#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h" ++ ++namespace ui { ++ ++ShellObjectFactory::ShellObjectFactory() = default; ++ShellObjectFactory::~ShellObjectFactory() = default; ++ ++std::unique_ptr<ShellSurfaceWrapper> ++ShellObjectFactory::CreateShellSurfaceWrapper(WaylandConnection* connection, ++ WaylandWindow* wayland_window) { ++ if (connection->shell() || connection->shell_v6()) { ++ auto surface = ++ std::make_unique<XDGSurfaceWrapperImpl>(wayland_window, connection); ++ return surface->Initialize(true /* with_top_level */) ? std::move(surface) ++ : nullptr; ++ } ++ LOG(WARNING) << "Shell protocol is not available."; ++ return nullptr; ++} ++ ++std::unique_ptr<ShellPopupWrapper> ShellObjectFactory::CreateShellPopupWrapper( ++ WaylandConnection* connection, ++ WaylandWindow* wayland_window, ++ const gfx::Rect& bounds) { ++ if (connection->shell() || connection->shell_v6()) { ++ auto surface = ++ std::make_unique<XDGSurfaceWrapperImpl>(wayland_window, connection); ++ if (!surface->Initialize(false /* with_top_level */)) ++ return nullptr; ++ ++ auto popup = std::make_unique<XDGPopupWrapperImpl>(std::move(surface), ++ wayland_window); ++ return popup->Initialize(connection, bounds) ? std::move(popup) : nullptr; ++ } ++ LOG(WARNING) << "Shell protocol is not available."; ++ return nullptr; ++} ++ ++} // namespace ui +\ No newline at end of file +diff --git a/ui/ozone/platform/wayland/host/shell_object_factory.h b/ui/ozone/platform/wayland/host/shell_object_factory.h +new file mode 100644 +index 000000000000..a915326c23fb +--- /dev/null ++++ b/ui/ozone/platform/wayland/host/shell_object_factory.h +@@ -0,0 +1,44 @@ ++// Copyright 2019 The Chromium Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_OBJECT_FACTORY_H_ ++#define UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_OBJECT_FACTORY_H_ ++ ++#include <memory> ++ ++namespace gfx { ++class Rect; ++} ++ ++namespace ui { ++ ++class ShellSurfaceWrapper; ++class ShellPopupWrapper; ++class WaylandConnection; ++class WaylandWindow; ++ ++// Shell factory that creates shell objects for different protocols. Preferred ++// protocols are defined in the following order: ++// 1) xdg-shell-stable-protocol. ++// 2) xdg-shell-v6-unstable-protocol. ++class ShellObjectFactory { ++ public: ++ ShellObjectFactory(); ++ ~ShellObjectFactory(); ++ ++ // Creates and initializes a ShellSurfaceWrapper. ++ std::unique_ptr<ShellSurfaceWrapper> CreateShellSurfaceWrapper( ++ WaylandConnection* connection, ++ WaylandWindow* wayland_window); ++ ++ // Creates and intitializes a ShellPopupSurface. ++ std::unique_ptr<ShellPopupWrapper> CreateShellPopupWrapper( ++ WaylandConnection* connection, ++ WaylandWindow* wayland_window, ++ const gfx::Rect& bounds); ++}; ++ ++} // namespace ui ++ ++#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_OBJECT_FACTORY_H_ +\ No newline at end of file +diff --git a/ui/ozone/platform/wayland/host/shell_popup_wrapper.h b/ui/ozone/platform/wayland/host/shell_popup_wrapper.h +index 952c0a2a278a..2970549dd09b 100644 +--- a/ui/ozone/platform/wayland/host/shell_popup_wrapper.h ++++ b/ui/ozone/platform/wayland/host/shell_popup_wrapper.h +@@ -10,6 +10,8 @@ + + namespace ui { + ++class WaylandConnection; ++ + enum class MenuType { + TYPE_RIGHT_CLICK, + TYPE_3DOT_PARENT_MENU, +@@ -67,6 +69,10 @@ inline WlConstraintAdjustment operator&(WlConstraintAdjustment a, + class ShellPopupWrapper { + public: + virtual ~ShellPopupWrapper() {} ++ ++ // Initializes the popup surface. ++ virtual bool Initialize(WaylandConnection* connection, ++ const gfx::Rect& bounds) = 0; + }; + + gfx::Rect GetAnchorRect(MenuType menu_type, +diff --git a/ui/ozone/platform/wayland/host/shell_surface_wrapper.h b/ui/ozone/platform/wayland/host/shell_surface_wrapper.h +index 49b27e4c7214..c75e87a627b4 100644 +--- a/ui/ozone/platform/wayland/host/shell_surface_wrapper.h ++++ b/ui/ozone/platform/wayland/host/shell_surface_wrapper.h +@@ -21,6 +21,10 @@ class ShellSurfaceWrapper { + public: + virtual ~ShellSurfaceWrapper() {} + ++ // Initializes the ShellSurface. Some protocols may require to create shell ++ // surface without toplevel role and assign a popup role to it later. ++ virtual bool Initialize(bool with_toplevel) = 0; ++ + // Sets a native window to maximized state. + virtual void SetMaximized() = 0; + +diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc +index 4787a1f3b396..95c6e5a46b3e 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window.cc ++++ b/ui/ozone/platform/wayland/host/wayland_window.cc +@@ -16,6 +16,7 @@ + #include "ui/events/event_utils.h" + #include "ui/events/ozone/events_ozone.h" + #include "ui/gfx/geometry/point_f.h" ++#include "ui/ozone/platform/wayland/host/shell_object_factory.h" + #include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h" + #include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h" + #include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h" +@@ -23,50 +24,12 @@ + #include "ui/ozone/platform/wayland/host/wayland_cursor_position.h" + #include "ui/ozone/platform/wayland/host/wayland_output_manager.h" + #include "ui/ozone/platform/wayland/host/wayland_pointer.h" +-#include "ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h" +-#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h" + #include "ui/platform_window/platform_window_handler/wm_drop_handler.h" + + namespace ui { + + namespace { + +-// Factory, which decides which version type of xdg object to build. +-class XDGShellObjectFactory { +- public: +- XDGShellObjectFactory() = default; +- ~XDGShellObjectFactory() = default; +- +- std::unique_ptr<ShellPopupWrapper> CreateXDGPopup( +- WaylandConnection* connection, +- WaylandWindow* wayland_window, +- const gfx::Rect& bounds) { +- std::unique_ptr<XDGSurfaceWrapperImpl> surface = +- std::make_unique<XDGSurfaceWrapperImpl>(wayland_window); +- if (connection->shell()) { +- surface->InitializeStable(connection, wayland_window->surface(), false); +- std::unique_ptr<XDGPopupWrapperImpl> popup = +- std::make_unique<XDGPopupWrapperImpl>(std::move(surface), +- wayland_window); +- popup->InitializeStable(connection, wayland_window->surface(), +- wayland_window->parent_window(), bounds); +- return popup; +- } +- DCHECK(connection->shell_v6()); +- +- surface->InitializeV6(connection, wayland_window->surface(), false); +- std::unique_ptr<XDGPopupWrapperImpl> popup = +- std::make_unique<XDGPopupWrapperImpl>(std::move(surface), +- wayland_window); +- popup->InitializeV6(connection, wayland_window->surface(), +- wayland_window->parent_window(), bounds); +- return popup; +- } +- +- private: +- DISALLOW_COPY_AND_ASSIGN(XDGShellObjectFactory); +-}; +- + // Translates bounds relative to top level window to specified parent. + gfx::Rect TranslateBoundsToParentCoordinates(const gfx::Rect& child_bounds, + const gfx::Rect& parent_bounds) { +@@ -89,7 +52,6 @@ WaylandWindow::WaylandWindow(PlatformWindowDelegate* delegate, + WaylandConnection* connection) + : delegate_(delegate), + connection_(connection), +- xdg_shell_objects_factory_(new XDGShellObjectFactory()), + state_(PlatformWindowState::kNormal), + pending_state_(PlatformWindowState::kUnknown) { + // Set a class property key, which allows |this| to be used for interactive +@@ -124,8 +86,6 @@ WaylandWindow* WaylandWindow::FromSurface(wl_surface* surface) { + } + + bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) { +- DCHECK(xdg_shell_objects_factory_); +- + // Properties contain DIP bounds but the buffer scale is initially 1 so it's + // OK to assign. The bounds will be recalculated when the buffer scale + // changes. +@@ -244,35 +204,19 @@ void WaylandWindow::CreateShellPopup() { + + auto bounds_px = AdjustPopupWindowPosition(); + +- shell_popup_ = +- xdg_shell_objects_factory_->CreateXDGPopup(connection_, this, bounds_px); +- +- if (!shell_popup_) { ++ ShellObjectFactory factory; ++ shell_popup_ = factory.CreateShellPopupWrapper(connection_, this, bounds_px); ++ if (!shell_popup_) + CHECK(false) << "Failed to create Wayland shell popup"; +- } + + parent_window_->set_child_window(this); + } + + void WaylandWindow::CreateShellSurface() { +- std::unique_ptr<XDGSurfaceWrapperImpl> xdg_surface = +- std::make_unique<XDGSurfaceWrapperImpl>(this); +- if (!xdg_surface) { +- CHECK(false) << "Failed to create Wayland shell surface"; +- return; +- } +- +- if (connection_->shell()) { +- if (!xdg_surface->InitializeStable(connection_, surface_.get())) { +- CHECK(false) << "Failed to initialize Wayland shell surface"; +- } +- } else { +- DCHECK(connection_->shell_v6()); +- if (!xdg_surface->InitializeV6(connection_, surface_.get())) { +- CHECK(false) << "Failed to initialize Wayland shell surface"; +- } +- } +- shell_surface_ = std::move(xdg_surface); ++ ShellObjectFactory factory; ++ shell_surface_ = factory.CreateShellSurfaceWrapper(connection_, this); ++ if (!shell_surface_) ++ CHECK(false) << "Failed to initialize Wayland shell surface"; + } + + void WaylandWindow::CreateAndShowTooltipSubSurface() { +diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h +index 2745dde85c32..4233216d7a6f 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window.h ++++ b/ui/ozone/platform/wayland/host/wayland_window.h +@@ -35,10 +35,6 @@ class WaylandConnection; + class ShellPopupWrapper; + class ShellSurfaceWrapper; + +-namespace { +-class XDGShellObjectFactory; +-} // namespace +- + class WaylandWindow : public PlatformWindow, + public PlatformEventDispatcher, + public WmMoveResizeHandler, +@@ -229,9 +225,6 @@ class WaylandWindow : public PlatformWindow, + WaylandWindow* parent_window_ = nullptr; + WaylandWindow* child_window_ = nullptr; + +- // Creates xdg objects based on xdg shell version. +- std::unique_ptr<XDGShellObjectFactory> xdg_shell_objects_factory_; +- + wl::Object<wl_surface> surface_; + wl::Object<wl_subsurface> tooltip_subsurface_; + +diff --git a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc +index 0c6683828e74..abf6e7fa6461 100644 +--- a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc ++++ b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc +@@ -260,40 +260,45 @@ XDGPopupWrapperImpl::XDGPopupWrapperImpl( + WaylandWindow* wayland_window) + : wayland_window_(wayland_window), xdg_surface_(std::move(surface)) { + DCHECK(xdg_surface_); ++ DCHECK(wayland_window_ && wayland_window_->parent_window()); + } + +-XDGPopupWrapperImpl::~XDGPopupWrapperImpl() {} ++XDGPopupWrapperImpl::~XDGPopupWrapperImpl() = default; ++ ++bool XDGPopupWrapperImpl::Initialize(WaylandConnection* connection, ++ const gfx::Rect& bounds) { ++ if (connection->shell()) ++ return InitializeStable(connection, bounds); ++ else if (connection->shell_v6()) ++ return InitializeV6(connection, bounds); ++ NOTREACHED() << "Wrong shell protocol"; ++ return false; ++} + + bool XDGPopupWrapperImpl::InitializeStable(WaylandConnection* connection, +- wl_surface* surface, +- WaylandWindow* parent_window, + const gfx::Rect& bounds) { +- DCHECK(connection && surface && parent_window); + static const struct xdg_popup_listener xdg_popup_listener = { + &XDGPopupWrapperImpl::ConfigureStable, + &XDGPopupWrapperImpl::PopupDoneStable, + }; + +- if (!xdg_surface_) +- return false; +- + XDGSurfaceWrapperImpl* parent_xdg_surface; + // If the parent window is a popup, the surface of that popup must be used as + // a parent. +- if (parent_window->shell_popup()) { +- XDGPopupWrapperImpl* popup = +- reinterpret_cast<XDGPopupWrapperImpl*>(parent_window->shell_popup()); ++ if (wayland_window_->parent_window()->shell_popup()) { ++ XDGPopupWrapperImpl* popup = reinterpret_cast<XDGPopupWrapperImpl*>( ++ wayland_window_->parent_window()->shell_popup()); + parent_xdg_surface = popup->xdg_surface(); + } else { + parent_xdg_surface = reinterpret_cast<XDGSurfaceWrapperImpl*>( +- parent_window->shell_surface()); ++ wayland_window_->parent_window()->shell_surface()); + } + + if (!parent_xdg_surface) + return false; + +- struct xdg_positioner* positioner = +- CreatePositionerStable(connection, parent_window, bounds); ++ struct xdg_positioner* positioner = CreatePositionerStable( ++ connection, wayland_window_->parent_window(), bounds); + if (!positioner) + return false; + +@@ -337,7 +342,7 @@ bool XDGPopupWrapperImpl::InitializeStable(WaylandConnection* connection, + } + xdg_popup_add_listener(xdg_popup_.get(), &xdg_popup_listener, this); + +- wl_surface_commit(surface); ++ wl_surface_commit(wayland_window_->surface()); + return true; + } + +@@ -383,10 +388,7 @@ struct xdg_positioner* XDGPopupWrapperImpl::CreatePositionerStable( + } + + bool XDGPopupWrapperImpl::InitializeV6(WaylandConnection* connection, +- wl_surface* surface, +- WaylandWindow* parent_window, + const gfx::Rect& bounds) { +- DCHECK(connection && surface && parent_window); + static const struct zxdg_popup_v6_listener zxdg_popup_v6_listener = { + &XDGPopupWrapperImpl::ConfigureV6, + &XDGPopupWrapperImpl::PopupDoneV6, +@@ -398,20 +400,20 @@ bool XDGPopupWrapperImpl::InitializeV6(WaylandConnection* connection, + XDGSurfaceWrapperImpl* parent_xdg_surface; + // If the parent window is a popup, the surface of that popup must be used as + // a parent. +- if (parent_window->shell_popup()) { +- XDGPopupWrapperImpl* popup = +- reinterpret_cast<XDGPopupWrapperImpl*>(parent_window->shell_popup()); ++ if (wayland_window_->parent_window()->shell_popup()) { ++ XDGPopupWrapperImpl* popup = reinterpret_cast<XDGPopupWrapperImpl*>( ++ wayland_window_->parent_window()->shell_popup()); + parent_xdg_surface = popup->xdg_surface(); + } else { + parent_xdg_surface = reinterpret_cast<XDGSurfaceWrapperImpl*>( +- parent_window->shell_surface()); ++ wayland_window_->parent_window()->shell_surface()); + } + + if (!parent_xdg_surface) + return false; + + zxdg_positioner_v6* positioner = +- CreatePositionerV6(connection, parent_window, bounds); ++ CreatePositionerV6(connection, wayland_window_->parent_window(), bounds); + if (!positioner) + return false; + +@@ -457,7 +459,7 @@ bool XDGPopupWrapperImpl::InitializeV6(WaylandConnection* connection, + zxdg_popup_v6_add_listener(zxdg_popup_v6_.get(), &zxdg_popup_v6_listener, + this); + +- wl_surface_commit(surface); ++ wl_surface_commit(wayland_window_->surface()); + return true; + } + +diff --git a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h +index 371f18157d73..2a900818ff6a 100644 +--- a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h ++++ b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h +@@ -23,19 +23,16 @@ class XDGPopupWrapperImpl : public ShellPopupWrapper { + ~XDGPopupWrapperImpl() override; + + // XDGPopupWrapper: +- bool InitializeStable(WaylandConnection* connection, +- wl_surface* surface, +- WaylandWindow* parent_window, +- const gfx::Rect& bounds); +- bool InitializeV6(WaylandConnection* connection, +- wl_surface* surface, +- WaylandWindow* parent_window, +- const gfx::Rect& bounds); ++ bool Initialize(WaylandConnection* connection, ++ const gfx::Rect& bounds) override; + + private: ++ bool InitializeStable(WaylandConnection* connection, const gfx::Rect& bounds); + struct xdg_positioner* CreatePositionerStable(WaylandConnection* connection, + WaylandWindow* parent_window, + const gfx::Rect& bounds); ++ ++ bool InitializeV6(WaylandConnection* connection, const gfx::Rect& bounds); + struct zxdg_positioner_v6* CreatePositionerV6(WaylandConnection* connection, + WaylandWindow* parent_window, + const gfx::Rect& bounds); +@@ -64,9 +61,15 @@ class XDGPopupWrapperImpl : public ShellPopupWrapper { + + XDGSurfaceWrapperImpl* xdg_surface(); + ++ // Non-owned WaylandWindow that uses this popup. + WaylandWindow* const wayland_window_; ++ ++ // Ground surface for this popup. + std::unique_ptr<XDGSurfaceWrapperImpl> xdg_surface_; ++ ++ // XDG Shell Stable object. + wl::Object<xdg_popup> xdg_popup_; ++ // XDG Shell V6 object. + wl::Object<zxdg_popup_v6> zxdg_popup_v6_; + + DISALLOW_COPY_AND_ASSIGN(XDGPopupWrapperImpl); +diff --git a/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc +index d4078e1bc139..e7df772ae472 100644 +--- a/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc ++++ b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc +@@ -15,84 +15,19 @@ + + namespace ui { + +-XDGSurfaceWrapperImpl::XDGSurfaceWrapperImpl(WaylandWindow* wayland_window) +- : wayland_window_(wayland_window) {} ++XDGSurfaceWrapperImpl::XDGSurfaceWrapperImpl(WaylandWindow* wayland_window, ++ WaylandConnection* connection) ++ : wayland_window_(wayland_window), connection_(connection) {} + + XDGSurfaceWrapperImpl::~XDGSurfaceWrapperImpl() {} + +-bool XDGSurfaceWrapperImpl::InitializeStable(WaylandConnection* connection, +- wl_surface* surface, +- bool with_toplevel) { +- static const xdg_surface_listener xdg_surface_listener = { +- &XDGSurfaceWrapperImpl::ConfigureStable, +- }; +- static const xdg_toplevel_listener xdg_toplevel_listener = { +- &XDGSurfaceWrapperImpl::ConfigureTopLevelStable, +- &XDGSurfaceWrapperImpl::CloseTopLevelStable, +- }; +- +- // if this surface is created for the popup role, mark that it requires +- // configuration acknowledgement on each configure event. +- surface_for_popup_ = !with_toplevel; +- +- xdg_surface_.reset(xdg_wm_base_get_xdg_surface(connection->shell(), surface)); +- if (!xdg_surface_) { +- LOG(ERROR) << "Failed to create xdg_surface"; +- return false; +- } +- xdg_surface_add_listener(xdg_surface_.get(), &xdg_surface_listener, this); +- // XDGPopup requires a separate surface to be created, so this is just a +- // request to get an xdg_surface for it. +- if (surface_for_popup_) +- return true; +- +- xdg_toplevel_.reset(xdg_surface_get_toplevel(xdg_surface_.get())); +- if (!xdg_toplevel_) { +- LOG(ERROR) << "Failed to create xdg_toplevel"; +- return false; +- } +- xdg_toplevel_add_listener(xdg_toplevel_.get(), &xdg_toplevel_listener, this); +- wl_surface_commit(surface); +- return true; +-} +- +-bool XDGSurfaceWrapperImpl::InitializeV6(WaylandConnection* connection, +- wl_surface* surface, +- bool with_toplevel) { +- static const zxdg_surface_v6_listener zxdg_surface_v6_listener = { +- &XDGSurfaceWrapperImpl::ConfigureV6, +- }; +- static const zxdg_toplevel_v6_listener zxdg_toplevel_v6_listener = { +- &XDGSurfaceWrapperImpl::ConfigureTopLevelV6, +- &XDGSurfaceWrapperImpl::CloseTopLevelV6, +- }; +- +- // if this surface is created for the popup role, mark that it requires +- // configuration acknowledgement on each configure event. +- surface_for_popup_ = !with_toplevel; +- +- zxdg_surface_v6_.reset( +- zxdg_shell_v6_get_xdg_surface(connection->shell_v6(), surface)); +- if (!zxdg_surface_v6_) { +- LOG(ERROR) << "Failed to create zxdg_surface"; +- return false; +- } +- zxdg_surface_v6_add_listener(zxdg_surface_v6_.get(), +- &zxdg_surface_v6_listener, this); +- // XDGPopupV6 requires a separate surface to be created, so this is just a +- // request to get an xdg_surface for it. +- if (surface_for_popup_) +- return true; +- +- zxdg_toplevel_v6_.reset(zxdg_surface_v6_get_toplevel(zxdg_surface_v6_.get())); +- if (!zxdg_toplevel_v6_) { +- LOG(ERROR) << "Failed to create zxdg_toplevel"; +- return false; +- } +- zxdg_toplevel_v6_add_listener(zxdg_toplevel_v6_.get(), +- &zxdg_toplevel_v6_listener, this); +- wl_surface_commit(surface); +- return true; ++bool XDGSurfaceWrapperImpl::Initialize(bool with_toplevel) { ++ if (connection_->shell()) ++ return InitializeStable(with_toplevel); ++ else if (connection_->shell_v6()) ++ return InitializeV6(with_toplevel); ++ NOTREACHED() << "Wrong shell protocol"; ++ return false; + } + + void XDGSurfaceWrapperImpl::SetMaximized() { +@@ -142,25 +77,25 @@ void XDGSurfaceWrapperImpl::SetMinimized() { + + void XDGSurfaceWrapperImpl::SurfaceMove(WaylandConnection* connection) { + if (xdg_toplevel_) { +- xdg_toplevel_move(xdg_toplevel_.get(), connection->seat(), +- connection->serial()); ++ xdg_toplevel_move(xdg_toplevel_.get(), connection_->seat(), ++ connection_->serial()); + } else { + DCHECK(zxdg_toplevel_v6_); +- zxdg_toplevel_v6_move(zxdg_toplevel_v6_.get(), connection->seat(), +- connection->serial()); ++ zxdg_toplevel_v6_move(zxdg_toplevel_v6_.get(), connection_->seat(), ++ connection_->serial()); + } + } + + void XDGSurfaceWrapperImpl::SurfaceResize(WaylandConnection* connection, + uint32_t hittest) { + if (xdg_toplevel_) { +- xdg_toplevel_resize(xdg_toplevel_.get(), connection->seat(), +- connection->serial(), ++ xdg_toplevel_resize(xdg_toplevel_.get(), connection_->seat(), ++ connection_->serial(), + wl::IdentifyDirection(*connection, hittest)); + } else { + DCHECK(zxdg_toplevel_v6_); +- zxdg_toplevel_v6_resize(zxdg_toplevel_v6_.get(), connection->seat(), +- connection->serial(), ++ zxdg_toplevel_v6_resize(zxdg_toplevel_v6_.get(), connection_->seat(), ++ connection_->serial(), + wl::IdentifyDirection(*connection, hittest)); + } + } +@@ -317,4 +252,84 @@ xdg_surface* XDGSurfaceWrapperImpl::xdg_surface() const { + return xdg_surface_.get(); + } + ++bool XDGSurfaceWrapperImpl::InitializeStable(bool with_toplevel) { ++ static const xdg_surface_listener xdg_surface_listener = { ++ &XDGSurfaceWrapperImpl::ConfigureStable, ++ }; ++ static const xdg_toplevel_listener xdg_toplevel_listener = { ++ &XDGSurfaceWrapperImpl::ConfigureTopLevelStable, ++ &XDGSurfaceWrapperImpl::CloseTopLevelStable, ++ }; ++ ++ // if this surface is created for the popup role, mark that it requires ++ // configuration acknowledgement on each configure event. ++ surface_for_popup_ = !with_toplevel; ++ ++ xdg_surface_.reset(xdg_wm_base_get_xdg_surface(connection_->shell(), ++ wayland_window_->surface())); ++ if (!xdg_surface_) { ++ LOG(ERROR) << "Failed to create xdg_surface"; ++ return false; ++ } ++ xdg_surface_add_listener(xdg_surface_.get(), &xdg_surface_listener, this); ++ // XDGPopup requires a separate surface to be created, so this is just a ++ // request to get an xdg_surface for it. ++ if (surface_for_popup_) { ++ connection_->ScheduleFlush(); ++ return true; ++ } ++ ++ xdg_toplevel_.reset(xdg_surface_get_toplevel(xdg_surface_.get())); ++ if (!xdg_toplevel_) { ++ LOG(ERROR) << "Failed to create xdg_toplevel"; ++ return false; ++ } ++ xdg_toplevel_add_listener(xdg_toplevel_.get(), &xdg_toplevel_listener, this); ++ wl_surface_commit(wayland_window_->surface()); ++ ++ connection_->ScheduleFlush(); ++ return true; ++} ++ ++bool XDGSurfaceWrapperImpl::InitializeV6(bool with_toplevel) { ++ static const zxdg_surface_v6_listener zxdg_surface_v6_listener = { ++ &XDGSurfaceWrapperImpl::ConfigureV6, ++ }; ++ static const zxdg_toplevel_v6_listener zxdg_toplevel_v6_listener = { ++ &XDGSurfaceWrapperImpl::ConfigureTopLevelV6, ++ &XDGSurfaceWrapperImpl::CloseTopLevelV6, ++ }; ++ ++ // if this surface is created for the popup role, mark that it requires ++ // configuration acknowledgement on each configure event. ++ surface_for_popup_ = !with_toplevel; ++ ++ zxdg_surface_v6_.reset(zxdg_shell_v6_get_xdg_surface( ++ connection_->shell_v6(), wayland_window_->surface())); ++ if (!zxdg_surface_v6_) { ++ LOG(ERROR) << "Failed to create zxdg_surface"; ++ return false; ++ } ++ zxdg_surface_v6_add_listener(zxdg_surface_v6_.get(), ++ &zxdg_surface_v6_listener, this); ++ // XDGPopupV6 requires a separate surface to be created, so this is just a ++ // request to get an xdg_surface for it. ++ if (surface_for_popup_) { ++ connection_->ScheduleFlush(); ++ return true; ++ } ++ ++ zxdg_toplevel_v6_.reset(zxdg_surface_v6_get_toplevel(zxdg_surface_v6_.get())); ++ if (!zxdg_toplevel_v6_) { ++ LOG(ERROR) << "Failed to create zxdg_toplevel"; ++ return false; ++ } ++ zxdg_toplevel_v6_add_listener(zxdg_toplevel_v6_.get(), ++ &zxdg_toplevel_v6_listener, this); ++ wl_surface_commit(wayland_window_->surface()); ++ ++ connection_->ScheduleFlush(); ++ return true; ++} ++ + } // namespace ui +diff --git a/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h +index e14956ebe3e7..b34f4b2281ec 100644 +--- a/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h ++++ b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h +@@ -7,11 +7,10 @@ + + #include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h" + ++#include "base/macros.h" + #include "base/strings/string16.h" + #include "ui/ozone/platform/wayland/common/wayland_object.h" + +-#include "base/macros.h" +- + namespace gfx { + class Rect; + } +@@ -24,15 +23,12 @@ class WaylandWindow; + // Surface wrapper for xdg-shell stable and xdg-shell-unstable-v6 + class XDGSurfaceWrapperImpl : public ShellSurfaceWrapper { + public: +- XDGSurfaceWrapperImpl(WaylandWindow* wayland_window); ++ XDGSurfaceWrapperImpl(WaylandWindow* wayland_window, ++ WaylandConnection* connection); + ~XDGSurfaceWrapperImpl() override; + +- bool InitializeV6(WaylandConnection* connection, +- wl_surface* surface, +- bool with_toplevel = true); +- bool InitializeStable(WaylandConnection* connection, +- wl_surface* surface, +- bool with_toplevel = true); ++ // ShellSurfaceWrapper overrides: ++ bool Initialize(bool with_toplevel) override; + void SetMaximized() override; + void UnSetMaximized() override; + void SetFullscreen() override; +@@ -76,8 +72,17 @@ class XDGSurfaceWrapperImpl : public ShellSurfaceWrapper { + zxdg_surface_v6* zxdg_surface() const; + + private: +- WaylandWindow* wayland_window_; +- uint32_t pending_configure_serial_; ++ // Initializes using XDG Shell Stable protocol. ++ bool InitializeStable(bool with_toplevel); ++ // Initializes using XDG Shell V6 protocol. ++ bool InitializeV6(bool with_toplevel); ++ ++ // Non-owing WaylandWindow that uses this surface wrapper. ++ WaylandWindow* const wayland_window_; ++ WaylandConnection* const connection_; ++ ++ uint32_t pending_configure_serial_ = 0; ++ + wl::Object<zxdg_surface_v6> zxdg_surface_v6_; + wl::Object<zxdg_toplevel_v6> zxdg_toplevel_v6_; + wl::Object<struct xdg_surface> xdg_surface_; +-- +2.24.1 + diff --git a/0002-ozone-Wayland-Add-WaylandWindow-factory-method.patch b/0002-ozone-Wayland-Add-WaylandWindow-factory-method.patch new file mode 100644 index 000000000000..5962d788740d --- /dev/null +++ b/0002-ozone-Wayland-Add-WaylandWindow-factory-method.patch @@ -0,0 +1,646 @@ +From 53e253ee8daeff98359dfd1fd8f9374879e6aaa5 Mon Sep 17 00:00:00 2001 +From: Maksim Sisov <msisov@igalia.com> +Date: Fri, 6 Dec 2019 19:55:37 +0000 +Subject: [PATCH 2/9] ozone/Wayland: Add WaylandWindow factory method. + +To hide future different types of WaylandWindows (WaylandSurface, +WaylandPopup and WaylandSubsurface), add a factory method, which +will handle everything on its own. + +Also make unittests and OzonePlatformWayland use this factory. + +Bug: 1028919 +Change-Id: I745f99024b6657be3686ee92b0baf4c93f08b9a7 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1954470 +Commit-Queue: Maksim Sisov <msisov@igalia.com> +Reviewed-by: Michael Spang <spang@chromium.org> +Cr-Commit-Position: refs/heads/master@{#722586} +--- + ui/ozone/platform/wayland/BUILD.gn | 1 + + .../wayland/host/wayland_pointer_unittest.cc | 5 +- + .../wayland/host/wayland_screen_unittest.cc | 5 +- + .../platform/wayland/host/wayland_window.cc | 132 +++++++++--------- + .../platform/wayland/host/wayland_window.h | 17 ++- + .../wayland/host/wayland_window_factory.cc | 26 ++++ + .../host/wayland_window_manager_unittests.cc | 8 +- + .../wayland/host/wayland_window_unittest.cc | 120 ++++++++-------- + .../wayland/ozone_platform_wayland.cc | 6 +- + .../platform/wayland/test/wayland_test.cc | 4 +- + .../wayland_buffer_manager_unittest.cc | 6 +- + 11 files changed, 184 insertions(+), 146 deletions(-) + create mode 100644 ui/ozone/platform/wayland/host/wayland_window_factory.cc + +diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn +index 9c2cbc52500b..a9c0302f162f 100644 +--- a/ui/ozone/platform/wayland/BUILD.gn ++++ b/ui/ozone/platform/wayland/BUILD.gn +@@ -95,6 +95,7 @@ source_set("wayland") { + "host/wayland_touch.h", + "host/wayland_window.cc", + "host/wayland_window.h", ++ "host/wayland_window_factory.cc", + "host/wayland_window_manager.cc", + "host/wayland_window_manager.h", + "host/wayland_window_observer.cc", +diff --git a/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc b/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc +index be9cd942d6ec..b96f2e6f73f9 100644 +--- a/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc ++++ b/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc +@@ -72,14 +72,15 @@ TEST_P(WaylandPointerTest, Enter) { + + TEST_P(WaylandPointerTest, Leave) { + MockPlatformWindowDelegate other_delegate; +- WaylandWindow other_window(&other_delegate, connection_.get()); + gfx::AcceleratedWidget other_widget = gfx::kNullAcceleratedWidget; + EXPECT_CALL(other_delegate, OnAcceleratedWidgetAvailable(_)) + .WillOnce(SaveArg<0>(&other_widget)); ++ + PlatformWindowInitProperties properties; + properties.bounds = gfx::Rect(0, 0, 10, 10); + properties.type = PlatformWindowType::kWindow; +- ASSERT_TRUE(other_window.Initialize(std::move(properties))); ++ auto other_window = WaylandWindow::Create(&other_delegate, connection_.get(), ++ std::move(properties)); + ASSERT_NE(other_widget, gfx::kNullAcceleratedWidget); + + Sync(); +diff --git a/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc b/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc +index e1e3cc823ac3..9198aa88e054 100644 +--- a/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc ++++ b/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc +@@ -89,13 +89,12 @@ class WaylandScreenTest : public WaylandTest { + PlatformWindowType window_type, + gfx::AcceleratedWidget parent_widget, + MockPlatformWindowDelegate* delegate) { +- auto window = std::make_unique<WaylandWindow>(delegate, connection_.get()); + PlatformWindowInitProperties properties; + properties.bounds = bounds; + properties.type = window_type; + properties.parent_widget = parent_widget; +- EXPECT_TRUE(window->Initialize(std::move(properties))); +- return window; ++ return WaylandWindow::Create(delegate, connection_.get(), ++ std::move(properties)); + } + + void UpdateOutputGeometry(wl_resource* output_resource, +diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc +index 95c6e5a46b3e..da9a4cb368b8 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window.cc ++++ b/ui/ozone/platform/wayland/host/wayland_window.cc +@@ -85,72 +85,6 @@ WaylandWindow* WaylandWindow::FromSurface(wl_surface* surface) { + wl_proxy_get_user_data(reinterpret_cast<wl_proxy*>(surface))); + } + +-bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) { +- // Properties contain DIP bounds but the buffer scale is initially 1 so it's +- // OK to assign. The bounds will be recalculated when the buffer scale +- // changes. +- DCHECK_EQ(buffer_scale_, 1); +- bounds_px_ = properties.bounds; +- opacity_ = properties.opacity; +- +- surface_.reset(wl_compositor_create_surface(connection_->compositor())); +- if (!surface_) { +- LOG(ERROR) << "Failed to create wl_surface"; +- return false; +- } +- wl_surface_set_user_data(surface_.get(), this); +- AddSurfaceListener(); +- +- connection_->wayland_window_manager()->AddWindow(GetWidget(), this); +- +- ui::PlatformWindowType ui_window_type = properties.type; +- switch (ui_window_type) { +- case ui::PlatformWindowType::kMenu: +- case ui::PlatformWindowType::kPopup: +- parent_window_ = GetParentWindow(properties.parent_widget); +- +- // Popups need to know their scale earlier to position themselves. +- if (!parent_window_) { +- LOG(ERROR) << "Failed to get a parent window for this popup"; +- return false; +- } +- +- SetBufferScale(parent_window_->buffer_scale_, false); +- ui_scale_ = parent_window_->ui_scale_; +- +- // TODO(msisov, jkim): Handle notification windows, which are marked +- // as popup windows as well. Those are the windows that do not have +- // parents and pop up when the browser receives a notification. +- CreateShellPopup(); +- break; +- case ui::PlatformWindowType::kTooltip: +- // Tooltips subsurfaces are created on demand, upon ::Show calls. +- is_tooltip_ = true; +- break; +- case ui::PlatformWindowType::kWindow: +- case ui::PlatformWindowType::kBubble: +- case ui::PlatformWindowType::kDrag: +- // TODO(msisov): Figure out what kind of surface we need to create for +- // bubble and drag windows. +- CreateShellSurface(); +- break; +- } +- +- if (shell_surface_ && !properties.wm_class_class.empty()) +- shell_surface_->SetAppId(properties.wm_class_class); +- +- connection_->ScheduleFlush(); +- +- PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); +- delegate_->OnAcceleratedWidgetAvailable(GetWidget()); +- +- // Will do nothing for popups because they have got their scale above. +- UpdateBufferScale(false); +- +- MaybeUpdateOpaqueRegion(); +- return true; +-} +- + void WaylandWindow::UpdateBufferScale(bool update_bounds) { + DCHECK(connection_->wayland_output_manager()); + const auto* screen = connection_->wayland_output_manager()->wayland_screen(); +@@ -792,6 +726,72 @@ void WaylandWindow::OnDragSessionClose(uint32_t dnd_action) { + connection_->ResetPointerFlags(); + } + ++bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) { ++ // Properties contain DIP bounds but the buffer scale is initially 1 so it's ++ // OK to assign. The bounds will be recalculated when the buffer scale ++ // changes. ++ DCHECK_EQ(buffer_scale_, 1); ++ bounds_px_ = properties.bounds; ++ opacity_ = properties.opacity; ++ ++ surface_.reset(wl_compositor_create_surface(connection_->compositor())); ++ if (!surface_) { ++ LOG(ERROR) << "Failed to create wl_surface"; ++ return false; ++ } ++ wl_surface_set_user_data(surface_.get(), this); ++ AddSurfaceListener(); ++ ++ connection_->wayland_window_manager()->AddWindow(GetWidget(), this); ++ ++ ui::PlatformWindowType ui_window_type = properties.type; ++ switch (ui_window_type) { ++ case ui::PlatformWindowType::kMenu: ++ case ui::PlatformWindowType::kPopup: ++ parent_window_ = GetParentWindow(properties.parent_widget); ++ ++ // Popups need to know their scale earlier to position themselves. ++ if (!parent_window_) { ++ LOG(ERROR) << "Failed to get a parent window for this popup"; ++ return false; ++ } ++ ++ SetBufferScale(parent_window_->buffer_scale_, false); ++ ui_scale_ = parent_window_->ui_scale_; ++ ++ // TODO(msisov, jkim): Handle notification windows, which are marked ++ // as popup windows as well. Those are the windows that do not have ++ // parents and pop up when the browser receives a notification. ++ CreateShellPopup(); ++ break; ++ case ui::PlatformWindowType::kTooltip: ++ // Tooltips subsurfaces are created on demand, upon ::Show calls. ++ is_tooltip_ = true; ++ break; ++ case ui::PlatformWindowType::kWindow: ++ case ui::PlatformWindowType::kBubble: ++ case ui::PlatformWindowType::kDrag: ++ // TODO(msisov): Figure out what kind of surface we need to create for ++ // bubble and drag windows. ++ CreateShellSurface(); ++ break; ++ } ++ ++ if (shell_surface_ && !properties.wm_class_class.empty()) ++ shell_surface_->SetAppId(properties.wm_class_class); ++ ++ connection_->ScheduleFlush(); ++ ++ PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); ++ delegate_->OnAcceleratedWidgetAvailable(GetWidget()); ++ ++ // Will do nothing for popups because they have got their scale above. ++ UpdateBufferScale(false); ++ ++ MaybeUpdateOpaqueRegion(); ++ return true; ++} ++ + void WaylandWindow::SetBoundsDip(const gfx::Rect& bounds_dip) { + SetBounds(gfx::ScaleToRoundedRect(bounds_dip, buffer_scale_)); + } +diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h +index 4233216d7a6f..b8cdc991e30e 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window.h ++++ b/ui/ozone/platform/wayland/host/wayland_window.h +@@ -40,13 +40,16 @@ class WaylandWindow : public PlatformWindow, + public WmMoveResizeHandler, + public WmDragHandler { + public: +- WaylandWindow(PlatformWindowDelegate* delegate, +- WaylandConnection* connection); + ~WaylandWindow() override; + +- static WaylandWindow* FromSurface(wl_surface* surface); ++ // A factory method that can create any of the derived types of WaylandWindow ++ // (WaylandSurface, WaylandPopup and WaylandSubsurface). ++ static std::unique_ptr<WaylandWindow> Create( ++ PlatformWindowDelegate* delegate, ++ WaylandConnection* connection, ++ PlatformWindowInitProperties properties); + +- bool Initialize(PlatformWindowInitProperties properties); ++ static WaylandWindow* FromSurface(wl_surface* surface); + + // Updates the surface buffer scale of the window. Top level windows take + // scale from the output attached to either their current display or the +@@ -168,6 +171,12 @@ class WaylandWindow : public PlatformWindow, + private: + FRIEND_TEST_ALL_PREFIXES(WaylandScreenTest, SetBufferScale); + ++ WaylandWindow(PlatformWindowDelegate* delegate, ++ WaylandConnection* connection); ++ ++ // Initializes the WaylandWindow with supplied properties. ++ bool Initialize(PlatformWindowInitProperties properties); ++ + void SetBoundsDip(const gfx::Rect& bounds_dip); + void SetBufferScale(int32_t scale, bool update_bounds); + +diff --git a/ui/ozone/platform/wayland/host/wayland_window_factory.cc b/ui/ozone/platform/wayland/host/wayland_window_factory.cc +new file mode 100644 +index 000000000000..19da59357d55 +--- /dev/null ++++ b/ui/ozone/platform/wayland/host/wayland_window_factory.cc +@@ -0,0 +1,26 @@ ++// Copyright 2019 The Chromium Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#include "ui/ozone/platform/wayland/host/wayland_window.h" ++ ++#include <memory> ++ ++#include "ui/ozone/platform/wayland/host/wayland_window.h" ++ ++namespace ui { ++ ++// static ++std::unique_ptr<WaylandWindow> WaylandWindow::Create( ++ PlatformWindowDelegate* delegate, ++ WaylandConnection* connection, ++ PlatformWindowInitProperties properties) { ++ // TODO(msisov): once WaylandWindow becomes a base class, add switch cases to ++ // create different Wayland windows. ++ std::unique_ptr<WaylandWindow> window( ++ new WaylandWindow(delegate, connection)); ++ return window->Initialize(std::move(properties)) ? std::move(window) ++ : nullptr; ++} ++ ++} // namespace ui +\ No newline at end of file +diff --git a/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc b/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc +index 737c7cdd25d9..64a387723560 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc ++++ b/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc +@@ -36,12 +36,8 @@ class WaylandWindowManagerTest : public WaylandTest { + PlatformWindowInitProperties properties; + properties.bounds = bounds; + properties.type = type; +- +- std::unique_ptr<WaylandWindow> window = +- std::make_unique<WaylandWindow>(delegate, connection_.get()); +- +- EXPECT_TRUE(window->Initialize(std::move(properties))); +- return window; ++ return WaylandWindow::Create(delegate, connection_.get(), ++ std::move(properties)); + } + + WaylandWindowManager* manager_ = nullptr; +diff --git a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc +index f8dc4429c073..b03a28daadf2 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc ++++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc +@@ -150,20 +150,19 @@ class WaylandWindowTest : public WaylandTest { + return result; + } + +- bool CreateWaylandWindowWithParams(PlatformWindowType type, +- gfx::AcceleratedWidget parent_widget, +- const gfx::Rect bounds, +- MockPlatformWindowDelegate* delegate, +- std::unique_ptr<WaylandWindow>* window) { ++ std::unique_ptr<WaylandWindow> CreateWaylandWindowWithParams( ++ PlatformWindowType type, ++ gfx::AcceleratedWidget parent_widget, ++ const gfx::Rect bounds, ++ MockPlatformWindowDelegate* delegate) { + PlatformWindowInitProperties properties; + // TODO(msisov): use a fancy method to calculate position of a popup window. + properties.bounds = bounds; + properties.type = type; + properties.parent_widget = parent_widget; + +- *window = std::make_unique<WaylandWindow>(delegate, connection_.get()); +- +- return (*window)->Initialize(std::move(properties)); ++ return WaylandWindow::Create(delegate, connection_.get(), ++ std::move(properties)); + } + + void InitializeWithSupportedHitTestValues(std::vector<int>* hit_tests) { +@@ -736,27 +735,29 @@ TEST_P(WaylandWindowTest, CanCreateMenuWindow) { + ASSERT_TRUE(connection_->pointer() && connection_->touch()); + window_->SetPointerFocus(true); + +- std::unique_ptr<WaylandWindow> menu_window; +- EXPECT_TRUE(CreateWaylandWindowWithParams( ++ std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget, +- gfx::Rect(0, 0, 10, 10), &menu_window_delegate, &menu_window)); ++ gfx::Rect(0, 0, 10, 10), &menu_window_delegate); ++ EXPECT_TRUE(menu_window); + + Sync(); + + window_->SetPointerFocus(false); + window_->set_touch_focus(false); + +- EXPECT_FALSE(CreateWaylandWindowWithParams( ++ menu_window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget, +- gfx::Rect(0, 0, 10, 10), &menu_window_delegate, &menu_window)); ++ gfx::Rect(0, 0, 10, 10), &menu_window_delegate); ++ EXPECT_FALSE(menu_window); + + Sync(); + + window_->set_touch_focus(true); + +- EXPECT_TRUE(CreateWaylandWindowWithParams( ++ menu_window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget, +- gfx::Rect(0, 0, 10, 10), &menu_window_delegate, &menu_window)); ++ gfx::Rect(0, 0, 10, 10), &menu_window_delegate); ++ EXPECT_TRUE(menu_window); + + Sync(); + } +@@ -767,29 +768,30 @@ TEST_P(WaylandWindowTest, CreateAndDestroyNestedMenuWindow) { + EXPECT_CALL(menu_window_delegate, OnAcceleratedWidgetAvailable(_)) + .WillOnce(SaveArg<0>(&menu_window_widget)); + +- std::unique_ptr<WaylandWindow> menu_window; +- EXPECT_TRUE(CreateWaylandWindowWithParams( ++ std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, widget_, gfx::Rect(0, 0, 10, 10), +- &menu_window_delegate, &menu_window)); ++ &menu_window_delegate); ++ EXPECT_TRUE(menu_window); + ASSERT_NE(menu_window_widget, gfx::kNullAcceleratedWidget); + + Sync(); + + MockPlatformWindowDelegate nested_menu_window_delegate; +- std::unique_ptr<WaylandWindow> nested_menu_window; +- EXPECT_TRUE(CreateWaylandWindowWithParams( +- PlatformWindowType::kMenu, menu_window_widget, gfx::Rect(20, 0, 10, 10), +- &nested_menu_window_delegate, &nested_menu_window)); ++ std::unique_ptr<WaylandWindow> nested_menu_window = ++ CreateWaylandWindowWithParams( ++ PlatformWindowType::kMenu, menu_window_widget, ++ gfx::Rect(20, 0, 10, 10), &nested_menu_window_delegate); ++ EXPECT_TRUE(nested_menu_window); + + Sync(); + } + + TEST_P(WaylandWindowTest, CanDispatchEventToMenuWindowNonNested) { + MockPlatformWindowDelegate menu_window_delegate; +- std::unique_ptr<WaylandWindow> menu_window; +- EXPECT_TRUE(CreateWaylandWindowWithParams( ++ std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, widget_, gfx::Rect(0, 0, 10, 10), +- &menu_window_delegate, &menu_window)); ++ &menu_window_delegate); ++ EXPECT_TRUE(menu_window); + + wl_seat_send_capabilities(server_.seat()->resource(), + WL_SEAT_CAPABILITY_POINTER); +@@ -812,18 +814,19 @@ TEST_P(WaylandWindowTest, CanDispatchEventToMenuWindowNested) { + EXPECT_CALL(menu_window_delegate, OnAcceleratedWidgetAvailable(_)) + .WillOnce(SaveArg<0>(&menu_window_widget)); + +- std::unique_ptr<WaylandWindow> menu_window; +- EXPECT_TRUE(CreateWaylandWindowWithParams( ++ std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, widget_, gfx::Rect(0, 0, 10, 10), +- &menu_window_delegate, &menu_window)); ++ &menu_window_delegate); ++ EXPECT_TRUE(menu_window); + + Sync(); + + MockPlatformWindowDelegate nested_menu_window_delegate; +- std::unique_ptr<WaylandWindow> nested_menu_window; +- EXPECT_TRUE(CreateWaylandWindowWithParams( +- PlatformWindowType::kMenu, menu_window_widget, gfx::Rect(20, 0, 10, 10), +- &nested_menu_window_delegate, &nested_menu_window)); ++ std::unique_ptr<WaylandWindow> nested_menu_window = ++ CreateWaylandWindowWithParams( ++ PlatformWindowType::kMenu, menu_window_widget, ++ gfx::Rect(20, 0, 10, 10), &nested_menu_window_delegate); ++ EXPECT_TRUE(nested_menu_window); + + Sync(); + +@@ -903,10 +906,10 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) { + MockPlatformWindowDelegate menu_window_delegate; + gfx::Rect menu_window_bounds(gfx::Point(440, 76), + menu_window_positioner.size); +- std::unique_ptr<WaylandWindow> menu_window; +- EXPECT_TRUE(CreateWaylandWindowWithParams( ++ std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, toplevel_window->GetWidget(), +- menu_window_bounds, &menu_window_delegate, &menu_window)); ++ menu_window_bounds, &menu_window_delegate); ++ EXPECT_TRUE(menu_window); + + Sync(); + +@@ -924,10 +927,11 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) { + MockPlatformWindowDelegate nested_menu_window_delegate; + gfx::Rect nested_menu_window_bounds(gfx::Point(723, 156), + nested_menu_window_positioner.size); +- std::unique_ptr<WaylandWindow> nested_menu_window; +- EXPECT_TRUE(CreateWaylandWindowWithParams( +- PlatformWindowType::kMenu, menu_window_widget, nested_menu_window_bounds, +- &nested_menu_window_delegate, &nested_menu_window)); ++ std::unique_ptr<WaylandWindow> nested_menu_window = ++ CreateWaylandWindowWithParams( ++ PlatformWindowType::kMenu, menu_window_widget, ++ nested_menu_window_bounds, &nested_menu_window_delegate); ++ EXPECT_TRUE(nested_menu_window); + + Sync(); + +@@ -985,9 +989,10 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) { + // side. Thus, we have to check that anchor rect is correct. + nested_menu_window.reset(); + nested_menu_window_bounds.set_origin({723, 258}); +- EXPECT_TRUE(CreateWaylandWindowWithParams( ++ nested_menu_window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, menu_window_widget, nested_menu_window_bounds, +- &nested_menu_window_delegate, &nested_menu_window)); ++ &nested_menu_window_delegate); ++ EXPECT_TRUE(nested_menu_window); + + Sync(); + +@@ -1050,9 +1055,10 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) { + window_->SetBounds(gfx::Rect(0, 0, 2493, 1413)); + + menu_window_bounds.set_origin({2206, 67}); +- EXPECT_TRUE(CreateWaylandWindowWithParams( ++ menu_window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, toplevel_window->GetWidget(), +- menu_window_bounds, &menu_window_delegate, &menu_window)); ++ menu_window_bounds, &menu_window_delegate); ++ EXPECT_TRUE(menu_window); + + Sync(); + +@@ -1066,9 +1072,10 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) { + Sync(); + + nested_menu_window_bounds.set_origin({1905, 147}); +- EXPECT_TRUE(CreateWaylandWindowWithParams( ++ nested_menu_window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, menu_window_widget, nested_menu_window_bounds, +- &nested_menu_window_delegate, &nested_menu_window)); ++ &nested_menu_window_delegate); ++ EXPECT_TRUE(nested_menu_window); + + Sync(); + +@@ -1096,9 +1103,10 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) { + + nested_menu_window.reset(); + +- EXPECT_TRUE(CreateWaylandWindowWithParams( ++ nested_menu_window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, menu_window_widget, nested_menu_window_bounds, +- &nested_menu_window_delegate, &nested_menu_window)); ++ &nested_menu_window_delegate); ++ EXPECT_TRUE(nested_menu_window); + + Sync(); + +@@ -1174,10 +1182,10 @@ TEST_P(WaylandWindowTest, TooltipSimpleParent) { + VerifyAndClearExpectations(); + + gfx::Rect tooltip_window_bounds(gfx::Point(15, 15), gfx::Size(10, 10)); +- std::unique_ptr<WaylandWindow> tooltip_window; +- EXPECT_TRUE(CreateWaylandWindowWithParams( ++ std::unique_ptr<WaylandWindow> tooltip_window = CreateWaylandWindowWithParams( + PlatformWindowType::kTooltip, window_->GetWidget(), tooltip_window_bounds, +- &delegate_, &tooltip_window)); ++ &delegate_); ++ EXPECT_TRUE(tooltip_window); + + window_->SetPointerFocus(true); + +@@ -1199,18 +1207,18 @@ TEST_P(WaylandWindowTest, TooltipNestedParent) { + VerifyAndClearExpectations(); + + gfx::Rect menu_window_bounds(gfx::Point(10, 10), gfx::Size(100, 100)); +- std::unique_ptr<WaylandWindow> menu_window; +- EXPECT_TRUE(CreateWaylandWindowWithParams( ++ std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds, +- &delegate_, &menu_window)); ++ &delegate_); ++ EXPECT_TRUE(menu_window); + + VerifyAndClearExpectations(); + + gfx::Rect tooltip_window_bounds(gfx::Point(15, 15), gfx::Size(10, 10)); +- std::unique_ptr<WaylandWindow> tooltip_window; +- EXPECT_TRUE(CreateWaylandWindowWithParams( ++ std::unique_ptr<WaylandWindow> tooltip_window = CreateWaylandWindowWithParams( + PlatformWindowType::kTooltip, menu_window->GetWidget(), +- tooltip_window_bounds, &delegate_, &tooltip_window)); ++ tooltip_window_bounds, &delegate_); ++ EXPECT_TRUE(tooltip_window); + + VerifyAndClearExpectations(); + +diff --git a/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/ui/ozone/platform/wayland/ozone_platform_wayland.cc +index 541d9c4848d7..dbf880e9a0c1 100644 +--- a/ui/ozone/platform/wayland/ozone_platform_wayland.cc ++++ b/ui/ozone/platform/wayland/ozone_platform_wayland.cc +@@ -107,10 +107,8 @@ class OzonePlatformWayland : public OzonePlatform { + std::unique_ptr<PlatformWindow> CreatePlatformWindow( + PlatformWindowDelegate* delegate, + PlatformWindowInitProperties properties) override { +- auto window = std::make_unique<WaylandWindow>(delegate, connection_.get()); +- if (!window->Initialize(std::move(properties))) +- return nullptr; +- return std::move(window); ++ return WaylandWindow::Create(delegate, connection_.get(), ++ std::move(properties)); + } + + std::unique_ptr<display::NativeDisplayDelegate> CreateNativeDisplayDelegate() +diff --git a/ui/ozone/platform/wayland/test/wayland_test.cc b/ui/ozone/platform/wayland/test/wayland_test.cc +index 2bd8c38219c1..2543981d8c38 100644 +--- a/ui/ozone/platform/wayland/test/wayland_test.cc ++++ b/ui/ozone/platform/wayland/test/wayland_test.cc +@@ -37,7 +37,6 @@ WaylandTest::WaylandTest() + buffer_manager_gpu_ = std::make_unique<WaylandBufferManagerGpu>(); + surface_factory_ = std::make_unique<WaylandSurfaceFactory>( + connection_.get(), buffer_manager_gpu_.get()); +- window_ = std::make_unique<WaylandWindow>(&delegate_, connection_.get()); + } + + WaylandTest::~WaylandTest() {} +@@ -52,7 +51,8 @@ void WaylandTest::SetUp() { + PlatformWindowInitProperties properties; + properties.bounds = gfx::Rect(0, 0, 800, 600); + properties.type = PlatformWindowType::kWindow; +- ASSERT_TRUE(window_->Initialize(std::move(properties))); ++ window_ = WaylandWindow::Create(&delegate_, connection_.get(), ++ std::move(properties)); + ASSERT_NE(widget_, gfx::kNullAcceleratedWidget); + + // Wait for the client to flush all pending requests from initialization. +diff --git a/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc b/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc +index 21b0c3eefd9b..767f9354f6da 100644 +--- a/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc ++++ b/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc +@@ -189,12 +189,12 @@ class WaylandBufferManagerTest : public WaylandTest { + + std::unique_ptr<WaylandWindow> CreateWindow() { + testing::Mock::VerifyAndClearExpectations(&delegate_); +- auto new_window = +- std::make_unique<WaylandWindow>(&delegate_, connection_.get()); + PlatformWindowInitProperties properties; + properties.bounds = gfx::Rect(0, 0, 800, 600); + properties.type = PlatformWindowType::kWindow; +- EXPECT_TRUE(new_window->Initialize(std::move(properties))); ++ auto new_window = WaylandWindow::Create(&delegate_, connection_.get(), ++ std::move(properties)); ++ EXPECT_TRUE(new_window); + + Sync(); + +-- +2.24.1 + diff --git a/0003-ozone-Wayland-move-bounds-translation-util-to-utilit.patch b/0003-ozone-Wayland-move-bounds-translation-util-to-utilit.patch new file mode 100644 index 000000000000..14d5143a81e3 --- /dev/null +++ b/0003-ozone-Wayland-move-bounds-translation-util-to-utilit.patch @@ -0,0 +1,137 @@ +From d7680c81c95c4609bf4ffbad05656a09d589a382 Mon Sep 17 00:00:00 2001 +From: Maksim Sisov <msisov@igalia.com> +Date: Fri, 6 Dec 2019 19:49:45 +0000 +Subject: [PATCH 3/9] ozone/Wayland: move bounds translation util to utilities. + +Just moving the translation helper method to utilities. + +Bug: 1028919 +Change-Id: I6e60bcdf804e4aaff9cb39d437e4302af2ed3fd2 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1953710 +Commit-Queue: Maksim Sisov <msisov@igalia.com> +Reviewed-by: Michael Spang <spang@chromium.org> +Cr-Commit-Position: refs/heads/master@{#722582} +--- + .../platform/wayland/common/wayland_util.cc | 14 ++++++++++ + .../platform/wayland/common/wayland_util.h | 8 ++++++ + .../platform/wayland/host/wayland_window.cc | 27 +++---------------- + 3 files changed, 26 insertions(+), 23 deletions(-) + +diff --git a/ui/ozone/platform/wayland/common/wayland_util.cc b/ui/ozone/platform/wayland/common/wayland_util.cc +index 0201f689e90d..e0430b860adf 100644 +--- a/ui/ozone/platform/wayland/common/wayland_util.cc ++++ b/ui/ozone/platform/wayland/common/wayland_util.cc +@@ -141,4 +141,18 @@ void ReadDataFromFD(base::ScopedFD fd, std::vector<uint8_t>* contents) { + contents->insert(contents->end(), buffer, buffer + length); + } + ++gfx::Rect TranslateBoundsToParentCoordinates(const gfx::Rect& child_bounds, ++ const gfx::Rect& parent_bounds) { ++ return gfx::Rect( ++ (child_bounds.origin() - parent_bounds.origin().OffsetFromOrigin()), ++ child_bounds.size()); ++} ++ ++gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds, ++ const gfx::Rect& parent_bounds) { ++ return gfx::Rect( ++ (child_bounds.origin() + parent_bounds.origin().OffsetFromOrigin()), ++ child_bounds.size()); ++} ++ + } // namespace wl +diff --git a/ui/ozone/platform/wayland/common/wayland_util.h b/ui/ozone/platform/wayland/common/wayland_util.h +index 368f3d9a9427..48332e059da0 100644 +--- a/ui/ozone/platform/wayland/common/wayland_util.h ++++ b/ui/ozone/platform/wayland/common/wayland_util.h +@@ -13,6 +13,7 @@ + #include "base/containers/flat_map.h" + #include "base/files/scoped_file.h" + #include "base/macros.h" ++#include "ui/gfx/geometry/rect.h" + #include "ui/ozone/platform/wayland/common/wayland_object.h" + + class SkBitmap; +@@ -50,6 +51,13 @@ bool DrawBitmap(const SkBitmap& bitmap, ui::WaylandShmBuffer* out_buffer); + // Helper function to read data from a file. + void ReadDataFromFD(base::ScopedFD fd, std::vector<uint8_t>* contents); + ++// Translates bounds relative to top level window to specified parent. ++gfx::Rect TranslateBoundsToParentCoordinates(const gfx::Rect& child_bounds, ++ const gfx::Rect& parent_bounds); ++// Translates bounds relative to parent window to top level window. ++gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds, ++ const gfx::Rect& parent_bounds); ++ + } // namespace wl + + #endif // UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_ +diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc +index da9a4cb368b8..709fb681f7d9 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window.cc ++++ b/ui/ozone/platform/wayland/host/wayland_window.cc +@@ -16,6 +16,7 @@ + #include "ui/events/event_utils.h" + #include "ui/events/ozone/events_ozone.h" + #include "ui/gfx/geometry/point_f.h" ++#include "ui/ozone/platform/wayland/common/wayland_util.h" + #include "ui/ozone/platform/wayland/host/shell_object_factory.h" + #include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h" + #include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h" +@@ -28,26 +29,6 @@ + + namespace ui { + +-namespace { +- +-// Translates bounds relative to top level window to specified parent. +-gfx::Rect TranslateBoundsToParentCoordinates(const gfx::Rect& child_bounds, +- const gfx::Rect& parent_bounds) { +- return gfx::Rect(gfx::Point(child_bounds.x() - parent_bounds.x(), +- child_bounds.y() - parent_bounds.y()), +- child_bounds.size()); +-} +- +-// Translates bounds relative to parent window to top level window. +-gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds, +- const gfx::Rect& parent_bounds) { +- return gfx::Rect(gfx::Point(child_bounds.x() + parent_bounds.x(), +- child_bounds.y() + parent_bounds.y()), +- child_bounds.size()); +-} +- +-} // namespace +- + WaylandWindow::WaylandWindow(PlatformWindowDelegate* delegate, + WaylandConnection* connection) + : delegate_(delegate), +@@ -177,7 +158,7 @@ void WaylandWindow::CreateAndShowTooltipSubSurface() { + const auto parent_bounds_dip = + gfx::ScaleToRoundedRect(parent_window->GetBounds(), 1.0 / ui_scale_); + auto new_bounds_dip = +- TranslateBoundsToParentCoordinates(bounds_px_, parent_bounds_dip); ++ wl::TranslateBoundsToParentCoordinates(bounds_px_, parent_bounds_dip); + auto bounds_px = + gfx::ScaleToRoundedRect(new_bounds_dip, ui_scale_ / buffer_scale_); + +@@ -671,7 +652,7 @@ void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds_dip) { + // window, which automatically becomes the same as relative to an origin of + // a display. + new_bounds_dip = gfx::ScaleToRoundedRect( +- TranslateBoundsToTopLevelCoordinates( ++ wl::TranslateBoundsToTopLevelCoordinates( + gfx::ScaleToRoundedRect(new_bounds_dip, buffer_scale_), + parent_window_->GetBounds()), + 1.0 / buffer_scale_); +@@ -962,7 +943,7 @@ gfx::Rect WaylandWindow::AdjustPopupWindowPosition() const { + const gfx::Rect parent_bounds_dip = + gfx::ScaleToRoundedRect(parent_window_->GetBounds(), 1.0 / ui_scale_); + gfx::Rect new_bounds_dip = +- TranslateBoundsToParentCoordinates(bounds_px_, parent_bounds_dip); ++ wl::TranslateBoundsToParentCoordinates(bounds_px_, parent_bounds_dip); + + // Chromium may decide to position nested menu windows on the left side + // instead of the right side of parent menu windows when the size of the +-- +2.24.1 + diff --git a/0004-ozone-wayland-Fix-regression-with-hiding-nested-wind.patch b/0004-ozone-wayland-Fix-regression-with-hiding-nested-wind.patch new file mode 100644 index 000000000000..2e6b2a4b770c --- /dev/null +++ b/0004-ozone-wayland-Fix-regression-with-hiding-nested-wind.patch @@ -0,0 +1,33 @@ +From 738a0d76c3102509e052927e49f978b197bc3a3c Mon Sep 17 00:00:00 2001 +From: Maksim Sisov <msisov@igalia.com> +Date: Fri, 6 Dec 2019 19:19:30 +0000 +Subject: [PATCH 4/9] ozone/wayland: Fix regression with hiding nested windows. + +It must be non-tooltip that closes children windows. + +Bug: 1028046 +Change-Id: I9b5212873cb2c1a4179a28e915edd5fe84b29c5e +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1954483 +Reviewed-by: Michael Spang <spang@chromium.org> +Commit-Queue: Maksim Sisov <msisov@igalia.com> +Cr-Commit-Position: refs/heads/master@{#722560} +--- + ui/ozone/platform/wayland/host/wayland_window.cc | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc +index 709fb681f7d9..1f8cc423d4aa 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window.cc ++++ b/ui/ozone/platform/wayland/host/wayland_window.cc +@@ -247,7 +247,7 @@ void WaylandWindow::Show(bool inactive) { + } + + void WaylandWindow::Hide() { +- if (!is_tooltip_) { ++ if (is_tooltip_) { + tooltip_subsurface_.reset(); + } else { + if (child_window_) +-- +2.24.1 + diff --git a/0005-ozone-Wayland-extract-toplevel-surface-methods-into-.patch b/0005-ozone-Wayland-extract-toplevel-surface-methods-into-.patch new file mode 100644 index 000000000000..2307bfec56ac --- /dev/null +++ b/0005-ozone-Wayland-extract-toplevel-surface-methods-into-.patch @@ -0,0 +1,1424 @@ +From 0bbc15f0d57b4bcbd389776b3bee492a75fd60a5 Mon Sep 17 00:00:00 2001 +From: Maksim Sisov <msisov@igalia.com> +Date: Fri, 6 Dec 2019 20:31:04 +0000 +Subject: [PATCH 5/9] ozone/Wayland: extract toplevel surface methods into + WaylandSurface. + +WaylandWindow handles too many things and confuses developers that +are not familiar with it. To make things better, extract +surface methods into WaylandSurface. + +This change does not bring any functional changes except removed +is_active() method that was only used by tests. Instead, tests +just rely on the PlatformWindowDelegate::OnActivationChanged calls. + +Test: ozone_unittests +Bug: 1028919 +Change-Id: Ia58577f86d8e31ec93b113d887b34166fbe19cf0 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1954478 +Commit-Queue: Maksim Sisov <msisov@igalia.com> +Reviewed-by: Michael Spang <spang@chromium.org> +Cr-Commit-Position: refs/heads/master@{#722592} +--- + ui/ozone/platform/wayland/BUILD.gn | 2 + + .../platform/wayland/host/wayland_surface.cc | 348 ++++++++++++++++++ + .../platform/wayland/host/wayland_surface.h | 114 ++++++ + .../platform/wayland/host/wayland_window.cc | 346 ++--------------- + .../platform/wayland/host/wayland_window.h | 110 ++---- + .../wayland/host/wayland_window_factory.cc | 31 +- + .../wayland/host/wayland_window_unittest.cc | 14 +- + .../wayland/host/xdg_popup_wrapper_impl.cc | 9 +- + 8 files changed, 572 insertions(+), 402 deletions(-) + create mode 100644 ui/ozone/platform/wayland/host/wayland_surface.cc + create mode 100644 ui/ozone/platform/wayland/host/wayland_surface.h + +diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn +index a9c0302f162f..b6059c7d9962 100644 +--- a/ui/ozone/platform/wayland/BUILD.gn ++++ b/ui/ozone/platform/wayland/BUILD.gn +@@ -91,6 +91,8 @@ source_set("wayland") { + "host/wayland_shm.h", + "host/wayland_shm_buffer.cc", + "host/wayland_shm_buffer.h", ++ "host/wayland_surface.cc", ++ "host/wayland_surface.h", + "host/wayland_touch.cc", + "host/wayland_touch.h", + "host/wayland_window.cc", +diff --git a/ui/ozone/platform/wayland/host/wayland_surface.cc b/ui/ozone/platform/wayland/host/wayland_surface.cc +new file mode 100644 +index 000000000000..cfd4349db885 +--- /dev/null ++++ b/ui/ozone/platform/wayland/host/wayland_surface.cc +@@ -0,0 +1,348 @@ ++// Copyright 2019 The Chromium Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#include "ui/ozone/platform/wayland/host/wayland_surface.h" ++ ++#include "ui/base/dragdrop/drag_drop_types.h" ++#include "ui/base/dragdrop/os_exchange_data.h" ++#include "ui/base/hit_test.h" ++#include "ui/gfx/native_widget_types.h" ++#include "ui/ozone/platform/wayland/host/shell_object_factory.h" ++#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h" ++#include "ui/ozone/platform/wayland/host/wayland_connection.h" ++#include "ui/platform_window/platform_window_handler/wm_drop_handler.h" ++ ++namespace ui { ++ ++WaylandSurface::WaylandSurface(PlatformWindowDelegate* delegate, ++ WaylandConnection* connection) ++ : WaylandWindow(delegate, connection), ++ state_(PlatformWindowState::kNormal), ++ pending_state_(PlatformWindowState::kUnknown) { ++ // Set a class property key, which allows |this| to be used for interactive ++ // events, e.g. move or resize. ++ SetWmMoveResizeHandler(this, AsWmMoveResizeHandler()); ++ ++ // Set a class property key, which allows |this| to be used for drag action. ++ SetWmDragHandler(this, this); ++} ++ ++WaylandSurface::~WaylandSurface() { ++ if (drag_closed_callback_) { ++ std::move(drag_closed_callback_) ++ .Run(DragDropTypes::DragOperation::DRAG_NONE); ++ } ++} ++ ++void WaylandSurface::CreateShellSurface() { ++ ShellObjectFactory factory; ++ shell_surface_ = factory.CreateShellSurfaceWrapper(connection(), this); ++ if (!shell_surface_) ++ CHECK(false) << "Failed to initialize Wayland shell surface"; ++} ++ ++void WaylandSurface::ApplyPendingBounds() { ++ if (pending_bounds_dip_.IsEmpty()) ++ return; ++ DCHECK(shell_surface_); ++ ++ SetBoundsDip(pending_bounds_dip_); ++ shell_surface_->SetWindowGeometry(pending_bounds_dip_); ++ pending_bounds_dip_ = gfx::Rect(); ++ connection()->ScheduleFlush(); ++} ++ ++void WaylandSurface::DispatchHostWindowDragMovement( ++ int hittest, ++ const gfx::Point& pointer_location_in_px) { ++ DCHECK(shell_surface_); ++ ++ connection()->ResetPointerFlags(); ++ if (hittest == HTCAPTION) ++ shell_surface_->SurfaceMove(connection()); ++ else ++ shell_surface_->SurfaceResize(connection(), hittest); ++ ++ connection()->ScheduleFlush(); ++} ++ ++void WaylandSurface::StartDrag(const ui::OSExchangeData& data, ++ int operation, ++ gfx::NativeCursor cursor, ++ base::OnceCallback<void(int)> callback) { ++ DCHECK(!drag_closed_callback_); ++ drag_closed_callback_ = std::move(callback); ++ connection()->StartDrag(data, operation); ++} ++ ++void WaylandSurface::Show(bool inactive) { ++ set_keyboard_focus(true); ++ // TODO(msisov): recreate |shell_surface_| on show calls. ++} ++ ++void WaylandSurface::Hide() { ++ // TODO(msisov): destroy |shell_surface_| on hide calls. ++} ++ ++bool WaylandSurface::IsVisible() const { ++ // X and Windows return true if the window is minimized. For consistency, do ++ // the same. ++ return !!shell_surface_ || IsMinimized(); ++} ++ ++void WaylandSurface::SetTitle(const base::string16& title) { ++ DCHECK(shell_surface_); ++ shell_surface_->SetTitle(title); ++ connection()->ScheduleFlush(); ++} ++ ++void WaylandSurface::ToggleFullscreen() { ++ DCHECK(shell_surface_); ++ ++ // There are some cases, when Chromium triggers a fullscreen state change ++ // before the surface is activated. In such cases, Wayland may ignore state ++ // changes and such flags as --kiosk or --start-fullscreen will be ignored. ++ // To overcome this, set a pending state, and once the surface is activated, ++ // trigger the change. ++ if (!is_active_) { ++ DCHECK(!IsFullscreen()); ++ pending_state_ = PlatformWindowState::kFullScreen; ++ return; ++ } ++ ++ // TODO(msisov, tonikitoo): add multiscreen support. As the documentation says ++ // if shell_surface_set_fullscreen() is not provided with wl_output, it's up ++ // to the compositor to choose which display will be used to map this surface. ++ if (!IsFullscreen()) { ++ // Fullscreen state changes have to be handled manually and then checked ++ // against configuration events, which come from a compositor. The reason ++ // of manually changing the |state_| is that the compositor answers about ++ // state changes asynchronously, which leads to a wrong return value in ++ // DesktopWindowTreeHostPlatform::IsFullscreen, for example, and media ++ // files can never be set to fullscreen. ++ state_ = PlatformWindowState::kFullScreen; ++ shell_surface_->SetFullscreen(); ++ } else { ++ // Check the comment above. If it's not handled synchronously, media files ++ // may not leave the fullscreen mode. ++ state_ = PlatformWindowState::kUnknown; ++ shell_surface_->UnSetFullscreen(); ++ } ++ ++ connection()->ScheduleFlush(); ++} ++ ++void WaylandSurface::Maximize() { ++ DCHECK(shell_surface_); ++ ++ if (IsFullscreen()) ++ ToggleFullscreen(); ++ ++ shell_surface_->SetMaximized(); ++ connection()->ScheduleFlush(); ++} ++ ++void WaylandSurface::Minimize() { ++ DCHECK(shell_surface_); ++ DCHECK(!is_minimizing_); ++ // Wayland doesn't explicitly say if a window is minimized. Instead, it ++ // notifies that the window is not activated. But there are many cases, when ++ // the window is not minimized and deactivated. In order to properly record ++ // the minimized state, mark this window as being minimized. And as soon as a ++ // configuration event comes, check if the window has been deactivated and has ++ // |is_minimizing_| set. ++ is_minimizing_ = true; ++ shell_surface_->SetMinimized(); ++ connection()->ScheduleFlush(); ++} ++ ++void WaylandSurface::Restore() { ++ DCHECK(shell_surface_); ++ ++ // Unfullscreen the window if it is fullscreen. ++ if (IsFullscreen()) ++ ToggleFullscreen(); ++ ++ shell_surface_->UnSetMaximized(); ++ connection()->ScheduleFlush(); ++} ++ ++PlatformWindowState WaylandSurface::GetPlatformWindowState() const { ++ return state_; ++} ++ ++void WaylandSurface::SizeConstraintsChanged() { ++ // Size constraints only make sense for normal windows. ++ if (!shell_surface_) ++ return; ++ ++ DCHECK(delegate()); ++ auto min_size = delegate()->GetMinimumSizeForWindow(); ++ auto max_size = delegate()->GetMaximumSizeForWindow(); ++ ++ if (min_size.has_value()) ++ shell_surface_->SetMinSize(min_size->width(), min_size->height()); ++ if (max_size.has_value()) ++ shell_surface_->SetMaxSize(max_size->width(), max_size->height()); ++ ++ connection()->ScheduleFlush(); ++} ++ ++void WaylandSurface::HandleSurfaceConfigure(int32_t width, ++ int32_t height, ++ bool is_maximized, ++ bool is_fullscreen, ++ bool is_activated) { ++ // Propagate the window state information to the client. ++ PlatformWindowState old_state = state_; ++ ++ // Ensure that manually handled state changes to fullscreen correspond to the ++ // configuration events from a compositor. ++ DCHECK_EQ(is_fullscreen, IsFullscreen()); ++ ++ // There are two cases, which must be handled for the minimized state. ++ // The first one is the case, when the surface goes into the minimized state ++ // (check comment in WaylandSurface::Minimize), and the second case is when ++ // the surface still has been minimized, but another configuration event with ++ // !is_activated comes. For this, check if the WaylandSurface has been ++ // minimized before and !is_activated is sent. ++ if ((is_minimizing_ || IsMinimized()) && !is_activated) { ++ is_minimizing_ = false; ++ state_ = PlatformWindowState::kMinimized; ++ } else if (is_fullscreen) { ++ // To ensure the |delegate()| is notified about state changes to fullscreen, ++ // assume the old_state is UNKNOWN (check comment in ToggleFullscreen). ++ old_state = PlatformWindowState::kUnknown; ++ DCHECK(state_ == PlatformWindowState::kFullScreen); ++ } else if (is_maximized) { ++ state_ = PlatformWindowState::kMaximized; ++ } else { ++ state_ = PlatformWindowState::kNormal; ++ } ++ const bool state_changed = old_state != state_; ++ const bool is_normal = !IsFullscreen() && !IsMaximized(); ++ ++ // Update state before notifying delegate. ++ const bool did_active_change = is_active_ != is_activated; ++ is_active_ = is_activated; ++ ++ // Rather than call SetBounds here for every configure event, just save the ++ // most recent bounds, and have WaylandConnection call ApplyPendingBounds ++ // when it has finished processing events. We may get many configure events ++ // in a row during an interactive resize, and only the last one matters. ++ // ++ // Width or height set to 0 means that we should decide on width and height by ++ // ourselves, but we don't want to set them to anything else. Use restored ++ // bounds size or the current bounds iff the current state is normal (neither ++ // maximized nor fullscreen). ++ // ++ // Note: if the browser was started with --start-fullscreen and a user exits ++ // the fullscreen mode, wayland may set the width and height to be 1. Instead, ++ // explicitly set the bounds to the current desired ones or the previous ++ // bounds. ++ if (width > 1 && height > 1) { ++ pending_bounds_dip_ = gfx::Rect(0, 0, width, height); ++ } else if (is_normal) { ++ pending_bounds_dip_.set_size( ++ gfx::ScaleToRoundedSize(GetRestoredBoundsInPixels().IsEmpty() ++ ? GetBounds().size() ++ : GetRestoredBoundsInPixels().size(), ++ ++ 1.0 / buffer_scale())); ++ } ++ ++ if (state_changed) { ++ // The |restored_bounds_| are used when the window gets back to normal ++ // state after it went maximized or fullscreen. So we reset these if the ++ // window has just become normal and store the current bounds if it is ++ // either going out of normal state or simply changes the state and we don't ++ // have any meaningful value stored. ++ if (is_normal) { ++ SetRestoredBoundsInPixels({}); ++ } else if (old_state == PlatformWindowState::kNormal || ++ GetRestoredBoundsInPixels().IsEmpty()) { ++ SetRestoredBoundsInPixels(GetBounds()); ++ } ++ ++ delegate()->OnWindowStateChanged(state_); ++ } ++ ++ ApplyPendingBounds(); ++ ++ if (did_active_change) ++ delegate()->OnActivationChanged(is_active_); ++ ++ MaybeTriggerPendingStateChange(); ++} ++ ++void WaylandSurface::OnDragEnter(const gfx::PointF& point, ++ std::unique_ptr<OSExchangeData> data, ++ int operation) { ++ WmDropHandler* drop_handler = GetWmDropHandler(*this); ++ if (!drop_handler) ++ return; ++ drop_handler->OnDragEnter(point, std::move(data), operation); ++} ++ ++int WaylandSurface::OnDragMotion(const gfx::PointF& point, ++ uint32_t time, ++ int operation) { ++ WmDropHandler* drop_handler = GetWmDropHandler(*this); ++ if (!drop_handler) ++ return 0; ++ ++ return drop_handler->OnDragMotion(point, operation); ++} ++ ++void WaylandSurface::OnDragDrop(std::unique_ptr<OSExchangeData> data) { ++ WmDropHandler* drop_handler = GetWmDropHandler(*this); ++ if (!drop_handler) ++ return; ++ drop_handler->OnDragDrop(std::move(data)); ++} ++ ++void WaylandSurface::OnDragLeave() { ++ WmDropHandler* drop_handler = GetWmDropHandler(*this); ++ if (!drop_handler) ++ return; ++ drop_handler->OnDragLeave(); ++} ++ ++void WaylandSurface::OnDragSessionClose(uint32_t dnd_action) { ++ std::move(drag_closed_callback_).Run(dnd_action); ++ connection()->ResetPointerFlags(); ++} ++ ++bool WaylandSurface::OnInitialize(PlatformWindowInitProperties properties) { ++ CreateShellSurface(); ++ if (shell_surface_ && !properties.wm_class_class.empty()) ++ shell_surface_->SetAppId(properties.wm_class_class); ++ return !!shell_surface_; ++} ++ ++bool WaylandSurface::IsMinimized() const { ++ return state_ == PlatformWindowState::kMinimized; ++} ++ ++bool WaylandSurface::IsMaximized() const { ++ return state_ == PlatformWindowState::kMaximized; ++} ++ ++bool WaylandSurface::IsFullscreen() const { ++ return state_ == PlatformWindowState::kFullScreen; ++} ++ ++void WaylandSurface::MaybeTriggerPendingStateChange() { ++ if (pending_state_ == PlatformWindowState::kUnknown || !is_active_) ++ return; ++ DCHECK_EQ(pending_state_, PlatformWindowState::kFullScreen); ++ pending_state_ = PlatformWindowState::kUnknown; ++ ToggleFullscreen(); ++} ++ ++WmMoveResizeHandler* WaylandSurface::AsWmMoveResizeHandler() { ++ return static_cast<WmMoveResizeHandler*>(this); ++} ++ ++} // namespace ui +diff --git a/ui/ozone/platform/wayland/host/wayland_surface.h b/ui/ozone/platform/wayland/host/wayland_surface.h +new file mode 100644 +index 000000000000..0f7204db3c48 +--- /dev/null ++++ b/ui/ozone/platform/wayland/host/wayland_surface.h +@@ -0,0 +1,114 @@ ++// Copyright 2019 The Chromium Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SURFACE_H_ ++#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SURFACE_H_ ++ ++#include "ui/ozone/platform/wayland/host/wayland_window.h" ++ ++#include "ui/platform_window/platform_window_handler/wm_drag_handler.h" ++#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h" ++ ++namespace ui { ++ ++class ShellSurfaceWrapper; ++ ++class WaylandSurface : public WaylandWindow, ++ public WmMoveResizeHandler, ++ public WmDragHandler { ++ public: ++ WaylandSurface(PlatformWindowDelegate* delegate, ++ WaylandConnection* connection); ++ ~WaylandSurface() override; ++ ++ ShellSurfaceWrapper* shell_surface() const { return shell_surface_.get(); } ++ ++ // Apply the bounds specified in the most recent configure event. This should ++ // be called after processing all pending events in the wayland connection. ++ void ApplyPendingBounds(); ++ ++ // WmMoveResizeHandler ++ void DispatchHostWindowDragMovement( ++ int hittest, ++ const gfx::Point& pointer_location_in_px) override; ++ ++ // WmDragHandler ++ void StartDrag(const ui::OSExchangeData& data, ++ int operation, ++ gfx::NativeCursor cursor, ++ base::OnceCallback<void(int)> callback) override; ++ ++ // PlatformWindow ++ void Show(bool inactive) override; ++ void Hide() override; ++ bool IsVisible() const override; ++ void SetTitle(const base::string16& title) override; ++ void ToggleFullscreen() override; ++ void Maximize() override; ++ void Minimize() override; ++ void Restore() override; ++ PlatformWindowState GetPlatformWindowState() const override; ++ void SizeConstraintsChanged() override; ++ ++ private: ++ // WaylandWindow overrides: ++ void HandleSurfaceConfigure(int32_t widht, ++ int32_t height, ++ bool is_maximized, ++ bool is_fullscreen, ++ bool is_activated) override; ++ void OnDragEnter(const gfx::PointF& point, ++ std::unique_ptr<OSExchangeData> data, ++ int operation) override; ++ int OnDragMotion(const gfx::PointF& point, ++ uint32_t time, ++ int operation) override; ++ void OnDragDrop(std::unique_ptr<OSExchangeData> data) override; ++ void OnDragLeave() override; ++ void OnDragSessionClose(uint32_t dnd_action) override; ++ bool OnInitialize(PlatformWindowInitProperties properties) override; ++ ++ bool IsMinimized() const; ++ bool IsMaximized() const; ++ bool IsFullscreen() const; ++ ++ void MaybeTriggerPendingStateChange(); ++ ++ // Creates a surface window, which is visible as a main window. ++ void CreateShellSurface(); ++ ++ WmMoveResizeHandler* AsWmMoveResizeHandler(); ++ ++ // Wrappers around shell surface. ++ std::unique_ptr<ShellSurfaceWrapper> shell_surface_; ++ ++ base::OnceCallback<void(int)> drag_closed_callback_; ++ ++ // These bounds attributes below have suffices that indicate units used. ++ // Wayland operates in DIP but the platform operates in physical pixels so ++ // our WaylandSurface is the link that has to translate the units. See also ++ // comments in the implementation. ++ // ++ // Bounds that will be applied when the window state is finalized. The window ++ // may get several configuration events that update the pending bounds, and ++ // only upon finalizing the state is the latest value stored as the current ++ // bounds via |ApplyPendingBounds|. Measured in DIP because updated in the ++ // handler that receives DIP from Wayland. ++ gfx::Rect pending_bounds_dip_; ++ ++ // Stores current states of the window. ++ PlatformWindowState state_; ++ // Stores a pending state of the window, which is used before the surface is ++ // activated. ++ PlatformWindowState pending_state_; ++ ++ bool is_active_ = false; ++ bool is_minimizing_ = false; ++ ++ DISALLOW_COPY_AND_ASSIGN(WaylandSurface); ++}; ++ ++} // namespace ui ++ ++#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SURFACE_H_ +diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc +index 1f8cc423d4aa..cdc95f904347 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window.cc ++++ b/ui/ozone/platform/wayland/host/wayland_window.cc +@@ -9,9 +9,6 @@ + + #include "base/bind.h" + #include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h" +-#include "ui/base/dragdrop/drag_drop_types.h" +-#include "ui/base/dragdrop/os_exchange_data.h" +-#include "ui/base/hit_test.h" + #include "ui/events/event.h" + #include "ui/events/event_utils.h" + #include "ui/events/ozone/events_ozone.h" +@@ -19,36 +16,19 @@ + #include "ui/ozone/platform/wayland/common/wayland_util.h" + #include "ui/ozone/platform/wayland/host/shell_object_factory.h" + #include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h" +-#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h" + #include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h" + #include "ui/ozone/platform/wayland/host/wayland_connection.h" + #include "ui/ozone/platform/wayland/host/wayland_cursor_position.h" + #include "ui/ozone/platform/wayland/host/wayland_output_manager.h" + #include "ui/ozone/platform/wayland/host/wayland_pointer.h" +-#include "ui/platform_window/platform_window_handler/wm_drop_handler.h" + + namespace ui { + + WaylandWindow::WaylandWindow(PlatformWindowDelegate* delegate, + WaylandConnection* connection) +- : delegate_(delegate), +- connection_(connection), +- state_(PlatformWindowState::kNormal), +- pending_state_(PlatformWindowState::kUnknown) { +- // Set a class property key, which allows |this| to be used for interactive +- // events, e.g. move or resize. +- SetWmMoveResizeHandler(this, AsWmMoveResizeHandler()); +- +- // Set a class property key, which allows |this| to be used for drag action. +- SetWmDragHandler(this, this); +-} ++ : delegate_(delegate), connection_(connection) {} + + WaylandWindow::~WaylandWindow() { +- if (drag_closed_callback_) { +- std::move(drag_closed_callback_) +- .Run(DragDropTypes::DragOperation::DRAG_NONE); +- } +- + PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); + if (surface_) + connection_->wayland_window_manager()->RemoveWindow(GetWidget()); +@@ -127,13 +107,6 @@ void WaylandWindow::CreateShellPopup() { + parent_window_->set_child_window(this); + } + +-void WaylandWindow::CreateShellSurface() { +- ShellObjectFactory factory; +- shell_surface_ = factory.CreateShellSurfaceWrapper(connection_, this); +- if (!shell_surface_) +- CHECK(false) << "Failed to initialize Wayland shell surface"; +-} +- + void WaylandWindow::CreateAndShowTooltipSubSurface() { + // Since Aura does not not provide a reference parent window, needed by + // Wayland, we get the current focused window to place and show the tooltips. +@@ -172,21 +145,6 @@ void WaylandWindow::CreateAndShowTooltipSubSurface() { + connection_->ScheduleFlush(); + } + +-void WaylandWindow::ApplyPendingBounds() { +- if (pending_bounds_dip_.IsEmpty()) +- return; +- DCHECK(shell_surface_); +- +- SetBoundsDip(pending_bounds_dip_); +- shell_surface_->SetWindowGeometry(pending_bounds_dip_); +- pending_bounds_dip_ = gfx::Rect(); +- connection_->ScheduleFlush(); +- +- // Opaque region is based on the size of the window. Thus, update the region +- // on each update. +- MaybeUpdateOpaqueRegion(); +-} +- + void WaylandWindow::SetPointerFocus(bool focus) { + has_pointer_focus_ = focus; + +@@ -197,36 +155,10 @@ void WaylandWindow::SetPointerFocus(bool focus) { + connection_->SetCursorBitmap(bitmap_->bitmaps(), bitmap_->hotspot()); + } + +-void WaylandWindow::DispatchHostWindowDragMovement( +- int hittest, +- const gfx::Point& pointer_location_in_px) { +- DCHECK(shell_surface_); +- +- connection_->ResetPointerFlags(); +- if (hittest == HTCAPTION) +- shell_surface_->SurfaceMove(connection_); +- else +- shell_surface_->SurfaceResize(connection_, hittest); +- +- connection_->ScheduleFlush(); +-} +- +-void WaylandWindow::StartDrag(const ui::OSExchangeData& data, +- int operation, +- gfx::NativeCursor cursor, +- base::OnceCallback<void(int)> callback) { +- DCHECK(!drag_closed_callback_); +- drag_closed_callback_ = std::move(callback); +- connection_->StartDrag(data, operation); +-} +- + void WaylandWindow::Show(bool inactive) { + if (!is_tooltip_) // Tooltip windows should not get keyboard focus + set_keyboard_focus(true); + +- if (shell_surface_) +- return; +- + if (is_tooltip_) { + CreateAndShowTooltipSubSurface(); + return; +@@ -260,8 +192,7 @@ void WaylandWindow::Hide() { + + // Detach buffer from surface in order to completely shutdown popups and + // tooltips, and release resources. +- if (!shell_surface()) +- connection_->buffer_manager_host()->ResetSurfaceContents(GetWidget()); ++ connection_->buffer_manager_host()->ResetSurfaceContents(GetWidget()); + } + + void WaylandWindow::Close() { +@@ -269,9 +200,7 @@ void WaylandWindow::Close() { + } + + bool WaylandWindow::IsVisible() const { +- // X and Windows return true if the window is minimized. For consistency, do +- // the same. +- return (!!shell_surface_ || !!shell_popup_) || IsMinimized(); ++ return !!shell_popup_; + } + + void WaylandWindow::PrepareForShutdown() {} +@@ -281,6 +210,10 @@ void WaylandWindow::SetBounds(const gfx::Rect& bounds_px) { + return; + bounds_px_ = bounds_px; + ++ // Opaque region is based on the size of the window. Thus, update the region ++ // on each update. ++ MaybeUpdateOpaqueRegion(); ++ + delegate_->OnBoundsChanged(bounds_px_); + } + +@@ -288,11 +221,7 @@ gfx::Rect WaylandWindow::GetBounds() { + return bounds_px_; + } + +-void WaylandWindow::SetTitle(const base::string16& title) { +- DCHECK(shell_surface_); +- shell_surface_->SetTitle(title); +- connection_->ScheduleFlush(); +-} ++void WaylandWindow::SetTitle(const base::string16& title) {} + + void WaylandWindow::SetCapture() { + // Wayland does implicit grabs, and doesn't allow for explicit grabs. The +@@ -309,79 +238,18 @@ bool WaylandWindow::HasCapture() const { + return shell_popup() ? true : has_implicit_grab_; + } + +-void WaylandWindow::ToggleFullscreen() { +- DCHECK(shell_surface_); ++void WaylandWindow::ToggleFullscreen() {} + +- // There are some cases, when Chromium triggers a fullscreen state change +- // before the surface is activated. In such cases, Wayland may ignore state +- // changes and such flags as --kiosk or --start-fullscreen will be ignored. +- // To overcome this, set a pending state, and once the surface is activated, +- // trigger the change. +- if (!is_active_) { +- DCHECK(!IsFullscreen()); +- pending_state_ = PlatformWindowState::kFullScreen; +- return; +- } +- +- // TODO(msisov, tonikitoo): add multiscreen support. As the documentation says +- // if shell_surface_set_fullscreen() is not provided with wl_output, it's up +- // to the compositor to choose which display will be used to map this surface. +- if (!IsFullscreen()) { +- // Fullscreen state changes have to be handled manually and then checked +- // against configuration events, which come from a compositor. The reason +- // of manually changing the |state_| is that the compositor answers about +- // state changes asynchronously, which leads to a wrong return value in +- // DesktopWindowTreeHostPlatform::IsFullscreen, for example, and media +- // files can never be set to fullscreen. +- state_ = PlatformWindowState::kFullScreen; +- shell_surface_->SetFullscreen(); +- } else { +- // Check the comment above. If it's not handled synchronously, media files +- // may not leave the fullscreen mode. +- state_ = PlatformWindowState::kUnknown; +- shell_surface_->UnSetFullscreen(); +- } +- +- connection_->ScheduleFlush(); +-} ++void WaylandWindow::Maximize() {} + +-void WaylandWindow::Maximize() { +- DCHECK(shell_surface_); ++void WaylandWindow::Minimize() {} + +- if (IsFullscreen()) +- ToggleFullscreen(); +- +- shell_surface_->SetMaximized(); +- connection_->ScheduleFlush(); +-} +- +-void WaylandWindow::Minimize() { +- DCHECK(shell_surface_); +- DCHECK(!is_minimizing_); +- // Wayland doesn't explicitly say if a window is minimized. Instead, it +- // notifies that the window is not activated. But there are many cases, when +- // the window is not minimized and deactivated. In order to properly record +- // the minimized state, mark this window as being minimized. And as soon as a +- // configuration event comes, check if the window has been deactivated and has +- // |is_minimizing_| set. +- is_minimizing_ = true; +- shell_surface_->SetMinimized(); +- connection_->ScheduleFlush(); +-} +- +-void WaylandWindow::Restore() { +- DCHECK(shell_surface_); +- +- // Unfullscreen the window if it is fullscreen. +- if (IsFullscreen()) +- ToggleFullscreen(); +- +- shell_surface_->UnSetMaximized(); +- connection_->ScheduleFlush(); +-} ++void WaylandWindow::Restore() {} + + PlatformWindowState WaylandWindow::GetPlatformWindowState() const { +- return state_; ++ // Remove normal state for all the other types of windows as it's only the ++ // WaylandSurface that supports state changes. ++ return PlatformWindowState::kNormal; + } + + void WaylandWindow::Activate() { +@@ -448,22 +316,7 @@ void WaylandWindow::SetWindowIcons(const gfx::ImageSkia& window_icon, + NOTIMPLEMENTED_LOG_ONCE(); + } + +-void WaylandWindow::SizeConstraintsChanged() { +- // Size constraints only make sense for normal windows. +- if (!shell_surface_) +- return; +- +- DCHECK(delegate_); +- auto min_size = delegate_->GetMinimumSizeForWindow(); +- auto max_size = delegate_->GetMaximumSizeForWindow(); +- +- if (min_size.has_value()) +- shell_surface_->SetMinSize(min_size->width(), min_size->height()); +- if (max_size.has_value()) +- shell_surface_->SetMaxSize(max_size->width(), max_size->height()); +- +- connection_->ScheduleFlush(); +-} ++void WaylandWindow::SizeConstraintsChanged() {} + + bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) { + // This window is a nested popup window, all the events must be forwarded +@@ -508,7 +361,7 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) { + if (event->IsLocatedEvent() && shell_popup()) { + // Parent window of the main menu window is not a popup, but rather an + // xdg surface. +- DCHECK(!parent_window_->shell_popup() && parent_window_->shell_surface()); ++ DCHECK(!parent_window_->shell_popup() || !parent_window_->is_tooltip_); + auto* window = + connection_->wayland_window_manager()->GetCurrentFocusedWindow(); + if (window) { +@@ -524,92 +377,13 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) { + return POST_DISPATCH_STOP_PROPAGATION; + } + +-void WaylandWindow::HandleSurfaceConfigure(int32_t width, ++void WaylandWindow::HandleSurfaceConfigure(int32_t widht, + int32_t height, + bool is_maximized, + bool is_fullscreen, + bool is_activated) { +- DCHECK(!shell_popup()); +- +- // Propagate the window state information to the client. +- PlatformWindowState old_state = state_; +- +- // Ensure that manually handled state changes to fullscreen correspond to the +- // configuration events from a compositor. +- DCHECK_EQ(is_fullscreen, IsFullscreen()); +- +- // There are two cases, which must be handled for the minimized state. +- // The first one is the case, when the surface goes into the minimized state +- // (check comment in WaylandWindow::Minimize), and the second case is when the +- // surface still has been minimized, but another cofiguration event with +- // !is_activated comes. For this, check if the WaylandWindow has been +- // minimized before and !is_activated is sent. +- if ((is_minimizing_ || IsMinimized()) && !is_activated) { +- is_minimizing_ = false; +- state_ = PlatformWindowState::kMinimized; +- } else if (is_fullscreen) { +- // To ensure the |delegate_| is notified about state changes to fullscreen, +- // assume the old_state is UNKNOWN (check comment in ToggleFullscreen). +- old_state = PlatformWindowState::kUnknown; +- DCHECK(state_ == PlatformWindowState::kFullScreen); +- } else if (is_maximized) { +- state_ = PlatformWindowState::kMaximized; +- } else { +- state_ = PlatformWindowState::kNormal; +- } +- const bool state_changed = old_state != state_; +- const bool is_normal = !IsFullscreen() && !IsMaximized(); +- +- // Update state before notifying delegate. +- const bool did_active_change = is_active_ != is_activated; +- is_active_ = is_activated; +- +- // Rather than call SetBounds here for every configure event, just save the +- // most recent bounds, and have WaylandConnection call ApplyPendingBounds +- // when it has finished processing events. We may get many configure events +- // in a row during an interactive resize, and only the last one matters. +- // +- // Width or height set to 0 means that we should decide on width and height by +- // ourselves, but we don't want to set them to anything else. Use restored +- // bounds size or the current bounds iff the current state is normal (neither +- // maximized nor fullscreen). +- // +- // Note: if the browser was started with --start-fullscreen and a user exits +- // the fullscreen mode, wayland may set the width and height to be 1. Instead, +- // explicitly set the bounds to the current desired ones or the previous +- // bounds. +- if (width > 1 && height > 1) { +- pending_bounds_dip_ = gfx::Rect(0, 0, width, height); +- } else if (is_normal) { +- pending_bounds_dip_.set_size(gfx::ScaleToRoundedSize( +- restored_bounds_px_.IsEmpty() ? GetBounds().size() +- : restored_bounds_px_.size(), +- +- 1.0 / buffer_scale_)); +- } +- +- if (state_changed) { +- // The |restored_bounds_| are used when the window gets back to normal +- // state after it went maximized or fullscreen. So we reset these if the +- // window has just become normal and store the current bounds if it is +- // either going out of normal state or simply changes the state and we don't +- // have any meaningful value stored. +- if (is_normal) { +- SetRestoredBoundsInPixels({}); +- } else if (old_state == PlatformWindowState::kNormal || +- restored_bounds_px_.IsEmpty()) { +- SetRestoredBoundsInPixels(bounds_px_); +- } +- +- delegate_->OnWindowStateChanged(state_); +- } +- +- ApplyPendingBounds(); +- +- if (did_active_change) +- delegate_->OnActivationChanged(is_active_); +- +- MaybeTriggerPendingStateChange(); ++ NOTREACHED() ++ << "Only shell surfaces must receive HandleSurfaceConfigure calls."; + } + + void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds_dip) { +@@ -671,40 +445,22 @@ void WaylandWindow::OnCloseRequest() { + + void WaylandWindow::OnDragEnter(const gfx::PointF& point, + std::unique_ptr<OSExchangeData> data, +- int operation) { +- WmDropHandler* drop_handler = GetWmDropHandler(*this); +- if (!drop_handler) +- return; +- drop_handler->OnDragEnter(point, std::move(data), operation); +-} ++ int operation) {} + + int WaylandWindow::OnDragMotion(const gfx::PointF& point, + uint32_t time, + int operation) { +- WmDropHandler* drop_handler = GetWmDropHandler(*this); +- if (!drop_handler) +- return 0; +- +- return drop_handler->OnDragMotion(point, operation); ++ return -1; + } + +-void WaylandWindow::OnDragDrop(std::unique_ptr<OSExchangeData> data) { +- WmDropHandler* drop_handler = GetWmDropHandler(*this); +- if (!drop_handler) +- return; +- drop_handler->OnDragDrop(std::move(data)); +-} ++void WaylandWindow::OnDragDrop(std::unique_ptr<OSExchangeData> data) {} + +-void WaylandWindow::OnDragLeave() { +- WmDropHandler* drop_handler = GetWmDropHandler(*this); +- if (!drop_handler) +- return; +- drop_handler->OnDragLeave(); +-} ++void WaylandWindow::OnDragLeave() {} + +-void WaylandWindow::OnDragSessionClose(uint32_t dnd_action) { +- std::move(drag_closed_callback_).Run(dnd_action); +- connection_->ResetPointerFlags(); ++void WaylandWindow::OnDragSessionClose(uint32_t dnd_action) {} ++ ++void WaylandWindow::SetBoundsDip(const gfx::Rect& bounds_dip) { ++ SetBounds(gfx::ScaleToRoundedRect(bounds_dip, buffer_scale_)); + } + + bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) { +@@ -752,15 +508,11 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) { + case ui::PlatformWindowType::kWindow: + case ui::PlatformWindowType::kBubble: + case ui::PlatformWindowType::kDrag: +- // TODO(msisov): Figure out what kind of surface we need to create for +- // bubble and drag windows. +- CreateShellSurface(); ++ if (!OnInitialize(std::move(properties))) ++ return false; + break; + } + +- if (shell_surface_ && !properties.wm_class_class.empty()) +- shell_surface_->SetAppId(properties.wm_class_class); +- + connection_->ScheduleFlush(); + + PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); +@@ -773,10 +525,6 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) { + return true; + } + +-void WaylandWindow::SetBoundsDip(const gfx::Rect& bounds_dip) { +- SetBounds(gfx::ScaleToRoundedRect(bounds_dip, buffer_scale_)); +-} +- + void WaylandWindow::SetBufferScale(int32_t new_scale, bool update_bounds) { + DCHECK_GT(new_scale, 0); + +@@ -793,26 +541,6 @@ void WaylandWindow::SetBufferScale(int32_t new_scale, bool update_bounds) { + connection_->ScheduleFlush(); + } + +-bool WaylandWindow::IsMinimized() const { +- return state_ == PlatformWindowState::kMinimized; +-} +- +-bool WaylandWindow::IsMaximized() const { +- return state_ == PlatformWindowState::kMaximized; +-} +- +-bool WaylandWindow::IsFullscreen() const { +- return state_ == PlatformWindowState::kFullScreen; +-} +- +-void WaylandWindow::MaybeTriggerPendingStateChange() { +- if (pending_state_ == PlatformWindowState::kUnknown || !is_active_) +- return; +- DCHECK_EQ(pending_state_, PlatformWindowState::kFullScreen); +- pending_state_ = PlatformWindowState::kUnknown; +- ToggleFullscreen(); +-} +- + WaylandWindow* WaylandWindow::GetParentWindow( + gfx::AcceleratedWidget parent_widget) { + auto* parent_window = +@@ -838,10 +566,6 @@ WaylandWindow* WaylandWindow::GetRootParentWindow() { + return parent_window_ ? parent_window_->GetRootParentWindow() : this; + } + +-WmMoveResizeHandler* WaylandWindow::AsWmMoveResizeHandler() { +- return static_cast<WmMoveResizeHandler*>(this); +-} +- + void WaylandWindow::AddSurfaceListener() { + static struct wl_surface_listener surface_listener = { + &WaylandWindow::Enter, +@@ -960,10 +684,12 @@ gfx::Rect WaylandWindow::AdjustPopupWindowPosition() const { + // the parent menu window, which results in showing it on a second display if + // more than one display is used. + if (parent_window_->shell_popup() && parent_window_->parent_window_ && +- !parent_window_->parent_window_->IsMaximized()) { ++ (parent_window_->parent_window()->GetPlatformWindowState() != ++ PlatformWindowState::kMaximized)) { + auto* top_level_window = parent_window_->parent_window_; + DCHECK(top_level_window && !top_level_window->shell_popup()); +- if (new_bounds_dip.x() <= 0 && !top_level_window->IsMaximized()) { ++ if (new_bounds_dip.x() <= 0 && top_level_window->GetPlatformWindowState() != ++ PlatformWindowState::kMaximized) { + // Position the child menu window on the right side of the parent window + // and let the Wayland compositor decide how to do constraint + // adjustements. +@@ -995,6 +721,10 @@ bool WaylandWindow::IsOpaqueWindow() const { + return opacity_ == ui::PlatformWindowOpacity::kOpaqueWindow; + } + ++bool WaylandWindow::OnInitialize(PlatformWindowInitProperties properties) { ++ return true; ++} ++ + // static + void WaylandWindow::Enter(void* data, + struct wl_surface* wl_surface, +diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h +index b8cdc991e30e..b9ee70d0ecd2 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window.h ++++ b/ui/ozone/platform/wayland/host/wayland_window.h +@@ -19,8 +19,6 @@ + #include "ui/ozone/platform/wayland/common/wayland_object.h" + #include "ui/platform_window/platform_window.h" + #include "ui/platform_window/platform_window_delegate.h" +-#include "ui/platform_window/platform_window_handler/wm_drag_handler.h" +-#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h" + #include "ui/platform_window/platform_window_init_properties.h" + + namespace gfx { +@@ -33,12 +31,8 @@ class BitmapCursorOzone; + class OSExchangeData; + class WaylandConnection; + class ShellPopupWrapper; +-class ShellSurfaceWrapper; + +-class WaylandWindow : public PlatformWindow, +- public PlatformEventDispatcher, +- public WmMoveResizeHandler, +- public WmDragHandler { ++class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { + public: + ~WaylandWindow() override; + +@@ -59,17 +53,12 @@ class WaylandWindow : public PlatformWindow, + void UpdateBufferScale(bool update_bounds); + + wl_surface* surface() const { return surface_.get(); } +- ShellSurfaceWrapper* shell_surface() const { return shell_surface_.get(); } + ShellPopupWrapper* shell_popup() const { return shell_popup_.get(); } + + WaylandWindow* parent_window() const { return parent_window_; } + + gfx::AcceleratedWidget GetWidget() const; + +- // Apply the bounds specified in the most recent configure event. This should +- // be called after processing all pending events in the wayland connection. +- void ApplyPendingBounds(); +- + // Set whether this window has pointer focus and should dispatch mouse events. + void SetPointerFocus(bool focus); + bool has_pointer_focus() const { return has_pointer_focus_; } +@@ -94,23 +83,10 @@ class WaylandWindow : public PlatformWindow, + + int32_t buffer_scale() const { return buffer_scale_; } + +- bool is_active() const { return is_active_; } +- + const base::flat_set<uint32_t>& entered_outputs_ids() const { + return entered_outputs_ids_; + } + +- // WmMoveResizeHandler +- void DispatchHostWindowDragMovement( +- int hittest, +- const gfx::Point& pointer_location_in_px) override; +- +- // WmDragHandler +- void StartDrag(const ui::OSExchangeData& data, +- int operation, +- gfx::NativeCursor cursor, +- base::OnceCallback<void(int)> callback) override; +- + // PlatformWindow + void Show(bool inactive) override; + void Hide() override; +@@ -147,49 +123,49 @@ class WaylandWindow : public PlatformWindow, + bool CanDispatchEvent(const PlatformEvent& event) override; + uint32_t DispatchEvent(const PlatformEvent& event) override; + +- // Handles the configuration events coming from the surface (see +- // |XDGSurfaceWrapperStable::ConfigureTopLevel| and +- // |XDGSurfaceWrapperV6::ConfigureTopLevel|. The width and height come in +- // DIP of the output that the surface is currently bound to. +- void HandleSurfaceConfigure(int32_t widht, +- int32_t height, +- bool is_maximized, +- bool is_fullscreen, +- bool is_activated); ++ // Handles the configuration events coming from the shell objects. ++ // The width and height come in DIP of the output that the surface is ++ // currently bound to. ++ virtual void HandleSurfaceConfigure(int32_t widht, ++ int32_t height, ++ bool is_maximized, ++ bool is_fullscreen, ++ bool is_activated); + void HandlePopupConfigure(const gfx::Rect& bounds); + + void OnCloseRequest(); + +- void OnDragEnter(const gfx::PointF& point, +- std::unique_ptr<OSExchangeData> data, +- int operation); +- int OnDragMotion(const gfx::PointF& point, uint32_t time, int operation); +- void OnDragDrop(std::unique_ptr<OSExchangeData> data); +- void OnDragLeave(); +- void OnDragSessionClose(uint32_t dnd_action); ++ // Notifies about drag/drop session events. ++ virtual void OnDragEnter(const gfx::PointF& point, ++ std::unique_ptr<OSExchangeData> data, ++ int operation); ++ virtual int OnDragMotion(const gfx::PointF& point, ++ uint32_t time, ++ int operation); ++ virtual void OnDragDrop(std::unique_ptr<OSExchangeData> data); ++ virtual void OnDragLeave(); ++ virtual void OnDragSessionClose(uint32_t dnd_action); ++ ++ protected: ++ WaylandWindow(PlatformWindowDelegate* delegate, ++ WaylandConnection* connection); ++ ++ WaylandConnection* connection() { return connection_; } ++ PlatformWindowDelegate* delegate() { return delegate_; } ++ ++ // Sets bounds in dip. ++ void SetBoundsDip(const gfx::Rect& bounds_dip); + + private: + FRIEND_TEST_ALL_PREFIXES(WaylandScreenTest, SetBufferScale); + +- WaylandWindow(PlatformWindowDelegate* delegate, +- WaylandConnection* connection); +- + // Initializes the WaylandWindow with supplied properties. + bool Initialize(PlatformWindowInitProperties properties); + +- void SetBoundsDip(const gfx::Rect& bounds_dip); + void SetBufferScale(int32_t scale, bool update_bounds); + +- bool IsMinimized() const; +- bool IsMaximized() const; +- bool IsFullscreen() const; +- +- void MaybeTriggerPendingStateChange(); +- + // Creates a popup window, which is visible as a menu window. + void CreateShellPopup(); +- // Creates a surface window, which is visible as a main window. +- void CreateShellSurface(); + // Creates (if necessary) and show subsurface window, to host + // tooltip's content. + void CreateAndShowTooltipSubSurface(); +@@ -200,8 +176,6 @@ class WaylandWindow : public PlatformWindow, + // Returns a root parent window. + WaylandWindow* GetRootParentWindow(); + +- WmMoveResizeHandler* AsWmMoveResizeHandler(); +- + // Install a surface listener and start getting wl_output enter/leave events. + void AddSurfaceListener(); + +@@ -221,6 +195,9 @@ class WaylandWindow : public PlatformWindow, + + bool IsOpaqueWindow() const; + ++ // Additional initialization of derived classes. ++ virtual bool OnInitialize(PlatformWindowInitProperties properties); ++ + // wl_surface_listener + static void Enter(void* data, + struct wl_surface* wl_surface, +@@ -239,25 +216,11 @@ class WaylandWindow : public PlatformWindow, + + // Wrappers around xdg v5 and xdg v6 objects. WaylandWindow doesn't + // know anything about the version. +- std::unique_ptr<ShellSurfaceWrapper> shell_surface_; + std::unique_ptr<ShellPopupWrapper> shell_popup_; + + // The current cursor bitmap (immutable). + scoped_refptr<BitmapCursorOzone> bitmap_; + +- base::OnceCallback<void(int)> drag_closed_callback_; +- +- // These bounds attributes below have suffices that indicate units used. +- // Wayland operates in DIP but the platform operates in physical pixels so +- // our WaylandWindow is the link that has to translate the units. See also +- // comments in the implementation. +- // +- // Bounds that will be applied when the window state is finalized. The window +- // may get several configuration events that update the pending bounds, and +- // only upon finalizing the state is the latest value stored as the current +- // bounds via |ApplyPendingBounds|. Measured in DIP because updated in the +- // handler that receives DIP from Wayland. +- gfx::Rect pending_bounds_dip_; + // Current bounds of the platform window. + gfx::Rect bounds_px_; + // The bounds of the platform window before it went maximized or fullscreen. +@@ -275,18 +238,9 @@ class WaylandWindow : public PlatformWindow, + // We need it to place and size the menus properly. + float ui_scale_ = 1.0; + +- // Stores current states of the window. +- PlatformWindowState state_; +- // Stores a pending state of the window, which is used before the surface is +- // activated. +- PlatformWindowState pending_state_; +- + // Stores current opacity of the window. Set on ::Initialize call. + ui::PlatformWindowOpacity opacity_; + +- bool is_active_ = false; +- bool is_minimizing_ = false; +- + bool is_tooltip_ = false; + + // For top level window, stores IDs of outputs that the window is currently +diff --git a/ui/ozone/platform/wayland/host/wayland_window_factory.cc b/ui/ozone/platform/wayland/host/wayland_window_factory.cc +index 19da59357d55..892902e7f845 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window_factory.cc ++++ b/ui/ozone/platform/wayland/host/wayland_window_factory.cc +@@ -6,6 +6,7 @@ + + #include <memory> + ++#include "ui/ozone/platform/wayland/host/wayland_surface.h" + #include "ui/ozone/platform/wayland/host/wayland_window.h" + + namespace ui { +@@ -15,12 +16,30 @@ std::unique_ptr<WaylandWindow> WaylandWindow::Create( + PlatformWindowDelegate* delegate, + WaylandConnection* connection, + PlatformWindowInitProperties properties) { +- // TODO(msisov): once WaylandWindow becomes a base class, add switch cases to +- // create different Wayland windows. +- std::unique_ptr<WaylandWindow> window( +- new WaylandWindow(delegate, connection)); +- return window->Initialize(std::move(properties)) ? std::move(window) +- : nullptr; ++ std::unique_ptr<WaylandWindow> window; ++ switch (properties.type) { ++ case PlatformWindowType::kMenu: ++ case PlatformWindowType::kPopup: ++ // TODO(msisov): Add WaylandPopup. ++ window.reset(new WaylandWindow(delegate, connection)); ++ break; ++ case PlatformWindowType::kTooltip: ++ // TODO(msisov): Add WaylandSubsurface. ++ window.reset(new WaylandWindow(delegate, connection)); ++ break; ++ case PlatformWindowType::kWindow: ++ case PlatformWindowType::kBubble: ++ case PlatformWindowType::kDrag: ++ // TODO(msisov): Figure out what kind of surface we need to create for ++ // bubble and drag windows. ++ window.reset(new WaylandSurface(delegate, connection)); ++ break; ++ default: ++ NOTREACHED(); ++ break; ++ } ++ return window && window->Initialize(std::move(properties)) ? std::move(window) ++ : nullptr; + } + + } // namespace ui +\ No newline at end of file +diff --git a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc +index b03a28daadf2..132f740b0eb1 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc ++++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc +@@ -26,6 +26,7 @@ + #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h" + #include "ui/ozone/platform/wayland/test/wayland_test.h" + #include "ui/ozone/test/mock_platform_window_delegate.h" ++#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h" + #include "ui/platform_window/platform_window_init_properties.h" + + using ::testing::_; +@@ -249,7 +250,6 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) { + SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 2, + inactive_maximized.get()); + Sync(); +- EXPECT_FALSE(window_->is_active()); + VerifyAndClearExpectations(); + + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(), +@@ -259,7 +259,6 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) { + SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 3, + active_maximized.get()); + Sync(); +- EXPECT_TRUE(window_->is_active()); + VerifyAndClearExpectations(); + + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(), +@@ -703,21 +702,17 @@ TEST_P(WaylandWindowTest, ConfigureEventWithNulledSize) { + } + + TEST_P(WaylandWindowTest, OnActivationChanged) { +- EXPECT_FALSE(window_->is_active()); +- + { + ScopedWlArray states = InitializeWlArrayWithActivatedState(); + EXPECT_CALL(delegate_, OnActivationChanged(Eq(true))); + SendConfigureEvent(0, 0, 1, states.get()); + Sync(); +- EXPECT_TRUE(window_->is_active()); + } + + ScopedWlArray states; + EXPECT_CALL(delegate_, OnActivationChanged(Eq(false))); + SendConfigureEvent(0, 0, 2, states.get()); + Sync(); +- EXPECT_FALSE(window_->is_active()); + } + + TEST_P(WaylandWindowTest, OnAcceleratedWidgetDestroy) { +@@ -847,7 +842,7 @@ TEST_P(WaylandWindowTest, CanDispatchEventToMenuWindowNested) { + + TEST_P(WaylandWindowTest, DispatchWindowMove) { + EXPECT_CALL(*GetXdgSurface(), Move(_)); +- window_->DispatchHostWindowDragMovement(HTCAPTION, gfx::Point()); ++ ui::GetWmMoveResizeHandler(*window_)->DispatchHostWindowDragMovement(HTCAPTION, gfx::Point()); + } + + // Makes sure hit tests are converted into right edges. +@@ -855,11 +850,14 @@ TEST_P(WaylandWindowTest, DispatchWindowResize) { + std::vector<int> hit_test_values; + InitializeWithSupportedHitTestValues(&hit_test_values); + ++ auto* wm_move_resize_handler = ui::GetWmMoveResizeHandler(*window_); ++ + for (const int value : hit_test_values) { + { + uint32_t direction = wl::IdentifyDirection(*(connection_.get()), value); + EXPECT_CALL(*GetXdgSurface(), Resize(_, Eq(direction))); +- window_->DispatchHostWindowDragMovement(value, gfx::Point()); ++ wm_move_resize_handler->DispatchHostWindowDragMovement(value, ++ gfx::Point()); + } + } + } +diff --git a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc +index abf6e7fa6461..e85236ce47d7 100644 +--- a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc ++++ b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc +@@ -14,6 +14,7 @@ + #include "ui/gfx/geometry/rect.h" + #include "ui/ozone/platform/wayland/host/wayland_connection.h" + #include "ui/ozone/platform/wayland/host/wayland_pointer.h" ++#include "ui/ozone/platform/wayland/host/wayland_surface.h" + #include "ui/ozone/platform/wayland/host/wayland_window.h" + #include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h" + +@@ -290,8 +291,10 @@ bool XDGPopupWrapperImpl::InitializeStable(WaylandConnection* connection, + wayland_window_->parent_window()->shell_popup()); + parent_xdg_surface = popup->xdg_surface(); + } else { ++ WaylandSurface* wayland_surface = ++ static_cast<WaylandSurface*>(wayland_window_->parent_window()); + parent_xdg_surface = reinterpret_cast<XDGSurfaceWrapperImpl*>( +- wayland_window_->parent_window()->shell_surface()); ++ wayland_surface->shell_surface()); + } + + if (!parent_xdg_surface) +@@ -405,8 +408,10 @@ bool XDGPopupWrapperImpl::InitializeV6(WaylandConnection* connection, + wayland_window_->parent_window()->shell_popup()); + parent_xdg_surface = popup->xdg_surface(); + } else { ++ WaylandSurface* wayland_surface = ++ static_cast<WaylandSurface*>(wayland_window_->parent_window()); + parent_xdg_surface = reinterpret_cast<XDGSurfaceWrapperImpl*>( +- wayland_window_->parent_window()->shell_surface()); ++ wayland_surface->shell_surface()); + } + + if (!parent_xdg_surface) +-- +2.24.1 + diff --git a/0006-ozone-wayland-extract-popup-methods-to-WaylandPopup.patch b/0006-ozone-wayland-extract-popup-methods-to-WaylandPopup.patch new file mode 100644 index 000000000000..2d62b81885fd --- /dev/null +++ b/0006-ozone-wayland-extract-popup-methods-to-WaylandPopup.patch @@ -0,0 +1,1043 @@ +From 0cff96c5189fee16e0b2f79685c86e73216652aa Mon Sep 17 00:00:00 2001 +From: Maksim Sisov <msisov@igalia.com> +Date: Wed, 11 Dec 2019 09:50:09 +0000 +Subject: [PATCH 6/9] ozone/wayland: extract popup methods to WaylandPopup + +This change does not bring any functional changes and just +extracts menus/popups methods to a separate class named +WaylandPopup. + +Also, to avoid code duplicate, the XdgPopupWrapperImpl::Initialize +gets a parent xdg surface and passes it to ::InitializeStable and +::InitializeV6 methods. + +Test: ozone_unittests +Bug: 1028919 +Change-Id: I216e1374b7e6e97080e40043634db91a20a7b4cf +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1958989 +Reviewed-by: Michael Spang <spang@chromium.org> +Commit-Queue: Maksim Sisov <msisov@igalia.com> +Cr-Commit-Position: refs/heads/master@{#723755} +--- + ui/ozone/platform/wayland/BUILD.gn | 2 + + .../platform/wayland/common/wayland_util.cc | 5 + + .../platform/wayland/common/wayland_util.h | 4 + + .../platform/wayland/host/wayland_popup.cc | 210 +++++++++++++++ + .../platform/wayland/host/wayland_popup.h | 49 ++++ + .../platform/wayland/host/wayland_window.cc | 243 +++--------------- + .../platform/wayland/host/wayland_window.h | 41 +-- + .../wayland/host/wayland_window_factory.cc | 3 +- + .../wayland/host/xdg_popup_wrapper_impl.cc | 83 +++--- + .../wayland/host/xdg_popup_wrapper_impl.h | 8 +- + 10 files changed, 371 insertions(+), 277 deletions(-) + create mode 100644 ui/ozone/platform/wayland/host/wayland_popup.cc + create mode 100644 ui/ozone/platform/wayland/host/wayland_popup.h + +diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn +index b6059c7d9962..4bfe93352f34 100644 +--- a/ui/ozone/platform/wayland/BUILD.gn ++++ b/ui/ozone/platform/wayland/BUILD.gn +@@ -85,6 +85,8 @@ source_set("wayland") { + "host/wayland_output_manager.h", + "host/wayland_pointer.cc", + "host/wayland_pointer.h", ++ "host/wayland_popup.cc", ++ "host/wayland_popup.h", + "host/wayland_screen.cc", + "host/wayland_screen.h", + "host/wayland_shm.cc", +diff --git a/ui/ozone/platform/wayland/common/wayland_util.cc b/ui/ozone/platform/wayland/common/wayland_util.cc +index e0430b860adf..578bab8930c8 100644 +--- a/ui/ozone/platform/wayland/common/wayland_util.cc ++++ b/ui/ozone/platform/wayland/common/wayland_util.cc +@@ -155,4 +155,9 @@ gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds, + child_bounds.size()); + } + ++bool IsMenuType(ui::PlatformWindowType type) { ++ return type == ui::PlatformWindowType::kMenu || ++ type == ui::PlatformWindowType::kPopup; ++} ++ + } // namespace wl +diff --git a/ui/ozone/platform/wayland/common/wayland_util.h b/ui/ozone/platform/wayland/common/wayland_util.h +index 48332e059da0..3db369654025 100644 +--- a/ui/ozone/platform/wayland/common/wayland_util.h ++++ b/ui/ozone/platform/wayland/common/wayland_util.h +@@ -15,6 +15,7 @@ + #include "base/macros.h" + #include "ui/gfx/geometry/rect.h" + #include "ui/ozone/platform/wayland/common/wayland_object.h" ++#include "ui/platform_window/platform_window_init_properties.h" + + class SkBitmap; + +@@ -58,6 +59,9 @@ gfx::Rect TranslateBoundsToParentCoordinates(const gfx::Rect& child_bounds, + gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds, + const gfx::Rect& parent_bounds); + ++// Says if the type is kPopup or kMenu. ++bool IsMenuType(ui::PlatformWindowType type); ++ + } // namespace wl + + #endif // UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_ +diff --git a/ui/ozone/platform/wayland/host/wayland_popup.cc b/ui/ozone/platform/wayland/host/wayland_popup.cc +new file mode 100644 +index 000000000000..45aac6e51bfc +--- /dev/null ++++ b/ui/ozone/platform/wayland/host/wayland_popup.cc +@@ -0,0 +1,210 @@ ++// Copyright 2019 The Chromium Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#include "ui/ozone/platform/wayland/host/wayland_popup.h" ++ ++#include "ui/ozone/platform/wayland/common/wayland_util.h" ++#include "ui/ozone/platform/wayland/host/shell_object_factory.h" ++#include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h" ++#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h" ++#include "ui/ozone/platform/wayland/host/wayland_connection.h" ++ ++namespace ui { ++ ++WaylandPopup::WaylandPopup(PlatformWindowDelegate* delegate, ++ WaylandConnection* connection) ++ : WaylandWindow(delegate, connection) {} ++ ++WaylandPopup::~WaylandPopup() = default; ++ ++void WaylandPopup::CreateShellPopup() { ++ if (GetBounds().IsEmpty()) ++ return; ++ ++ // TODO(jkim): Consider how to support DropArrow window on tabstrip. ++ // When it starts dragging, as described the protocol, https://goo.gl/1Mskq3, ++ // the client must have an active implicit grab. If we try to create a popup ++ // window while dragging is executed, it gets 'popup_done' directly from ++ // Wayland compositor and it's destroyed through 'popup_done'. It causes ++ // a crash when aura::Window is destroyed. ++ // https://crbug.com/875164 ++ if (connection()->IsDragInProgress()) { ++ LOG(ERROR) << "Wayland can't create a popup window during dragging."; ++ return; ++ } ++ ++ DCHECK(parent_window() && !shell_popup_); ++ ++ auto bounds_px = AdjustPopupWindowPosition(); ++ ++ ShellObjectFactory factory; ++ shell_popup_ = factory.CreateShellPopupWrapper(connection(), this, bounds_px); ++ if (!shell_popup_) ++ CHECK(false) << "Failed to create Wayland shell popup"; ++ ++ parent_window()->set_child_window(this); ++} ++ ++void WaylandPopup::Show(bool inactive) { ++ set_keyboard_focus(true); ++ ++ if (!shell_popup_) { ++ // When showing a sub-menu after it has been previously shown and hidden, ++ // Wayland sends SetBounds prior to Show, and |bounds_px| takes the pixel ++ // bounds. This makes a difference against the normal flow when the ++ // window is created (see |Initialize|). To equalize things, rescale ++ // |bounds_px_| to DIP. It will be adjusted while creating the popup. ++ SetBounds(gfx::ScaleToRoundedRect(GetBounds(), 1.0 / ui_scale())); ++ CreateShellPopup(); ++ connection()->ScheduleFlush(); ++ } ++ ++ UpdateBufferScale(false); ++} ++ ++void WaylandPopup::Hide() { ++ if (child_window()) ++ child_window()->Hide(); ++ ++ if (shell_popup_) { ++ parent_window()->set_child_window(nullptr); ++ shell_popup_.reset(); ++ } ++ ++ // Detach buffer from surface in order to completely shutdown popups and ++ // tooltips, and release resources. ++ connection()->buffer_manager_host()->ResetSurfaceContents(GetWidget()); ++} ++ ++bool WaylandPopup::IsVisible() const { ++ return !!shell_popup_; ++} ++ ++bool WaylandPopup::HasCapture() const { ++ // WaylandPopups always have captures. ++ return shell_popup(); ++} ++ ++void WaylandPopup::HandlePopupConfigure(const gfx::Rect& bounds_dip) { ++ DCHECK(shell_popup()); ++ DCHECK(parent_window()); ++ ++ SetBufferScale(parent_window()->buffer_scale(), true); ++ ++ gfx::Rect new_bounds_dip = bounds_dip; ++ ++ // It's not enough to just set new bounds. If it is a menu window, whose ++ // parent is a top level window a.k.a browser window, it can be flipped ++ // vertically along y-axis and have negative values set. Chromium cannot ++ // understand that and starts to position nested menu windows incorrectly. To ++ // fix that, we have to bear in mind that Wayland compositor does not share ++ // global coordinates for any surfaces, and Chromium assumes the top level ++ // window is always located at 0,0 origin. What is more, child windows must ++ // always be positioned relative to parent window local surface coordinates. ++ // Thus, if the menu window is flipped along y-axis by Wayland and its origin ++ // is above the top level parent window, the origin of the top level window ++ // has to be shifted by that value on y-axis so that the origin of the menu ++ // becomes x,0, and events can be handled normally. ++ if (!wl::IsMenuType(parent_window()->type())) { ++ gfx::Rect parent_bounds = parent_window()->GetBounds(); ++ // The menu window is flipped along y-axis and have x,-y origin. Shift the ++ // parent top level window instead. ++ if (new_bounds_dip.y() < 0) { ++ // Move parent bounds along y-axis. ++ parent_bounds.set_y(-(new_bounds_dip.y() * buffer_scale())); ++ new_bounds_dip.set_y(0); ++ } else { ++ // If the menu window is located at correct origin from the browser point ++ // of view, return the top level window back to 0,0. ++ parent_bounds.set_y(0); ++ } ++ parent_window()->SetBounds(parent_bounds); ++ } else { ++ // The nested menu windows are located relative to the parent menu windows. ++ // Thus, the location must be translated to be relative to the top level ++ // window, which automatically becomes the same as relative to an origin of ++ // a display. ++ new_bounds_dip = gfx::ScaleToRoundedRect( ++ wl::TranslateBoundsToTopLevelCoordinates( ++ gfx::ScaleToRoundedRect(new_bounds_dip, buffer_scale()), ++ parent_window()->GetBounds()), ++ 1.0 / buffer_scale()); ++ DCHECK(new_bounds_dip.y() >= 0); ++ } ++ ++ SetBoundsDip(new_bounds_dip); ++} ++ ++void WaylandPopup::OnCloseRequest() { ++ // Before calling OnCloseRequest, the |shell_popup_| must become hidden and ++ // only then call OnCloseRequest(). ++ DCHECK(!shell_popup_); ++ WaylandWindow::OnCloseRequest(); ++} ++ ++bool WaylandPopup::OnInitialize(PlatformWindowInitProperties properties) { ++ if (!wl::IsMenuType(type())) ++ return false; ++ ++ set_parent_window(GetParentWindow(properties.parent_widget)); ++ if (!parent_window()) { ++ LOG(ERROR) << "Failed to get a parent window for this popup"; ++ return false; ++ } ++ // If parent window is known in advanced, we may set the scale early. ++ SetBufferScale(parent_window()->buffer_scale(), false); ++ set_ui_scale(parent_window()->ui_scale()); ++ CreateShellPopup(); ++ return true; ++} ++ ++gfx::Rect WaylandPopup::AdjustPopupWindowPosition() { ++ auto* top_level_parent = wl::IsMenuType(parent_window()->type()) ++ ? parent_window()->parent_window() ++ : parent_window(); ++ DCHECK(top_level_parent); ++ DCHECK(buffer_scale() == top_level_parent->buffer_scale()); ++ DCHECK(ui_scale() == top_level_parent->ui_scale()); ++ ++ // Chromium positions windows in screen coordinates, but Wayland requires them ++ // to be in local surface coordinates a.k.a relative to parent window. ++ const gfx::Rect parent_bounds_dip = ++ gfx::ScaleToRoundedRect(parent_window()->GetBounds(), 1.0 / ui_scale()); ++ gfx::Rect new_bounds_dip = ++ wl::TranslateBoundsToParentCoordinates(GetBounds(), parent_bounds_dip); ++ ++ // Chromium may decide to position nested menu windows on the left side ++ // instead of the right side of parent menu windows when the size of the ++ // window becomes larger than the display it is shown on. It's correct when ++ // the window is located on one display and occupies the whole work area, but ++ // as soon as it's moved and there is space on the right side, Chromium ++ // continues positioning the nested menus on the left side relative to the ++ // parent menu (Wayland does not provide clients with global coordinates). ++ // Instead, reposition that window to be on the right side of the parent menu ++ // window and let the compositor decide how to position it if it does not fit ++ // a single display. However, there is one exception - if the window is ++ // maximized, let Chromium position it on the left side as long as the Wayland ++ // compositor may decide to position the nested window on the right side of ++ // the parent menu window, which results in showing it on a second display if ++ // more than one display is used. ++ if (wl::IsMenuType(parent_window()->type()) && ++ parent_window()->parent_window() && ++ (parent_window()->parent_window()->GetPlatformWindowState() != ++ PlatformWindowState::kMaximized)) { ++ auto* top_level_window = parent_window()->parent_window(); ++ DCHECK(top_level_window && !wl::IsMenuType(top_level_window->type())); ++ if (new_bounds_dip.x() <= 0 && top_level_window->GetPlatformWindowState() != ++ PlatformWindowState::kMaximized) { ++ // Position the child menu window on the right side of the parent window ++ // and let the Wayland compositor decide how to do constraint ++ // adjustments. ++ int new_x = parent_bounds_dip.width() - ++ (new_bounds_dip.width() + new_bounds_dip.x()); ++ new_bounds_dip.set_x(new_x); ++ } ++ } ++ return gfx::ScaleToRoundedRect(new_bounds_dip, ui_scale() / buffer_scale()); ++} ++ ++} // namespace ui +diff --git a/ui/ozone/platform/wayland/host/wayland_popup.h b/ui/ozone/platform/wayland/host/wayland_popup.h +new file mode 100644 +index 000000000000..2d45986ba36a +--- /dev/null ++++ b/ui/ozone/platform/wayland/host/wayland_popup.h +@@ -0,0 +1,49 @@ ++// Copyright 2019 The Chromium Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_POPUP_H_ ++#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_POPUP_H_ ++ ++#include "ui/ozone/platform/wayland/host/wayland_window.h" ++ ++namespace ui { ++ ++class WaylandConnection; ++class ShellPopupWrapper; ++ ++class WaylandPopup : public WaylandWindow { ++ public: ++ WaylandPopup(PlatformWindowDelegate* delegate, WaylandConnection* connection); ++ ~WaylandPopup() override; ++ ++ ShellPopupWrapper* shell_popup() const { return shell_popup_.get(); } ++ ++ // PlatformWindow ++ void Show(bool inactive) override; ++ void Hide() override; ++ bool IsVisible() const override; ++ bool HasCapture() const override; ++ ++ private: ++ // WaylandWindow overrides: ++ void HandlePopupConfigure(const gfx::Rect& bounds) override; ++ void OnCloseRequest() override; ++ bool OnInitialize(PlatformWindowInitProperties properties) override; ++ ++ // Creates a popup window, which is visible as a menu window. ++ void CreateShellPopup(); ++ ++ // Returns bounds with origin relative to parent window's origin. ++ gfx::Rect AdjustPopupWindowPosition(); ++ ++ // Wrappers around xdg v5 and xdg v6 objects. WaylandPopup doesn't ++ // know anything about the version. ++ std::unique_ptr<ShellPopupWrapper> shell_popup_; ++ ++ DISALLOW_COPY_AND_ASSIGN(WaylandPopup); ++}; ++ ++} // namespace ui ++ ++#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_POPUP_H_ +diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc +index cdc95f904347..045f922a759e 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window.cc ++++ b/ui/ozone/platform/wayland/host/wayland_window.cc +@@ -14,8 +14,6 @@ + #include "ui/events/ozone/events_ozone.h" + #include "ui/gfx/geometry/point_f.h" + #include "ui/ozone/platform/wayland/common/wayland_util.h" +-#include "ui/ozone/platform/wayland/host/shell_object_factory.h" +-#include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h" + #include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h" + #include "ui/ozone/platform/wayland/host/wayland_connection.h" + #include "ui/ozone/platform/wayland/host/wayland_cursor_position.h" +@@ -78,35 +76,6 @@ gfx::AcceleratedWidget WaylandWindow::GetWidget() const { + return surface_.id(); + } + +-void WaylandWindow::CreateShellPopup() { +- if (bounds_px_.IsEmpty()) +- return; +- +- // TODO(jkim): Consider how to support DropArrow window on tabstrip. +- // When it starts dragging, as described the protocol, https://goo.gl/1Mskq3, +- // the client must have an active implicit grab. If we try to create a popup +- // window while dragging is executed, it gets 'popup_done' directly from +- // Wayland compositor and it's destroyed through 'popup_done'. It causes +- // a crash when aura::Window is destroyed. +- // https://crbug.com/875164 +- if (connection_->IsDragInProgress()) { +- surface_.reset(); +- LOG(ERROR) << "Wayland can't create a popup window during dragging."; +- return; +- } +- +- DCHECK(parent_window_ && !shell_popup_); +- +- auto bounds_px = AdjustPopupWindowPosition(); +- +- ShellObjectFactory factory; +- shell_popup_ = factory.CreateShellPopupWrapper(connection_, this, bounds_px); +- if (!shell_popup_) +- CHECK(false) << "Failed to create Wayland shell popup"; +- +- parent_window_->set_child_window(this); +-} +- + void WaylandWindow::CreateAndShowTooltipSubSurface() { + // Since Aura does not not provide a reference parent window, needed by + // Wayland, we get the current focused window to place and show the tooltips. +@@ -156,41 +125,17 @@ void WaylandWindow::SetPointerFocus(bool focus) { + } + + void WaylandWindow::Show(bool inactive) { +- if (!is_tooltip_) // Tooltip windows should not get keyboard focus +- set_keyboard_focus(true); +- +- if (is_tooltip_) { +- CreateAndShowTooltipSubSurface(); +- return; +- } +- +- if (!shell_popup_) { +- // When showing a sub-menu after it has been previously shown and hidden, +- // Wayland sends SetBounds prior to Show, and |bounds_px| takes the pixel +- // bounds. This makes a difference against the normal flow when the +- // window is created (see |Initialize|). To equalize things, rescale +- // |bounds_px_| to DIP. It will be adjusted while creating the popup. +- bounds_px_ = gfx::ScaleToRoundedRect(bounds_px_, 1.0 / ui_scale_); +- CreateShellPopup(); +- connection_->ScheduleFlush(); +- } ++ DCHECK(is_tooltip_); ++ CreateAndShowTooltipSubSurface(); + + UpdateBufferScale(false); + } + + void WaylandWindow::Hide() { +- if (is_tooltip_) { +- tooltip_subsurface_.reset(); +- } else { +- if (child_window_) +- child_window_->Hide(); +- if (shell_popup_) { +- parent_window_->set_child_window(nullptr); +- shell_popup_.reset(); +- } +- } ++ DCHECK(is_tooltip_); ++ tooltip_subsurface_.reset(); + +- // Detach buffer from surface in order to completely shutdown popups and ++ // Detach buffer from surface in order to completely shutdown menus and + // tooltips, and release resources. + connection_->buffer_manager_host()->ResetSurfaceContents(GetWidget()); + } +@@ -200,7 +145,7 @@ void WaylandWindow::Close() { + } + + bool WaylandWindow::IsVisible() const { +- return !!shell_popup_; ++ return !!tooltip_subsurface_; + } + + void WaylandWindow::PrepareForShutdown() {} +@@ -225,8 +170,8 @@ void WaylandWindow::SetTitle(const base::string16& title) {} + + void WaylandWindow::SetCapture() { + // Wayland does implicit grabs, and doesn't allow for explicit grabs. The +- // exception to that are popups, but we explicitly send events to a +- // parent popup if such exists. ++ // exception to that are menus, but we explicitly send events to a ++ // parent menu if such exists. + } + + void WaylandWindow::ReleaseCapture() { +@@ -234,8 +179,7 @@ void WaylandWindow::ReleaseCapture() { + } + + bool WaylandWindow::HasCapture() const { +- // If WaylandWindow is a popup window, assume it has the capture. +- return shell_popup() ? true : has_implicit_grab_; ++ return has_implicit_grab_; + } + + void WaylandWindow::ToggleFullscreen() {} +@@ -319,14 +263,14 @@ void WaylandWindow::SetWindowIcons(const gfx::ImageSkia& window_icon, + void WaylandWindow::SizeConstraintsChanged() {} + + bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) { +- // This window is a nested popup window, all the events must be forwarded +- // to the main popup window. +- if (child_window_ && child_window_->shell_popup()) +- return !!shell_popup_.get(); ++ // This window is a nested menu window, all the events must be forwarded ++ // to the main menu window. ++ if (child_window_ && wl::IsMenuType(child_window_->type())) ++ return wl::IsMenuType(type()); + + // If this is a nested menu window with a parent, it mustn't recieve any + // events. +- if (parent_window_ && parent_window_->shell_popup()) ++ if (parent_window_ && wl::IsMenuType(parent_window_->type())) + return false; + + // If another window has capture, return early before checking focus. +@@ -344,7 +288,6 @@ bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) { + + uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) { + Event* event = static_cast<Event*>(native_event); +- + if (event->IsLocatedEvent()) { + // Wayland sends locations in DIP so they need to be translated to + // physical pixels. +@@ -355,13 +298,14 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) { + } + + // If the window does not have a pointer focus, but received this event, it +- // means the window is a popup window with a child popup window. In this case, +- // the location of the event must be converted from the nested popup to the +- // main popup, which the menu controller needs to properly handle events. +- if (event->IsLocatedEvent() && shell_popup()) { +- // Parent window of the main menu window is not a popup, but rather an ++ // means the window is a menu window with a child menu window. In this case, ++ // the location of the event must be converted from the nested menu to the ++ // main menu, which the menu controller needs to properly handle events. ++ if (event->IsLocatedEvent() && wl::IsMenuType(type())) { ++ // Parent window of the main menu window is not a menu, but rather an + // xdg surface. +- DCHECK(!parent_window_->shell_popup() || !parent_window_->is_tooltip_); ++ DCHECK(!wl::IsMenuType(parent_window_->type()) || ++ !parent_window_->is_tooltip_); + auto* window = + connection_->wayland_window_manager()->GetCurrentFocusedWindow(); + if (window) { +@@ -387,59 +331,10 @@ void WaylandWindow::HandleSurfaceConfigure(int32_t widht, + } + + void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds_dip) { +- DCHECK(shell_popup()); +- DCHECK(parent_window_); +- +- SetBufferScale(parent_window_->buffer_scale_, true); +- +- gfx::Rect new_bounds_dip = bounds_dip; +- +- // It's not enough to just set new bounds. If it is a menu window, whose +- // parent is a top level window aka browser window, it can be flipped +- // vertically along y-axis and have negative values set. Chromium cannot +- // understand that and starts to position nested menu windows incorrectly. To +- // fix that, we have to bear in mind that Wayland compositor does not share +- // global coordinates for any surfaces, and Chromium assumes the top level +- // window is always located at 0,0 origin. What is more, child windows must +- // always be positioned relative to parent window local surface coordinates. +- // Thus, if the menu window is flipped along y-axis by Wayland and its origin +- // is above the top level parent window, the origin of the top level window +- // has to be shifted by that value on y-axis so that the origin of the menu +- // becomes x,0, and events can be handled normally. +- if (!parent_window_->shell_popup()) { +- gfx::Rect parent_bounds = parent_window_->GetBounds(); +- // The menu window is flipped along y-axis and have x,-y origin. Shift the +- // parent top level window instead. +- if (new_bounds_dip.y() < 0) { +- // Move parent bounds along y-axis. +- parent_bounds.set_y(-(new_bounds_dip.y() * buffer_scale_)); +- new_bounds_dip.set_y(0); +- } else { +- // If the menu window is located at correct origin from the browser point +- // of view, return the top level window back to 0,0. +- parent_bounds.set_y(0); +- } +- parent_window_->SetBounds(parent_bounds); +- } else { +- // The nested menu windows are located relative to the parent menu windows. +- // Thus, the location must be translated to be relative to the top level +- // window, which automatically becomes the same as relative to an origin of +- // a display. +- new_bounds_dip = gfx::ScaleToRoundedRect( +- wl::TranslateBoundsToTopLevelCoordinates( +- gfx::ScaleToRoundedRect(new_bounds_dip, buffer_scale_), +- parent_window_->GetBounds()), +- 1.0 / buffer_scale_); +- DCHECK(new_bounds_dip.y() >= 0); +- } +- +- SetBoundsDip(new_bounds_dip); ++ NOTREACHED() << "Only shell popups must receive HandlePopupConfigure calls."; + } + + void WaylandWindow::OnCloseRequest() { +- // Before calling OnCloseRequest, the |shell_popup_| must become hidden and +- // only then call OnCloseRequest(). +- DCHECK(!shell_popup_); + delegate_->OnCloseRequest(); + } + +@@ -470,6 +365,7 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) { + DCHECK_EQ(buffer_scale_, 1); + bounds_px_ = properties.bounds; + opacity_ = properties.opacity; ++ type_ = properties.type; + + surface_.reset(wl_compositor_create_surface(connection_->compositor())); + if (!surface_) { +@@ -481,44 +377,18 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) { + + connection_->wayland_window_manager()->AddWindow(GetWidget(), this); + +- ui::PlatformWindowType ui_window_type = properties.type; +- switch (ui_window_type) { +- case ui::PlatformWindowType::kMenu: +- case ui::PlatformWindowType::kPopup: +- parent_window_ = GetParentWindow(properties.parent_widget); +- +- // Popups need to know their scale earlier to position themselves. +- if (!parent_window_) { +- LOG(ERROR) << "Failed to get a parent window for this popup"; +- return false; +- } +- +- SetBufferScale(parent_window_->buffer_scale_, false); +- ui_scale_ = parent_window_->ui_scale_; +- +- // TODO(msisov, jkim): Handle notification windows, which are marked +- // as popup windows as well. Those are the windows that do not have +- // parents and pop up when the browser receives a notification. +- CreateShellPopup(); +- break; +- case ui::PlatformWindowType::kTooltip: +- // Tooltips subsurfaces are created on demand, upon ::Show calls. +- is_tooltip_ = true; +- break; +- case ui::PlatformWindowType::kWindow: +- case ui::PlatformWindowType::kBubble: +- case ui::PlatformWindowType::kDrag: +- if (!OnInitialize(std::move(properties))) +- return false; +- break; +- } ++ if (type_ == ui::PlatformWindowType::kTooltip) ++ is_tooltip_ = true; ++ ++ if (!OnInitialize(std::move(properties))) ++ return false; + + connection_->ScheduleFlush(); + + PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); + delegate_->OnAcceleratedWidgetAvailable(GetWidget()); + +- // Will do nothing for popups because they have got their scale above. ++ // Will do nothing for menus because they have got their scale above. + UpdateBufferScale(false); + + MaybeUpdateOpaqueRegion(); +@@ -575,10 +445,10 @@ void WaylandWindow::AddSurfaceListener() { + } + + void WaylandWindow::AddEnteredOutputId(struct wl_output* output) { +- // Wayland does weird things for popups so instead of tracking outputs that ++ // Wayland does weird things for menus so instead of tracking outputs that + // we entered or left, we take that from the parent window and ignore this + // event. +- if (shell_popup()) ++ if (wl::IsMenuType(type())) + return; + + const uint32_t entered_output_id = +@@ -591,10 +461,10 @@ void WaylandWindow::AddEnteredOutputId(struct wl_output* output) { + } + + void WaylandWindow::RemoveEnteredOutputId(struct wl_output* output) { +- // Wayland does weird things for popups so instead of tracking outputs that ++ // Wayland does weird things for menus so instead of tracking outputs that + // we entered or left, we take that from the parent window and ignore this + // event. +- if (shell_popup()) ++ if (wl::IsMenuType(type())) + return; + + const uint32_t left_output_id = +@@ -654,53 +524,6 @@ void WaylandWindow::UpdateCursorPositionFromEvent( + } + } + +-gfx::Rect WaylandWindow::AdjustPopupWindowPosition() const { +- auto* parent_window = parent_window_->shell_popup() +- ? parent_window_->parent_window_ +- : parent_window_; +- DCHECK(parent_window); +- DCHECK(buffer_scale_ == parent_window->buffer_scale_); +- DCHECK(ui_scale_ == parent_window->ui_scale_); +- +- // Chromium positions windows in screen coordinates, but Wayland requires them +- // to be in local surface coordinates aka relative to parent window. +- const gfx::Rect parent_bounds_dip = +- gfx::ScaleToRoundedRect(parent_window_->GetBounds(), 1.0 / ui_scale_); +- gfx::Rect new_bounds_dip = +- wl::TranslateBoundsToParentCoordinates(bounds_px_, parent_bounds_dip); +- +- // Chromium may decide to position nested menu windows on the left side +- // instead of the right side of parent menu windows when the size of the +- // window becomes larger than the display it is shown on. It's correct when +- // the window is located on one display and occupies the whole work area, but +- // as soon as it's moved and there is space on the right side, Chromium +- // continues positioning the nested menus on the left side relative to the +- // parent menu (Wayland does not provide clients with global coordinates). +- // Instead, reposition that window to be on the right side of the parent menu +- // window and let the compositor decide how to position it if it does not fit +- // a single display. However, there is one exception - if the window is +- // maximized, let Chromium position it on the left side as long as the Wayland +- // compositor may decide to position the nested window on the right side of +- // the parent menu window, which results in showing it on a second display if +- // more than one display is used. +- if (parent_window_->shell_popup() && parent_window_->parent_window_ && +- (parent_window_->parent_window()->GetPlatformWindowState() != +- PlatformWindowState::kMaximized)) { +- auto* top_level_window = parent_window_->parent_window_; +- DCHECK(top_level_window && !top_level_window->shell_popup()); +- if (new_bounds_dip.x() <= 0 && top_level_window->GetPlatformWindowState() != +- PlatformWindowState::kMaximized) { +- // Position the child menu window on the right side of the parent window +- // and let the Wayland compositor decide how to do constraint +- // adjustements. +- int new_x = parent_bounds_dip.width() - +- (new_bounds_dip.width() + new_bounds_dip.x()); +- new_bounds_dip.set_x(new_x); +- } +- } +- return gfx::ScaleToRoundedRect(new_bounds_dip, ui_scale_ / buffer_scale_); +-} +- + WaylandWindow* WaylandWindow::GetTopLevelWindow() { + return parent_window_ ? parent_window_->GetTopLevelWindow() : this; + } +diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h +index b9ee70d0ecd2..3eca745b38c4 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window.h ++++ b/ui/ozone/platform/wayland/host/wayland_window.h +@@ -30,7 +30,6 @@ namespace ui { + class BitmapCursorOzone; + class OSExchangeData; + class WaylandConnection; +-class ShellPopupWrapper; + + class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { + public: +@@ -53,8 +52,10 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { + void UpdateBufferScale(bool update_bounds); + + wl_surface* surface() const { return surface_.get(); } +- ShellPopupWrapper* shell_popup() const { return shell_popup_.get(); } + ++ void set_parent_window(WaylandWindow* parent_window) { ++ parent_window_ = parent_window; ++ } + WaylandWindow* parent_window() const { return parent_window_; } + + gfx::AcceleratedWidget GetWidget() const; +@@ -75,6 +76,7 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { + // Set a child of this window. It is very important in case of nested + // shell_popups as long as they must be destroyed in the back order. + void set_child_window(WaylandWindow* window) { child_window_ = window; } ++ WaylandWindow* child_window() const { return child_window_; } + + // Set whether this window has an implicit grab (often referred to as capture + // in Chrome code). Implicit grabs happen while a pointer is down. +@@ -82,11 +84,15 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { + bool has_implicit_grab() const { return has_implicit_grab_; } + + int32_t buffer_scale() const { return buffer_scale_; } ++ int32_t ui_scale() const { return ui_scale_; } + + const base::flat_set<uint32_t>& entered_outputs_ids() const { + return entered_outputs_ids_; + } + ++ // Returns current type of the window. ++ PlatformWindowType type() const { return type_; } ++ + // PlatformWindow + void Show(bool inactive) override; + void Hide() override; +@@ -131,9 +137,10 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { + bool is_maximized, + bool is_fullscreen, + bool is_activated); +- void HandlePopupConfigure(const gfx::Rect& bounds); ++ virtual void HandlePopupConfigure(const gfx::Rect& bounds); + +- void OnCloseRequest(); ++ // Handles close requests. ++ virtual void OnCloseRequest(); + + // Notifies about drag/drop session events. + virtual void OnDragEnter(const gfx::PointF& point, +@@ -156,23 +163,25 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { + // Sets bounds in dip. + void SetBoundsDip(const gfx::Rect& bounds_dip); + ++ // Gets a parent window for this window. ++ WaylandWindow* GetParentWindow(gfx::AcceleratedWidget parent_widget); ++ ++ // Sets the buffer scale. ++ void SetBufferScale(int32_t scale, bool update_bounds); ++ ++ // Sets the ui scale. ++ void set_ui_scale(int32_t ui_scale) { ui_scale_ = ui_scale; } ++ + private: + FRIEND_TEST_ALL_PREFIXES(WaylandScreenTest, SetBufferScale); + + // Initializes the WaylandWindow with supplied properties. + bool Initialize(PlatformWindowInitProperties properties); + +- void SetBufferScale(int32_t scale, bool update_bounds); +- +- // Creates a popup window, which is visible as a menu window. +- void CreateShellPopup(); + // Creates (if necessary) and show subsurface window, to host + // tooltip's content. + void CreateAndShowTooltipSubSurface(); + +- // Gets a parent window for this window. +- WaylandWindow* GetParentWindow(gfx::AcceleratedWidget parent_widget); +- + // Returns a root parent window. + WaylandWindow* GetRootParentWindow(); + +@@ -184,9 +193,6 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { + + void UpdateCursorPositionFromEvent(std::unique_ptr<Event> event); + +- // Returns bounds with origin relative to parent window's origin. +- gfx::Rect AdjustPopupWindowPosition() const; +- + WaylandWindow* GetTopLevelWindow(); + + // It's important to set opaque region for opaque windows (provides +@@ -214,10 +220,6 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { + wl::Object<wl_surface> surface_; + wl::Object<wl_subsurface> tooltip_subsurface_; + +- // Wrappers around xdg v5 and xdg v6 objects. WaylandWindow doesn't +- // know anything about the version. +- std::unique_ptr<ShellPopupWrapper> shell_popup_; +- + // The current cursor bitmap (immutable). + scoped_refptr<BitmapCursorOzone> bitmap_; + +@@ -253,6 +255,9 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { + // we ask its parent. + base::flat_set<uint32_t> entered_outputs_ids_; + ++ // The type of the current WaylandWindow object. ++ ui::PlatformWindowType type_ = ui::PlatformWindowType::kWindow; ++ + DISALLOW_COPY_AND_ASSIGN(WaylandWindow); + }; + +diff --git a/ui/ozone/platform/wayland/host/wayland_window_factory.cc b/ui/ozone/platform/wayland/host/wayland_window_factory.cc +index 892902e7f845..4c887fa3c1c8 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window_factory.cc ++++ b/ui/ozone/platform/wayland/host/wayland_window_factory.cc +@@ -6,6 +6,7 @@ + + #include <memory> + ++#include "ui/ozone/platform/wayland/host/wayland_popup.h" + #include "ui/ozone/platform/wayland/host/wayland_surface.h" + #include "ui/ozone/platform/wayland/host/wayland_window.h" + +@@ -21,7 +22,7 @@ std::unique_ptr<WaylandWindow> WaylandWindow::Create( + case PlatformWindowType::kMenu: + case PlatformWindowType::kPopup: + // TODO(msisov): Add WaylandPopup. +- window.reset(new WaylandWindow(delegate, connection)); ++ window.reset(new WaylandPopup(delegate, connection)); + break; + case PlatformWindowType::kTooltip: + // TODO(msisov): Add WaylandSubsurface. +diff --git a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc +index e85236ce47d7..62b54680e9e7 100644 +--- a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc ++++ b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc +@@ -12,10 +12,11 @@ + #include "base/nix/xdg_util.h" + #include "ui/events/event_constants.h" + #include "ui/gfx/geometry/rect.h" ++#include "ui/ozone/platform/wayland/common/wayland_util.h" + #include "ui/ozone/platform/wayland/host/wayland_connection.h" + #include "ui/ozone/platform/wayland/host/wayland_pointer.h" ++#include "ui/ozone/platform/wayland/host/wayland_popup.h" + #include "ui/ozone/platform/wayland/host/wayland_surface.h" +-#include "ui/ozone/platform/wayland/host/wayland_window.h" + #include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h" + + namespace ui { +@@ -268,38 +269,46 @@ XDGPopupWrapperImpl::~XDGPopupWrapperImpl() = default; + + bool XDGPopupWrapperImpl::Initialize(WaylandConnection* connection, + const gfx::Rect& bounds) { +- if (connection->shell()) +- return InitializeStable(connection, bounds); +- else if (connection->shell_v6()) +- return InitializeV6(connection, bounds); +- NOTREACHED() << "Wrong shell protocol"; +- return false; +-} +- +-bool XDGPopupWrapperImpl::InitializeStable(WaylandConnection* connection, +- const gfx::Rect& bounds) { +- static const struct xdg_popup_listener xdg_popup_listener = { +- &XDGPopupWrapperImpl::ConfigureStable, +- &XDGPopupWrapperImpl::PopupDoneStable, +- }; ++ if (!connection->shell() && !connection->shell_v6()) { ++ NOTREACHED() << "Wrong shell protocol"; ++ return false; ++ } + +- XDGSurfaceWrapperImpl* parent_xdg_surface; ++ XDGSurfaceWrapperImpl* parent_xdg_surface = nullptr; + // If the parent window is a popup, the surface of that popup must be used as + // a parent. +- if (wayland_window_->parent_window()->shell_popup()) { +- XDGPopupWrapperImpl* popup = reinterpret_cast<XDGPopupWrapperImpl*>( +- wayland_window_->parent_window()->shell_popup()); ++ if (wl::IsMenuType(wayland_window_->parent_window()->type())) { ++ auto* wayland_popup = ++ static_cast<WaylandPopup*>(wayland_window_->parent_window()); ++ XDGPopupWrapperImpl* popup = ++ static_cast<XDGPopupWrapperImpl*>(wayland_popup->shell_popup()); + parent_xdg_surface = popup->xdg_surface(); + } else { + WaylandSurface* wayland_surface = + static_cast<WaylandSurface*>(wayland_window_->parent_window()); +- parent_xdg_surface = reinterpret_cast<XDGSurfaceWrapperImpl*>( +- wayland_surface->shell_surface()); ++ parent_xdg_surface = ++ static_cast<XDGSurfaceWrapperImpl*>(wayland_surface->shell_surface()); + } + +- if (!parent_xdg_surface) ++ if (!xdg_surface_ || !parent_xdg_surface) + return false; + ++ if (connection->shell()) ++ return InitializeStable(connection, bounds, parent_xdg_surface); ++ else if (connection->shell_v6()) ++ return InitializeV6(connection, bounds, parent_xdg_surface); ++ return false; ++} ++ ++bool XDGPopupWrapperImpl::InitializeStable( ++ WaylandConnection* connection, ++ const gfx::Rect& bounds, ++ XDGSurfaceWrapperImpl* parent_xdg_surface) { ++ static const struct xdg_popup_listener xdg_popup_listener = { ++ &XDGPopupWrapperImpl::ConfigureStable, ++ &XDGPopupWrapperImpl::PopupDoneStable, ++ }; ++ + struct xdg_positioner* positioner = CreatePositionerStable( + connection, wayland_window_->parent_window(), bounds); + if (!positioner) +@@ -369,7 +378,7 @@ struct xdg_positioner* XDGPopupWrapperImpl::CreatePositionerStable( + MenuType menu_type = MenuType::TYPE_UNKNOWN; + if (is_right_click_menu) + menu_type = MenuType::TYPE_RIGHT_CLICK; +- else if (parent_window->shell_popup()) ++ else if (wl::IsMenuType(parent_window->type())) + menu_type = MenuType::TYPE_3DOT_CHILD_MENU; + else + menu_type = MenuType::TYPE_3DOT_PARENT_MENU; +@@ -390,33 +399,15 @@ struct xdg_positioner* XDGPopupWrapperImpl::CreatePositionerStable( + return positioner; + } + +-bool XDGPopupWrapperImpl::InitializeV6(WaylandConnection* connection, +- const gfx::Rect& bounds) { ++bool XDGPopupWrapperImpl::InitializeV6( ++ WaylandConnection* connection, ++ const gfx::Rect& bounds, ++ XDGSurfaceWrapperImpl* parent_xdg_surface) { + static const struct zxdg_popup_v6_listener zxdg_popup_v6_listener = { + &XDGPopupWrapperImpl::ConfigureV6, + &XDGPopupWrapperImpl::PopupDoneV6, + }; + +- if (!xdg_surface_) +- return false; +- +- XDGSurfaceWrapperImpl* parent_xdg_surface; +- // If the parent window is a popup, the surface of that popup must be used as +- // a parent. +- if (wayland_window_->parent_window()->shell_popup()) { +- XDGPopupWrapperImpl* popup = reinterpret_cast<XDGPopupWrapperImpl*>( +- wayland_window_->parent_window()->shell_popup()); +- parent_xdg_surface = popup->xdg_surface(); +- } else { +- WaylandSurface* wayland_surface = +- static_cast<WaylandSurface*>(wayland_window_->parent_window()); +- parent_xdg_surface = reinterpret_cast<XDGSurfaceWrapperImpl*>( +- wayland_surface->shell_surface()); +- } +- +- if (!parent_xdg_surface) +- return false; +- + zxdg_positioner_v6* positioner = + CreatePositionerV6(connection, wayland_window_->parent_window(), bounds); + if (!positioner) +@@ -488,7 +479,7 @@ zxdg_positioner_v6* XDGPopupWrapperImpl::CreatePositionerV6( + MenuType menu_type = MenuType::TYPE_UNKNOWN; + if (is_right_click_menu) + menu_type = MenuType::TYPE_RIGHT_CLICK; +- else if (parent_window->shell_popup()) ++ else if (wl::IsMenuType(parent_window->type())) + menu_type = MenuType::TYPE_3DOT_CHILD_MENU; + else + menu_type = MenuType::TYPE_3DOT_PARENT_MENU; +diff --git a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h +index 2a900818ff6a..c0479cfff7fb 100644 +--- a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h ++++ b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h +@@ -27,12 +27,16 @@ class XDGPopupWrapperImpl : public ShellPopupWrapper { + const gfx::Rect& bounds) override; + + private: +- bool InitializeStable(WaylandConnection* connection, const gfx::Rect& bounds); ++ bool InitializeStable(WaylandConnection* connection, ++ const gfx::Rect& bounds, ++ XDGSurfaceWrapperImpl* parent_xdg_surface); + struct xdg_positioner* CreatePositionerStable(WaylandConnection* connection, + WaylandWindow* parent_window, + const gfx::Rect& bounds); + +- bool InitializeV6(WaylandConnection* connection, const gfx::Rect& bounds); ++ bool InitializeV6(WaylandConnection* connection, ++ const gfx::Rect& bounds, ++ XDGSurfaceWrapperImpl* parent_xdg_surface); + struct zxdg_positioner_v6* CreatePositionerV6(WaylandConnection* connection, + WaylandWindow* parent_window, + const gfx::Rect& bounds); +-- +2.24.1 + diff --git a/0007-ozone-wayland-Extract-subsurface-from-WaylandWindow.patch b/0007-ozone-wayland-Extract-subsurface-from-WaylandWindow.patch new file mode 100644 index 000000000000..62ceae75d155 --- /dev/null +++ b/0007-ozone-wayland-Extract-subsurface-from-WaylandWindow.patch @@ -0,0 +1,347 @@ +From 33a754dd22a0fa37654b569232ffd606aaa5e3b9 Mon Sep 17 00:00:00 2001 +From: Maksim Sisov <msisov@igalia.com> +Date: Wed, 11 Dec 2019 10:04:19 +0000 +Subject: [PATCH 7/9] ozone/wayland: Extract subsurface from WaylandWindow + +This CL does not bring any functional changes, but rather moves +the subsurface methods to WaylandSubsurface. + +Test: ozone_unittests +Bug: 1028919 +Change-Id: I96dbf21267a80022779cd7eebeb56c96a243128b +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1960265 +Commit-Queue: Maksim Sisov <msisov@igalia.com> +Reviewed-by: Michael Spang <spang@chromium.org> +Cr-Commit-Position: refs/heads/master@{#723758} +--- + ui/ozone/platform/wayland/BUILD.gn | 2 + + .../wayland/host/wayland_subsurface.cc | 80 +++++++++++++++++++ + .../wayland/host/wayland_subsurface.h | 37 +++++++++ + .../platform/wayland/host/wayland_window.cc | 63 ++------------- + .../platform/wayland/host/wayland_window.h | 9 +-- + .../wayland/host/wayland_window_factory.cc | 4 +- + 6 files changed, 127 insertions(+), 68 deletions(-) + create mode 100644 ui/ozone/platform/wayland/host/wayland_subsurface.cc + create mode 100644 ui/ozone/platform/wayland/host/wayland_subsurface.h + +diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn +index 4bfe93352f34..f6f21cdb0161 100644 +--- a/ui/ozone/platform/wayland/BUILD.gn ++++ b/ui/ozone/platform/wayland/BUILD.gn +@@ -93,6 +93,8 @@ source_set("wayland") { + "host/wayland_shm.h", + "host/wayland_shm_buffer.cc", + "host/wayland_shm_buffer.h", ++ "host/wayland_subsurface.cc", ++ "host/wayland_subsurface.h", + "host/wayland_surface.cc", + "host/wayland_surface.h", + "host/wayland_touch.cc", +diff --git a/ui/ozone/platform/wayland/host/wayland_subsurface.cc b/ui/ozone/platform/wayland/host/wayland_subsurface.cc +new file mode 100644 +index 000000000000..d261b910fc97 +--- /dev/null ++++ b/ui/ozone/platform/wayland/host/wayland_subsurface.cc +@@ -0,0 +1,80 @@ ++// Copyright 2019 The Chromium Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#include "ui/ozone/platform/wayland/host/wayland_subsurface.h" ++ ++#include "ui/ozone/platform/wayland/common/wayland_util.h" ++#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h" ++#include "ui/ozone/platform/wayland/host/wayland_connection.h" ++#include "ui/ozone/platform/wayland/host/wayland_window_manager.h" ++ ++namespace ui { ++ ++WaylandSubsurface::WaylandSubsurface(PlatformWindowDelegate* delegate, ++ WaylandConnection* connection) ++ : WaylandWindow(delegate, connection) {} ++ ++WaylandSubsurface::~WaylandSubsurface() = default; ++ ++void WaylandSubsurface::Show(bool inactive) { ++ CreateSubsurface(); ++ UpdateBufferScale(false); ++} ++ ++void WaylandSubsurface::Hide() { ++ subsurface_.reset(); ++ ++ // Detach buffer from surface in order to completely shutdown menus and ++ // tooltips, and release resources. ++ connection()->buffer_manager_host()->ResetSurfaceContents(GetWidget()); ++} ++ ++bool WaylandSubsurface::IsVisible() const { ++ return !!subsurface_; ++} ++ ++void WaylandSubsurface::CreateSubsurface() { ++ // Since Aura does not not provide a reference parent window, needed by ++ // Wayland, we get the current focused window to place and show the tooltips. ++ auto* parent_window = ++ connection()->wayland_window_manager()->GetCurrentFocusedWindow(); ++ ++ // Tooltip creation is an async operation. By the time Aura actually creates ++ // the tooltip, it is possible that the user has already moved the ++ // mouse/pointer out of the window that triggered the tooptip. In this case, ++ // parent_window is NULL. ++ if (!parent_window) ++ return; ++ ++ wl_subcompositor* subcompositor = connection()->subcompositor(); ++ DCHECK(subcompositor); ++ subsurface_.reset(wl_subcompositor_get_subsurface(subcompositor, surface(), ++ parent_window->surface())); ++ ++ // Chromium positions tooltip windows in screen coordinates, but Wayland ++ // requires them to be in local surface coordinates a.k.a relative to parent ++ // window. ++ const auto parent_bounds_dip = ++ gfx::ScaleToRoundedRect(parent_window->GetBounds(), 1.0 / ui_scale()); ++ auto new_bounds_dip = ++ wl::TranslateBoundsToParentCoordinates(GetBounds(), parent_bounds_dip); ++ auto bounds_px = ++ gfx::ScaleToRoundedRect(new_bounds_dip, ui_scale() / buffer_scale()); ++ ++ DCHECK(subsurface_); ++ // Convert position to DIP. ++ wl_subsurface_set_position(subsurface_.get(), bounds_px.x() / buffer_scale(), ++ bounds_px.y() / buffer_scale()); ++ wl_subsurface_set_desync(subsurface_.get()); ++ wl_surface_commit(parent_window->surface()); ++ connection()->ScheduleFlush(); ++} ++ ++bool WaylandSubsurface::OnInitialize(PlatformWindowInitProperties properties) { ++ // TODO(msisov): if the subsurface is not provided with a parent widget, then ++ // it must always use a focused window ++ return true; ++} ++ ++} // namespace ui +diff --git a/ui/ozone/platform/wayland/host/wayland_subsurface.h b/ui/ozone/platform/wayland/host/wayland_subsurface.h +new file mode 100644 +index 000000000000..fd159a7bd465 +--- /dev/null ++++ b/ui/ozone/platform/wayland/host/wayland_subsurface.h +@@ -0,0 +1,37 @@ ++// Copyright 2019 The Chromium Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SUBSURFACE_H_ ++#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SUBSURFACE_H_ ++ ++#include "ui/ozone/platform/wayland/host/wayland_window.h" ++ ++namespace ui { ++ ++class WaylandSubsurface : public WaylandWindow { ++ public: ++ WaylandSubsurface(PlatformWindowDelegate* delegate, ++ WaylandConnection* connection); ++ ~WaylandSubsurface() override; ++ ++ // PlatformWindow overrides: ++ void Show(bool inactive) override; ++ void Hide() override; ++ bool IsVisible() const override; ++ ++ private: ++ // WaylandWindow overrides: ++ bool OnInitialize(PlatformWindowInitProperties properties) override; ++ ++ // Creates (if necessary) and shows a subsurface window. ++ void CreateSubsurface(); ++ ++ wl::Object<wl_subsurface> subsurface_; ++ ++ DISALLOW_COPY_AND_ASSIGN(WaylandSubsurface); ++}; ++ ++} // namespace ui ++ ++#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SUBSURFACE_H_ +diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc +index 045f922a759e..c752ad3c0048 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window.cc ++++ b/ui/ozone/platform/wayland/host/wayland_window.cc +@@ -75,45 +75,6 @@ gfx::AcceleratedWidget WaylandWindow::GetWidget() const { + return gfx::kNullAcceleratedWidget; + return surface_.id(); + } +- +-void WaylandWindow::CreateAndShowTooltipSubSurface() { +- // Since Aura does not not provide a reference parent window, needed by +- // Wayland, we get the current focused window to place and show the tooltips. +- auto* parent_window = +- connection_->wayland_window_manager()->GetCurrentFocusedWindow(); +- +- // Tooltip creation is an async operation. By the time Aura actually creates +- // the tooltip, it is possible that the user has already moved the +- // mouse/pointer out of the window that triggered the tooptip. In this case, +- // parent_window is NULL. +- if (!parent_window) +- return; +- +- wl_subcompositor* subcompositor = connection_->subcompositor(); +- DCHECK(subcompositor); +- tooltip_subsurface_.reset(wl_subcompositor_get_subsurface( +- subcompositor, surface_.get(), parent_window->surface())); +- +- // Chromium positions tooltip windows in screen coordinates, but Wayland +- // requires them to be in local surface coordinates aka relative to parent +- // window. +- const auto parent_bounds_dip = +- gfx::ScaleToRoundedRect(parent_window->GetBounds(), 1.0 / ui_scale_); +- auto new_bounds_dip = +- wl::TranslateBoundsToParentCoordinates(bounds_px_, parent_bounds_dip); +- auto bounds_px = +- gfx::ScaleToRoundedRect(new_bounds_dip, ui_scale_ / buffer_scale_); +- +- DCHECK(tooltip_subsurface_); +- // Convert position to DIP. +- wl_subsurface_set_position(tooltip_subsurface_.get(), +- bounds_px.x() / buffer_scale_, +- bounds_px.y() / buffer_scale_); +- wl_subsurface_set_desync(tooltip_subsurface_.get()); +- wl_surface_commit(parent_window->surface()); +- connection_->ScheduleFlush(); +-} +- + void WaylandWindow::SetPointerFocus(bool focus) { + has_pointer_focus_ = focus; + +@@ -125,19 +86,11 @@ void WaylandWindow::SetPointerFocus(bool focus) { + } + + void WaylandWindow::Show(bool inactive) { +- DCHECK(is_tooltip_); +- CreateAndShowTooltipSubSurface(); +- +- UpdateBufferScale(false); ++ NOTREACHED(); + } + + void WaylandWindow::Hide() { +- DCHECK(is_tooltip_); +- tooltip_subsurface_.reset(); +- +- // Detach buffer from surface in order to completely shutdown menus and +- // tooltips, and release resources. +- connection_->buffer_manager_host()->ResetSurfaceContents(GetWidget()); ++ NOTREACHED(); + } + + void WaylandWindow::Close() { +@@ -145,7 +98,8 @@ void WaylandWindow::Close() { + } + + bool WaylandWindow::IsVisible() const { +- return !!tooltip_subsurface_; ++ NOTREACHED(); ++ return false; + } + + void WaylandWindow::PrepareForShutdown() {} +@@ -305,7 +259,7 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) { + // Parent window of the main menu window is not a menu, but rather an + // xdg surface. + DCHECK(!wl::IsMenuType(parent_window_->type()) || +- !parent_window_->is_tooltip_); ++ parent_window_->type() != PlatformWindowType::kTooltip); + auto* window = + connection_->wayland_window_manager()->GetCurrentFocusedWindow(); + if (window) { +@@ -377,9 +331,6 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) { + + connection_->wayland_window_manager()->AddWindow(GetWidget(), this); + +- if (type_ == ui::PlatformWindowType::kTooltip) +- is_tooltip_ = true; +- + if (!OnInitialize(std::move(properties))) + return false; + +@@ -544,10 +495,6 @@ bool WaylandWindow::IsOpaqueWindow() const { + return opacity_ == ui::PlatformWindowOpacity::kOpaqueWindow; + } + +-bool WaylandWindow::OnInitialize(PlatformWindowInitProperties properties) { +- return true; +-} +- + // static + void WaylandWindow::Enter(void* data, + struct wl_surface* wl_surface, +diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h +index 3eca745b38c4..08658f1df87c 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window.h ++++ b/ui/ozone/platform/wayland/host/wayland_window.h +@@ -178,10 +178,6 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { + // Initializes the WaylandWindow with supplied properties. + bool Initialize(PlatformWindowInitProperties properties); + +- // Creates (if necessary) and show subsurface window, to host +- // tooltip's content. +- void CreateAndShowTooltipSubSurface(); +- + // Returns a root parent window. + WaylandWindow* GetRootParentWindow(); + +@@ -202,7 +198,7 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { + bool IsOpaqueWindow() const; + + // Additional initialization of derived classes. +- virtual bool OnInitialize(PlatformWindowInitProperties properties); ++ virtual bool OnInitialize(PlatformWindowInitProperties properties) = 0; + + // wl_surface_listener + static void Enter(void* data, +@@ -218,7 +214,6 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { + WaylandWindow* child_window_ = nullptr; + + wl::Object<wl_surface> surface_; +- wl::Object<wl_subsurface> tooltip_subsurface_; + + // The current cursor bitmap (immutable). + scoped_refptr<BitmapCursorOzone> bitmap_; +@@ -243,8 +238,6 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { + // Stores current opacity of the window. Set on ::Initialize call. + ui::PlatformWindowOpacity opacity_; + +- bool is_tooltip_ = false; +- + // For top level window, stores IDs of outputs that the window is currently + // rendered at. + // +diff --git a/ui/ozone/platform/wayland/host/wayland_window_factory.cc b/ui/ozone/platform/wayland/host/wayland_window_factory.cc +index 4c887fa3c1c8..869c1d0aa1f8 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window_factory.cc ++++ b/ui/ozone/platform/wayland/host/wayland_window_factory.cc +@@ -7,8 +7,8 @@ + #include <memory> + + #include "ui/ozone/platform/wayland/host/wayland_popup.h" ++#include "ui/ozone/platform/wayland/host/wayland_subsurface.h" + #include "ui/ozone/platform/wayland/host/wayland_surface.h" +-#include "ui/ozone/platform/wayland/host/wayland_window.h" + + namespace ui { + +@@ -26,7 +26,7 @@ std::unique_ptr<WaylandWindow> WaylandWindow::Create( + break; + case PlatformWindowType::kTooltip: + // TODO(msisov): Add WaylandSubsurface. +- window.reset(new WaylandWindow(delegate, connection)); ++ window.reset(new WaylandSubsurface(delegate, connection)); + break; + case PlatformWindowType::kWindow: + case PlatformWindowType::kBubble: +-- +2.24.1 + diff --git a/0008-ozone-wayland-Recreate-ShellSurface-and-ShellPopup-o.patch b/0008-ozone-wayland-Recreate-ShellSurface-and-ShellPopup-o.patch new file mode 100644 index 000000000000..a6c9bc9f2714 --- /dev/null +++ b/0008-ozone-wayland-Recreate-ShellSurface-and-ShellPopup-o.patch @@ -0,0 +1,1148 @@ +From 8f007d6dd7e450f4661e49a7053ed64e4cafbc1a Mon Sep 17 00:00:00 2001 +From: Maksim Sisov <msisov@igalia.com> +Date: Thu, 12 Dec 2019 13:22:46 +0000 +Subject: [PATCH 8/9] ozone/wayland: Recreate ShellSurface and ShellPopup on + Show calls. + +In Wayland, there is no explicit method for showing surfaces. Instead, +one must create/destroy resources to trigger mapping of the +base wl_surface and show xdg surfaces and xdg popups on a screen. + +Actually, we have already been doing so for WaylandPopups and +WaylandSubsurfaces, but WaylandSurface just ignored that. + +This CL brings the following changes: +1) WaylandSurface: create ShellSurface on Show and destroy on Hide. +If Show fails, tell the delegate to Close the window. Also, restore +min and max size, title and app id on each Show call. +2) WaylandPopup: do no create ShellPopup on Initialize, but rather +wait until Show call comes. +3) Tests: Instead of unretained implementation, use the template +that creates resources and manages their lifetime automatically +so that MockXdgPopup and MockXdgSurface could be destroyed +automatically once the client destroyes the allocated resources. +4) WaylandSubsurface: do not try to Show if the subsurface has already +shown or do not try to Hide if the subsurface has already been +hidden. +5) Also added 3 tests to exercise above changes. + +SetsPropertiesOnShow + +Test: DestroysCreatesSurfaceOnHideShow, DestroysCreatesPopupsOnHideShow +Bug: 578890 +Change-Id: Ifb873eb1b089775e945705b1254ac048eddbb4e8 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1961201 +Commit-Queue: Maksim Sisov <msisov@igalia.com> +Reviewed-by: Michael Spang <spang@chromium.org> +Cr-Commit-Position: refs/heads/master@{#724184} +--- + .../platform/wayland/host/wayland_popup.cc | 41 +++-- + .../platform/wayland/host/wayland_popup.h | 2 +- + .../wayland/host/wayland_subsurface.cc | 6 + + .../platform/wayland/host/wayland_surface.cc | 78 +++++--- + .../platform/wayland/host/wayland_surface.h | 18 +- + .../host/wayland_window_manager_unittests.cc | 13 +- + .../wayland/host/wayland_window_unittest.cc | 170 +++++++++++++++--- + ui/ozone/platform/wayland/test/mock_surface.h | 18 +- + .../platform/wayland/test/mock_xdg_popup.cc | 10 +- + .../platform/wayland/test/mock_xdg_popup.h | 6 +- + .../platform/wayland/test/mock_xdg_shell.cc | 9 +- + .../platform/wayland/test/mock_xdg_surface.cc | 116 +++++++----- + .../platform/wayland/test/mock_xdg_surface.h | 69 ++++--- + .../platform/wayland/test/wayland_test.cc | 2 + + 14 files changed, 402 insertions(+), 156 deletions(-) + +diff --git a/ui/ozone/platform/wayland/host/wayland_popup.cc b/ui/ozone/platform/wayland/host/wayland_popup.cc +index 45aac6e51bfc..98cadd54555c 100644 +--- a/ui/ozone/platform/wayland/host/wayland_popup.cc ++++ b/ui/ozone/platform/wayland/host/wayland_popup.cc +@@ -18,9 +18,9 @@ WaylandPopup::WaylandPopup(PlatformWindowDelegate* delegate, + + WaylandPopup::~WaylandPopup() = default; + +-void WaylandPopup::CreateShellPopup() { ++bool WaylandPopup::CreateShellPopup() { + if (GetBounds().IsEmpty()) +- return; ++ return false; + + // TODO(jkim): Consider how to support DropArrow window on tabstrip. + // When it starts dragging, as described the protocol, https://goo.gl/1Mskq3, +@@ -30,8 +30,8 @@ void WaylandPopup::CreateShellPopup() { + // a crash when aura::Window is destroyed. + // https://crbug.com/875164 + if (connection()->IsDragInProgress()) { +- LOG(ERROR) << "Wayland can't create a popup window during dragging."; +- return; ++ LOG(WARNING) << "Wayland can't create a popup window during dragging."; ++ return false; + } + + DCHECK(parent_window() && !shell_popup_); +@@ -40,30 +40,40 @@ void WaylandPopup::CreateShellPopup() { + + ShellObjectFactory factory; + shell_popup_ = factory.CreateShellPopupWrapper(connection(), this, bounds_px); +- if (!shell_popup_) +- CHECK(false) << "Failed to create Wayland shell popup"; ++ if (!shell_popup_) { ++ LOG(ERROR) << "Failed to create Wayland shell popup"; ++ return false; ++ } + + parent_window()->set_child_window(this); ++ return true; + } + + void WaylandPopup::Show(bool inactive) { ++ if (shell_popup_) ++ return; ++ + set_keyboard_focus(true); + +- if (!shell_popup_) { +- // When showing a sub-menu after it has been previously shown and hidden, +- // Wayland sends SetBounds prior to Show, and |bounds_px| takes the pixel +- // bounds. This makes a difference against the normal flow when the +- // window is created (see |Initialize|). To equalize things, rescale +- // |bounds_px_| to DIP. It will be adjusted while creating the popup. +- SetBounds(gfx::ScaleToRoundedRect(GetBounds(), 1.0 / ui_scale())); +- CreateShellPopup(); +- connection()->ScheduleFlush(); ++ // When showing a sub-menu after it has been previously shown and hidden, ++ // Wayland sends SetBounds prior to Show, and |bounds_px| takes the pixel ++ // bounds. This makes a difference against the normal flow when the ++ // window is created (see |Initialize|). To equalize things, rescale ++ // |bounds_px_| to DIP. It will be adjusted while creating the popup. ++ SetBounds(gfx::ScaleToRoundedRect(GetBounds(), 1.0 / ui_scale())); ++ if (!CreateShellPopup()) { ++ Close(); ++ return; + } + + UpdateBufferScale(false); ++ connection()->ScheduleFlush(); + } + + void WaylandPopup::Hide() { ++ if (!shell_popup_) ++ return; ++ + if (child_window()) + child_window()->Hide(); + +@@ -155,7 +165,6 @@ bool WaylandPopup::OnInitialize(PlatformWindowInitProperties properties) { + // If parent window is known in advanced, we may set the scale early. + SetBufferScale(parent_window()->buffer_scale(), false); + set_ui_scale(parent_window()->ui_scale()); +- CreateShellPopup(); + return true; + } + +diff --git a/ui/ozone/platform/wayland/host/wayland_popup.h b/ui/ozone/platform/wayland/host/wayland_popup.h +index 2d45986ba36a..7bc48bb29a06 100644 +--- a/ui/ozone/platform/wayland/host/wayland_popup.h ++++ b/ui/ozone/platform/wayland/host/wayland_popup.h +@@ -32,7 +32,7 @@ class WaylandPopup : public WaylandWindow { + bool OnInitialize(PlatformWindowInitProperties properties) override; + + // Creates a popup window, which is visible as a menu window. +- void CreateShellPopup(); ++ bool CreateShellPopup(); + + // Returns bounds with origin relative to parent window's origin. + gfx::Rect AdjustPopupWindowPosition(); +diff --git a/ui/ozone/platform/wayland/host/wayland_subsurface.cc b/ui/ozone/platform/wayland/host/wayland_subsurface.cc +index d261b910fc97..94ca613ecaf1 100644 +--- a/ui/ozone/platform/wayland/host/wayland_subsurface.cc ++++ b/ui/ozone/platform/wayland/host/wayland_subsurface.cc +@@ -18,11 +18,17 @@ WaylandSubsurface::WaylandSubsurface(PlatformWindowDelegate* delegate, + WaylandSubsurface::~WaylandSubsurface() = default; + + void WaylandSubsurface::Show(bool inactive) { ++ if (subsurface_) ++ return; ++ + CreateSubsurface(); + UpdateBufferScale(false); + } + + void WaylandSubsurface::Hide() { ++ if (!subsurface_) ++ return; ++ + subsurface_.reset(); + + // Detach buffer from surface in order to completely shutdown menus and +diff --git a/ui/ozone/platform/wayland/host/wayland_surface.cc b/ui/ozone/platform/wayland/host/wayland_surface.cc +index cfd4349db885..b800a526e64e 100644 +--- a/ui/ozone/platform/wayland/host/wayland_surface.cc ++++ b/ui/ozone/platform/wayland/host/wayland_surface.cc +@@ -10,6 +10,7 @@ + #include "ui/gfx/native_widget_types.h" + #include "ui/ozone/platform/wayland/host/shell_object_factory.h" + #include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h" ++#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h" + #include "ui/ozone/platform/wayland/host/wayland_connection.h" + #include "ui/platform_window/platform_window_handler/wm_drop_handler.h" + +@@ -35,11 +36,18 @@ WaylandSurface::~WaylandSurface() { + } + } + +-void WaylandSurface::CreateShellSurface() { ++bool WaylandSurface::CreateShellSurface() { + ShellObjectFactory factory; + shell_surface_ = factory.CreateShellSurfaceWrapper(connection(), this); +- if (!shell_surface_) +- CHECK(false) << "Failed to initialize Wayland shell surface"; ++ if (!shell_surface_) { ++ LOG(ERROR) << "Failed to create a ShellSurface."; ++ return false; ++ } ++ ++ shell_surface_->SetAppId(app_id_); ++ shell_surface_->SetTitle(window_title_); ++ SetSizeConstraints(); ++ return true; + } + + void WaylandSurface::ApplyPendingBounds() { +@@ -77,12 +85,33 @@ void WaylandSurface::StartDrag(const ui::OSExchangeData& data, + } + + void WaylandSurface::Show(bool inactive) { ++ if (shell_surface_) ++ return; ++ ++ if (!CreateShellSurface()) { ++ Close(); ++ return; ++ } ++ + set_keyboard_focus(true); +- // TODO(msisov): recreate |shell_surface_| on show calls. ++ UpdateBufferScale(false); + } + + void WaylandSurface::Hide() { +- // TODO(msisov): destroy |shell_surface_| on hide calls. ++ if (!shell_surface_) ++ return; ++ ++ if (child_window()) { ++ child_window()->Hide(); ++ set_child_window(nullptr); ++ } ++ ++ shell_surface_.reset(); ++ connection()->ScheduleFlush(); ++ ++ // Detach buffer from surface in order to completely shutdown menus and ++ // tooltips, and release resources. ++ connection()->buffer_manager_host()->ResetSurfaceContents(GetWidget()); + } + + bool WaylandSurface::IsVisible() const { +@@ -92,9 +121,15 @@ bool WaylandSurface::IsVisible() const { + } + + void WaylandSurface::SetTitle(const base::string16& title) { +- DCHECK(shell_surface_); +- shell_surface_->SetTitle(title); +- connection()->ScheduleFlush(); ++ if (window_title_ == title) ++ return; ++ ++ window_title_ = title; ++ ++ if (shell_surface_) { ++ shell_surface_->SetTitle(title); ++ connection()->ScheduleFlush(); ++ } + } + + void WaylandSurface::ToggleFullscreen() { +@@ -178,15 +213,9 @@ void WaylandSurface::SizeConstraintsChanged() { + return; + + DCHECK(delegate()); +- auto min_size = delegate()->GetMinimumSizeForWindow(); +- auto max_size = delegate()->GetMaximumSizeForWindow(); +- +- if (min_size.has_value()) +- shell_surface_->SetMinSize(min_size->width(), min_size->height()); +- if (max_size.has_value()) +- shell_surface_->SetMaxSize(max_size->width(), max_size->height()); +- +- connection()->ScheduleFlush(); ++ min_size_ = delegate()->GetMinimumSizeForWindow(); ++ max_size_ = delegate()->GetMaximumSizeForWindow(); ++ SetSizeConstraints(); + } + + void WaylandSurface::HandleSurfaceConfigure(int32_t width, +@@ -315,10 +344,8 @@ void WaylandSurface::OnDragSessionClose(uint32_t dnd_action) { + } + + bool WaylandSurface::OnInitialize(PlatformWindowInitProperties properties) { +- CreateShellSurface(); +- if (shell_surface_ && !properties.wm_class_class.empty()) +- shell_surface_->SetAppId(properties.wm_class_class); +- return !!shell_surface_; ++ app_id_ = properties.wm_class_class; ++ return true; + } + + bool WaylandSurface::IsMinimized() const { +@@ -345,4 +372,13 @@ WmMoveResizeHandler* WaylandSurface::AsWmMoveResizeHandler() { + return static_cast<WmMoveResizeHandler*>(this); + } + ++void WaylandSurface::SetSizeConstraints() { ++ if (min_size_.has_value()) ++ shell_surface_->SetMinSize(min_size_->width(), min_size_->height()); ++ if (max_size_.has_value()) ++ shell_surface_->SetMaxSize(max_size_->width(), max_size_->height()); ++ ++ connection()->ScheduleFlush(); ++} ++ + } // namespace ui +diff --git a/ui/ozone/platform/wayland/host/wayland_surface.h b/ui/ozone/platform/wayland/host/wayland_surface.h +index 0f7204db3c48..677eaca6ef56 100644 +--- a/ui/ozone/platform/wayland/host/wayland_surface.h ++++ b/ui/ozone/platform/wayland/host/wayland_surface.h +@@ -76,10 +76,13 @@ class WaylandSurface : public WaylandWindow, + void MaybeTriggerPendingStateChange(); + + // Creates a surface window, which is visible as a main window. +- void CreateShellSurface(); ++ bool CreateShellSurface(); + + WmMoveResizeHandler* AsWmMoveResizeHandler(); + ++ // Propagates the |min_size_| and |max_size_| to the ShellSurface. ++ void SetSizeConstraints(); ++ + // Wrappers around shell surface. + std::unique_ptr<ShellSurfaceWrapper> shell_surface_; + +@@ -106,6 +109,19 @@ class WaylandSurface : public WaylandWindow, + bool is_active_ = false; + bool is_minimizing_ = false; + ++ // Id of the chromium app passed through ++ // PlatformWindowInitProperties::wm_class_class. This is used by Wayland ++ // compositor to identify the app, unite it's windows into the same stack of ++ // windows and find *.desktop file to set various preferences including icons. ++ std::string app_id_; ++ ++ // Title of the ShellSurface. ++ base::string16 window_title_; ++ ++ // Max and min sizes of the WaylandSurface window. ++ base::Optional<gfx::Size> min_size_; ++ base::Optional<gfx::Size> max_size_; ++ + DISALLOW_COPY_AND_ASSIGN(WaylandSurface); + }; + +diff --git a/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc b/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc +index 64a387723560..a4b1fc7d9436 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc ++++ b/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc +@@ -36,8 +36,11 @@ class WaylandWindowManagerTest : public WaylandTest { + PlatformWindowInitProperties properties; + properties.bounds = bounds; + properties.type = type; +- return WaylandWindow::Create(delegate, connection_.get(), +- std::move(properties)); ++ auto window = WaylandWindow::Create(delegate, connection_.get(), ++ std::move(properties)); ++ if (window) ++ window->Show(false); ++ return window; + } + + WaylandWindowManager* manager_ = nullptr; +@@ -87,6 +90,9 @@ TEST_P(WaylandWindowManagerTest, GetCurrentFocusedWindow) { + + auto window1 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow, + kDefaultBounds, &delegate); ++ // When window is shown, it automatically gets keyboard focus. Reset it. ++ window_->set_keyboard_focus(false); ++ window1->set_keyboard_focus(false); + + Sync(); + +@@ -121,6 +127,9 @@ TEST_P(WaylandWindowManagerTest, GetCurrentKeyboardFocusedWindow) { + + auto window1 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow, + kDefaultBounds, &delegate); ++ // When window is shown, it automatically gets keyboard focus. Reset it. ++ window_->set_keyboard_focus(false); ++ window1->set_keyboard_focus(false); + + Sync(); + +diff --git a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc +index 132f740b0eb1..f56b96690eea 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc ++++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc +@@ -128,11 +128,7 @@ class WaylandWindowTest : public WaylandTest { + } + } + +- // Depending on a shell version, xdg_surface_ or xdg_toplevel surface should +- // get the mock calls. This method decided, which surface to use. +- wl::MockXdgSurface* GetXdgSurface() { +- return xdg_surface_->xdg_toplevel(); +- } ++ wl::MockXdgTopLevel* GetXdgToplevel() { return xdg_surface_->xdg_toplevel(); } + + void AddStateToWlArray(uint32_t state, wl_array* states) { + *static_cast<uint32_t*>(wl_array_add(states, sizeof state)) = state; +@@ -162,8 +158,11 @@ class WaylandWindowTest : public WaylandTest { + properties.type = type; + properties.parent_widget = parent_widget; + +- return WaylandWindow::Create(delegate, connection_.get(), +- std::move(properties)); ++ auto window = WaylandWindow::Create(delegate, connection_.get(), ++ std::move(properties)); ++ if (window) ++ window->Show(false); ++ return window; + } + + void InitializeWithSupportedHitTestValues(std::vector<int>* hit_tests) { +@@ -213,7 +212,7 @@ class WaylandWindowTest : public WaylandTest { + }; + + TEST_P(WaylandWindowTest, SetTitle) { +- EXPECT_CALL(*GetXdgSurface(), SetTitle(StrEq("hello"))); ++ EXPECT_CALL(*GetXdgToplevel(), SetTitle(StrEq("hello"))); + window_->SetTitle(base::ASCIIToUTF16("hello")); + } + +@@ -229,7 +228,7 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) { + + auto active_maximized = MakeStateArray( + {XDG_TOPLEVEL_STATE_ACTIVATED, XDG_TOPLEVEL_STATE_MAXIMIZED}); +- EXPECT_CALL(*GetXdgSurface(), SetMaximized()); ++ EXPECT_CALL(*GetXdgToplevel(), SetMaximized()); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(), + kMaximizedBounds.height())); + EXPECT_CALL(delegate_, OnActivationChanged(Eq(true))); +@@ -267,7 +266,7 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) { + OnWindowStateChanged(Eq(PlatformWindowState::kNormal))); + EXPECT_CALL(delegate_, OnActivationChanged(_)).Times(0); + EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds)); +- EXPECT_CALL(*GetXdgSurface(), UnsetMaximized()); ++ EXPECT_CALL(*GetXdgToplevel(), UnsetMaximized()); + window_->Restore(); + // Reinitialize wl_array, which removes previous old states. + auto active = InitializeWlArrayWithActivatedState(); +@@ -283,7 +282,7 @@ TEST_P(WaylandWindowTest, Minimize) { + SendConfigureEvent(0, 0, 1, states.get()); + Sync(); + +- EXPECT_CALL(*GetXdgSurface(), SetMinimized()); ++ EXPECT_CALL(*GetXdgToplevel(), SetMinimized()); + // Wayland compositor doesn't notify clients about minimized state, but rather + // if a window is not activated. Thus, a WaylandWindow marks itself as being + // minimized and as soon as a configuration event with not activated state +@@ -319,7 +318,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) { + + AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get()); + +- EXPECT_CALL(*GetXdgSurface(), SetFullscreen()); ++ EXPECT_CALL(*GetXdgToplevel(), SetFullscreen()); + EXPECT_CALL(delegate_, + OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen))); + window_->ToggleFullscreen(); +@@ -330,7 +329,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) { + SendConfigureEvent(0, 0, 2, states.get()); + Sync(); + +- EXPECT_CALL(*GetXdgSurface(), UnsetFullscreen()); ++ EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen()); + EXPECT_CALL(delegate_, + OnWindowStateChanged(Eq(PlatformWindowState::kNormal))); + window_->Restore(); +@@ -347,7 +346,7 @@ TEST_P(WaylandWindowTest, StartWithFullscreen) { + + // The state must not be changed to the fullscreen before the surface is + // activated. +- EXPECT_CALL(*GetXdgSurface(), SetFullscreen()).Times(0); ++ EXPECT_CALL(*GetXdgToplevel(), SetFullscreen()).Times(0); + EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); + window_->ToggleFullscreen(); + // The state of the window must still be a normal one. +@@ -357,7 +356,7 @@ TEST_P(WaylandWindowTest, StartWithFullscreen) { + + // Once the surface will be activated, the window will automatically trigger + // the state change. +- EXPECT_CALL(*GetXdgSurface(), SetFullscreen()); ++ EXPECT_CALL(*GetXdgToplevel(), SetFullscreen()); + EXPECT_CALL(delegate_, + OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen))); + +@@ -391,7 +390,7 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) { + + auto active_maximized = MakeStateArray( + {XDG_TOPLEVEL_STATE_ACTIVATED, XDG_TOPLEVEL_STATE_MAXIMIZED}); +- EXPECT_CALL(*GetXdgSurface(), SetMaximized()); ++ EXPECT_CALL(*GetXdgToplevel(), SetMaximized()); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(), + kMaximizedBounds.height())); + EXPECT_CALL(delegate_, OnActivationChanged(Eq(true))); +@@ -404,7 +403,7 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) { + Sync(); + VerifyAndClearExpectations(); + +- EXPECT_CALL(*GetXdgSurface(), SetFullscreen()); ++ EXPECT_CALL(*GetXdgToplevel(), SetFullscreen()); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(), + kMaximizedBounds.height())); + EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); +@@ -419,8 +418,8 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) { + + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(), + kNormalBounds.height())); +- EXPECT_CALL(*GetXdgSurface(), UnsetFullscreen()); +- EXPECT_CALL(*GetXdgSurface(), UnsetMaximized()); ++ EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen()); ++ EXPECT_CALL(*GetXdgToplevel(), UnsetMaximized()); + EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds)); + EXPECT_CALL(delegate_, + OnWindowStateChanged(Eq(PlatformWindowState::kNormal))); +@@ -841,7 +840,7 @@ TEST_P(WaylandWindowTest, CanDispatchEventToMenuWindowNested) { + } + + TEST_P(WaylandWindowTest, DispatchWindowMove) { +- EXPECT_CALL(*GetXdgSurface(), Move(_)); ++ EXPECT_CALL(*GetXdgToplevel(), Move(_)); + ui::GetWmMoveResizeHandler(*window_)->DispatchHostWindowDragMovement(HTCAPTION, gfx::Point()); + } + +@@ -855,7 +854,7 @@ TEST_P(WaylandWindowTest, DispatchWindowResize) { + for (const int value : hit_test_values) { + { + uint32_t direction = wl::IdentifyDirection(*(connection_.get()), value); +- EXPECT_CALL(*GetXdgSurface(), Resize(_, Eq(direction))); ++ EXPECT_CALL(*GetXdgToplevel(), Resize(_, Eq(direction))); + wm_move_resize_handler->DispatchHostWindowDragMovement(value, + gfx::Point()); + } +@@ -1092,7 +1091,7 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) { + // shown on another display. + auto active_maximized = MakeStateArray( + {XDG_TOPLEVEL_STATE_ACTIVATED, XDG_TOPLEVEL_STATE_MAXIMIZED}); +- EXPECT_CALL(*GetXdgSurface(), SetMaximized()); ++ EXPECT_CALL(*GetXdgToplevel(), SetMaximized()); + + window_->Maximize(); + SendConfigureEvent(2493, 1413, 1, active_maximized.get()); +@@ -1252,9 +1251,9 @@ TEST_P(WaylandWindowTest, OnSizeConstraintsChanged) { + EXPECT_CALL(delegate_, GetMaximumSizeForWindow()) + .WillOnce(Return(max_size)); + +- EXPECT_CALL(*GetXdgSurface(), SetMinSize(100, 200)) ++ EXPECT_CALL(*GetXdgToplevel(), SetMinSize(100, 200)) + .Times(has_min_size ? 1 : 0); +- EXPECT_CALL(*GetXdgSurface(), SetMaxSize(300, 400)) ++ EXPECT_CALL(*GetXdgToplevel(), SetMaxSize(300, 400)) + .Times(has_max_size ? 1 : 0); + + window_->SizeConstraintsChanged(); +@@ -1265,6 +1264,129 @@ TEST_P(WaylandWindowTest, OnSizeConstraintsChanged) { + } + } + ++TEST_P(WaylandWindowTest, DestroysCreatesSurfaceOnHideShow) { ++ MockPlatformWindowDelegate delegate; ++ auto window = CreateWaylandWindowWithParams( ++ PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget, ++ gfx::Rect(0, 0, 100, 100), &delegate); ++ ASSERT_TRUE(window); ++ ++ Sync(); ++ ++ auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget()); ++ EXPECT_TRUE(mock_surface->xdg_surface()); ++ EXPECT_TRUE(mock_surface->xdg_surface()->xdg_toplevel()); ++ ++ Sync(); ++ ++ window->Hide(); ++ ++ Sync(); ++ ++ EXPECT_FALSE(mock_surface->xdg_surface()); ++ ++ window->Show(false); ++ ++ Sync(); ++ ++ EXPECT_TRUE(mock_surface->xdg_surface()); ++ EXPECT_TRUE(mock_surface->xdg_surface()->xdg_toplevel()); ++} ++ ++TEST_P(WaylandWindowTest, DestroysCreatesPopupsOnHideShow) { ++ MockPlatformWindowDelegate delegate; ++ auto window = CreateWaylandWindowWithParams( ++ PlatformWindowType::kMenu, window_->GetWidget(), gfx::Rect(0, 0, 50, 50), ++ &delegate); ++ ASSERT_TRUE(window); ++ ++ Sync(); ++ ++ auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget()); ++ EXPECT_TRUE(mock_surface->xdg_surface()); ++ EXPECT_TRUE(mock_surface->xdg_surface()->xdg_popup()); ++ ++ Sync(); ++ ++ window->Hide(); ++ ++ Sync(); ++ ++ EXPECT_FALSE(mock_surface->xdg_surface()); ++ ++ window->Show(false); ++ ++ Sync(); ++ ++ EXPECT_TRUE(mock_surface->xdg_surface()); ++ EXPECT_TRUE(mock_surface->xdg_surface()->xdg_popup()); ++} ++ ++// Tests that if the window gets hidden and shown again, the title, app id and ++// size constraints remain the same. ++TEST_P(WaylandWindowTest, SetsPropertiesOnShow) { ++ constexpr char kAppId[] = "wayland_test"; ++ const base::string16 kTitle(base::UTF8ToUTF16("WaylandWindowTest")); ++ ++ PlatformWindowInitProperties properties; ++ properties.bounds = gfx::Rect(0, 0, 100, 100); ++ properties.type = PlatformWindowType::kWindow; ++ properties.wm_class_class = kAppId; ++ ++ MockPlatformWindowDelegate delegate; ++ auto window = WaylandWindow::Create(&delegate, connection_.get(), ++ std::move(properties)); ++ DCHECK(window); ++ window->Show(false); ++ ++ Sync(); ++ ++ auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget()); ++ auto* mock_xdg_toplevel = mock_surface->xdg_surface()->xdg_toplevel(); ++ ++ // Only app id must be set now. ++ EXPECT_EQ(std::string(kAppId), mock_xdg_toplevel->app_id()); ++ EXPECT_TRUE(mock_xdg_toplevel->title().empty()); ++ EXPECT_TRUE(mock_xdg_toplevel->min_size().IsEmpty()); ++ EXPECT_TRUE(mock_xdg_toplevel->max_size().IsEmpty()); ++ ++ // Now, propagate size constraints and title. ++ base::Optional<gfx::Size> min_size(gfx::Size(1, 1)); ++ base::Optional<gfx::Size> max_size(gfx::Size(100, 100)); ++ EXPECT_CALL(delegate, GetMinimumSizeForWindow()).WillOnce(Return(min_size)); ++ EXPECT_CALL(delegate, GetMaximumSizeForWindow()).WillOnce(Return(max_size)); ++ ++ EXPECT_CALL(*mock_xdg_toplevel, ++ SetMinSize(min_size.value().width(), min_size.value().height())); ++ EXPECT_CALL(*mock_xdg_toplevel, ++ SetMaxSize(max_size.value().width(), max_size.value().height())); ++ EXPECT_CALL(*mock_xdg_toplevel, SetTitle(base::UTF16ToUTF8(kTitle))); ++ ++ window->SetTitle(kTitle); ++ window->SizeConstraintsChanged(); ++ ++ Sync(); ++ ++ window->Hide(); ++ ++ Sync(); ++ ++ window->Show(false); ++ ++ Sync(); ++ ++ mock_xdg_toplevel = mock_surface->xdg_surface()->xdg_toplevel(); ++ ++ // We can't mock all those methods above as long as the xdg_toplevel is ++ // created and destroyed on each show and hide call. However, it is the same ++ // WaylandSurface object that cached the values we set and must restore them ++ // on Show(). ++ EXPECT_EQ(mock_xdg_toplevel->min_size(), min_size.value()); ++ EXPECT_EQ(mock_xdg_toplevel->max_size(), max_size.value()); ++ EXPECT_EQ(std::string(kAppId), mock_xdg_toplevel->app_id()); ++ EXPECT_EQ(mock_xdg_toplevel->title(), base::UTF16ToUTF8(kTitle)); ++} ++ + INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest, + WaylandWindowTest, + ::testing::Values(kXdgShellStable)); +diff --git a/ui/ozone/platform/wayland/test/mock_surface.h b/ui/ozone/platform/wayland/test/mock_surface.h +index 27f7a2c09aab..47dc4680d50b 100644 +--- a/ui/ozone/platform/wayland/test/mock_surface.h ++++ b/ui/ozone/platform/wayland/test/mock_surface.h +@@ -42,15 +42,10 @@ class MockSurface : public ServerObject { + MOCK_METHOD4(DamageBuffer, + void(int32_t x, int32_t y, int32_t width, int32_t height)); + +- void set_xdg_surface(std::unique_ptr<MockXdgSurface> xdg_surface) { +- xdg_surface_ = std::move(xdg_surface); ++ void set_xdg_surface(MockXdgSurface* xdg_surface) { ++ xdg_surface_ = xdg_surface; + } +- MockXdgSurface* xdg_surface() const { return xdg_surface_.get(); } +- +- void set_xdg_popup(std::unique_ptr<MockXdgPopup> xdg_popup) { +- xdg_popup_ = std::move(xdg_popup); +- } +- MockXdgPopup* xdg_popup() const { return xdg_popup_.get(); } ++ MockXdgSurface* xdg_surface() const { return xdg_surface_; } + + void set_sub_surface(TestSubSurface* sub_surface) { + sub_surface_ = sub_surface; +@@ -62,17 +57,14 @@ class MockSurface : public ServerObject { + frame_callback_ = callback_resource; + } + +- bool has_role() const { +- return !!xdg_surface_ || !!xdg_popup_ || !!sub_surface_; +- } ++ bool has_role() const { return !!xdg_surface_ || !!sub_surface_; } + + void AttachNewBuffer(wl_resource* buffer_resource, int32_t x, int32_t y); + void ReleasePrevAttachedBuffer(); + void SendFrameCallback(); + + private: +- std::unique_ptr<MockXdgSurface> xdg_surface_; +- std::unique_ptr<MockXdgPopup> xdg_popup_; ++ MockXdgSurface* xdg_surface_ = nullptr; + TestSubSurface* sub_surface_ = nullptr; + + wl_resource* frame_callback_ = nullptr; +diff --git a/ui/ozone/platform/wayland/test/mock_xdg_popup.cc b/ui/ozone/platform/wayland/test/mock_xdg_popup.cc +index ebf449ca3e55..4a92c79edab0 100644 +--- a/ui/ozone/platform/wayland/test/mock_xdg_popup.cc ++++ b/ui/ozone/platform/wayland/test/mock_xdg_popup.cc +@@ -4,6 +4,8 @@ + + #include "ui/ozone/platform/wayland/test/mock_xdg_popup.h" + ++#include "ui/ozone/platform/wayland/test/mock_xdg_surface.h" ++ + namespace wl { + + namespace { +@@ -27,9 +29,11 @@ const struct zxdg_popup_v6_interface kZxdgPopupV6Impl = { + &Grab, // grab + }; + +-MockXdgPopup::MockXdgPopup(wl_resource* resource, const void* implementation) +- : ServerObject(resource) { +- SetImplementationUnretained(resource, implementation, this); ++MockXdgPopup::MockXdgPopup(wl_resource* resource, wl_resource* surface) ++ : ServerObject(resource), surface_(surface) { ++ auto* mock_xdg_surface = GetUserDataAs<MockXdgSurface>(surface_); ++ if (mock_xdg_surface) ++ mock_xdg_surface->set_xdg_popup(nullptr); + } + + MockXdgPopup::~MockXdgPopup() {} +diff --git a/ui/ozone/platform/wayland/test/mock_xdg_popup.h b/ui/ozone/platform/wayland/test/mock_xdg_popup.h +index 27b02361d897..61a805130200 100644 +--- a/ui/ozone/platform/wayland/test/mock_xdg_popup.h ++++ b/ui/ozone/platform/wayland/test/mock_xdg_popup.h +@@ -24,7 +24,7 @@ extern const struct zxdg_popup_v6_interface kZxdgPopupV6Impl; + + class MockXdgPopup : public ServerObject { + public: +- MockXdgPopup(wl_resource* resource, const void* implementation); ++ MockXdgPopup(wl_resource* resource, wl_resource* surface); + ~MockXdgPopup() override; + + MOCK_METHOD1(Grab, void(uint32_t serial)); +@@ -42,9 +42,11 @@ class MockXdgPopup : public ServerObject { + } + + private: +- // Position of the popup. Used only with V6. + struct TestPositioner::PopupPosition position_; + ++ // Ground surface for this popup. ++ wl_resource* surface_ = nullptr; ++ + DISALLOW_COPY_AND_ASSIGN(MockXdgPopup); + }; + +diff --git a/ui/ozone/platform/wayland/test/mock_xdg_shell.cc b/ui/ozone/platform/wayland/test/mock_xdg_shell.cc +index 1ba63d431015..cd76626a1245 100644 +--- a/ui/ozone/platform/wayland/test/mock_xdg_shell.cc ++++ b/ui/ozone/platform/wayland/test/mock_xdg_shell.cc +@@ -29,15 +29,16 @@ void GetXdgSurfaceImpl(wl_client* client, + wl_resource_post_error(resource, xdg_error, "surface already has a role"); + return; + } +- wl_resource* xdg_surface_resource = wl_resource_create( +- client, interface, wl_resource_get_version(resource), id); + ++ wl_resource* xdg_surface_resource = ++ CreateResourceWithImpl<::testing::NiceMock<MockXdgSurface>>( ++ client, interface, wl_resource_get_version(resource), implementation, ++ id, surface_resource); + if (!xdg_surface_resource) { + wl_client_post_no_memory(client); + return; + } +- surface->set_xdg_surface( +- std::make_unique<MockXdgSurface>(xdg_surface_resource, implementation)); ++ surface->set_xdg_surface(GetUserDataAs<MockXdgSurface>(xdg_surface_resource)); + } + + void CreatePositioner(wl_client* client, +diff --git a/ui/ozone/platform/wayland/test/mock_xdg_surface.cc b/ui/ozone/platform/wayland/test/mock_xdg_surface.cc +index 35963f84b963..d0bd03add2bd 100644 +--- a/ui/ozone/platform/wayland/test/mock_xdg_surface.cc ++++ b/ui/ozone/platform/wayland/test/mock_xdg_surface.cc +@@ -4,6 +4,7 @@ + + #include <xdg-shell-unstable-v6-server-protocol.h> + ++#include "ui/ozone/platform/wayland/test/mock_surface.h" + #include "ui/ozone/platform/wayland/test/mock_xdg_popup.h" + #include "ui/ozone/platform/wayland/test/mock_xdg_surface.h" + #include "ui/ozone/platform/wayland/test/test_positioner.h" +@@ -11,18 +12,26 @@ + namespace wl { + + void SetTitle(wl_client* client, wl_resource* resource, const char* title) { +- GetUserDataAs<MockXdgSurface>(resource)->SetTitle(title); ++ auto* toplevel = GetUserDataAs<MockXdgTopLevel>(resource); ++ // As it this can be envoked during construction of the XdgSurface, cache the ++ // result so that tests are able to access that information. ++ toplevel->set_title(title); ++ toplevel->SetTitle(toplevel->title()); + } + + void SetAppId(wl_client* client, wl_resource* resource, const char* app_id) { +- GetUserDataAs<MockXdgSurface>(resource)->SetAppId(app_id); ++ auto* toplevel = GetUserDataAs<MockXdgTopLevel>(resource); ++ toplevel->SetAppId(app_id); ++ // As it this can be envoked during construction of the XdgSurface, cache the ++ // result so that tests are able to access that information. ++ toplevel->set_app_id(app_id); + } + + void Move(wl_client* client, + wl_resource* resource, + wl_resource* seat, + uint32_t serial) { +- GetUserDataAs<MockXdgSurface>(resource)->Move(serial); ++ GetUserDataAs<MockXdgTopLevel>(resource)->Move(serial); + } + + void Resize(wl_client* client, +@@ -30,7 +39,7 @@ void Resize(wl_client* client, + wl_resource* seat, + uint32_t serial, + uint32_t edges) { +- GetUserDataAs<MockXdgSurface>(resource)->Resize(serial, edges); ++ GetUserDataAs<MockXdgTopLevel>(resource)->Resize(serial, edges); + } + + void AckConfigure(wl_client* client, wl_resource* resource, uint32_t serial) { +@@ -48,25 +57,47 @@ void SetWindowGeometry(wl_client* client, + } + + void SetMaximized(wl_client* client, wl_resource* resource) { +- GetUserDataAs<MockXdgSurface>(resource)->SetMaximized(); ++ GetUserDataAs<MockXdgTopLevel>(resource)->SetMaximized(); + } + + void UnsetMaximized(wl_client* client, wl_resource* resource) { +- GetUserDataAs<MockXdgSurface>(resource)->UnsetMaximized(); ++ GetUserDataAs<MockXdgTopLevel>(resource)->UnsetMaximized(); + } + + void SetFullscreen(wl_client* client, + wl_resource* resource, + wl_resource* output) { +- GetUserDataAs<MockXdgSurface>(resource)->SetFullscreen(); ++ GetUserDataAs<MockXdgTopLevel>(resource)->SetFullscreen(); + } + + void UnsetFullscreen(wl_client* client, wl_resource* resource) { +- GetUserDataAs<MockXdgSurface>(resource)->UnsetFullscreen(); ++ GetUserDataAs<MockXdgTopLevel>(resource)->UnsetFullscreen(); + } + + void SetMinimized(wl_client* client, wl_resource* resource) { +- GetUserDataAs<MockXdgSurface>(resource)->SetMinimized(); ++ GetUserDataAs<MockXdgTopLevel>(resource)->SetMinimized(); ++} ++ ++void SetMaxSize(wl_client* client, ++ wl_resource* resource, ++ int32_t width, ++ int32_t height) { ++ auto* toplevel = GetUserDataAs<MockXdgTopLevel>(resource); ++ toplevel->SetMaxSize(width, height); ++ // As it this can be envoked during construction of the XdgSurface, cache the ++ // result so that tests are able to access that information. ++ toplevel->set_max_size(gfx::Size(width, height)); ++} ++ ++void SetMinSize(wl_client* client, ++ wl_resource* resource, ++ int32_t width, ++ int32_t height) { ++ auto* toplevel = GetUserDataAs<MockXdgTopLevel>(resource); ++ toplevel->SetMinSize(width, height); ++ // As it this can be envoked during construction of the XdgSurface, cache the ++ // result so that tests are able to access that information. ++ toplevel->set_min_size(gfx::Size(width, height)); + } + + void GetTopLevel(wl_client* client, wl_resource* resource, uint32_t id) { +@@ -120,13 +151,22 @@ void GetXdgPopup(struct wl_client* client, + return; + } + +- wl_resource* xdg_popup_resource = wl_resource_create( +- client, &xdg_popup_interface, wl_resource_get_version(resource), id); ++ wl_resource* xdg_popup_resource = ++ CreateResourceWithImpl<::testing::NiceMock<MockXdgPopup>>( ++ client, &xdg_popup_interface, wl_resource_get_version(resource), ++ &kXdgPopupImpl, id, resource); ++ ++ if (!xdg_popup_resource) { ++ wl_client_post_no_memory(client); ++ return; ++ } ++ ++ auto* mock_xdg_popup = GetUserDataAs<MockXdgPopup>(xdg_popup_resource); ++ DCHECK(mock_xdg_popup); ++ + auto* positioner = GetUserDataAs<TestPositioner>(positioner_resource); + DCHECK(positioner); + +- auto mock_xdg_popup = +- std::make_unique<MockXdgPopup>(xdg_popup_resource, &kXdgPopupImpl); + mock_xdg_popup->set_position(positioner->position()); + if (mock_xdg_popup->size().IsEmpty() || + mock_xdg_popup->anchor_rect().IsEmpty()) { +@@ -135,7 +175,7 @@ void GetXdgPopup(struct wl_client* client, + return; + } + +- mock_xdg_surface->set_xdg_popup(std::move(mock_xdg_popup)); ++ mock_xdg_surface->set_xdg_popup(mock_xdg_popup); + } + + void GetZXdgPopupV6(struct wl_client* client, +@@ -156,13 +196,22 @@ void GetZXdgPopupV6(struct wl_client* client, + return; + } + +- wl_resource* xdg_popup_resource = wl_resource_create( +- client, &zxdg_popup_v6_interface, wl_resource_get_version(resource), id); ++ wl_resource* xdg_popup_resource = ++ CreateResourceWithImpl<::testing::NiceMock<MockXdgPopup>>( ++ client, &zxdg_popup_v6_interface, wl_resource_get_version(resource), ++ &kZxdgPopupV6Impl, id, resource); ++ ++ if (!xdg_popup_resource) { ++ wl_client_post_no_memory(client); ++ return; ++ } ++ ++ auto* mock_xdg_popup = GetUserDataAs<MockXdgPopup>(xdg_popup_resource); ++ DCHECK(mock_xdg_popup); ++ + auto* positioner = GetUserDataAs<TestPositioner>(positioner_resource); + DCHECK(positioner); + +- auto mock_xdg_popup = +- std::make_unique<MockXdgPopup>(xdg_popup_resource, &kZxdgPopupV6Impl); + mock_xdg_popup->set_position(positioner->position()); + if (mock_xdg_popup->size().IsEmpty() || + mock_xdg_popup->anchor_rect().IsEmpty()) { +@@ -171,21 +220,7 @@ void GetZXdgPopupV6(struct wl_client* client, + return; + } + +- mock_xdg_surface->set_xdg_popup(std::move(mock_xdg_popup)); +-} +- +-void SetMaxSize(wl_client* client, +- wl_resource* resource, +- int32_t width, +- int32_t height) { +- GetUserDataAs<MockXdgSurface>(resource)->SetMaxSize(width, height); +-} +- +-void SetMinSize(wl_client* client, +- wl_resource* resource, +- int32_t width, +- int32_t height) { +- GetUserDataAs<MockXdgSurface>(resource)->SetMinSize(width, height); ++ mock_xdg_surface->set_xdg_popup(mock_xdg_popup); + } + + const struct xdg_surface_interface kMockXdgSurfaceImpl = { +@@ -238,17 +273,18 @@ const struct zxdg_toplevel_v6_interface kMockZxdgToplevelV6Impl = { + &SetMinimized, // set_minimized + }; + +-MockXdgSurface::MockXdgSurface(wl_resource* resource, +- const void* implementation) +- : ServerObject(resource) { +- SetImplementationUnretained(resource, implementation, this); +-} ++MockXdgSurface::MockXdgSurface(wl_resource* resource, wl_resource* surface) ++ : ServerObject(resource), surface_(surface) {} + +-MockXdgSurface::~MockXdgSurface() {} ++MockXdgSurface::~MockXdgSurface() { ++ auto* mock_surface = GetUserDataAs<MockSurface>(surface_); ++ if (mock_surface) ++ mock_surface->set_xdg_surface(nullptr); ++} + + MockXdgTopLevel::MockXdgTopLevel(wl_resource* resource, + const void* implementation) +- : MockXdgSurface(resource, implementation) { ++ : ServerObject(resource) { + SetImplementationUnretained(resource, implementation, this); + } + +diff --git a/ui/ozone/platform/wayland/test/mock_xdg_surface.h b/ui/ozone/platform/wayland/test/mock_xdg_surface.h +index 20e0f96bdfcb..c41a6ed8fa32 100644 +--- a/ui/ozone/platform/wayland/test/mock_xdg_surface.h ++++ b/ui/ozone/platform/wayland/test/mock_xdg_surface.h +@@ -30,60 +30,71 @@ class MockXdgTopLevel; + // UI. + class MockXdgSurface : public ServerObject { + public: +- MockXdgSurface(wl_resource* resource, const void* implementation); ++ MockXdgSurface(wl_resource* resource, wl_resource* surface); + ~MockXdgSurface() override; + +- // These mock methods are shared between xdg_surface and zxdg_toplevel +- // surface. +- MOCK_METHOD1(SetParent, void(wl_resource* parent)); +- MOCK_METHOD1(SetTitle, void(const char* title)); +- MOCK_METHOD1(SetAppId, void(const char* app_id)); +- MOCK_METHOD1(Move, void(uint32_t serial)); +- MOCK_METHOD2(Resize, void(uint32_t serial, uint32_t edges)); + MOCK_METHOD1(AckConfigure, void(uint32_t serial)); + MOCK_METHOD4(SetWindowGeometry, + void(int32_t x, int32_t y, int32_t width, int32_t height)); +- MOCK_METHOD0(SetMaximized, void()); +- MOCK_METHOD0(UnsetMaximized, void()); +- MOCK_METHOD0(SetFullscreen, void()); +- MOCK_METHOD0(UnsetFullscreen, void()); +- MOCK_METHOD0(SetMinimized, void()); +- +- // These methods are for zxdg_toplevel only. +- MOCK_METHOD2(SetMaxSize, void(int32_t width, int32_t height)); +- MOCK_METHOD2(SetMinSize, void(int32_t width, int32_t height)); + + void set_xdg_toplevel(std::unique_ptr<MockXdgTopLevel> xdg_toplevel) { + xdg_toplevel_ = std::move(xdg_toplevel); + } + MockXdgTopLevel* xdg_toplevel() const { return xdg_toplevel_.get(); } + +- void set_xdg_popup(std::unique_ptr<MockXdgPopup> xdg_popup) { +- xdg_popup_ = std::move(xdg_popup); +- } +- MockXdgPopup* xdg_popup() const { return xdg_popup_.get(); } ++ void set_xdg_popup(MockXdgPopup* xdg_popup) { xdg_popup_ = xdg_popup; } ++ MockXdgPopup* xdg_popup() const { return xdg_popup_; } + + private: +- // Used when xdg v6 is used. ++ // Has either toplevel role.. + std::unique_ptr<MockXdgTopLevel> xdg_toplevel_; ++ // Or popup role. ++ MockXdgPopup* xdg_popup_ = nullptr; + +- std::unique_ptr<MockXdgPopup> xdg_popup_; ++ // MockSurface that is the ground for this xdg_surface. ++ wl_resource* surface_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(MockXdgSurface); + }; + + // Manage zxdg_toplevel for providing desktop UI. +-class MockXdgTopLevel : public MockXdgSurface { ++class MockXdgTopLevel : public ServerObject { + public: +- explicit MockXdgTopLevel(wl_resource* resource, const void* implementation); ++ MockXdgTopLevel(wl_resource* resource, const void* implementation); + ~MockXdgTopLevel() override; + +- // TODO(msisov): mock other zxdg_toplevel specific methods once +- // implementation +- // is done. example: MOCK_METHOD2(SetMaxSize, void(int32_t width, int32_t +- // height()); ++ MOCK_METHOD1(SetParent, void(wl_resource* parent)); ++ MOCK_METHOD1(SetTitle, void(const std::string& title)); ++ MOCK_METHOD1(SetAppId, void(const char* app_id)); ++ MOCK_METHOD1(Move, void(uint32_t serial)); ++ MOCK_METHOD2(Resize, void(uint32_t serial, uint32_t edges)); ++ MOCK_METHOD0(SetMaximized, void()); ++ MOCK_METHOD0(UnsetMaximized, void()); ++ MOCK_METHOD0(SetFullscreen, void()); ++ MOCK_METHOD0(UnsetFullscreen, void()); ++ MOCK_METHOD0(SetMinimized, void()); ++ MOCK_METHOD2(SetMaxSize, void(int32_t width, int32_t height)); ++ MOCK_METHOD2(SetMinSize, void(int32_t width, int32_t height)); ++ ++ const std::string& app_id() const { return app_id_; } ++ void set_app_id(const char* app_id) { app_id_ = std::string(app_id); } ++ ++ std::string title() const { return title_; } ++ void set_title(const char* title) { title_ = std::string(title); } ++ ++ const gfx::Size& min_size() const { return min_size_; } ++ void set_min_size(const gfx::Size& min_size) { min_size_ = min_size; } ++ ++ const gfx::Size& max_size() const { return max_size_; } ++ void set_max_size(const gfx::Size& max_size) { max_size_ = max_size; } + + private: ++ gfx::Size min_size_; ++ gfx::Size max_size_; ++ ++ std::string title_; ++ std::string app_id_; ++ + DISALLOW_COPY_AND_ASSIGN(MockXdgTopLevel); + }; + +diff --git a/ui/ozone/platform/wayland/test/wayland_test.cc b/ui/ozone/platform/wayland/test/wayland_test.cc +index 2543981d8c38..2866ab6a07f8 100644 +--- a/ui/ozone/platform/wayland/test/wayland_test.cc ++++ b/ui/ozone/platform/wayland/test/wayland_test.cc +@@ -55,6 +55,8 @@ void WaylandTest::SetUp() { + std::move(properties)); + ASSERT_NE(widget_, gfx::kNullAcceleratedWidget); + ++ window_->Show(false); ++ + // Wait for the client to flush all pending requests from initialization. + base::RunLoop().RunUntilIdle(); + +-- +2.24.1 + diff --git a/0009-ozone-wayland-window-state-change-must-be-synchronou.patch b/0009-ozone-wayland-window-state-change-must-be-synchronou.patch new file mode 100644 index 000000000000..1386e82e4e62 --- /dev/null +++ b/0009-ozone-wayland-window-state-change-must-be-synchronou.patch @@ -0,0 +1,665 @@ +From f70d9e1475b402cc70ff0b4539c26ff86ef1116c Mon Sep 17 00:00:00 2001 +From: Maksim Sisov <msisov@igalia.com> +Date: Tue, 7 Jan 2020 18:17:05 +0000 +Subject: [PATCH 9/9] ozone/wayland: window state change must be synchronous. + +This CL fixes two issues: + +1) After we changed to only create ShellSurfaces after Show calls, starting the +browser with maximized or fullscreen modes broke. That is, in Wayland, it +is required to assign a role to wl_surface and make higher level objects like +xdg_surface and xdg_toplevel that are used by desktop xdg shell. + +State manipulation can only be done through those higher level objects and +we must defer setting state to maximized/fullscreen until they are created. + +2) Also, this CL changes the intermidiate result of state changes: now, all of +them are considered synchronous and if Wayland decides to change the state +to something else, the state will be overriden and OnWindowStateChange will +be called. Otherwise, if it was the client, who changed the state, no +notification is sent. + +Test: StartMaximized, StartWithFullscreen, CompositorSideChanges +Bug: 1033525 + +Change-Id: I89728297d572d62db59f2d3b1628f2d735dbd4b0 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1965031 +Reviewed-by: Michael Spang <spang@chromium.org> +Commit-Queue: Maksim Sisov <msisov@igalia.com> +Cr-Commit-Position: refs/heads/master@{#728996} +--- + .../platform/wayland/host/wayland_surface.cc | 173 ++++++-------- + .../platform/wayland/host/wayland_surface.h | 17 +- + .../wayland/host/wayland_window_unittest.cc | 212 +++++++++++++++--- + 3 files changed, 249 insertions(+), 153 deletions(-) + +diff --git a/ui/ozone/platform/wayland/host/wayland_surface.cc b/ui/ozone/platform/wayland/host/wayland_surface.cc +index b800a526e64e..c90e499fc796 100644 +--- a/ui/ozone/platform/wayland/host/wayland_surface.cc ++++ b/ui/ozone/platform/wayland/host/wayland_surface.cc +@@ -19,8 +19,7 @@ namespace ui { + WaylandSurface::WaylandSurface(PlatformWindowDelegate* delegate, + WaylandConnection* connection) + : WaylandWindow(delegate, connection), +- state_(PlatformWindowState::kNormal), +- pending_state_(PlatformWindowState::kUnknown) { ++ state_(PlatformWindowState::kNormal) { + // Set a class property key, which allows |this| to be used for interactive + // events, e.g. move or resize. + SetWmMoveResizeHandler(this, AsWmMoveResizeHandler()); +@@ -47,6 +46,7 @@ bool WaylandSurface::CreateShellSurface() { + shell_surface_->SetAppId(app_id_); + shell_surface_->SetTitle(window_title_); + SetSizeConstraints(); ++ TriggerStateChanges(); + return true; + } + +@@ -117,7 +117,7 @@ void WaylandSurface::Hide() { + bool WaylandSurface::IsVisible() const { + // X and Windows return true if the window is minimized. For consistency, do + // the same. +- return !!shell_surface_ || IsMinimized(); ++ return !!shell_surface_ || state_ == PlatformWindowState::kMinimized; + } + + void WaylandSurface::SetTitle(const base::string16& title) { +@@ -133,74 +133,36 @@ void WaylandSurface::SetTitle(const base::string16& title) { + } + + void WaylandSurface::ToggleFullscreen() { +- DCHECK(shell_surface_); +- +- // There are some cases, when Chromium triggers a fullscreen state change +- // before the surface is activated. In such cases, Wayland may ignore state +- // changes and such flags as --kiosk or --start-fullscreen will be ignored. +- // To overcome this, set a pending state, and once the surface is activated, +- // trigger the change. +- if (!is_active_) { +- DCHECK(!IsFullscreen()); +- pending_state_ = PlatformWindowState::kFullScreen; +- return; +- } +- + // TODO(msisov, tonikitoo): add multiscreen support. As the documentation says +- // if shell_surface_set_fullscreen() is not provided with wl_output, it's up ++ // if xdg_toplevel_set_fullscreen() is not provided with wl_output, it's up + // to the compositor to choose which display will be used to map this surface. +- if (!IsFullscreen()) { +- // Fullscreen state changes have to be handled manually and then checked +- // against configuration events, which come from a compositor. The reason +- // of manually changing the |state_| is that the compositor answers about +- // state changes asynchronously, which leads to a wrong return value in +- // DesktopWindowTreeHostPlatform::IsFullscreen, for example, and media +- // files can never be set to fullscreen. +- state_ = PlatformWindowState::kFullScreen; +- shell_surface_->SetFullscreen(); ++ ++ // We must track the previous state to correctly say our state as long as it ++ // can be the maximized instead of normal one. ++ PlatformWindowState new_state = PlatformWindowState::kUnknown; ++ if (state_ == PlatformWindowState::kFullScreen) { ++ if (previous_state_ == PlatformWindowState::kMaximized) ++ new_state = previous_state_; ++ else ++ new_state = PlatformWindowState::kNormal; + } else { +- // Check the comment above. If it's not handled synchronously, media files +- // may not leave the fullscreen mode. +- state_ = PlatformWindowState::kUnknown; +- shell_surface_->UnSetFullscreen(); ++ new_state = PlatformWindowState::kFullScreen; + } + +- connection()->ScheduleFlush(); ++ SetWindowState(new_state); + } + + void WaylandSurface::Maximize() { +- DCHECK(shell_surface_); +- +- if (IsFullscreen()) +- ToggleFullscreen(); +- +- shell_surface_->SetMaximized(); +- connection()->ScheduleFlush(); ++ SetWindowState(PlatformWindowState::kMaximized); + } + + void WaylandSurface::Minimize() { +- DCHECK(shell_surface_); +- DCHECK(!is_minimizing_); +- // Wayland doesn't explicitly say if a window is minimized. Instead, it +- // notifies that the window is not activated. But there are many cases, when +- // the window is not minimized and deactivated. In order to properly record +- // the minimized state, mark this window as being minimized. And as soon as a +- // configuration event comes, check if the window has been deactivated and has +- // |is_minimizing_| set. +- is_minimizing_ = true; +- shell_surface_->SetMinimized(); +- connection()->ScheduleFlush(); ++ SetWindowState(PlatformWindowState::kMinimized); + } + + void WaylandSurface::Restore() { + DCHECK(shell_surface_); +- +- // Unfullscreen the window if it is fullscreen. +- if (IsFullscreen()) +- ToggleFullscreen(); +- +- shell_surface_->UnSetMaximized(); +- connection()->ScheduleFlush(); ++ SetWindowState(PlatformWindowState::kNormal); + } + + PlatformWindowState WaylandSurface::GetPlatformWindowState() const { +@@ -223,34 +185,21 @@ void WaylandSurface::HandleSurfaceConfigure(int32_t width, + bool is_maximized, + bool is_fullscreen, + bool is_activated) { +- // Propagate the window state information to the client. ++ // Store the old state to propagte state changes if Wayland decides to change ++ // the state to something else. + PlatformWindowState old_state = state_; +- +- // Ensure that manually handled state changes to fullscreen correspond to the +- // configuration events from a compositor. +- DCHECK_EQ(is_fullscreen, IsFullscreen()); +- +- // There are two cases, which must be handled for the minimized state. +- // The first one is the case, when the surface goes into the minimized state +- // (check comment in WaylandSurface::Minimize), and the second case is when +- // the surface still has been minimized, but another configuration event with +- // !is_activated comes. For this, check if the WaylandSurface has been +- // minimized before and !is_activated is sent. +- if ((is_minimizing_ || IsMinimized()) && !is_activated) { +- is_minimizing_ = false; ++ if (state_ == PlatformWindowState::kMinimized && !is_activated) { + state_ = PlatformWindowState::kMinimized; + } else if (is_fullscreen) { +- // To ensure the |delegate()| is notified about state changes to fullscreen, +- // assume the old_state is UNKNOWN (check comment in ToggleFullscreen). +- old_state = PlatformWindowState::kUnknown; +- DCHECK(state_ == PlatformWindowState::kFullScreen); ++ state_ = PlatformWindowState::kFullScreen; + } else if (is_maximized) { + state_ = PlatformWindowState::kMaximized; + } else { + state_ = PlatformWindowState::kNormal; + } ++ + const bool state_changed = old_state != state_; +- const bool is_normal = !IsFullscreen() && !IsMaximized(); ++ const bool is_normal = state_ == PlatformWindowState::kNormal; + + // Update state before notifying delegate. + const bool did_active_change = is_active_ != is_activated; +@@ -281,28 +230,17 @@ void WaylandSurface::HandleSurfaceConfigure(int32_t width, + 1.0 / buffer_scale())); + } + +- if (state_changed) { +- // The |restored_bounds_| are used when the window gets back to normal +- // state after it went maximized or fullscreen. So we reset these if the +- // window has just become normal and store the current bounds if it is +- // either going out of normal state or simply changes the state and we don't +- // have any meaningful value stored. +- if (is_normal) { +- SetRestoredBoundsInPixels({}); +- } else if (old_state == PlatformWindowState::kNormal || +- GetRestoredBoundsInPixels().IsEmpty()) { +- SetRestoredBoundsInPixels(GetBounds()); +- } ++ // Store the restored bounds of current state differs from the normal state. ++ // It can be client or compositor side change from normal to something else. ++ // Thus, we must store previous bounds to restore later. ++ SetOrResetRestoredBounds(); ++ ApplyPendingBounds(); + ++ if (state_changed) + delegate()->OnWindowStateChanged(state_); +- } +- +- ApplyPendingBounds(); + + if (did_active_change) + delegate()->OnActivationChanged(is_active_); +- +- MaybeTriggerPendingStateChange(); + } + + void WaylandSurface::OnDragEnter(const gfx::PointF& point, +@@ -348,24 +286,34 @@ bool WaylandSurface::OnInitialize(PlatformWindowInitProperties properties) { + return true; + } + +-bool WaylandSurface::IsMinimized() const { +- return state_ == PlatformWindowState::kMinimized; +-} ++void WaylandSurface::TriggerStateChanges() { ++ if (!shell_surface_) ++ return; + +-bool WaylandSurface::IsMaximized() const { +- return state_ == PlatformWindowState::kMaximized; +-} ++ if (state_ == PlatformWindowState::kFullScreen) ++ shell_surface_->SetFullscreen(); ++ else ++ shell_surface_->UnSetFullscreen(); ++ ++ // Call UnSetMaximized only if current state is normal. Otherwise, if the ++ // current state is fullscreen and the previous is maximized, calling ++ // UnSetMaximized may result in wrong restored window position that clients ++ // are not allowed to know about. ++ if (state_ == PlatformWindowState::kMaximized) ++ shell_surface_->SetMaximized(); ++ else if (state_ == PlatformWindowState::kNormal) ++ shell_surface_->UnSetMaximized(); ++ ++ if (state_ == PlatformWindowState::kMinimized) ++ shell_surface_->SetMinimized(); + +-bool WaylandSurface::IsFullscreen() const { +- return state_ == PlatformWindowState::kFullScreen; ++ connection()->ScheduleFlush(); + } + +-void WaylandSurface::MaybeTriggerPendingStateChange() { +- if (pending_state_ == PlatformWindowState::kUnknown || !is_active_) +- return; +- DCHECK_EQ(pending_state_, PlatformWindowState::kFullScreen); +- pending_state_ = PlatformWindowState::kUnknown; +- ToggleFullscreen(); ++void WaylandSurface::SetWindowState(PlatformWindowState state) { ++ previous_state_ = state_; ++ state_ = state; ++ TriggerStateChanges(); + } + + WmMoveResizeHandler* WaylandSurface::AsWmMoveResizeHandler() { +@@ -381,4 +329,17 @@ void WaylandSurface::SetSizeConstraints() { + connection()->ScheduleFlush(); + } + ++void WaylandSurface::SetOrResetRestoredBounds() { ++ // The |restored_bounds_| are used when the window gets back to normal ++ // state after it went maximized or fullscreen. So we reset these if the ++ // window has just become normal and store the current bounds if it is ++ // either going out of normal state or simply changes the state and we don't ++ // have any meaningful value stored. ++ if (GetPlatformWindowState() == PlatformWindowState::kNormal) { ++ SetRestoredBoundsInPixels({}); ++ } else if (GetRestoredBoundsInPixels().IsEmpty()) { ++ SetRestoredBoundsInPixels(GetBounds()); ++ } ++} ++ + } // namespace ui +diff --git a/ui/ozone/platform/wayland/host/wayland_surface.h b/ui/ozone/platform/wayland/host/wayland_surface.h +index 677eaca6ef56..ceda32d24a7c 100644 +--- a/ui/ozone/platform/wayland/host/wayland_surface.h ++++ b/ui/ozone/platform/wayland/host/wayland_surface.h +@@ -69,11 +69,8 @@ class WaylandSurface : public WaylandWindow, + void OnDragSessionClose(uint32_t dnd_action) override; + bool OnInitialize(PlatformWindowInitProperties properties) override; + +- bool IsMinimized() const; +- bool IsMaximized() const; +- bool IsFullscreen() const; +- +- void MaybeTriggerPendingStateChange(); ++ void TriggerStateChanges(); ++ void SetWindowState(PlatformWindowState state); + + // Creates a surface window, which is visible as a main window. + bool CreateShellSurface(); +@@ -83,6 +80,8 @@ class WaylandSurface : public WaylandWindow, + // Propagates the |min_size_| and |max_size_| to the ShellSurface. + void SetSizeConstraints(); + ++ void SetOrResetRestoredBounds(); ++ + // Wrappers around shell surface. + std::unique_ptr<ShellSurfaceWrapper> shell_surface_; + +@@ -100,14 +99,12 @@ class WaylandSurface : public WaylandWindow, + // handler that receives DIP from Wayland. + gfx::Rect pending_bounds_dip_; + +- // Stores current states of the window. ++ // Contains the current state of the window. + PlatformWindowState state_; +- // Stores a pending state of the window, which is used before the surface is +- // activated. +- PlatformWindowState pending_state_; ++ // Contains the previous state of the window. ++ PlatformWindowState previous_state_; + + bool is_active_ = false; +- bool is_minimizing_ = false; + + // Id of the chromium app passed through + // PlatformWindowInitProperties::wm_class_class. This is used by Wayland +diff --git a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc +index f56b96690eea..c72d27edff66 100644 +--- a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc ++++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc +@@ -233,8 +233,7 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) { + kMaximizedBounds.height())); + EXPECT_CALL(delegate_, OnActivationChanged(Eq(true))); + EXPECT_CALL(delegate_, OnBoundsChanged(kMaximizedBounds)); +- EXPECT_CALL(delegate_, +- OnWindowStateChanged(Eq(PlatformWindowState::kMaximized))); ++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); + window_->Maximize(); + SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 1, + active_maximized.get()); +@@ -262,8 +261,7 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) { + + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(), + kNormalBounds.height())); +- EXPECT_CALL(delegate_, +- OnWindowStateChanged(Eq(PlatformWindowState::kNormal))); ++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); + EXPECT_CALL(delegate_, OnActivationChanged(_)).Times(0); + EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds)); + EXPECT_CALL(*GetXdgToplevel(), UnsetMaximized()); +@@ -283,19 +281,21 @@ TEST_P(WaylandWindowTest, Minimize) { + Sync(); + + EXPECT_CALL(*GetXdgToplevel(), SetMinimized()); +- // Wayland compositor doesn't notify clients about minimized state, but rather +- // if a window is not activated. Thus, a WaylandWindow marks itself as being +- // minimized and as soon as a configuration event with not activated state +- // comes, its state is changed to minimized. This EXPECT_CALL ensures this +- // behaviour. +- EXPECT_CALL(delegate_, +- OnWindowStateChanged(Eq(PlatformWindowState::kMinimized))); ++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); + window_->Minimize(); ++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMinimized); ++ + // Reinitialize wl_array, which removes previous old states. + states = ScopedWlArray(); + SendConfigureEvent(0, 0, 2, states.get()); + Sync(); + ++ // Wayland compositor doesn't notify clients about minimized state, but rather ++ // if a window is not activated. Thus, a WaylandSurface marks itself as being ++ // minimized and and sets state to minimized. Thus, the state mustn't change ++ // after the configuration event is sent. ++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMinimized); ++ + // Send one additional empty configuration event (which means the surface is + // not maximized, fullscreen or activated) to ensure, WaylandWindow stays in + // the same minimized state and doesn't notify its delegate. +@@ -319,8 +319,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) { + AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get()); + + EXPECT_CALL(*GetXdgToplevel(), SetFullscreen()); +- EXPECT_CALL(delegate_, +- OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen))); ++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); + window_->ToggleFullscreen(); + // Make sure than WaylandWindow manually handles fullscreen states. Check the + // comment in the WaylandWindow::ToggleFullscreen. +@@ -330,51 +329,181 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) { + Sync(); + + EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen()); +- EXPECT_CALL(delegate_, +- OnWindowStateChanged(Eq(PlatformWindowState::kNormal))); ++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); + window_->Restore(); +- EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kUnknown); ++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal); + // Reinitialize wl_array, which removes previous old states. + states = InitializeWlArrayWithActivatedState(); + SendConfigureEvent(0, 0, 3, states.get()); + Sync(); ++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal); + } + + TEST_P(WaylandWindowTest, StartWithFullscreen) { ++ MockPlatformWindowDelegate delegate; ++ PlatformWindowInitProperties properties; ++ properties.bounds = gfx::Rect(0, 0, 100, 100); ++ properties.type = PlatformWindowType::kWindow; ++ // We need to create a window avoid calling Show() on it as it is what upper ++ // views layer does - when Widget initialize DesktopWindowTreeHost, the Show() ++ // is called later down the road, but Maximize may be called earlier. We ++ // cannot process them and set a pending state instead, because ShellSurface ++ // is not created by that moment. ++ auto window = WaylandWindow::Create(&delegate, connection_.get(), ++ std::move(properties)); ++ ++ Sync(); ++ ++ // Make sure the window is initialized to normal state from the beginning. ++ EXPECT_EQ(PlatformWindowState::kNormal, window->GetPlatformWindowState()); ++ ++ // The state must not be changed to the fullscreen before the surface is ++ // activated. ++ auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget()); ++ EXPECT_FALSE(mock_surface->xdg_surface()); ++ EXPECT_CALL(delegate, OnWindowStateChanged(_)).Times(0); ++ window->ToggleFullscreen(); ++ // The state of the window must already be fullscreen one. ++ EXPECT_EQ(window->GetPlatformWindowState(), PlatformWindowState::kFullScreen); ++ ++ Sync(); ++ ++ // We mustn't receive any state changes if that does not differ from the last ++ // state. ++ EXPECT_CALL(delegate, OnWindowStateChanged(_)).Times(0); ++ ++ // Activate the surface. ++ ScopedWlArray states = InitializeWlArrayWithActivatedState(); ++ AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get()); ++ SendConfigureEvent(0, 0, 1, states.get()); ++ ++ Sync(); ++ ++ // It must be still the same state. ++ EXPECT_EQ(window->GetPlatformWindowState(), PlatformWindowState::kFullScreen); ++} ++ ++TEST_P(WaylandWindowTest, StartMaximized) { ++ MockPlatformWindowDelegate delegate; ++ PlatformWindowInitProperties properties; ++ properties.bounds = gfx::Rect(0, 0, 100, 100); ++ properties.type = PlatformWindowType::kWindow; ++ // We need to create a window avoid calling Show() on it as it is what upper ++ // views layer does - when Widget initialize DesktopWindowTreeHost, the Show() ++ // is called later down the road, but Maximize may be called earlier. We ++ // cannot process them and set a pending state instead, because ShellSurface ++ // is not created by that moment. ++ auto window = WaylandWindow::Create(&delegate, connection_.get(), ++ std::move(properties)); ++ ++ Sync(); ++ + // Make sure the window is initialized to normal state from the beginning. + EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState()); + + // The state must not be changed to the fullscreen before the surface is + // activated. +- EXPECT_CALL(*GetXdgToplevel(), SetFullscreen()).Times(0); ++ auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget()); ++ EXPECT_FALSE(mock_surface->xdg_surface()); + EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); +- window_->ToggleFullscreen(); +- // The state of the window must still be a normal one. +- EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal); ++ ++ window_->Maximize(); ++ // The state of the window must already be fullscreen one. ++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized); + + Sync(); + +- // Once the surface will be activated, the window will automatically trigger +- // the state change. +- EXPECT_CALL(*GetXdgToplevel(), SetFullscreen()); +- EXPECT_CALL(delegate_, +- OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen))); ++ // Once the surface will be activated, the window state mustn't be changed ++ // and retain the same. ++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); ++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized); + + // Activate the surface. + ScopedWlArray states = InitializeWlArrayWithActivatedState(); ++ AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get()); + SendConfigureEvent(0, 0, 1, states.get()); + + Sync(); + +- // The wayland window manually handles the fullscreen state changes, and it +- // must change to a fullscreen before the state change is confirmed by the +- // wayland. See comment in the WaylandWindow::ToggleFullscreen. +- EXPECT_EQ(window_->GetPlatformWindowState(), +- PlatformWindowState::kFullScreen); ++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized); ++} + +- AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get()); ++TEST_P(WaylandWindowTest, CompositorSideStateChanges) { ++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal); ++ auto normal_bounds = window_->GetBounds(); ++ ++ ScopedWlArray states = InitializeWlArrayWithActivatedState(); ++ AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get()); ++ SendConfigureEvent(2000, 2000, 1, states.get()); ++ ++ EXPECT_CALL(delegate_, ++ OnWindowStateChanged(Eq(PlatformWindowState::kMaximized))) ++ .Times(1); ++ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2000, 2000)); ++ ++ Sync(); ++ ++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized); ++ ++ // Unmaximize ++ states = InitializeWlArrayWithActivatedState(); + SendConfigureEvent(0, 0, 2, states.get()); + ++ EXPECT_CALL(delegate_, OnWindowStateChanged(Eq(PlatformWindowState::kNormal))) ++ .Times(1); ++ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, normal_bounds.width(), ++ normal_bounds.height())); ++ ++ // Now, set to fullscreen. ++ AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get()); ++ SendConfigureEvent(2005, 2005, 3, states.get()); ++ EXPECT_CALL(delegate_, ++ OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen))) ++ .Times(1); ++ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2005, 2005)); ++ ++ Sync(); ++ ++ // Unfullscreen ++ states = InitializeWlArrayWithActivatedState(); ++ SendConfigureEvent(0, 0, 4, states.get()); ++ ++ EXPECT_CALL(delegate_, OnWindowStateChanged(Eq(PlatformWindowState::kNormal))) ++ .Times(1); ++ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, normal_bounds.width(), ++ normal_bounds.height())); ++ ++ Sync(); ++ ++ // Now, maximize, fullscreen and restore. ++ states = InitializeWlArrayWithActivatedState(); ++ AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get()); ++ SendConfigureEvent(2000, 2000, 1, states.get()); ++ ++ EXPECT_CALL(delegate_, ++ OnWindowStateChanged(Eq(PlatformWindowState::kMaximized))) ++ .Times(1); ++ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2000, 2000)); ++ ++ Sync(); ++ ++ AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get()); ++ SendConfigureEvent(2005, 2005, 1, states.get()); ++ ++ EXPECT_CALL(delegate_, ++ OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen))) ++ .Times(1); ++ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2005, 2005)); ++ ++ // Restore ++ states = InitializeWlArrayWithActivatedState(); ++ SendConfigureEvent(0, 0, 4, states.get()); ++ ++ EXPECT_CALL(delegate_, OnWindowStateChanged(Eq(PlatformWindowState::kNormal))) ++ .Times(1); ++ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, normal_bounds.width(), ++ normal_bounds.height())); ++ + Sync(); + } + +@@ -395,25 +524,33 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) { + kMaximizedBounds.height())); + EXPECT_CALL(delegate_, OnActivationChanged(Eq(true))); + EXPECT_CALL(delegate_, OnBoundsChanged(kMaximizedBounds)); +- EXPECT_CALL(delegate_, +- OnWindowStateChanged(Eq(PlatformWindowState::kMaximized))); ++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); + window_->Maximize(); ++ // State changes are synchronous. ++ EXPECT_EQ(PlatformWindowState::kMaximized, window_->GetPlatformWindowState()); + SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 2, + active_maximized.get()); + Sync(); ++ // Verify that the state has not been changed. ++ EXPECT_EQ(PlatformWindowState::kMaximized, window_->GetPlatformWindowState()); + VerifyAndClearExpectations(); + + EXPECT_CALL(*GetXdgToplevel(), SetFullscreen()); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(), + kMaximizedBounds.height())); + EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); +- EXPECT_CALL(delegate_, +- OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen))); ++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); + window_->ToggleFullscreen(); ++ // State changes are synchronous. ++ EXPECT_EQ(PlatformWindowState::kFullScreen, ++ window_->GetPlatformWindowState()); + AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, active_maximized.get()); + SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 3, + active_maximized.get()); + Sync(); ++ // Verify that the state has not been changed. ++ EXPECT_EQ(PlatformWindowState::kFullScreen, ++ window_->GetPlatformWindowState()); + VerifyAndClearExpectations(); + + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(), +@@ -421,13 +558,14 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) { + EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen()); + EXPECT_CALL(*GetXdgToplevel(), UnsetMaximized()); + EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds)); +- EXPECT_CALL(delegate_, +- OnWindowStateChanged(Eq(PlatformWindowState::kNormal))); ++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); + window_->Restore(); ++ EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState()); + // Reinitialize wl_array, which removes previous old states. + auto active = InitializeWlArrayWithActivatedState(); + SendConfigureEvent(0, 0, 4, active.get()); + Sync(); ++ EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState()); + } + + TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximize) { +-- +2.24.1 + @@ -5,7 +5,7 @@ # Contributor: Daniel J Griffiths <ghost1227@archlinux.us> pkgname=chromium-ozone -pkgver=79.0.3945.117 +pkgver=80.0.3987.42 pkgrel=1 _launcher_ver=6 pkgdesc="Chromium built with patches for wayland support via Ozone" @@ -27,27 +27,21 @@ optdepends=('pepper-flash: support for Flash content' install=chromium.install source=(https://commondatastorage.googleapis.com/chromium-browser-official/chromium-$pkgver.tar.xz chromium-launcher-$_launcher_ver.tar.gz::https://github.com/foutrelis/chromium-launcher/archive/v$_launcher_ver.tar.gz - launch_manager.h-uses-std-vector.patch - include-algorithm-to-use-std-lower_bound.patch 0001-Add-missing-algorithm-header-in-bitmap_cursor_factor.patch - 0001-ozone-wayland-Complete-submission-of-a-buffer-submit.patch - icu65.patch + 0001-cros-search-service-Include-cmath-for-std-pow.patch + 0001-BookmarkModelMerger-Move-RemoteTreeNode-declaration-.patch chromium-system-icu.patch chromium-system-zlib.patch - chromium-system-hb.patch fix-spammy-unique-font-matching-log.patch chromium-widevine.patch chromium-skia-harmony.patch) -sha256sums=('4d960e8bd790cc1c8e7f0632790424957c4996a8a91b9d899eb572acec854ef1' +sha256sums=('160c02ed00d45a074246c8984144a35b092102e9b9a31e2bc9c2dad49f297945' '04917e3cd4307d8e31bfb0027a5dce6d086edb10ff8a716024fbb8bb0c7dccf1' - 'bd0fae907c451252e91c4cbf1ad301716bc9f8a4644ecc60e9590a64197477d3' - '1f906676563e866e2b59719679e76e0b2f7f082f48ef0593e86da0351a586c73' '716c28bed9f6e9c32e3617e125c1b04806700aef691763923cd4ed14b8d23279' - '9e9e5c66d4555c787736c5d5d5fcef8b5e14d913b138041c9c90d1976ee46845' - '1de9bdbfed482295dda45c7d4e323cee55a34e42f66b892da1c1a778682b7a41' + '4c892f046ab10df609aa39d9985248d368c77306783a64d335ff713dabad60b0' + 'a44ed59db5258221ee187dc2501040e5ebfc5c1353ac98d4313ac6a12ae32d1f' 'e73cc2ee8d3ea35aab18c478d76fdfc68ca4463e1e10306fa1e738c03b3f26b5' 'eb67eda4945a89c3b90473fa8dc20637511ca4dcb58879a8ed6bf403700ca9c8' - 'c0ad3fa426cb8fc1a237ddc6309a6b2dd4055bbe41dd07f50071ee61f969b81a' '6fbffe59b886195b92c9a55137cef83021c16593f49714acb20023633e3ebb19' '709e2fddba3c1f2ed4deb3a239fc0479bfa50c46e054e7f32db4fb1365fed070' '771292942c0901092a402cc60ee883877a99fb804cb54d568c8c6c94565a48e1') @@ -66,7 +60,7 @@ declare -gA _system_libs=( #[libpng]=libpng # https://crbug.com/752403#c10 #[libvpx]=libvpx # https://github.com/webmproject/libvpx/commit/5a0242ba5c [libwebp]=libwebp - [libxml]=libxml2 + # [libxml]=libxml2 [libxslt]=libxslt [opus]=opus [re2]=re2 @@ -87,13 +81,12 @@ _google_api_key=AIzaSyDwr302FpOSkGRpLlUpPThNTDPbXcIn_FM _google_default_client_id=413772536636.apps.googleusercontent.com _google_default_client_secret=0ZChLK6AxeA3Isu96MkwqDR4 -# Branch point: 706915 +# Branch point: 722274 # Extra commits related specifically to wayland support: # These consist of the above commits and their dependencies # generated with `git-deps -r -e <release tag> <commit>^! ...` (in reverse order) _bugfix_patches=( - '0001-ozone-wayland-Complete-submission-of-a-buffer-submit.patch' ) prepare() { @@ -109,21 +102,17 @@ prepare() { third_party/blink/renderer/core/xml/parser/xml_document_parser.cc \ third_party/libxml/chromium/libxml_utils.cc - # https://crbug.com/819294 - patch -Np1 -i ../launch_manager.h-uses-std-vector.patch - patch -Np1 -i ../include-algorithm-to-use-std-lower_bound.patch + # build fixes patch -Np1 -i ../0001-Add-missing-algorithm-header-in-bitmap_cursor_factor.patch - - # https://crbug.com/1014272 - patch -Np1 -i ../icu65.patch - + patch -Np1 -i ../0001-cros-search-service-Include-cmath-for-std-pow.patch + patch -Np1 -i ../0001-BookmarkModelMerger-Move-RemoteTreeNode-declaration-.patch + # Fixes from Gentoo patch -Np1 -i ../chromium-system-icu.patch patch -Np1 -i ../chromium-system-zlib.patch - patch -Np1 -i ../chromium-system-hb.patch # https://crbug.com/1005508 - patch -Np1 -i ../fix-spammy-unique-font-matching-log.patch + # patch -Np1 -i ../fix-spammy-unique-font-matching-log.patch # Load bundled Widevine CDM if available (see chromium-widevine in the AUR) # M79 is supposed to download it as a component but it doesn't seem to work diff --git a/chromium-system-hb.patch b/chromium-system-hb.patch deleted file mode 100644 index 83e0621777f1..000000000000 --- a/chromium-system-hb.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff --git a/components/paint_preview/common/subset_font.cc b/components/paint_preview/common/subset_font.cc -index a218d63..6a5bdae 100644 ---- a/components/paint_preview/common/subset_font.cc -+++ b/components/paint_preview/common/subset_font.cc -@@ -10,11 +10,12 @@ - #include "base/bind.h" - #include "base/callback.h" - #include "base/macros.h" --#include "third_party/harfbuzz-ng/src/src/hb-subset.h" --#include "third_party/harfbuzz-ng/src/src/hb.h" - #include "third_party/skia/include/core/SkStream.h" - #include "third_party/skia/include/core/SkTypeface.h" - -+#include <hb-subset.h> -+#include <hb.h> -+ - namespace paint_preview { - - namespace { diff --git a/icu65.patch b/icu65.patch deleted file mode 100644 index 811d56286a98..000000000000 --- a/icu65.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 5679c3c191ed62b62d8db22f1657a296ee9bfe8e Mon Sep 17 00:00:00 2001 -From: Frank Tang <ftang@chromium.org> -Date: Wed, 30 Oct 2019 22:49:47 +0000 -Subject: [PATCH] Update ICU to 65.1 from 64 and fix broken tests - -ICU 65-1 release note -http://site.icu-project.org/download/65 - -CLDR 36 release blog -http://blog.unicode.org/2019/10/unicode-cldr-version-36-languagelocale.html - -Most of the test expectation change is due to CLDR 36 update -of Grapheme Cluster for Indic languages -See the following for related changes in ICU 65.1 in this area: -https://unicode-org.atlassian.net/browse/CLDR-10994 -https://unicode-org.atlassian.net/browse/ICU-13637 -https://github.com/unicode-org/cldr/blob/master/common/properties/segments/readme.txt - -Bug: chromium:1014272, chromium:1017047 -Change-Id: I9fc6d4620bf2a4c189940d06d8c79893502db3dd -Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_layout_ng_disabled -Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1866059 -Reviewed-by: Jungshik Shin <jshin@chromium.org> -Reviewed-by: Doug Turner <dougt@chromium.org> -Reviewed-by: Michael Wasserman <msw@chromium.org> -Reviewed-by: Kent Tamura <tkent@chromium.org> -Reviewed-by: Trent Apted <tapted@chromium.org> -Reviewed-by: Mason Freed <masonfreed@chromium.org> -Commit-Queue: Frank Tang <ftang@chromium.org> -Cr-Commit-Position: refs/heads/master@{#711027} ---- - third_party/blink/renderer/core/dom/document.cc | 2 +- - ui/gfx/render_text_harfbuzz.cc | 5 ++++- - 2 files changed, 5 insertions(+), 2 deletions(-) - -diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc -index 511aac29086..f188cf548a6 100644 ---- a/third_party/blink/renderer/core/dom/document.cc -+++ b/third_party/blink/renderer/core/dom/document.cc -@@ -6191,7 +6191,7 @@ static ParseQualifiedNameResult ParseQualifiedNameInternal( - - for (unsigned i = 0; i < length;) { - UChar32 c; -- U16_NEXT(characters, i, length, c) -+ U16_NEXT(characters, i, length, c); - if (c == ':') { - if (saw_colon) - return ParseQualifiedNameResult(kQNMultipleColons); -diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc -index 50e86af6b97..0339ff3ff8e 100644 ---- a/ui/gfx/render_text_harfbuzz.cc -+++ b/ui/gfx/render_text_harfbuzz.cc -@@ -971,7 +971,10 @@ RangeF TextRunHarfBuzz::GetGraphemeBounds(RenderTextHarfBuzz* render_text, - ++total; - } - } -- DCHECK_GT(total, 0); -+ // With ICU 65.1, DCHECK_GT() below fails. -+ // See https://crbug.com/1017047 for more details. -+ // -+ // DCHECK_GT(total, 0); - - // It's possible for |text_index| to point to a diacritical mark, at the end - // of |chars|. In this case all the grapheme boundaries come before it. Just diff --git a/include-algorithm-to-use-std-lower_bound.patch b/include-algorithm-to-use-std-lower_bound.patch deleted file mode 100644 index dc376321ffc4..000000000000 --- a/include-algorithm-to-use-std-lower_bound.patch +++ /dev/null @@ -1,49 +0,0 @@ -From f7c177d35242311ea7a2cf49a0980c61664f27ba Mon Sep 17 00:00:00 2001 -From: Jose Dapena Paz <jose.dapena@lge.com> -Date: Fri, 25 Oct 2019 15:07:09 +0000 -Subject: [PATCH] IWYU: include algorithm to use std::lower_bound in - ui/gfx/font.cc -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Fix GCC build because of missing include: -../../ui/gfx/font.cc: In function ‘gfx::Font::Weight gfx::FontWeightFromInt(int)’: -../../ui/gfx/font.cc:114:8: error: no matching function for call to ‘lower_bound(const gfx::Font::Weight*, const gfx::Font::Weight*, int&, gfx::FontWeightFromInt(int)::<lambda(const gfx::Font::Weight&, const int&)>)’ - }); - ^ -In file included from /usr/include/c++/8/bits/char_traits.h:39, - from /usr/include/c++/8/string:40, - from ../../ui/gfx/font.h:8, - from ../../ui/gfx/font.cc:5: -/usr/include/c++/8/bits/stl_algobase.h:984:5: note: candidate: ‘template<class _ForwardIterator, class _Tp> _ForwardIterator std::lower_bound(_ForwardIterator, _ForwardIterator, const _Tp&)’ - lower_bound(_ForwardIterator __first, _ForwardIterator __last, - ^~~~~~~~~~~ -/usr/include/c++/8/bits/stl_algobase.h:984:5: note: template argument deduction/substitution failed: -../../ui/gfx/font.cc:114:8: note: candidate expects 3 arguments, 4 provided - }); - ^ - -Bug: 819294 -Change-Id: Ic59dcf3a06bdd54d1d426c08a61624873a0ff30c -Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1879909 -Commit-Queue: Alexei Svitkine <asvitkine@chromium.org> -Reviewed-by: Alexei Svitkine <asvitkine@chromium.org> -Cr-Commit-Position: refs/heads/master@{#709472} ---- - ui/gfx/font.cc | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/ui/gfx/font.cc b/ui/gfx/font.cc -index 21367fd7297..92b159e13d1 100644 ---- a/ui/gfx/font.cc -+++ b/ui/gfx/font.cc -@@ -4,6 +4,8 @@ - - #include "ui/gfx/font.h" - -+#include <algorithm> -+ - #include "base/strings/utf_string_conversions.h" - #include "build/build_config.h" - #include "ui/gfx/platform_font.h" diff --git a/launch_manager.h-uses-std-vector.patch b/launch_manager.h-uses-std-vector.patch deleted file mode 100644 index 72abe9b9ce69..000000000000 --- a/launch_manager.h-uses-std-vector.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 97eb905ba262382bc3583078761c68f4452aea71 Mon Sep 17 00:00:00 2001 -From: Jose Dapena Paz <jose.dapena@lge.com> -Date: Fri, 25 Oct 2019 09:27:53 +0000 -Subject: [PATCH] IWYU: launch_manager.h uses std::vector -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add #include <vector> for using std::vector. This fixes GCC build. - -./../chrome/browser/apps/launch_service/launch_manager.h:46:15: error: ‘vector’ in namespace ‘std’ does not name a template type - static std::vector<base::FilePath> GetLaunchFilesFromCommandLine( - ^~~~~~ - -Bug: 819294 -Change-Id: I02ec3a2914a8fbe3aa0041017a0228f4b0ca1ec9 -Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1879289 -Reviewed-by: Alexey Baskakov <loyso@chromium.org> -Commit-Queue: José Dapena Paz <jose.dapena@lge.com> -Cr-Commit-Position: refs/heads/master@{#709411} ---- - chrome/browser/apps/launch_service/launch_manager.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/chrome/browser/apps/launch_service/launch_manager.h b/chrome/browser/apps/launch_service/launch_manager.h -index 00aeb9d9c2a..76570ead0f9 100644 ---- a/chrome/browser/apps/launch_service/launch_manager.h -+++ b/chrome/browser/apps/launch_service/launch_manager.h -@@ -6,6 +6,7 @@ - #define CHROME_BROWSER_APPS_LAUNCH_SERVICE_LAUNCH_MANAGER_H_ - - #include <string> -+#include <vector> - - #include "base/macros.h" - |