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