| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "services/ui/public/cpp/window_tree_client.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 | |
| 9 #include <string> | |
| 10 #include <utility> | |
| 11 #include <vector> | |
| 12 | |
| 13 #include "base/bind.h" | |
| 14 #include "base/memory/ptr_util.h" | |
| 15 #include "base/strings/stringprintf.h" | |
| 16 #include "mojo/public/cpp/bindings/map.h" | |
| 17 #include "services/service_manager/public/cpp/connector.h" | |
| 18 #include "services/ui/common/util.h" | |
| 19 #include "services/ui/public/cpp/in_flight_change.h" | |
| 20 #include "services/ui/public/cpp/input_event_handler.h" | |
| 21 #include "services/ui/public/cpp/window_drop_target.h" | |
| 22 #include "services/ui/public/cpp/window_manager_delegate.h" | |
| 23 #include "services/ui/public/cpp/window_observer.h" | |
| 24 #include "services/ui/public/cpp/window_private.h" | |
| 25 #include "services/ui/public/cpp/window_tracker.h" | |
| 26 #include "services/ui/public/cpp/window_tree_client_delegate.h" | |
| 27 #include "services/ui/public/cpp/window_tree_client_observer.h" | |
| 28 #include "services/ui/public/interfaces/constants.mojom.h" | |
| 29 #include "services/ui/public/interfaces/window_manager_window_tree_factory.mojom
.h" | |
| 30 #include "ui/display/screen.h" | |
| 31 #include "ui/events/event.h" | |
| 32 #include "ui/gfx/geometry/dip_util.h" | |
| 33 #include "ui/gfx/geometry/insets.h" | |
| 34 #include "ui/gfx/geometry/size.h" | |
| 35 | |
| 36 namespace ui { | |
| 37 | |
| 38 Id MakeTransportId(ClientSpecificId client_id, ClientSpecificId local_id) { | |
| 39 return (client_id << 16) | local_id; | |
| 40 } | |
| 41 | |
| 42 // Helper function to get the device_scale_factor() of the display::Display | |
| 43 // with |display_id|. | |
| 44 float ScaleFactorForDisplay(int64_t display_id) { | |
| 45 // TODO(jonross): Remove this once aura-mus is complete. Currently the screen | |
| 46 // is not being set properly for mus-in-renderer. (http://crbug.com/659155) | |
| 47 if (!display::Screen::GetScreen()) | |
| 48 return 1.f; | |
| 49 | |
| 50 // TODO(riajiang): Change to use display::GetDisplayWithDisplayId() after | |
| 51 // https://codereview.chromium.org/2361283002/ is landed. | |
| 52 std::vector<display::Display> displays = | |
| 53 display::Screen::GetScreen()->GetAllDisplays(); | |
| 54 auto iter = std::find_if(displays.begin(), displays.end(), | |
| 55 [display_id](const display::Display& display) { | |
| 56 return display.id() == display_id; | |
| 57 }); | |
| 58 if (iter != displays.end()) | |
| 59 return iter->device_scale_factor(); | |
| 60 return 1.f; | |
| 61 } | |
| 62 | |
| 63 // Helper called to construct a local window object from transport data. | |
| 64 Window* AddWindowToClient(WindowTreeClient* client, | |
| 65 Window* parent, | |
| 66 const mojom::WindowDataPtr& window_data) { | |
| 67 // We don't use the ctor that takes a WindowTreeClient here, since it will | |
| 68 // call back to the service and attempt to create a new window. | |
| 69 Window* window = WindowPrivate::LocalCreate(); | |
| 70 WindowPrivate private_window(window); | |
| 71 private_window.set_client(client); | |
| 72 private_window.set_server_id(window_data->window_id); | |
| 73 private_window.set_visible(window_data->visible); | |
| 74 private_window.set_properties( | |
| 75 mojo::UnorderedMapToMap(window_data->properties)); | |
| 76 client->AddWindow(window); | |
| 77 private_window.LocalSetBounds( | |
| 78 gfx::Rect(), | |
| 79 gfx::ConvertRectToDIP(ScaleFactorForDisplay(window->display_id()), | |
| 80 window_data->bounds)); | |
| 81 if (parent) | |
| 82 WindowPrivate(parent).LocalAddChild(window); | |
| 83 return window; | |
| 84 } | |
| 85 | |
| 86 struct WindowTreeClient::CurrentDragState { | |
| 87 // The current change id of the current drag an drop ipc. | |
| 88 uint32_t change_id; | |
| 89 | |
| 90 // The effect to return when we send our finish signal. | |
| 91 uint32_t completed_action; | |
| 92 | |
| 93 // Callback executed when a drag initiated by PerformDragDrop() is completed. | |
| 94 base::Callback<void(bool, uint32_t)> on_finished; | |
| 95 }; | |
| 96 | |
| 97 WindowTreeClient::WindowTreeClient( | |
| 98 WindowTreeClientDelegate* delegate, | |
| 99 WindowManagerDelegate* window_manager_delegate, | |
| 100 mojo::InterfaceRequest<mojom::WindowTreeClient> request) | |
| 101 : client_id_(0), | |
| 102 next_window_id_(1), | |
| 103 next_change_id_(1), | |
| 104 delegate_(delegate), | |
| 105 window_manager_delegate_(window_manager_delegate), | |
| 106 capture_window_(nullptr), | |
| 107 focused_window_(nullptr), | |
| 108 binding_(this), | |
| 109 tree_(nullptr), | |
| 110 in_destructor_(false), | |
| 111 weak_factory_(this) { | |
| 112 // Allow for a null request in tests. | |
| 113 if (request.is_pending()) | |
| 114 binding_.Bind(std::move(request)); | |
| 115 if (window_manager_delegate) | |
| 116 window_manager_delegate->SetWindowManagerClient(this); | |
| 117 } | |
| 118 | |
| 119 WindowTreeClient::~WindowTreeClient() { | |
| 120 in_destructor_ = true; | |
| 121 | |
| 122 for (auto& observer : observers_) | |
| 123 observer.OnWillDestroyClient(this); | |
| 124 | |
| 125 std::vector<Window*> non_owned; | |
| 126 WindowTracker tracker; | |
| 127 while (!windows_.empty()) { | |
| 128 IdToWindowMap::iterator it = windows_.begin(); | |
| 129 if (it->second->WasCreatedByThisClient()) { | |
| 130 it->second->Destroy(); | |
| 131 } else { | |
| 132 tracker.Add(it->second); | |
| 133 windows_.erase(it); | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 // Delete the non-owned windows last. In the typical case these are roots. The | |
| 138 // exception is the window manager and embed roots, which may know about | |
| 139 // other random windows that it doesn't own. | |
| 140 // NOTE: we manually delete as we're a friend. | |
| 141 while (!tracker.windows().empty()) | |
| 142 delete tracker.windows().front(); | |
| 143 | |
| 144 for (auto& observer : observers_) | |
| 145 observer.OnDidDestroyClient(this); | |
| 146 } | |
| 147 | |
| 148 void WindowTreeClient::ConnectViaWindowTreeFactory( | |
| 149 service_manager::Connector* connector) { | |
| 150 // The client id doesn't really matter, we use 101 purely for debugging. | |
| 151 client_id_ = 101; | |
| 152 | |
| 153 mojom::WindowTreeFactoryPtr factory; | |
| 154 connector->BindInterface(ui::mojom::kServiceName, &factory); | |
| 155 mojom::WindowTreePtr window_tree; | |
| 156 factory->CreateWindowTree(MakeRequest(&window_tree), | |
| 157 binding_.CreateInterfacePtrAndBind()); | |
| 158 SetWindowTree(std::move(window_tree)); | |
| 159 } | |
| 160 | |
| 161 void WindowTreeClient::ConnectAsWindowManager( | |
| 162 service_manager::Connector* connector) { | |
| 163 DCHECK(window_manager_delegate_); | |
| 164 | |
| 165 mojom::WindowManagerWindowTreeFactoryPtr factory; | |
| 166 connector->BindInterface(ui::mojom::kServiceName, &factory); | |
| 167 mojom::WindowTreePtr window_tree; | |
| 168 factory->CreateWindowTree(MakeRequest(&window_tree), | |
| 169 binding_.CreateInterfacePtrAndBind()); | |
| 170 SetWindowTree(std::move(window_tree)); | |
| 171 } | |
| 172 | |
| 173 void WindowTreeClient::WaitForEmbed() { | |
| 174 DCHECK(roots_.empty()); | |
| 175 // OnEmbed() is the first function called. | |
| 176 binding_.WaitForIncomingMethodCall(); | |
| 177 // TODO(sky): deal with pipe being closed before we get OnEmbed(). | |
| 178 } | |
| 179 | |
| 180 void WindowTreeClient::DestroyWindow(Window* window) { | |
| 181 DCHECK(tree_); | |
| 182 const uint32_t change_id = ScheduleInFlightChange( | |
| 183 base::MakeUnique<CrashInFlightChange>(window, ChangeType::DELETE_WINDOW)); | |
| 184 tree_->DeleteWindow(change_id, server_id(window)); | |
| 185 } | |
| 186 | |
| 187 void WindowTreeClient::AddChild(Window* parent, Id child_id) { | |
| 188 DCHECK(tree_); | |
| 189 const uint32_t change_id = ScheduleInFlightChange( | |
| 190 base::MakeUnique<CrashInFlightChange>(parent, ChangeType::ADD_CHILD)); | |
| 191 tree_->AddWindow(change_id, parent->server_id(), child_id); | |
| 192 } | |
| 193 | |
| 194 void WindowTreeClient::RemoveChild(Window* parent, Id child_id) { | |
| 195 DCHECK(tree_); | |
| 196 const uint32_t change_id = ScheduleInFlightChange( | |
| 197 base::MakeUnique<CrashInFlightChange>(parent, ChangeType::REMOVE_CHILD)); | |
| 198 tree_->RemoveWindowFromParent(change_id, child_id); | |
| 199 } | |
| 200 | |
| 201 void WindowTreeClient::AddTransientWindow(Window* window, | |
| 202 Id transient_window_id) { | |
| 203 DCHECK(tree_); | |
| 204 const uint32_t change_id = | |
| 205 ScheduleInFlightChange(base::MakeUnique<CrashInFlightChange>( | |
| 206 window, ChangeType::ADD_TRANSIENT_WINDOW)); | |
| 207 tree_->AddTransientWindow(change_id, server_id(window), transient_window_id); | |
| 208 } | |
| 209 | |
| 210 void WindowTreeClient::RemoveTransientWindowFromParent(Window* window) { | |
| 211 DCHECK(tree_); | |
| 212 const uint32_t change_id = | |
| 213 ScheduleInFlightChange(base::MakeUnique<CrashInFlightChange>( | |
| 214 window, ChangeType::REMOVE_TRANSIENT_WINDOW_FROM_PARENT)); | |
| 215 tree_->RemoveTransientWindowFromParent(change_id, server_id(window)); | |
| 216 } | |
| 217 | |
| 218 void WindowTreeClient::SetModal(Window* window) { | |
| 219 DCHECK(tree_); | |
| 220 const uint32_t change_id = | |
| 221 ScheduleInFlightChange(base::MakeUnique<InFlightSetModalChange>(window)); | |
| 222 tree_->SetModal(change_id, server_id(window)); | |
| 223 } | |
| 224 | |
| 225 void WindowTreeClient::Reorder(Window* window, | |
| 226 Id relative_window_id, | |
| 227 mojom::OrderDirection direction) { | |
| 228 DCHECK(tree_); | |
| 229 const uint32_t change_id = ScheduleInFlightChange( | |
| 230 base::MakeUnique<CrashInFlightChange>(window, ChangeType::REORDER)); | |
| 231 tree_->ReorderWindow(change_id, server_id(window), relative_window_id, | |
| 232 direction); | |
| 233 } | |
| 234 | |
| 235 bool WindowTreeClient::WasCreatedByThisClient(const Window* window) const { | |
| 236 // Windows created via CreateTopLevelWindow() are not owned by us, but have | |
| 237 // our client id. const_cast is required by set. | |
| 238 return HiWord(server_id(window)) == client_id_ && | |
| 239 roots_.count(const_cast<Window*>(window)) == 0; | |
| 240 } | |
| 241 | |
| 242 void WindowTreeClient::SetBounds(Window* window, | |
| 243 const gfx::Rect& old_bounds, | |
| 244 const gfx::Rect& bounds) { | |
| 245 DCHECK(tree_); | |
| 246 const uint32_t change_id = ScheduleInFlightChange( | |
| 247 base::MakeUnique<InFlightBoundsChange>(window, old_bounds)); | |
| 248 tree_->SetWindowBounds( | |
| 249 change_id, server_id(window), | |
| 250 gfx::ConvertRectToPixel(ScaleFactorForDisplay(window->display_id()), | |
| 251 bounds)); | |
| 252 } | |
| 253 | |
| 254 void WindowTreeClient::SetCapture(Window* window) { | |
| 255 // In order for us to get here we had to have exposed a window, which implies | |
| 256 // we got a client. | |
| 257 DCHECK(tree_); | |
| 258 if (capture_window_ == window) | |
| 259 return; | |
| 260 const uint32_t change_id = ScheduleInFlightChange( | |
| 261 base::MakeUnique<InFlightCaptureChange>(this, capture_window_)); | |
| 262 tree_->SetCapture(change_id, server_id(window)); | |
| 263 LocalSetCapture(window); | |
| 264 } | |
| 265 | |
| 266 void WindowTreeClient::ReleaseCapture(Window* window) { | |
| 267 // In order for us to get here we had to have exposed a window, which implies | |
| 268 // we got a client. | |
| 269 DCHECK(tree_); | |
| 270 if (capture_window_ != window) | |
| 271 return; | |
| 272 const uint32_t change_id = ScheduleInFlightChange( | |
| 273 base::MakeUnique<InFlightCaptureChange>(this, window)); | |
| 274 tree_->ReleaseCapture(change_id, server_id(window)); | |
| 275 LocalSetCapture(nullptr); | |
| 276 } | |
| 277 | |
| 278 void WindowTreeClient::SetClientArea( | |
| 279 Id window_id, | |
| 280 const gfx::Insets& client_area, | |
| 281 const std::vector<gfx::Rect>& additional_client_areas) { | |
| 282 DCHECK(tree_); | |
| 283 float device_scale_factor = | |
| 284 ScaleFactorForDisplay(GetWindowByServerId(window_id)->display_id()); | |
| 285 std::vector<gfx::Rect> additional_client_areas_in_pixel; | |
| 286 for (const gfx::Rect& area : additional_client_areas) { | |
| 287 additional_client_areas_in_pixel.push_back( | |
| 288 gfx::ConvertRectToPixel(device_scale_factor, area)); | |
| 289 } | |
| 290 tree_->SetClientArea( | |
| 291 window_id, gfx::ConvertInsetsToPixel(device_scale_factor, client_area), | |
| 292 additional_client_areas_in_pixel); | |
| 293 } | |
| 294 | |
| 295 void WindowTreeClient::SetHitTestMask(Id window_id, const gfx::Rect& mask) { | |
| 296 DCHECK(tree_); | |
| 297 tree_->SetHitTestMask( | |
| 298 window_id, | |
| 299 gfx::ConvertRectToPixel( | |
| 300 ScaleFactorForDisplay(GetWindowByServerId(window_id)->display_id()), | |
| 301 mask)); | |
| 302 } | |
| 303 | |
| 304 void WindowTreeClient::ClearHitTestMask(Id window_id) { | |
| 305 DCHECK(tree_); | |
| 306 tree_->SetHitTestMask(window_id, base::nullopt); | |
| 307 } | |
| 308 | |
| 309 void WindowTreeClient::SetFocus(Window* window) { | |
| 310 // In order for us to get here we had to have exposed a window, which implies | |
| 311 // we got a client. | |
| 312 DCHECK(tree_); | |
| 313 const uint32_t change_id = ScheduleInFlightChange( | |
| 314 base::MakeUnique<InFlightFocusChange>(this, focused_window_)); | |
| 315 tree_->SetFocus(change_id, window ? server_id(window) : 0); | |
| 316 LocalSetFocus(window); | |
| 317 } | |
| 318 | |
| 319 void WindowTreeClient::SetCanFocus(Id window_id, bool can_focus) { | |
| 320 DCHECK(tree_); | |
| 321 tree_->SetCanFocus(window_id, can_focus); | |
| 322 } | |
| 323 | |
| 324 void WindowTreeClient::SetPredefinedCursor(Id window_id, | |
| 325 ui::mojom::Cursor cursor_id) { | |
| 326 DCHECK(tree_); | |
| 327 | |
| 328 Window* window = GetWindowByServerId(window_id); | |
| 329 if (!window) | |
| 330 return; | |
| 331 | |
| 332 // We make an inflight change thing here. | |
| 333 const uint32_t change_id = | |
| 334 ScheduleInFlightChange(base::MakeUnique<InFlightPredefinedCursorChange>( | |
| 335 window, window->predefined_cursor())); | |
| 336 tree_->SetPredefinedCursor(change_id, window_id, cursor_id); | |
| 337 } | |
| 338 | |
| 339 void WindowTreeClient::SetVisible(Window* window, bool visible) { | |
| 340 DCHECK(tree_); | |
| 341 const uint32_t change_id = ScheduleInFlightChange( | |
| 342 base::MakeUnique<InFlightVisibleChange>(window, !visible)); | |
| 343 tree_->SetWindowVisibility(change_id, server_id(window), visible); | |
| 344 } | |
| 345 | |
| 346 void WindowTreeClient::SetOpacity(Window* window, float opacity) { | |
| 347 DCHECK(tree_); | |
| 348 const uint32_t change_id = ScheduleInFlightChange( | |
| 349 base::MakeUnique<InFlightOpacityChange>(window, window->opacity())); | |
| 350 tree_->SetWindowOpacity(change_id, server_id(window), opacity); | |
| 351 } | |
| 352 | |
| 353 void WindowTreeClient::SetProperty( | |
| 354 Window* window, | |
| 355 const std::string& name, | |
| 356 const base::Optional<std::vector<uint8_t>>& data) { | |
| 357 DCHECK(tree_); | |
| 358 | |
| 359 base::Optional<std::vector<uint8_t>> old_value; | |
| 360 if (window->HasSharedProperty(name)) | |
| 361 old_value.emplace(window->properties_[name]); | |
| 362 | |
| 363 const uint32_t change_id = | |
| 364 ScheduleInFlightChange(base::MakeUnique<InFlightPropertyChange>( | |
| 365 window, name, std::move(old_value))); | |
| 366 tree_->SetWindowProperty(change_id, server_id(window), name, data); | |
| 367 } | |
| 368 | |
| 369 void WindowTreeClient::SetWindowTextInputState( | |
| 370 Id window_id, | |
| 371 mojo::TextInputStatePtr state) { | |
| 372 DCHECK(tree_); | |
| 373 tree_->SetWindowTextInputState(window_id, std::move(state)); | |
| 374 } | |
| 375 | |
| 376 void WindowTreeClient::SetImeVisibility(Id window_id, | |
| 377 bool visible, | |
| 378 mojo::TextInputStatePtr state) { | |
| 379 DCHECK(tree_); | |
| 380 tree_->SetImeVisibility(window_id, visible, std::move(state)); | |
| 381 } | |
| 382 | |
| 383 void WindowTreeClient::Embed(Id window_id, | |
| 384 mojom::WindowTreeClientPtr client, | |
| 385 uint32_t flags, | |
| 386 const mojom::WindowTree::EmbedCallback& callback) { | |
| 387 DCHECK(tree_); | |
| 388 tree_->Embed(window_id, std::move(client), flags, callback); | |
| 389 } | |
| 390 | |
| 391 void WindowTreeClient::RequestClose(Window* window) { | |
| 392 if (window_manager_internal_client_) | |
| 393 window_manager_internal_client_->WmRequestClose(server_id(window)); | |
| 394 } | |
| 395 | |
| 396 void WindowTreeClient::AttachCompositorFrameSink( | |
| 397 Id window_id, | |
| 398 cc::mojom::MojoCompositorFrameSinkRequest compositor_frame_sink, | |
| 399 cc::mojom::MojoCompositorFrameSinkClientPtr client) { | |
| 400 DCHECK(tree_); | |
| 401 tree_->AttachCompositorFrameSink(window_id, std::move(compositor_frame_sink), | |
| 402 std::move(client)); | |
| 403 } | |
| 404 | |
| 405 void WindowTreeClient::LocalSetCapture(Window* window) { | |
| 406 if (capture_window_ == window) | |
| 407 return; | |
| 408 Window* lost_capture = capture_window_; | |
| 409 capture_window_ = window; | |
| 410 if (lost_capture) { | |
| 411 for (auto& observer : *WindowPrivate(lost_capture).observers()) | |
| 412 observer.OnWindowLostCapture(lost_capture); | |
| 413 } | |
| 414 for (auto& observer : observers_) | |
| 415 observer.OnWindowTreeCaptureChanged(window, lost_capture); | |
| 416 } | |
| 417 | |
| 418 void WindowTreeClient::LocalSetFocus(Window* focused) { | |
| 419 Window* blurred = focused_window_; | |
| 420 // Update |focused_window_| before calling any of the observers, so that the | |
| 421 // observers get the correct result from calling |Window::HasFocus()|, | |
| 422 // |WindowTreeClient::GetFocusedWindow()| etc. | |
| 423 focused_window_ = focused; | |
| 424 if (blurred) { | |
| 425 for (auto& observer : *WindowPrivate(blurred).observers()) | |
| 426 observer.OnWindowFocusChanged(focused, blurred); | |
| 427 } | |
| 428 if (focused) { | |
| 429 for (auto& observer : *WindowPrivate(focused).observers()) | |
| 430 observer.OnWindowFocusChanged(focused, blurred); | |
| 431 } | |
| 432 for (auto& observer : observers_) | |
| 433 observer.OnWindowTreeFocusChanged(focused, blurred); | |
| 434 } | |
| 435 | |
| 436 void WindowTreeClient::AddWindow(Window* window) { | |
| 437 DCHECK(windows_.find(server_id(window)) == windows_.end()); | |
| 438 windows_[server_id(window)] = window; | |
| 439 } | |
| 440 | |
| 441 void WindowTreeClient::OnWindowDestroying(Window* window) { | |
| 442 if (window == capture_window_) { | |
| 443 // Normally the queue updates itself upon window destruction. However since | |
| 444 // |window| is being destroyed, it will not be possible to notify its | |
| 445 // observers of the lost capture. Update local state now. | |
| 446 LocalSetCapture(nullptr); | |
| 447 } | |
| 448 // For |focused_window_| window destruction clears the entire focus state. | |
| 449 } | |
| 450 | |
| 451 void WindowTreeClient::OnWindowDestroyed(Window* window) { | |
| 452 windows_.erase(server_id(window)); | |
| 453 | |
| 454 for (auto& entry : embedded_windows_) { | |
| 455 auto it = entry.second.find(window); | |
| 456 if (it != entry.second.end()) { | |
| 457 entry.second.erase(it); | |
| 458 break; | |
| 459 } | |
| 460 } | |
| 461 | |
| 462 // Remove any InFlightChanges associated with the window. | |
| 463 std::set<uint32_t> in_flight_change_ids_to_remove; | |
| 464 for (const auto& pair : in_flight_map_) { | |
| 465 if (pair.second->window() == window) | |
| 466 in_flight_change_ids_to_remove.insert(pair.first); | |
| 467 } | |
| 468 for (auto change_id : in_flight_change_ids_to_remove) | |
| 469 in_flight_map_.erase(change_id); | |
| 470 | |
| 471 const bool was_root = roots_.erase(window) > 0; | |
| 472 if (!in_destructor_ && was_root && roots_.empty() && is_from_embed_) | |
| 473 delegate_->OnEmbedRootDestroyed(window); | |
| 474 } | |
| 475 | |
| 476 Window* WindowTreeClient::GetWindowByServerId(Id id) { | |
| 477 IdToWindowMap::const_iterator it = windows_.find(id); | |
| 478 return it != windows_.end() ? it->second : NULL; | |
| 479 } | |
| 480 | |
| 481 InFlightChange* WindowTreeClient::GetOldestInFlightChangeMatching( | |
| 482 const InFlightChange& change) { | |
| 483 for (const auto& pair : in_flight_map_) { | |
| 484 if (pair.second->window() == change.window() && | |
| 485 pair.second->change_type() == change.change_type() && | |
| 486 pair.second->Matches(change)) { | |
| 487 return pair.second.get(); | |
| 488 } | |
| 489 } | |
| 490 return nullptr; | |
| 491 } | |
| 492 | |
| 493 uint32_t WindowTreeClient::ScheduleInFlightChange( | |
| 494 std::unique_ptr<InFlightChange> change) { | |
| 495 DCHECK(!change->window() || | |
| 496 windows_.count(change->window()->server_id()) > 0); | |
| 497 const uint32_t change_id = next_change_id_++; | |
| 498 in_flight_map_[change_id] = std::move(change); | |
| 499 return change_id; | |
| 500 } | |
| 501 | |
| 502 bool WindowTreeClient::ApplyServerChangeToExistingInFlightChange( | |
| 503 const InFlightChange& change) { | |
| 504 InFlightChange* existing_change = GetOldestInFlightChangeMatching(change); | |
| 505 if (!existing_change) | |
| 506 return false; | |
| 507 | |
| 508 existing_change->SetRevertValueFrom(change); | |
| 509 return true; | |
| 510 } | |
| 511 | |
| 512 void WindowTreeClient::BuildWindowTree( | |
| 513 const std::vector<mojom::WindowDataPtr>& windows, | |
| 514 Window* initial_parent) { | |
| 515 for (const auto& window_data : windows) { | |
| 516 Window* parent = window_data->parent_id == 0 | |
| 517 ? nullptr | |
| 518 : GetWindowByServerId(window_data->parent_id); | |
| 519 Window* existing_window = GetWindowByServerId(window_data->window_id); | |
| 520 if (!existing_window) | |
| 521 AddWindowToClient(this, parent, window_data); | |
| 522 else if (parent) | |
| 523 WindowPrivate(parent).LocalAddChild(existing_window); | |
| 524 } | |
| 525 } | |
| 526 | |
| 527 Window* WindowTreeClient::NewWindowImpl( | |
| 528 NewWindowType type, | |
| 529 const Window::SharedProperties* properties) { | |
| 530 DCHECK(tree_); | |
| 531 Window* window = | |
| 532 new Window(this, MakeTransportId(client_id_, next_window_id_++)); | |
| 533 if (properties) | |
| 534 window->properties_ = *properties; | |
| 535 AddWindow(window); | |
| 536 | |
| 537 const uint32_t change_id = | |
| 538 ScheduleInFlightChange(base::MakeUnique<CrashInFlightChange>( | |
| 539 window, type == NewWindowType::CHILD | |
| 540 ? ChangeType::NEW_WINDOW | |
| 541 : ChangeType::NEW_TOP_LEVEL_WINDOW)); | |
| 542 std::unordered_map<std::string, std::vector<uint8_t>> transport_properties; | |
| 543 if (properties) | |
| 544 transport_properties = mojo::MapToUnorderedMap(*properties); | |
| 545 | |
| 546 if (type == NewWindowType::CHILD) { | |
| 547 tree_->NewWindow(change_id, server_id(window), | |
| 548 std::move(transport_properties)); | |
| 549 } else { | |
| 550 roots_.insert(window); | |
| 551 tree_->NewTopLevelWindow(change_id, server_id(window), | |
| 552 transport_properties); | |
| 553 } | |
| 554 return window; | |
| 555 } | |
| 556 | |
| 557 void WindowTreeClient::SetWindowTree(mojom::WindowTreePtr window_tree_ptr) { | |
| 558 tree_ptr_ = std::move(window_tree_ptr); | |
| 559 tree_ = tree_ptr_.get(); | |
| 560 | |
| 561 tree_ptr_->GetCursorLocationMemory( | |
| 562 base::Bind(&WindowTreeClient::OnReceivedCursorLocationMemory, | |
| 563 weak_factory_.GetWeakPtr())); | |
| 564 | |
| 565 tree_ptr_.set_connection_error_handler(base::Bind( | |
| 566 &WindowTreeClient::OnConnectionLost, weak_factory_.GetWeakPtr())); | |
| 567 | |
| 568 if (window_manager_delegate_) { | |
| 569 tree_ptr_->GetWindowManagerClient(MakeRequest( | |
| 570 &window_manager_internal_client_, tree_ptr_.associated_group())); | |
| 571 } | |
| 572 } | |
| 573 | |
| 574 void WindowTreeClient::OnConnectionLost() { | |
| 575 delegate_->OnLostConnection(this); | |
| 576 } | |
| 577 | |
| 578 void WindowTreeClient::OnEmbedImpl(mojom::WindowTree* window_tree, | |
| 579 ClientSpecificId client_id, | |
| 580 mojom::WindowDataPtr root_data, | |
| 581 int64_t display_id, | |
| 582 Id focused_window_id, | |
| 583 bool drawn) { | |
| 584 // WARNING: this is only called if WindowTreeClient was created as the | |
| 585 // result of an embedding. | |
| 586 tree_ = window_tree; | |
| 587 client_id_ = client_id; | |
| 588 | |
| 589 DCHECK(roots_.empty()); | |
| 590 Window* root = AddWindowToClient(this, nullptr, root_data); | |
| 591 WindowPrivate(root).LocalSetDisplay(display_id); | |
| 592 roots_.insert(root); | |
| 593 | |
| 594 focused_window_ = GetWindowByServerId(focused_window_id); | |
| 595 | |
| 596 WindowPrivate(root).LocalSetParentDrawn(drawn); | |
| 597 | |
| 598 delegate_->OnEmbed(root); | |
| 599 | |
| 600 if (focused_window_) { | |
| 601 for (auto& observer : observers_) | |
| 602 observer.OnWindowTreeFocusChanged(focused_window_, nullptr); | |
| 603 } | |
| 604 } | |
| 605 | |
| 606 void WindowTreeClient::WmNewDisplayAddedImpl(const display::Display& display, | |
| 607 mojom::WindowDataPtr root_data, | |
| 608 bool parent_drawn) { | |
| 609 DCHECK(window_manager_delegate_); | |
| 610 | |
| 611 Window* root = AddWindowToClient(this, nullptr, root_data); | |
| 612 WindowPrivate(root).LocalSetDisplay(display.id()); | |
| 613 WindowPrivate(root).LocalSetParentDrawn(parent_drawn); | |
| 614 roots_.insert(root); | |
| 615 | |
| 616 window_manager_delegate_->OnWmNewDisplay(root, display); | |
| 617 } | |
| 618 | |
| 619 void WindowTreeClient::OnReceivedCursorLocationMemory( | |
| 620 mojo::ScopedSharedBufferHandle handle) { | |
| 621 cursor_location_mapping_ = handle->Map(sizeof(base::subtle::Atomic32)); | |
| 622 DCHECK(cursor_location_mapping_); | |
| 623 } | |
| 624 | |
| 625 void WindowTreeClient::OnWmMoveLoopCompleted(uint32_t change_id, | |
| 626 bool completed) { | |
| 627 if (window_manager_internal_client_) | |
| 628 window_manager_internal_client_->WmResponse(change_id, completed); | |
| 629 | |
| 630 if (change_id == current_wm_move_loop_change_) { | |
| 631 current_wm_move_loop_change_ = 0; | |
| 632 current_wm_move_loop_window_id_ = 0; | |
| 633 } | |
| 634 } | |
| 635 | |
| 636 //////////////////////////////////////////////////////////////////////////////// | |
| 637 // WindowTreeClient, WindowTreeClient implementation: | |
| 638 | |
| 639 const std::set<Window*>& WindowTreeClient::GetRoots() { | |
| 640 return roots_; | |
| 641 } | |
| 642 | |
| 643 Window* WindowTreeClient::GetFocusedWindow() { | |
| 644 return focused_window_; | |
| 645 } | |
| 646 | |
| 647 void WindowTreeClient::ClearFocus() { | |
| 648 if (!focused_window_) | |
| 649 return; | |
| 650 | |
| 651 SetFocus(nullptr); | |
| 652 } | |
| 653 | |
| 654 gfx::Point WindowTreeClient::GetCursorScreenPoint() { | |
| 655 // We raced initialization. Return (0, 0). | |
| 656 if (!cursor_location_memory()) | |
| 657 return gfx::Point(); | |
| 658 | |
| 659 base::subtle::Atomic32 location = | |
| 660 base::subtle::NoBarrier_Load(cursor_location_memory()); | |
| 661 return gfx::Point(static_cast<int16_t>(location >> 16), | |
| 662 static_cast<int16_t>(location & 0xFFFF)); | |
| 663 } | |
| 664 | |
| 665 void WindowTreeClient::StartPointerWatcher(bool want_moves) { | |
| 666 if (has_pointer_watcher_) | |
| 667 StopPointerWatcher(); | |
| 668 has_pointer_watcher_ = true; | |
| 669 tree_->StartPointerWatcher(want_moves); | |
| 670 } | |
| 671 | |
| 672 void WindowTreeClient::StopPointerWatcher() { | |
| 673 DCHECK(has_pointer_watcher_); | |
| 674 tree_->StopPointerWatcher(); | |
| 675 has_pointer_watcher_ = false; | |
| 676 } | |
| 677 | |
| 678 void WindowTreeClient::PerformDragDrop( | |
| 679 Window* window, | |
| 680 const std::map<std::string, std::vector<uint8_t>>& drag_data, | |
| 681 int drag_operation, | |
| 682 const gfx::Point& cursor_location, | |
| 683 const SkBitmap& bitmap, | |
| 684 const base::Callback<void(bool, uint32_t)>& callback) { | |
| 685 DCHECK(!current_drag_state_); | |
| 686 | |
| 687 // TODO(erg): Pass |cursor_location| and |bitmap| in PerformDragDrop() when | |
| 688 // we start showing an image representation of the drag under the cursor. | |
| 689 | |
| 690 auto unordered_drag_data = mojo::MapToUnorderedMap(drag_data); | |
| 691 | |
| 692 if (window->drop_target()) { | |
| 693 // To minimize the number of round trips, copy the drag drop data to our | |
| 694 // handler here, instead of forcing mus to send this same data back. | |
| 695 OnDragDropStart(unordered_drag_data); | |
| 696 } | |
| 697 | |
| 698 uint32_t current_drag_change = ScheduleInFlightChange( | |
| 699 base::MakeUnique<InFlightDragChange>(window, ChangeType::DRAG_LOOP)); | |
| 700 current_drag_state_.reset(new CurrentDragState{ | |
| 701 current_drag_change, ui::mojom::kDropEffectNone, callback}); | |
| 702 | |
| 703 tree_->PerformDragDrop(current_drag_change, window->server_id(), | |
| 704 unordered_drag_data, drag_operation); | |
| 705 } | |
| 706 | |
| 707 void WindowTreeClient::CancelDragDrop(Window* window) { | |
| 708 // Server will clean up drag and fail the in-flight change. | |
| 709 tree_->CancelDragDrop(window->server_id()); | |
| 710 } | |
| 711 | |
| 712 void WindowTreeClient::PerformWindowMove( | |
| 713 Window* window, | |
| 714 ui::mojom::MoveLoopSource source, | |
| 715 const gfx::Point& cursor_location, | |
| 716 const base::Callback<void(bool)>& callback) { | |
| 717 DCHECK(on_current_move_finished_.is_null()); | |
| 718 on_current_move_finished_ = callback; | |
| 719 | |
| 720 current_move_loop_change_ = ScheduleInFlightChange( | |
| 721 base::MakeUnique<InFlightDragChange>(window, ChangeType::MOVE_LOOP)); | |
| 722 // Tell the window manager to take over moving us. | |
| 723 tree_->PerformWindowMove(current_move_loop_change_, window->server_id(), | |
| 724 source, cursor_location); | |
| 725 } | |
| 726 | |
| 727 void WindowTreeClient::CancelWindowMove(Window* window) { | |
| 728 tree_->CancelWindowMove(window->server_id()); | |
| 729 } | |
| 730 | |
| 731 Window* WindowTreeClient::NewWindow( | |
| 732 const Window::SharedProperties* properties) { | |
| 733 return NewWindowImpl(NewWindowType::CHILD, properties); | |
| 734 } | |
| 735 | |
| 736 Window* WindowTreeClient::NewTopLevelWindow( | |
| 737 const Window::SharedProperties* properties) { | |
| 738 Window* window = NewWindowImpl(NewWindowType::TOP_LEVEL, properties); | |
| 739 // Assume newly created top level windows are drawn by default, otherwise | |
| 740 // requests to focus will fail. We will get the real value in | |
| 741 // OnTopLevelCreated(). | |
| 742 window->LocalSetParentDrawn(true); | |
| 743 return window; | |
| 744 } | |
| 745 | |
| 746 #if !defined(NDEBUG) | |
| 747 std::string WindowTreeClient::GetDebugWindowHierarchy() const { | |
| 748 std::string result; | |
| 749 for (Window* root : roots_) | |
| 750 BuildDebugInfo(std::string(), root, &result); | |
| 751 return result; | |
| 752 } | |
| 753 | |
| 754 void WindowTreeClient::BuildDebugInfo(const std::string& depth, | |
| 755 Window* window, | |
| 756 std::string* result) const { | |
| 757 std::string name = window->GetName(); | |
| 758 *result += base::StringPrintf( | |
| 759 "%sid=%d visible=%s bounds=%d,%d %dx%d %s\n", depth.c_str(), | |
| 760 window->server_id(), window->visible() ? "true" : "false", | |
| 761 window->bounds().x(), window->bounds().y(), window->bounds().width(), | |
| 762 window->bounds().height(), !name.empty() ? name.c_str() : "(no name)"); | |
| 763 for (Window* child : window->children()) | |
| 764 BuildDebugInfo(depth + " ", child, result); | |
| 765 } | |
| 766 #endif // !defined(NDEBUG) | |
| 767 | |
| 768 //////////////////////////////////////////////////////////////////////////////// | |
| 769 // WindowTreeClient, WindowTreeClient implementation: | |
| 770 | |
| 771 void WindowTreeClient::AddObserver(WindowTreeClientObserver* observer) { | |
| 772 observers_.AddObserver(observer); | |
| 773 } | |
| 774 | |
| 775 void WindowTreeClient::RemoveObserver(WindowTreeClientObserver* observer) { | |
| 776 observers_.RemoveObserver(observer); | |
| 777 } | |
| 778 | |
| 779 void WindowTreeClient::SetCanAcceptDrops(Id window_id, bool can_accept_drops) { | |
| 780 DCHECK(tree_); | |
| 781 tree_->SetCanAcceptDrops(window_id, can_accept_drops); | |
| 782 } | |
| 783 | |
| 784 void WindowTreeClient::SetCanAcceptEvents(Id window_id, | |
| 785 bool can_accept_events) { | |
| 786 DCHECK(tree_); | |
| 787 tree_->SetCanAcceptEvents(window_id, can_accept_events); | |
| 788 } | |
| 789 | |
| 790 void WindowTreeClient::OnEmbed(ClientSpecificId client_id, | |
| 791 mojom::WindowDataPtr root_data, | |
| 792 mojom::WindowTreePtr tree, | |
| 793 int64_t display_id, | |
| 794 Id focused_window_id, | |
| 795 bool drawn) { | |
| 796 DCHECK(!tree_ptr_); | |
| 797 tree_ptr_ = std::move(tree); | |
| 798 | |
| 799 is_from_embed_ = true; | |
| 800 | |
| 801 if (window_manager_delegate_) { | |
| 802 tree_ptr_->GetWindowManagerClient(MakeRequest( | |
| 803 &window_manager_internal_client_, tree_ptr_.associated_group())); | |
| 804 } | |
| 805 | |
| 806 OnEmbedImpl(tree_ptr_.get(), client_id, std::move(root_data), display_id, | |
| 807 focused_window_id, drawn); | |
| 808 } | |
| 809 | |
| 810 void WindowTreeClient::OnEmbeddedAppDisconnected(Id window_id) { | |
| 811 Window* window = GetWindowByServerId(window_id); | |
| 812 if (window) { | |
| 813 for (auto& observer : *WindowPrivate(window).observers()) | |
| 814 observer.OnWindowEmbeddedAppDisconnected(window); | |
| 815 } | |
| 816 } | |
| 817 | |
| 818 void WindowTreeClient::OnUnembed(Id window_id) { | |
| 819 Window* window = GetWindowByServerId(window_id); | |
| 820 if (!window) | |
| 821 return; | |
| 822 | |
| 823 delegate_->OnUnembed(window); | |
| 824 WindowPrivate(window).LocalDestroy(); | |
| 825 } | |
| 826 | |
| 827 void WindowTreeClient::OnCaptureChanged(Id new_capture_window_id, | |
| 828 Id old_capture_window_id) { | |
| 829 Window* new_capture_window = GetWindowByServerId(new_capture_window_id); | |
| 830 Window* lost_capture_window = GetWindowByServerId(old_capture_window_id); | |
| 831 if (!new_capture_window && !lost_capture_window) | |
| 832 return; | |
| 833 | |
| 834 InFlightCaptureChange change(this, new_capture_window); | |
| 835 if (ApplyServerChangeToExistingInFlightChange(change)) | |
| 836 return; | |
| 837 | |
| 838 LocalSetCapture(new_capture_window); | |
| 839 } | |
| 840 | |
| 841 void WindowTreeClient::OnTopLevelCreated(uint32_t change_id, | |
| 842 mojom::WindowDataPtr data, | |
| 843 int64_t display_id, | |
| 844 bool drawn) { | |
| 845 // The server ack'd the top level window we created and supplied the state | |
| 846 // of the window at the time the server created it. For properties we do not | |
| 847 // have changes in flight for we can update them immediately. For properties | |
| 848 // with changes in flight we set the revert value from the server. | |
| 849 | |
| 850 if (!in_flight_map_.count(change_id)) { | |
| 851 // The window may have been destroyed locally before the server could finish | |
| 852 // creating the window, and before the server received the notification that | |
| 853 // the window has been destroyed. | |
| 854 return; | |
| 855 } | |
| 856 std::unique_ptr<InFlightChange> change(std::move(in_flight_map_[change_id])); | |
| 857 in_flight_map_.erase(change_id); | |
| 858 | |
| 859 Window* window = change->window(); | |
| 860 WindowPrivate window_private(window); | |
| 861 | |
| 862 // Drawn state and display-id always come from the server (they can't be | |
| 863 // modified locally). | |
| 864 window_private.LocalSetParentDrawn(drawn); | |
| 865 window_private.LocalSetDisplay(display_id); | |
| 866 | |
| 867 // The default visibilty is false, we only need update visibility if it | |
| 868 // differs from that. | |
| 869 if (data->visible) { | |
| 870 InFlightVisibleChange visible_change(window, data->visible); | |
| 871 InFlightChange* current_change = | |
| 872 GetOldestInFlightChangeMatching(visible_change); | |
| 873 if (current_change) | |
| 874 current_change->SetRevertValueFrom(visible_change); | |
| 875 else | |
| 876 window_private.LocalSetVisible(true); | |
| 877 } | |
| 878 | |
| 879 const gfx::Rect bounds(data->bounds); | |
| 880 { | |
| 881 InFlightBoundsChange bounds_change(window, bounds); | |
| 882 InFlightChange* current_change = | |
| 883 GetOldestInFlightChangeMatching(bounds_change); | |
| 884 if (current_change) | |
| 885 current_change->SetRevertValueFrom(bounds_change); | |
| 886 else if (window->bounds() != bounds) | |
| 887 window_private.LocalSetBounds(window->bounds(), bounds); | |
| 888 } | |
| 889 | |
| 890 // There is currently no API to bulk set properties, so we iterate over each | |
| 891 // property individually. | |
| 892 Window::SharedProperties properties = | |
| 893 mojo::UnorderedMapToMap(data->properties); | |
| 894 for (const auto& pair : properties) { | |
| 895 InFlightPropertyChange property_change(window, pair.first, pair.second); | |
| 896 InFlightChange* current_change = | |
| 897 GetOldestInFlightChangeMatching(property_change); | |
| 898 if (current_change) | |
| 899 current_change->SetRevertValueFrom(property_change); | |
| 900 else | |
| 901 window_private.LocalSetSharedProperty(pair.first, &(pair.second)); | |
| 902 } | |
| 903 | |
| 904 // Top level windows should not have a parent. | |
| 905 DCHECK_EQ(0u, data->parent_id); | |
| 906 } | |
| 907 | |
| 908 void WindowTreeClient::OnWindowBoundsChanged(Id window_id, | |
| 909 const gfx::Rect& old_bounds, | |
| 910 const gfx::Rect& new_bounds) { | |
| 911 Window* window = GetWindowByServerId(window_id); | |
| 912 if (!window) | |
| 913 return; | |
| 914 | |
| 915 float device_scale_factor = ScaleFactorForDisplay(window->display_id()); | |
| 916 gfx::Rect old_bounds_in_dip = | |
| 917 gfx::ConvertRectToDIP(device_scale_factor, old_bounds); | |
| 918 gfx::Rect new_bounds_in_dip = | |
| 919 gfx::ConvertRectToDIP(device_scale_factor, new_bounds); | |
| 920 | |
| 921 InFlightBoundsChange new_change(window, new_bounds_in_dip); | |
| 922 if (ApplyServerChangeToExistingInFlightChange(new_change)) | |
| 923 return; | |
| 924 WindowPrivate(window).LocalSetBounds(old_bounds_in_dip, new_bounds_in_dip); | |
| 925 } | |
| 926 | |
| 927 void WindowTreeClient::OnClientAreaChanged( | |
| 928 uint32_t window_id, | |
| 929 const gfx::Insets& new_client_area, | |
| 930 const std::vector<gfx::Rect>& new_additional_client_areas) { | |
| 931 Window* window = GetWindowByServerId(window_id); | |
| 932 if (window) { | |
| 933 float device_scale_factor = ScaleFactorForDisplay(window->display_id()); | |
| 934 std::vector<gfx::Rect> new_additional_client_areas_in_dip; | |
| 935 for (const gfx::Rect& area : new_additional_client_areas) { | |
| 936 new_additional_client_areas_in_dip.push_back( | |
| 937 gfx::ConvertRectToDIP(device_scale_factor, area)); | |
| 938 } | |
| 939 WindowPrivate(window).LocalSetClientArea( | |
| 940 gfx::ConvertInsetsToDIP(device_scale_factor, new_client_area), | |
| 941 new_additional_client_areas_in_dip); | |
| 942 } | |
| 943 } | |
| 944 | |
| 945 void WindowTreeClient::OnTransientWindowAdded( | |
| 946 uint32_t window_id, | |
| 947 uint32_t transient_window_id) { | |
| 948 Window* window = GetWindowByServerId(window_id); | |
| 949 Window* transient_window = GetWindowByServerId(transient_window_id); | |
| 950 // window or transient_window or both may be null if a local delete occurs | |
| 951 // with an in flight add from the server. | |
| 952 if (window && transient_window) | |
| 953 WindowPrivate(window).LocalAddTransientWindow(transient_window); | |
| 954 } | |
| 955 | |
| 956 void WindowTreeClient::OnTransientWindowRemoved( | |
| 957 uint32_t window_id, | |
| 958 uint32_t transient_window_id) { | |
| 959 Window* window = GetWindowByServerId(window_id); | |
| 960 Window* transient_window = GetWindowByServerId(transient_window_id); | |
| 961 // window or transient_window or both may be null if a local delete occurs | |
| 962 // with an in flight delete from the server. | |
| 963 if (window && transient_window) | |
| 964 WindowPrivate(window).LocalRemoveTransientWindow(transient_window); | |
| 965 } | |
| 966 | |
| 967 void WindowTreeClient::OnWindowHierarchyChanged( | |
| 968 Id window_id, | |
| 969 Id old_parent_id, | |
| 970 Id new_parent_id, | |
| 971 std::vector<mojom::WindowDataPtr> windows) { | |
| 972 Window* initial_parent = | |
| 973 windows.size() ? GetWindowByServerId(windows[0]->parent_id) : NULL; | |
| 974 | |
| 975 const bool was_window_known = GetWindowByServerId(window_id) != nullptr; | |
| 976 | |
| 977 BuildWindowTree(windows, initial_parent); | |
| 978 | |
| 979 // If the window was not known, then BuildWindowTree() will have created it | |
| 980 // and parented the window. | |
| 981 if (!was_window_known) | |
| 982 return; | |
| 983 | |
| 984 Window* new_parent = GetWindowByServerId(new_parent_id); | |
| 985 Window* old_parent = GetWindowByServerId(old_parent_id); | |
| 986 Window* window = GetWindowByServerId(window_id); | |
| 987 if (new_parent) | |
| 988 WindowPrivate(new_parent).LocalAddChild(window); | |
| 989 else | |
| 990 WindowPrivate(old_parent).LocalRemoveChild(window); | |
| 991 } | |
| 992 | |
| 993 void WindowTreeClient::OnWindowReordered(Id window_id, | |
| 994 Id relative_window_id, | |
| 995 mojom::OrderDirection direction) { | |
| 996 Window* window = GetWindowByServerId(window_id); | |
| 997 Window* relative_window = GetWindowByServerId(relative_window_id); | |
| 998 if (window && relative_window) | |
| 999 WindowPrivate(window).LocalReorder(relative_window, direction); | |
| 1000 } | |
| 1001 | |
| 1002 void WindowTreeClient::OnWindowDeleted(Id window_id) { | |
| 1003 Window* window = GetWindowByServerId(window_id); | |
| 1004 if (window) | |
| 1005 WindowPrivate(window).LocalDestroy(); | |
| 1006 } | |
| 1007 | |
| 1008 Window* WindowTreeClient::GetCaptureWindow() { | |
| 1009 return capture_window_; | |
| 1010 } | |
| 1011 | |
| 1012 void WindowTreeClient::OnWindowVisibilityChanged(Id window_id, | |
| 1013 bool visible) { | |
| 1014 Window* window = GetWindowByServerId(window_id); | |
| 1015 if (!window) | |
| 1016 return; | |
| 1017 | |
| 1018 InFlightVisibleChange new_change(window, visible); | |
| 1019 if (ApplyServerChangeToExistingInFlightChange(new_change)) | |
| 1020 return; | |
| 1021 | |
| 1022 WindowPrivate(window).LocalSetVisible(visible); | |
| 1023 } | |
| 1024 | |
| 1025 void WindowTreeClient::OnWindowOpacityChanged(Id window_id, | |
| 1026 float old_opacity, | |
| 1027 float new_opacity) { | |
| 1028 Window* window = GetWindowByServerId(window_id); | |
| 1029 if (!window) | |
| 1030 return; | |
| 1031 | |
| 1032 InFlightOpacityChange new_change(window, new_opacity); | |
| 1033 if (ApplyServerChangeToExistingInFlightChange(new_change)) | |
| 1034 return; | |
| 1035 | |
| 1036 WindowPrivate(window).LocalSetOpacity(new_opacity); | |
| 1037 } | |
| 1038 | |
| 1039 void WindowTreeClient::OnWindowParentDrawnStateChanged(Id window_id, | |
| 1040 bool drawn) { | |
| 1041 Window* window = GetWindowByServerId(window_id); | |
| 1042 if (window) | |
| 1043 WindowPrivate(window).LocalSetParentDrawn(drawn); | |
| 1044 } | |
| 1045 | |
| 1046 void WindowTreeClient::OnWindowSharedPropertyChanged( | |
| 1047 Id window_id, | |
| 1048 const std::string& name, | |
| 1049 const base::Optional<std::vector<uint8_t>>& new_data) { | |
| 1050 Window* window = GetWindowByServerId(window_id); | |
| 1051 if (!window) | |
| 1052 return; | |
| 1053 | |
| 1054 InFlightPropertyChange new_change(window, name, new_data); | |
| 1055 if (ApplyServerChangeToExistingInFlightChange(new_change)) | |
| 1056 return; | |
| 1057 | |
| 1058 WindowPrivate(window).LocalSetSharedProperty( | |
| 1059 name, new_data ? &new_data.value() : nullptr); | |
| 1060 } | |
| 1061 | |
| 1062 void WindowTreeClient::OnWindowInputEvent(uint32_t event_id, | |
| 1063 Id window_id, | |
| 1064 std::unique_ptr<ui::Event> event, | |
| 1065 bool matches_pointer_watcher) { | |
| 1066 DCHECK(event); | |
| 1067 Window* window = GetWindowByServerId(window_id); // May be null. | |
| 1068 | |
| 1069 if (matches_pointer_watcher && has_pointer_watcher_) { | |
| 1070 DCHECK(event->IsPointerEvent()); | |
| 1071 delegate_->OnPointerEventObserved(*event->AsPointerEvent(), window); | |
| 1072 } | |
| 1073 | |
| 1074 if (!window || !window->input_event_handler_) { | |
| 1075 tree_->OnWindowInputEventAck(event_id, mojom::EventResult::UNHANDLED); | |
| 1076 return; | |
| 1077 } | |
| 1078 | |
| 1079 std::unique_ptr<base::Callback<void(mojom::EventResult)>> ack_callback( | |
| 1080 new base::Callback<void(mojom::EventResult)>( | |
| 1081 base::Bind(&mojom::WindowTree::OnWindowInputEventAck, | |
| 1082 base::Unretained(tree_), event_id))); | |
| 1083 | |
| 1084 // TODO(moshayedi): crbug.com/617222. No need to convert to ui::MouseEvent or | |
| 1085 // ui::TouchEvent once we have proper support for pointer events. | |
| 1086 if (event->IsMousePointerEvent()) { | |
| 1087 if (event->type() == ui::ET_POINTER_WHEEL_CHANGED) { | |
| 1088 window->input_event_handler_->OnWindowInputEvent( | |
| 1089 window, ui::MouseWheelEvent(*event->AsPointerEvent()), &ack_callback); | |
| 1090 } else { | |
| 1091 window->input_event_handler_->OnWindowInputEvent( | |
| 1092 window, ui::MouseEvent(*event->AsPointerEvent()), &ack_callback); | |
| 1093 } | |
| 1094 } else if (event->IsTouchPointerEvent()) { | |
| 1095 window->input_event_handler_->OnWindowInputEvent( | |
| 1096 window, ui::TouchEvent(*event->AsPointerEvent()), &ack_callback); | |
| 1097 } else { | |
| 1098 window->input_event_handler_->OnWindowInputEvent(window, *event.get(), | |
| 1099 &ack_callback); | |
| 1100 } | |
| 1101 | |
| 1102 // The handler did not take ownership of the callback, so we send the ack, | |
| 1103 // marking the event as not consumed. | |
| 1104 if (ack_callback) | |
| 1105 ack_callback->Run(mojom::EventResult::UNHANDLED); | |
| 1106 } | |
| 1107 | |
| 1108 void WindowTreeClient::OnPointerEventObserved(std::unique_ptr<ui::Event> event, | |
| 1109 uint32_t window_id) { | |
| 1110 DCHECK(event); | |
| 1111 DCHECK(event->IsPointerEvent()); | |
| 1112 if (has_pointer_watcher_) { | |
| 1113 Window* target_window = GetWindowByServerId(window_id); | |
| 1114 delegate_->OnPointerEventObserved(*event->AsPointerEvent(), target_window); | |
| 1115 } | |
| 1116 } | |
| 1117 | |
| 1118 void WindowTreeClient::OnWindowFocused(Id focused_window_id) { | |
| 1119 Window* focused_window = GetWindowByServerId(focused_window_id); | |
| 1120 InFlightFocusChange new_change(this, focused_window); | |
| 1121 if (ApplyServerChangeToExistingInFlightChange(new_change)) | |
| 1122 return; | |
| 1123 | |
| 1124 LocalSetFocus(focused_window); | |
| 1125 } | |
| 1126 | |
| 1127 void WindowTreeClient::OnWindowPredefinedCursorChanged( | |
| 1128 Id window_id, | |
| 1129 mojom::Cursor cursor) { | |
| 1130 Window* window = GetWindowByServerId(window_id); | |
| 1131 if (!window) | |
| 1132 return; | |
| 1133 | |
| 1134 InFlightPredefinedCursorChange new_change(window, cursor); | |
| 1135 if (ApplyServerChangeToExistingInFlightChange(new_change)) | |
| 1136 return; | |
| 1137 | |
| 1138 WindowPrivate(window).LocalSetPredefinedCursor(cursor); | |
| 1139 } | |
| 1140 | |
| 1141 void WindowTreeClient::OnWindowSurfaceChanged( | |
| 1142 Id window_id, | |
| 1143 const cc::SurfaceInfo& surface_info) { | |
| 1144 Window* window = GetWindowByServerId(window_id); | |
| 1145 if (!window) | |
| 1146 return; | |
| 1147 WindowPrivate(window).LocalSetSurfaceInfo(surface_info); | |
| 1148 } | |
| 1149 | |
| 1150 void WindowTreeClient::OnDragDropStart( | |
| 1151 const std::unordered_map<std::string, std::vector<uint8_t>>& mime_data) { | |
| 1152 mime_drag_data_ = mojo::UnorderedMapToMap(mime_data); | |
| 1153 } | |
| 1154 | |
| 1155 void WindowTreeClient::OnDragEnter(Id window_id, | |
| 1156 uint32_t key_state, | |
| 1157 const gfx::Point& position, | |
| 1158 uint32_t effect_bitmask, | |
| 1159 const OnDragEnterCallback& callback) { | |
| 1160 Window* window = GetWindowByServerId(window_id); | |
| 1161 if (!window || !window->drop_target()) { | |
| 1162 callback.Run(mojom::kDropEffectNone); | |
| 1163 return; | |
| 1164 } | |
| 1165 | |
| 1166 if (!base::ContainsKey(drag_entered_windows_, window_id)) { | |
| 1167 window->drop_target()->OnDragDropStart(mime_drag_data_); | |
| 1168 drag_entered_windows_.insert(window_id); | |
| 1169 } | |
| 1170 | |
| 1171 uint32_t ret = | |
| 1172 window->drop_target()->OnDragEnter(key_state, position, effect_bitmask); | |
| 1173 callback.Run(ret); | |
| 1174 } | |
| 1175 | |
| 1176 void WindowTreeClient::OnDragOver(Id window_id, | |
| 1177 uint32_t key_state, | |
| 1178 const gfx::Point& position, | |
| 1179 uint32_t effect_bitmask, | |
| 1180 const OnDragOverCallback& callback) { | |
| 1181 Window* window = GetWindowByServerId(window_id); | |
| 1182 if (!window || !window->drop_target()) { | |
| 1183 callback.Run(mojom::kDropEffectNone); | |
| 1184 return; | |
| 1185 } | |
| 1186 | |
| 1187 uint32_t ret = | |
| 1188 window->drop_target()->OnDragOver(key_state, position, effect_bitmask); | |
| 1189 callback.Run(ret); | |
| 1190 } | |
| 1191 | |
| 1192 void WindowTreeClient::OnDragLeave(Id window_id) { | |
| 1193 Window* window = GetWindowByServerId(window_id); | |
| 1194 if (!window || !window->drop_target()) | |
| 1195 return; | |
| 1196 | |
| 1197 window->drop_target()->OnDragLeave(); | |
| 1198 } | |
| 1199 | |
| 1200 void WindowTreeClient::OnDragDropDone() { | |
| 1201 for (Id id : drag_entered_windows_) { | |
| 1202 Window* window = GetWindowByServerId(id); | |
| 1203 if (!window || !window->drop_target()) | |
| 1204 continue; | |
| 1205 window->drop_target()->OnDragDropDone(); | |
| 1206 } | |
| 1207 drag_entered_windows_.clear(); | |
| 1208 } | |
| 1209 | |
| 1210 void WindowTreeClient::OnCompleteDrop(Id window_id, | |
| 1211 uint32_t key_state, | |
| 1212 const gfx::Point& position, | |
| 1213 uint32_t effect_bitmask, | |
| 1214 const OnCompleteDropCallback& callback) { | |
| 1215 Window* window = GetWindowByServerId(window_id); | |
| 1216 if (!window || !window->drop_target()) { | |
| 1217 callback.Run(mojom::kDropEffectNone); | |
| 1218 return; | |
| 1219 } | |
| 1220 | |
| 1221 uint32_t ret = window->drop_target()->OnCompleteDrop(key_state, position, | |
| 1222 effect_bitmask); | |
| 1223 callback.Run(ret); | |
| 1224 } | |
| 1225 | |
| 1226 void WindowTreeClient::OnPerformDragDropCompleted(uint32_t change_id, | |
| 1227 bool success, | |
| 1228 uint32_t action_taken) { | |
| 1229 if (current_drag_state_ && change_id == current_drag_state_->change_id) { | |
| 1230 current_drag_state_->completed_action = action_taken; | |
| 1231 OnChangeCompleted(change_id, success); | |
| 1232 } | |
| 1233 } | |
| 1234 | |
| 1235 void WindowTreeClient::OnChangeCompleted(uint32_t change_id, bool success) { | |
| 1236 std::unique_ptr<InFlightChange> change(std::move(in_flight_map_[change_id])); | |
| 1237 in_flight_map_.erase(change_id); | |
| 1238 if (!change) | |
| 1239 return; | |
| 1240 | |
| 1241 if (!success) | |
| 1242 change->ChangeFailed(); | |
| 1243 | |
| 1244 InFlightChange* next_change = GetOldestInFlightChangeMatching(*change); | |
| 1245 if (next_change) { | |
| 1246 if (!success) | |
| 1247 next_change->SetRevertValueFrom(*change); | |
| 1248 } else if (!success) { | |
| 1249 change->Revert(); | |
| 1250 } | |
| 1251 | |
| 1252 if (change_id == current_move_loop_change_) { | |
| 1253 current_move_loop_change_ = 0; | |
| 1254 on_current_move_finished_.Run(success); | |
| 1255 on_current_move_finished_.Reset(); | |
| 1256 } | |
| 1257 | |
| 1258 if (current_drag_state_ && change_id == current_drag_state_->change_id) { | |
| 1259 OnDragDropDone(); | |
| 1260 | |
| 1261 current_drag_state_->on_finished.Run(success, | |
| 1262 current_drag_state_->completed_action); | |
| 1263 current_drag_state_.reset(); | |
| 1264 } | |
| 1265 } | |
| 1266 | |
| 1267 void WindowTreeClient::GetWindowManager( | |
| 1268 mojo::AssociatedInterfaceRequest<WindowManager> internal) { | |
| 1269 window_manager_internal_.reset( | |
| 1270 new mojo::AssociatedBinding<mojom::WindowManager>(this, | |
| 1271 std::move(internal))); | |
| 1272 } | |
| 1273 | |
| 1274 void WindowTreeClient::RequestClose(uint32_t window_id) { | |
| 1275 Window* window = GetWindowByServerId(window_id); | |
| 1276 if (!window || !IsRoot(window)) | |
| 1277 return; | |
| 1278 | |
| 1279 for (auto& observer : *WindowPrivate(window).observers()) | |
| 1280 observer.OnRequestClose(window); | |
| 1281 } | |
| 1282 | |
| 1283 void WindowTreeClient::OnConnect(ClientSpecificId client_id) { | |
| 1284 client_id_ = client_id; | |
| 1285 } | |
| 1286 | |
| 1287 void WindowTreeClient::WmNewDisplayAdded(const display::Display& display, | |
| 1288 mojom::WindowDataPtr root_data, | |
| 1289 bool parent_drawn) { | |
| 1290 WmNewDisplayAddedImpl(display, std::move(root_data), parent_drawn); | |
| 1291 } | |
| 1292 | |
| 1293 void WindowTreeClient::WmDisplayRemoved(int64_t display_id) { | |
| 1294 DCHECK(window_manager_delegate_); | |
| 1295 | |
| 1296 for (Window* root : roots_) { | |
| 1297 if (root->display_id() == display_id) { | |
| 1298 window_manager_delegate_->OnWmDisplayRemoved(root); | |
| 1299 return; | |
| 1300 } | |
| 1301 } | |
| 1302 } | |
| 1303 | |
| 1304 void WindowTreeClient::WmDisplayModified(const display::Display& display) { | |
| 1305 DCHECK(window_manager_delegate_); | |
| 1306 window_manager_delegate_->OnWmDisplayModified(display); | |
| 1307 } | |
| 1308 | |
| 1309 void WindowTreeClient::WmSetBounds(uint32_t change_id, | |
| 1310 Id window_id, | |
| 1311 const gfx::Rect& transit_bounds) { | |
| 1312 Window* window = GetWindowByServerId(window_id); | |
| 1313 bool result = false; | |
| 1314 if (window) { | |
| 1315 DCHECK(window_manager_delegate_); | |
| 1316 gfx::Rect transit_bounds_in_dip = gfx::ConvertRectToDIP( | |
| 1317 ScaleFactorForDisplay(window->display_id()), transit_bounds); | |
| 1318 gfx::Rect bounds = transit_bounds_in_dip; | |
| 1319 result = window_manager_delegate_->OnWmSetBounds(window, &bounds); | |
| 1320 if (result) { | |
| 1321 // If the resulting bounds differ return false. Returning false ensures | |
| 1322 // the client applies the bounds we set below. | |
| 1323 result = bounds == transit_bounds_in_dip; | |
| 1324 window->SetBounds(bounds); | |
| 1325 } | |
| 1326 } | |
| 1327 if (window_manager_internal_client_) | |
| 1328 window_manager_internal_client_->WmResponse(change_id, result); | |
| 1329 } | |
| 1330 | |
| 1331 void WindowTreeClient::WmSetProperty( | |
| 1332 uint32_t change_id, | |
| 1333 Id window_id, | |
| 1334 const std::string& name, | |
| 1335 const base::Optional<std::vector<uint8_t>>& transit_data) { | |
| 1336 Window* window = GetWindowByServerId(window_id); | |
| 1337 bool result = false; | |
| 1338 if (window) { | |
| 1339 DCHECK(window_manager_delegate_); | |
| 1340 std::unique_ptr<std::vector<uint8_t>> data; | |
| 1341 if (transit_data.has_value()) | |
| 1342 data.reset(new std::vector<uint8_t>(transit_data.value())); | |
| 1343 | |
| 1344 result = window_manager_delegate_->OnWmSetProperty(window, name, &data); | |
| 1345 if (result) { | |
| 1346 // If the resulting bounds differ return false. Returning false ensures | |
| 1347 // the client applies the bounds we set below. | |
| 1348 window->SetSharedPropertyInternal(name, data.get()); | |
| 1349 } | |
| 1350 } | |
| 1351 if (window_manager_internal_client_) | |
| 1352 window_manager_internal_client_->WmResponse(change_id, result); | |
| 1353 } | |
| 1354 | |
| 1355 void WindowTreeClient::WmCreateTopLevelWindow( | |
| 1356 uint32_t change_id, | |
| 1357 ClientSpecificId requesting_client_id, | |
| 1358 const std::unordered_map<std::string, std::vector<uint8_t>>& | |
| 1359 transport_properties) { | |
| 1360 std::map<std::string, std::vector<uint8_t>> properties = | |
| 1361 mojo::UnorderedMapToMap(transport_properties); | |
| 1362 Window* window = | |
| 1363 window_manager_delegate_->OnWmCreateTopLevelWindow(&properties); | |
| 1364 embedded_windows_[requesting_client_id].insert(window); | |
| 1365 if (window_manager_internal_client_) { | |
| 1366 window_manager_internal_client_->OnWmCreatedTopLevelWindow( | |
| 1367 change_id, server_id(window)); | |
| 1368 } | |
| 1369 } | |
| 1370 | |
| 1371 void WindowTreeClient::WmClientJankinessChanged(ClientSpecificId client_id, | |
| 1372 bool janky) { | |
| 1373 if (window_manager_delegate_) { | |
| 1374 auto it = embedded_windows_.find(client_id); | |
| 1375 CHECK(it != embedded_windows_.end()); | |
| 1376 window_manager_delegate_->OnWmClientJankinessChanged( | |
| 1377 embedded_windows_[client_id], janky); | |
| 1378 } | |
| 1379 } | |
| 1380 | |
| 1381 void WindowTreeClient::WmPerformMoveLoop(uint32_t change_id, | |
| 1382 Id window_id, | |
| 1383 mojom::MoveLoopSource source, | |
| 1384 const gfx::Point& cursor_location) { | |
| 1385 if (!window_manager_delegate_ || current_wm_move_loop_change_ != 0) { | |
| 1386 OnWmMoveLoopCompleted(change_id, false); | |
| 1387 return; | |
| 1388 } | |
| 1389 | |
| 1390 current_wm_move_loop_change_ = change_id; | |
| 1391 current_wm_move_loop_window_id_ = window_id; | |
| 1392 Window* window = GetWindowByServerId(window_id); | |
| 1393 if (window) { | |
| 1394 window_manager_delegate_->OnWmPerformMoveLoop( | |
| 1395 window, source, cursor_location, | |
| 1396 base::Bind(&WindowTreeClient::OnWmMoveLoopCompleted, | |
| 1397 weak_factory_.GetWeakPtr(), change_id)); | |
| 1398 } else { | |
| 1399 OnWmMoveLoopCompleted(change_id, false); | |
| 1400 } | |
| 1401 } | |
| 1402 | |
| 1403 void WindowTreeClient::WmCancelMoveLoop(uint32_t change_id) { | |
| 1404 if (!window_manager_delegate_ || change_id != current_wm_move_loop_change_) | |
| 1405 return; | |
| 1406 | |
| 1407 Window* window = GetWindowByServerId(current_wm_move_loop_window_id_); | |
| 1408 if (window) | |
| 1409 window_manager_delegate_->OnWmCancelMoveLoop(window); | |
| 1410 } | |
| 1411 | |
| 1412 void WindowTreeClient::WmDeactivateWindow(uint32_t window_id) {} | |
| 1413 | |
| 1414 void WindowTreeClient::OnAccelerator(uint32_t ack_id, | |
| 1415 uint32_t accelerator_id, | |
| 1416 std::unique_ptr<ui::Event> event) { | |
| 1417 DCHECK(event); | |
| 1418 const mojom::EventResult result = | |
| 1419 window_manager_delegate_->OnAccelerator(accelerator_id, *event.get()); | |
| 1420 if (ack_id && window_manager_internal_client_) | |
| 1421 window_manager_internal_client_->OnAcceleratorAck(ack_id, result); | |
| 1422 } | |
| 1423 | |
| 1424 void WindowTreeClient::SetFrameDecorationValues( | |
| 1425 mojom::FrameDecorationValuesPtr values) { | |
| 1426 if (window_manager_internal_client_) { | |
| 1427 window_manager_internal_client_->WmSetFrameDecorationValues( | |
| 1428 std::move(values)); | |
| 1429 } | |
| 1430 } | |
| 1431 | |
| 1432 void WindowTreeClient::SetNonClientCursor(Window* window, | |
| 1433 ui::mojom::Cursor cursor_id) { | |
| 1434 window_manager_internal_client_->WmSetNonClientCursor(server_id(window), | |
| 1435 cursor_id); | |
| 1436 } | |
| 1437 | |
| 1438 void WindowTreeClient::AddAccelerators( | |
| 1439 std::vector<mojom::AcceleratorPtr> accelerators, | |
| 1440 const base::Callback<void(bool)>& callback) { | |
| 1441 if (window_manager_internal_client_) { | |
| 1442 window_manager_internal_client_->AddAccelerators(std::move(accelerators), | |
| 1443 callback); | |
| 1444 } | |
| 1445 } | |
| 1446 | |
| 1447 void WindowTreeClient::RemoveAccelerator(uint32_t id) { | |
| 1448 if (window_manager_internal_client_) { | |
| 1449 window_manager_internal_client_->RemoveAccelerator(id); | |
| 1450 } | |
| 1451 } | |
| 1452 | |
| 1453 void WindowTreeClient::AddActivationParent(Window* window) { | |
| 1454 if (window_manager_internal_client_) | |
| 1455 window_manager_internal_client_->AddActivationParent(server_id(window)); | |
| 1456 } | |
| 1457 | |
| 1458 void WindowTreeClient::RemoveActivationParent(Window* window) { | |
| 1459 if (window_manager_internal_client_) | |
| 1460 window_manager_internal_client_->RemoveActivationParent(server_id(window)); | |
| 1461 } | |
| 1462 | |
| 1463 void WindowTreeClient::ActivateNextWindow() { | |
| 1464 if (window_manager_internal_client_) | |
| 1465 window_manager_internal_client_->ActivateNextWindow(); | |
| 1466 } | |
| 1467 | |
| 1468 void WindowTreeClient::SetUnderlaySurfaceOffsetAndExtendedHitArea( | |
| 1469 Window* window, | |
| 1470 const gfx::Vector2d& offset, | |
| 1471 const gfx::Insets& hit_area) { | |
| 1472 if (window_manager_internal_client_) { | |
| 1473 // TODO(riajiang): Figure out if |offset| needs to be converted. | |
| 1474 // (http://crbugs.com/646932) | |
| 1475 window_manager_internal_client_->SetUnderlaySurfaceOffsetAndExtendedHitArea( | |
| 1476 server_id(window), offset.x(), offset.y(), | |
| 1477 gfx::ConvertInsetsToDIP(ScaleFactorForDisplay(window->display_id()), | |
| 1478 hit_area)); | |
| 1479 } | |
| 1480 } | |
| 1481 | |
| 1482 } // namespace ui | |
| OLD | NEW |