OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/mus/ws/window_tree.h" | 5 #include "components/mus/ws/window_tree.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <string> | 9 #include <string> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/macros.h" | 12 #include "base/macros.h" |
13 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
14 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.h" |
15 #include "components/mus/common/types.h" | 15 #include "components/mus/common/types.h" |
16 #include "components/mus/common/util.h" | 16 #include "components/mus/common/util.h" |
| 17 #include "components/mus/public/cpp/lib/in_flight_change.h" |
17 #include "components/mus/public/interfaces/window_tree.mojom.h" | 18 #include "components/mus/public/interfaces/window_tree.mojom.h" |
18 #include "components/mus/surfaces/surfaces_state.h" | 19 #include "components/mus/surfaces/surfaces_state.h" |
19 #include "components/mus/ws/default_access_policy.h" | 20 #include "components/mus/ws/default_access_policy.h" |
20 #include "components/mus/ws/display_binding.h" | 21 #include "components/mus/ws/display_binding.h" |
21 #include "components/mus/ws/ids.h" | 22 #include "components/mus/ws/ids.h" |
22 #include "components/mus/ws/platform_display.h" | 23 #include "components/mus/ws/platform_display.h" |
23 #include "components/mus/ws/platform_display_factory.h" | 24 #include "components/mus/ws/platform_display_factory.h" |
24 #include "components/mus/ws/platform_display_init_params.h" | 25 #include "components/mus/ws/platform_display_init_params.h" |
25 #include "components/mus/ws/server_window.h" | 26 #include "components/mus/ws/server_window.h" |
26 #include "components/mus/ws/server_window_surface_manager_test_api.h" | 27 #include "components/mus/ws/server_window_surface_manager_test_api.h" |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 ->capture_window(); | 91 ->capture_window(); |
91 } | 92 } |
92 | 93 |
93 mojom::EventMatcherPtr CreateEventMatcher(ui::mojom::EventType type) { | 94 mojom::EventMatcherPtr CreateEventMatcher(ui::mojom::EventType type) { |
94 mojom::EventMatcherPtr matcher = mojom::EventMatcher::New(); | 95 mojom::EventMatcherPtr matcher = mojom::EventMatcher::New(); |
95 matcher->type_matcher = mojom::EventTypeMatcher::New(); | 96 matcher->type_matcher = mojom::EventTypeMatcher::New(); |
96 matcher->type_matcher->type = type; | 97 matcher->type_matcher->type = type; |
97 return matcher; | 98 return matcher; |
98 } | 99 } |
99 | 100 |
| 101 class TestMoveLoopWindowManager : public TestWindowManager { |
| 102 public: |
| 103 TestMoveLoopWindowManager(WindowTree* tree) : tree_(tree) {} |
| 104 ~TestMoveLoopWindowManager() override {} |
| 105 |
| 106 void WmPerformMoveLoop(uint32_t change_id, |
| 107 uint32_t window_id, |
| 108 const gfx::Point& cursor_location) override { |
| 109 static_cast<mojom::WindowManagerClient*>(tree_)->OnWmMoveLoopCompleted( |
| 110 change_id, true); |
| 111 } |
| 112 |
| 113 private: |
| 114 WindowTree* tree_; |
| 115 |
| 116 DISALLOW_COPY_AND_ASSIGN(TestMoveLoopWindowManager); |
| 117 }; |
| 118 |
100 } // namespace | 119 } // namespace |
101 | 120 |
102 // ----------------------------------------------------------------------------- | 121 // ----------------------------------------------------------------------------- |
103 | 122 |
104 class WindowTreeTest : public testing::Test { | 123 class WindowTreeTest : public testing::Test { |
105 public: | 124 public: |
106 WindowTreeTest() {} | 125 WindowTreeTest() {} |
107 ~WindowTreeTest() override {} | 126 ~WindowTreeTest() override {} |
108 | 127 |
109 mus::mojom::Cursor cursor_id() { | 128 mus::mojom::Cursor cursor_id() { |
(...skipping 894 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1004 EXPECT_EQ(owning_tree, wm_state_test_api.tree_awaiting_input_ack()); | 1023 EXPECT_EQ(owning_tree, wm_state_test_api.tree_awaiting_input_ack()); |
1005 AckPreviousEvent(); | 1024 AckPreviousEvent(); |
1006 | 1025 |
1007 // Set capture from the embedded client and make sure it gets the event. | 1026 // Set capture from the embedded client and make sure it gets the event. |
1008 ASSERT_TRUE( | 1027 ASSERT_TRUE( |
1009 embed_tree->SetCapture(ClientWindowIdForWindow(embed_tree, window))); | 1028 embed_tree->SetCapture(ClientWindowIdForWindow(embed_tree, window))); |
1010 DispatchEventWithoutAck(CreateMouseMoveEvent(22, 23)); | 1029 DispatchEventWithoutAck(CreateMouseMoveEvent(22, 23)); |
1011 EXPECT_EQ(embed_tree, wm_state_test_api.tree_awaiting_input_ack()); | 1030 EXPECT_EQ(embed_tree, wm_state_test_api.tree_awaiting_input_ack()); |
1012 } | 1031 } |
1013 | 1032 |
| 1033 TEST_F(WindowTreeTest, ValidMoveLoopWithWM) { |
| 1034 TestWindowManager wm_internal; |
| 1035 set_window_manager_internal(wm_tree(), &wm_internal); |
| 1036 |
| 1037 TestWindowTreeBinding* child_binding; |
| 1038 WindowTree* child_tree = CreateNewTree(wm_tree()->user_id(), &child_binding); |
| 1039 child_binding->client()->tracker()->changes()->clear(); |
| 1040 child_binding->client()->set_record_on_change_completed(true); |
| 1041 |
| 1042 // Create a new top level window. |
| 1043 mojo::Map<mojo::String, mojo::Array<uint8_t>> properties; |
| 1044 const uint32_t initial_change_id = 17; |
| 1045 // Explicitly use an id that does not contain the client id. |
| 1046 const ClientWindowId embed_window_id2_in_child(45 << 16 | 27); |
| 1047 static_cast<mojom::WindowTree*>(child_tree) |
| 1048 ->NewTopLevelWindow(initial_change_id, embed_window_id2_in_child.id, |
| 1049 std::move(properties)); |
| 1050 |
| 1051 // The binding should be paused until the wm acks the change. |
| 1052 uint32_t wm_change_id = 0u; |
| 1053 ASSERT_TRUE(wm_internal.did_call_create_top_level_window(&wm_change_id)); |
| 1054 EXPECT_TRUE(child_binding->is_paused()); |
| 1055 |
| 1056 // Create the window for |embed_window_id2_in_child|. |
| 1057 const ClientWindowId embed_window_id2 = BuildClientWindowId(wm_tree(), 2); |
| 1058 EXPECT_TRUE( |
| 1059 wm_tree()->NewWindow(embed_window_id2, ServerWindow::Properties())); |
| 1060 EXPECT_TRUE(wm_tree()->SetWindowVisibility(embed_window_id2, true)); |
| 1061 EXPECT_TRUE(wm_tree()->AddWindow(FirstRootId(wm_tree()), embed_window_id2)); |
| 1062 |
| 1063 // Ack the change, which should resume the binding. |
| 1064 child_binding->client()->tracker()->changes()->clear(); |
| 1065 static_cast<mojom::WindowManagerClient*>(wm_tree()) |
| 1066 ->OnWmCreatedTopLevelWindow(wm_change_id, embed_window_id2.id); |
| 1067 EXPECT_FALSE(child_binding->is_paused()); |
| 1068 |
| 1069 // The child_tree is the one that has to make this call; the |
| 1070 const uint32_t change_id = 7; |
| 1071 static_cast<mojom::WindowTree*>(child_tree) |
| 1072 ->PerformWindowMove(change_id, embed_window_id2_in_child.id, |
| 1073 gfx::Point(0, 0)); |
| 1074 |
| 1075 EXPECT_TRUE(wm_internal.on_perform_move_loop_called()); |
| 1076 } |
| 1077 |
| 1078 TEST_F(WindowTreeTest, MoveLoopAckOKByWM) { |
| 1079 TestMoveLoopWindowManager wm_internal(wm_tree()); |
| 1080 set_window_manager_internal(wm_tree(), &wm_internal); |
| 1081 |
| 1082 TestWindowTreeBinding* child_binding; |
| 1083 WindowTree* child_tree = CreateNewTree(wm_tree()->user_id(), &child_binding); |
| 1084 child_binding->client()->tracker()->changes()->clear(); |
| 1085 child_binding->client()->set_record_on_change_completed(true); |
| 1086 |
| 1087 // Create a new top level window. |
| 1088 mojo::Map<mojo::String, mojo::Array<uint8_t>> properties; |
| 1089 const uint32_t initial_change_id = 17; |
| 1090 // Explicitly use an id that does not contain the client id. |
| 1091 const ClientWindowId embed_window_id2_in_child(45 << 16 | 27); |
| 1092 static_cast<mojom::WindowTree*>(child_tree) |
| 1093 ->NewTopLevelWindow(initial_change_id, embed_window_id2_in_child.id, |
| 1094 std::move(properties)); |
| 1095 |
| 1096 // The binding should be paused until the wm acks the change. |
| 1097 uint32_t wm_change_id = 0u; |
| 1098 ASSERT_TRUE(wm_internal.did_call_create_top_level_window(&wm_change_id)); |
| 1099 EXPECT_TRUE(child_binding->is_paused()); |
| 1100 |
| 1101 // Create the window for |embed_window_id2_in_child|. |
| 1102 const ClientWindowId embed_window_id2 = BuildClientWindowId(wm_tree(), 2); |
| 1103 EXPECT_TRUE( |
| 1104 wm_tree()->NewWindow(embed_window_id2, ServerWindow::Properties())); |
| 1105 EXPECT_TRUE(wm_tree()->SetWindowVisibility(embed_window_id2, true)); |
| 1106 EXPECT_TRUE(wm_tree()->AddWindow(FirstRootId(wm_tree()), embed_window_id2)); |
| 1107 |
| 1108 // Ack the change, which should resume the binding. |
| 1109 child_binding->client()->tracker()->changes()->clear(); |
| 1110 static_cast<mojom::WindowManagerClient*>(wm_tree()) |
| 1111 ->OnWmCreatedTopLevelWindow(wm_change_id, embed_window_id2.id); |
| 1112 EXPECT_FALSE(child_binding->is_paused()); |
| 1113 |
| 1114 // The child_tree is the one that has to make this call; the |
| 1115 const uint32_t change_id = 7; |
| 1116 child_binding->client()->tracker()->changes()->clear(); |
| 1117 static_cast<mojom::WindowTree*>(child_tree) |
| 1118 ->PerformWindowMove(change_id, embed_window_id2_in_child.id, |
| 1119 gfx::Point(0, 0)); |
| 1120 |
| 1121 EXPECT_EQ("ChangeCompleted id=7 sucess=true", |
| 1122 SingleChangeToDescription( |
| 1123 *child_binding->client()->tracker()->changes())); |
| 1124 } |
| 1125 |
| 1126 TEST_F(WindowTreeTest, WindowManagerCantMoveLoop) { |
| 1127 TestWindowManager wm_internal; |
| 1128 set_window_manager_internal(wm_tree(), &wm_internal); |
| 1129 |
| 1130 TestWindowTreeBinding* child_binding; |
| 1131 WindowTree* child_tree = CreateNewTree(wm_tree()->user_id(), &child_binding); |
| 1132 child_binding->client()->tracker()->changes()->clear(); |
| 1133 child_binding->client()->set_record_on_change_completed(true); |
| 1134 |
| 1135 // Create a new top level window. |
| 1136 mojo::Map<mojo::String, mojo::Array<uint8_t>> properties; |
| 1137 const uint32_t initial_change_id = 17; |
| 1138 // Explicitly use an id that does not contain the client id. |
| 1139 const ClientWindowId embed_window_id2_in_child(45 << 16 | 27); |
| 1140 static_cast<mojom::WindowTree*>(child_tree) |
| 1141 ->NewTopLevelWindow(initial_change_id, embed_window_id2_in_child.id, |
| 1142 std::move(properties)); |
| 1143 |
| 1144 // The binding should be paused until the wm acks the change. |
| 1145 uint32_t wm_change_id = 0u; |
| 1146 ASSERT_TRUE(wm_internal.did_call_create_top_level_window(&wm_change_id)); |
| 1147 EXPECT_TRUE(child_binding->is_paused()); |
| 1148 |
| 1149 // Create the window for |embed_window_id2_in_child|. |
| 1150 const ClientWindowId embed_window_id2 = BuildClientWindowId(wm_tree(), 2); |
| 1151 EXPECT_TRUE( |
| 1152 wm_tree()->NewWindow(embed_window_id2, ServerWindow::Properties())); |
| 1153 EXPECT_TRUE(wm_tree()->SetWindowVisibility(embed_window_id2, true)); |
| 1154 EXPECT_TRUE(wm_tree()->AddWindow(FirstRootId(wm_tree()), embed_window_id2)); |
| 1155 |
| 1156 // Ack the change, which should resume the binding. |
| 1157 child_binding->client()->tracker()->changes()->clear(); |
| 1158 static_cast<mojom::WindowManagerClient*>(wm_tree()) |
| 1159 ->OnWmCreatedTopLevelWindow(wm_change_id, embed_window_id2.id); |
| 1160 EXPECT_FALSE(child_binding->is_paused()); |
| 1161 |
| 1162 // Making this call from the wm_tree() must be invalid. |
| 1163 const uint32_t change_id = 7; |
| 1164 static_cast<mojom::WindowTree*>(wm_tree())->PerformWindowMove( |
| 1165 change_id, embed_window_id2.id, gfx::Point(0, 0)); |
| 1166 |
| 1167 EXPECT_FALSE(wm_internal.on_perform_move_loop_called()); |
| 1168 } |
| 1169 |
| 1170 TEST_F(WindowTreeTest, RevertWindowBoundsOnMoveLoopFailure) { |
| 1171 TestWindowManager wm_internal; |
| 1172 set_window_manager_internal(wm_tree(), &wm_internal); |
| 1173 |
| 1174 TestWindowTreeBinding* child_binding; |
| 1175 WindowTree* child_tree = CreateNewTree(wm_tree()->user_id(), &child_binding); |
| 1176 child_binding->client()->tracker()->changes()->clear(); |
| 1177 child_binding->client()->set_record_on_change_completed(true); |
| 1178 |
| 1179 // Create a new top level window. |
| 1180 mojo::Map<mojo::String, mojo::Array<uint8_t>> properties; |
| 1181 const uint32_t initial_change_id = 17; |
| 1182 // Explicitly use an id that does not contain the client id. |
| 1183 const ClientWindowId embed_window_id2_in_child(45 << 16 | 27); |
| 1184 static_cast<mojom::WindowTree*>(child_tree) |
| 1185 ->NewTopLevelWindow(initial_change_id, embed_window_id2_in_child.id, |
| 1186 std::move(properties)); |
| 1187 |
| 1188 // The binding should be paused until the wm acks the change. |
| 1189 uint32_t wm_change_id = 0u; |
| 1190 ASSERT_TRUE(wm_internal.did_call_create_top_level_window(&wm_change_id)); |
| 1191 EXPECT_TRUE(child_binding->is_paused()); |
| 1192 |
| 1193 // Create the window for |embed_window_id2_in_child|. |
| 1194 const ClientWindowId embed_window_id2 = BuildClientWindowId(wm_tree(), 2); |
| 1195 EXPECT_TRUE( |
| 1196 wm_tree()->NewWindow(embed_window_id2, ServerWindow::Properties())); |
| 1197 EXPECT_TRUE(wm_tree()->SetWindowVisibility(embed_window_id2, true)); |
| 1198 EXPECT_TRUE(wm_tree()->AddWindow(FirstRootId(wm_tree()), embed_window_id2)); |
| 1199 |
| 1200 // Ack the change, which should resume the binding. |
| 1201 child_binding->client()->tracker()->changes()->clear(); |
| 1202 static_cast<mojom::WindowManagerClient*>(wm_tree()) |
| 1203 ->OnWmCreatedTopLevelWindow(wm_change_id, embed_window_id2.id); |
| 1204 EXPECT_FALSE(child_binding->is_paused()); |
| 1205 |
| 1206 // The child_tree is the one that has to make this call; the |
| 1207 const uint32_t change_id = 7; |
| 1208 static_cast<mojom::WindowTree*>(child_tree) |
| 1209 ->PerformWindowMove(change_id, embed_window_id2_in_child.id, |
| 1210 gfx::Point(0, 0)); |
| 1211 |
| 1212 ServerWindow* server_window = |
| 1213 wm_tree()->GetWindowByClientId(embed_window_id2); |
| 1214 gfx::Rect old_bounds = server_window->bounds(); |
| 1215 server_window->SetBounds(gfx::Rect(10, 10, 20, 20)); |
| 1216 |
| 1217 // Cancel the move loop. |
| 1218 const uint32_t kFirstWMChange = 1; |
| 1219 static_cast<mojom::WindowManagerClient*>(wm_tree())->OnWmMoveLoopCompleted( |
| 1220 kFirstWMChange, false); |
| 1221 |
| 1222 // Canceling the move loop should have reverted the bounds. |
| 1223 EXPECT_EQ(old_bounds, server_window->bounds()); |
| 1224 } |
| 1225 |
| 1226 TEST_F(WindowTreeTest, InvalidMoveLoopStillAcksAttempt) { |
| 1227 // We send a PerformWindowMove for an invalid window. We expect to receive a |
| 1228 // non-success OnMoveLoopCompleted() event. |
| 1229 TestWindowTreeClient* embed_client = nullptr; |
| 1230 WindowTree* tree = nullptr; |
| 1231 ServerWindow* window = nullptr; |
| 1232 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window)); |
| 1233 |
| 1234 embed_client->set_record_on_change_completed(true); |
| 1235 |
| 1236 const uint32_t kChangeId = 8; |
| 1237 const Id kInvalidWindowId = 1234567890; |
| 1238 static_cast<mojom::WindowTree*>(tree)->PerformWindowMove( |
| 1239 kChangeId, kInvalidWindowId, gfx::Point(0, 0)); |
| 1240 |
| 1241 EXPECT_EQ("ChangeCompleted id=8 sucess=false", |
| 1242 SingleChangeToDescription(*embed_client->tracker()->changes())); |
| 1243 } |
| 1244 |
1014 } // namespace test | 1245 } // namespace test |
1015 } // namespace ws | 1246 } // namespace ws |
1016 } // namespace mus | 1247 } // namespace mus |
OLD | NEW |