blob: 7125ab4d895032766f61c7e9399828dc9d50c79f [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/ui/ws/window_server.h"
#include <set>
#include <string>
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "components/viz/common/switches.h"
#include "services/ui/ws/display.h"
#include "services/ui/ws/display_creation_config.h"
#include "services/ui/ws/display_manager.h"
#include "services/ui/ws/frame_generator.h"
#include "services/ui/ws/gpu_host.h"
#include "services/ui/ws/operation.h"
#include "services/ui/ws/server_window.h"
#include "services/ui/ws/user_activity_monitor.h"
#include "services/ui/ws/window_manager_access_policy.h"
#include "services/ui/ws/window_manager_display_root.h"
#include "services/ui/ws/window_manager_state.h"
#include "services/ui/ws/window_manager_window_tree_factory.h"
#include "services/ui/ws/window_server_delegate.h"
#include "services/ui/ws/window_tree.h"
#include "services/ui/ws/window_tree_binding.h"
#include "ui/gfx/geometry/size_conversions.h"
namespace ui {
namespace ws {
namespace {
// Returns true if |window| is considered the active window manager for
// |display|.
bool IsWindowConsideredWindowManagerRoot(const Display* display,
const ServerWindow* window) {
if (!display)
return false;
const WindowManagerDisplayRoot* display_root =
display->window_manager_display_root();
return display_root && display_root->GetClientVisibleRoot() == window;
}
class VizHostProxyImpl : public VizHostProxy {
public:
explicit VizHostProxyImpl(viz::HostFrameSinkManager* manager)
: manager_(manager) {}
~VizHostProxyImpl() override = default;
// VizHostProxy:
void RegisterFrameSinkId(const viz::FrameSinkId& frame_sink_id,
viz::HostFrameSinkClient* client) override {
if (manager_)
manager_->RegisterFrameSinkId(frame_sink_id, client);
}
void SetFrameSinkDebugLabel(const viz::FrameSinkId& frame_sink_id,
const std::string& name) override {
if (manager_)
manager_->SetFrameSinkDebugLabel(frame_sink_id, name);
}
void InvalidateFrameSinkId(const viz::FrameSinkId& frame_sink_id) override {
if (manager_)
manager_->InvalidateFrameSinkId(frame_sink_id);
}
void RegisterFrameSinkHierarchy(const viz::FrameSinkId& new_parent,
const viz::FrameSinkId& child) override {
if (manager_)
manager_->RegisterFrameSinkHierarchy(new_parent, child);
}
void UnregisterFrameSinkHierarchy(const viz::FrameSinkId& old_parent,
const viz::FrameSinkId& child) override {
if (manager_)
manager_->UnregisterFrameSinkHierarchy(old_parent, child);
}
void CreateRootCompositorFrameSink(
viz::mojom::RootCompositorFrameSinkParamsPtr params) override {
// No software compositing on ChromeOS.
params->force_software_compositing = false;
if (manager_)
manager_->CreateRootCompositorFrameSink(std::move(params));
}
void CreateCompositorFrameSink(
const viz::FrameSinkId& frame_sink_id,
viz::mojom::CompositorFrameSinkRequest request,
viz::mojom::CompositorFrameSinkClientPtr client) override {
if (manager_) {
manager_->CreateCompositorFrameSink(frame_sink_id, std::move(request),
std::move(client));
}
}
viz::HitTestQuery* GetHitTestQuery(
const viz::FrameSinkId& frame_sink_id) override {
if (!manager_)
return nullptr;
const auto& display_hit_test_query_map = manager_->display_hit_test_query();
const auto iter = display_hit_test_query_map.find(frame_sink_id);
return (iter != display_hit_test_query_map.end()) ? iter->second.get()
: nullptr;
}
private:
viz::HostFrameSinkManager* const manager_;
DISALLOW_COPY_AND_ASSIGN(VizHostProxyImpl);
};
} // namespace
struct WindowServer::CurrentMoveLoopState {
uint32_t change_id;
ServerWindow* window;
WindowTree* initiator;
gfx::Rect revert_bounds;
};
struct WindowServer::CurrentDragLoopState {
uint32_t change_id;
ServerWindow* window;
WindowTree* initiator;
};
WindowServer::WindowServer(WindowServerDelegate* delegate, bool should_host_viz)
: delegate_(delegate),
next_client_id_(kWindowServerClientId + 1),
display_manager_(std::make_unique<DisplayManager>(this)),
current_operation_(nullptr),
in_destructor_(false),
next_wm_change_id_(0),
window_manager_window_tree_factory_(
std::make_unique<WindowManagerWindowTreeFactory>(this)),
host_frame_sink_manager_(
should_host_viz ? std::make_unique<viz::HostFrameSinkManager>()
: nullptr),
viz_host_proxy_(
std::make_unique<VizHostProxyImpl>(host_frame_sink_manager_.get())),
video_detector_(host_frame_sink_manager_.get()),
display_creation_config_(DisplayCreationConfig::UNKNOWN) {
if (host_frame_sink_manager_)
host_frame_sink_manager_->WillAssignTemporaryReferencesExternally();
user_activity_monitor_ = std::make_unique<UserActivityMonitor>(nullptr);
}
WindowServer::~WindowServer() {
in_destructor_ = true;
for (auto& pair : tree_map_)
pair.second->PrepareForWindowServerShutdown();
// Destroys the window trees results in querying for the display. Tear down
// the displays first so that the trees are notified of the display going
// away while the display is still valid.
display_manager_->DestroyAllDisplays();
while (!tree_map_.empty())
DestroyTree(tree_map_.begin()->second.get());
display_manager_.reset();
}
void WindowServer::SetDisplayCreationConfig(DisplayCreationConfig config) {
DCHECK(tree_map_.empty());
DCHECK_EQ(DisplayCreationConfig::UNKNOWN, display_creation_config_);
display_creation_config_ = config;
display_manager_->OnDisplayCreationConfigSet();
}
void WindowServer::SetGpuHost(std::unique_ptr<GpuHost> gpu_host) {
DCHECK(host_frame_sink_manager_);
gpu_host_ = std::move(gpu_host);
CreateFrameSinkManager();
}
ThreadedImageCursorsFactory* WindowServer::GetThreadedImageCursorsFactory() {
return delegate()->GetThreadedImageCursorsFactory();
}
ServerWindow* WindowServer::CreateServerWindow(
const viz::FrameSinkId& frame_sink_id,
const std::map<std::string, std::vector<uint8_t>>& properties) {
ServerWindow* window = new ServerWindow(this, frame_sink_id, properties);
window->AddObserver(this);
return window;
}
ClientSpecificId WindowServer::GetAndAdvanceNextClientId() {
const ClientSpecificId id = next_client_id_++;
CHECK_NE(0u, next_client_id_);
return id;
}
WindowTree* WindowServer::EmbedAtWindow(
ServerWindow* root,
mojom::WindowTreeClientPtr client,
uint32_t flags,
std::unique_ptr<AccessPolicy> access_policy) {
// TODO(sky): I suspect this code needs to reset the FrameSinkId to the
// ClientWindowId that was used at the time the window was created. As
// currently if there is a reembed the FrameSinkId from the last embedding
// is incorrectly used.
const bool is_for_embedding = true;
std::unique_ptr<WindowTree> tree_ptr = std::make_unique<WindowTree>(
this, is_for_embedding, root, std::move(access_policy));
WindowTree* tree = tree_ptr.get();
if (flags & mojom::kEmbedFlagEmbedderInterceptsEvents)
tree->set_embedder_intercepts_events();
if (flags & mojom::kEmbedFlagEmbedderControlsVisibility)
tree->set_can_change_root_window_visibility(false);
mojom::WindowTreePtr window_tree_ptr;
auto window_tree_request = mojo::MakeRequest(&window_tree_ptr);
std::unique_ptr<WindowTreeBinding> binding =
delegate_->CreateWindowTreeBinding(
WindowServerDelegate::BindingType::EMBED, this, tree,
&window_tree_request, &client);
if (!binding) {
binding = std::make_unique<ws::DefaultWindowTreeBinding>(
tree, this, std::move(window_tree_request), std::move(client));
}
AddTree(std::move(tree_ptr), std::move(binding), std::move(window_tree_ptr));
OnTreeMessagedClient(tree->id());
root->UpdateFrameSinkId(viz::FrameSinkId(tree->id(), 0));
return tree;
}
void WindowServer::AddTree(std::unique_ptr<WindowTree> tree_impl_ptr,
std::unique_ptr<WindowTreeBinding> binding,
mojom::WindowTreePtr tree_ptr) {
CHECK_EQ(0u, tree_map_.count(tree_impl_ptr->id()));
WindowTree* tree = tree_impl_ptr.get();
tree_map_[tree->id()] = std::move(tree_impl_ptr);
tree->Init(std::move(binding), std::move(tree_ptr));
}
WindowTree* WindowServer::CreateTreeForWindowManager(
mojom::WindowTreeRequest window_tree_request,
mojom::WindowTreeClientPtr window_tree_client,
bool automatically_create_display_roots) {
delegate_->OnWillCreateTreeForWindowManager(
automatically_create_display_roots);
const bool is_for_embedding = false;
std::unique_ptr<WindowTree> window_tree = std::make_unique<WindowTree>(
this, is_for_embedding, nullptr,
base::WrapUnique(new WindowManagerAccessPolicy));
std::unique_ptr<WindowTreeBinding> window_tree_binding =
delegate_->CreateWindowTreeBinding(
WindowServerDelegate::BindingType::WINDOW_MANAGER, this,
window_tree.get(), &window_tree_request, &window_tree_client);
if (!window_tree_binding) {
window_tree_binding = std::make_unique<DefaultWindowTreeBinding>(
window_tree.get(), this, std::move(window_tree_request),
std::move(window_tree_client));
}
WindowTree* window_tree_ptr = window_tree.get();
AddTree(std::move(window_tree), std::move(window_tree_binding), nullptr);
window_tree_ptr->ConfigureWindowManager(automatically_create_display_roots);
return window_tree_ptr;
}
void WindowServer::DestroyTree(WindowTree* tree) {
std::unique_ptr<WindowTree> tree_ptr;
{
auto iter = tree_map_.find(tree->id());
DCHECK(iter != tree_map_.end());
tree_ptr = std::move(iter->second);
tree_map_.erase(iter);
}
// Notify remaining connections so that they can cleanup.
for (auto& pair : tree_map_)
pair.second->OnWillDestroyTree(tree);
if (window_manager_window_tree_factory_->window_tree() == tree)
window_manager_window_tree_factory_->OnTreeDestroyed();
// Remove any requests from the client that resulted in a call to the window
// manager and we haven't gotten a response back yet.
std::set<uint32_t> to_remove;
for (auto& pair : in_flight_wm_change_map_) {
if (pair.second.client_id == tree->id())
to_remove.insert(pair.first);
}
for (uint32_t id : to_remove)
in_flight_wm_change_map_.erase(id);
}
WindowTree* WindowServer::GetTreeWithId(ClientSpecificId client_id) {
auto iter = tree_map_.find(client_id);
return iter == tree_map_.end() ? nullptr : iter->second.get();
}
WindowTree* WindowServer::GetTreeWithClientName(
const std::string& client_name) {
for (const auto& entry : tree_map_) {
if (entry.second->name() == client_name)
return entry.second.get();
}
return nullptr;
}
void WindowServer::OnTreeMessagedClient(ClientSpecificId id) {
if (current_operation_)
current_operation_->MarkTreeAsMessaged(id);
}
bool WindowServer::DidTreeMessageClient(ClientSpecificId id) const {
return current_operation_ && current_operation_->DidMessageTree(id);
}
const WindowTree* WindowServer::GetTreeWithRoot(
const ServerWindow* window) const {
if (!window)
return nullptr;
for (auto& pair : tree_map_) {
if (pair.second->HasRoot(window))
return pair.second.get();
}
return nullptr;
}
void WindowServer::BindWindowManagerWindowTreeFactory(
mojo::InterfaceRequest<mojom::WindowManagerWindowTreeFactory> request) {
if (window_manager_window_tree_factory_->is_bound()) {
DVLOG(1) << "Can only have one WindowManagerWindowTreeFactory";
return;
}
window_manager_window_tree_factory_->Bind(std::move(request));
}
bool WindowServer::SetFocusedWindow(ServerWindow* window) {
// TODO(sky): this should fail if there is modal dialog active and |window|
// is outside that.
ServerWindow* currently_focused = GetFocusedWindow();
Display* focused_display =
currently_focused
? display_manager_->GetDisplayContaining(currently_focused)
: nullptr;
if (!window)
return focused_display ? focused_display->SetFocusedWindow(nullptr) : true;
Display* display = display_manager_->GetDisplayContaining(window);
DCHECK(display); // It's assumed callers do validation before calling this.
const bool result = display->SetFocusedWindow(window);
// If the focus actually changed, and focus was in another display, then we
// need to notify the previously focused display so that it cleans up state
// and notifies appropriately.
if (result && display->GetFocusedWindow() && display != focused_display &&
focused_display) {
const bool cleared_focus = focused_display->SetFocusedWindow(nullptr);
DCHECK(cleared_focus);
}
return result;
}
ServerWindow* WindowServer::GetFocusedWindow() {
for (Display* display : display_manager_->displays()) {
ServerWindow* focused_window = display->GetFocusedWindow();
if (focused_window)
return focused_window;
}
return nullptr;
}
void WindowServer::SetHighContrastMode(bool enabled) {
// TODO(fsamuel): This doesn't really seem like it's a window server concept?
if (high_contrast_mode_ == enabled)
return;
high_contrast_mode_ = enabled;
// Propagate the change to all Displays so that FrameGenerators start
// requesting BeginFrames.
display_manager_->SetHighContrastMode(enabled);
}
uint32_t WindowServer::GenerateWindowManagerChangeId(
WindowTree* source,
uint32_t client_change_id) {
const uint32_t wm_change_id = next_wm_change_id_++;
in_flight_wm_change_map_[wm_change_id] = {source->id(), client_change_id};
return wm_change_id;
}
void WindowServer::WindowManagerChangeCompleted(
uint32_t window_manager_change_id,
bool success) {
InFlightWindowManagerChange change;
if (!GetAndClearInFlightWindowManagerChange(window_manager_change_id,
&change)) {
return;
}
WindowTree* tree = GetTreeWithId(change.client_id);
tree->OnChangeCompleted(change.client_change_id, success);
}
void WindowServer::WindowManagerCreatedTopLevelWindow(
WindowTree* wm_tree,
uint32_t window_manager_change_id,
ServerWindow* window) {
InFlightWindowManagerChange change;
if (!GetAndClearInFlightWindowManagerChange(window_manager_change_id,
&change)) {
DVLOG(1) << "WindowManager responded with invalid change id; most "
<< "likely bug in WindowManager processing WmCreateTopLevelWindow "
<< "change_id=" << window_manager_change_id;
return;
}
WindowTree* tree = GetTreeWithId(change.client_id);
// The window manager should have created the window already, and it should
// be ready for embedding.
if (!tree->IsWaitingForNewTopLevelWindow(window_manager_change_id)) {
DVLOG(1) << "WindowManager responded with valid change id, but client "
<< "is not waiting for top-level; possible bug in mus, change_id="
<< window_manager_change_id;
WindowManagerSentBogusMessage();
return;
}
if (window && (window->owning_tree_id() != wm_tree->id() ||
!window->children().empty() || GetTreeWithRoot(window))) {
DVLOG(1)
<< "WindowManager responded with invalid window; window should "
<< "not have any children, not be the root of a client and should be "
<< "created by the WindowManager, window_manager_change_id="
<< window_manager_change_id;
WindowManagerSentBogusMessage();
return;
}
viz::FrameSinkId updated_frame_sink_id =
tree->OnWindowManagerCreatedTopLevelWindow(
window_manager_change_id, change.client_change_id, window);
if (window)
window->UpdateFrameSinkId(updated_frame_sink_id);
}
void WindowServer::ProcessWindowBoundsChanged(
const ServerWindow* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
const base::Optional<viz::LocalSurfaceId>& local_surface_id) {
for (auto& pair : tree_map_) {
pair.second->ProcessWindowBoundsChanged(window, old_bounds, new_bounds,
IsOperationSource(pair.first),
local_surface_id);
}
}
void WindowServer::ProcessWindowTransformChanged(
const ServerWindow* window,
const gfx::Transform& old_transform,
const gfx::Transform& new_transform) {
for (auto& pair : tree_map_) {
pair.second->ProcessWindowTransformChanged(
window, old_transform, new_transform, IsOperationSource(pair.first));
}
}
void WindowServer::ProcessClientAreaChanged(
const ServerWindow* window,
const gfx::Insets& new_client_area,
const std::vector<gfx::Rect>& new_additional_client_areas) {
for (auto& pair : tree_map_) {
pair.second->ProcessClientAreaChanged(window, new_client_area,
new_additional_client_areas,
IsOperationSource(pair.first));
}
}
void WindowServer::ProcessCaptureChanged(const ServerWindow* new_capture,
const ServerWindow* old_capture) {
for (auto& pair : tree_map_) {
pair.second->ProcessCaptureChanged(new_capture, old_capture,
IsOperationSource(pair.first));
}
}
void WindowServer::ProcessWillChangeWindowHierarchy(
const ServerWindow* window,
const ServerWindow* new_parent,
const ServerWindow* old_parent) {
for (auto& pair : tree_map_) {
pair.second->ProcessWillChangeWindowHierarchy(
window, new_parent, old_parent, IsOperationSource(pair.first));
}
}
void WindowServer::ProcessWindowHierarchyChanged(
const ServerWindow* window,
const ServerWindow* new_parent,
const ServerWindow* old_parent) {
for (auto& pair : tree_map_) {
pair.second->ProcessWindowHierarchyChanged(window, new_parent, old_parent,
IsOperationSource(pair.first));
}
}
void WindowServer::ProcessWindowReorder(const ServerWindow* window,
const ServerWindow* relative_window,
const mojom::OrderDirection direction) {
// We'll probably do a bit of reshuffling when we add a transient window.
if ((current_operation_type() == OperationType::ADD_TRANSIENT_WINDOW) ||
(current_operation_type() ==
OperationType::REMOVE_TRANSIENT_WINDOW_FROM_PARENT)) {
return;
}
for (auto& pair : tree_map_) {
pair.second->ProcessWindowReorder(window, relative_window, direction,
IsOperationSource(pair.first));
}
}
void WindowServer::ProcessWindowDeleted(ServerWindow* window) {
for (auto& pair : tree_map_)
pair.second->ProcessWindowDeleted(window, IsOperationSource(pair.first));
}
void WindowServer::ProcessWillChangeWindowCursor(ServerWindow* window,
const ui::CursorData& cursor) {
for (auto& pair : tree_map_) {
pair.second->ProcessCursorChanged(window, cursor,
IsOperationSource(pair.first));
}
}
void WindowServer::SendToPointerWatchers(const ui::Event& event,
ServerWindow* target_window,
WindowTree* ignore_tree,
int64_t display_id) {
for (auto& pair : tree_map_) {
WindowTree* tree = pair.second.get();
if (tree != ignore_tree)
tree->SendToPointerWatcher(event, target_window, display_id);
}
}
void WindowServer::SetPaintCallback(
const base::Callback<void(ServerWindow*)>& callback) {
DCHECK(delegate_->IsTestConfig()) << "Paint callbacks are expensive, and "
<< "allowed only in tests.";
DCHECK(window_paint_callback_.is_null() || callback.is_null());
window_paint_callback_ = callback;
}
void WindowServer::StartMoveLoop(uint32_t change_id,
ServerWindow* window,
WindowTree* initiator,
const gfx::Rect& revert_bounds) {
current_move_loop_.reset(
new CurrentMoveLoopState{change_id, window, initiator, revert_bounds});
}
void WindowServer::EndMoveLoop() {
current_move_loop_.reset();
}
uint32_t WindowServer::GetCurrentMoveLoopChangeId() {
if (current_move_loop_)
return current_move_loop_->change_id;
return 0;
}
ServerWindow* WindowServer::GetCurrentMoveLoopWindow() {
if (current_move_loop_)
return current_move_loop_->window;
return nullptr;
}
WindowTree* WindowServer::GetCurrentMoveLoopInitiator() {
if (current_move_loop_)
return current_move_loop_->initiator;
return nullptr;
}
gfx::Rect WindowServer::GetCurrentMoveLoopRevertBounds() {
if (current_move_loop_)
return current_move_loop_->revert_bounds;
return gfx::Rect();
}
void WindowServer::StartDragLoop(uint32_t change_id,
ServerWindow* window,
WindowTree* initiator) {
current_drag_loop_.reset(
new CurrentDragLoopState{change_id, window, initiator});
}
void WindowServer::EndDragLoop() {
current_drag_loop_.reset();
}
uint32_t WindowServer::GetCurrentDragLoopChangeId() {
if (current_drag_loop_)
return current_drag_loop_->change_id;
return 0u;
}
ServerWindow* WindowServer::GetCurrentDragLoopWindow() {
if (current_drag_loop_)
return current_drag_loop_->window;
return nullptr;
}
WindowTree* WindowServer::GetCurrentDragLoopInitiator() {
if (current_drag_loop_)
return current_drag_loop_->initiator;
return nullptr;
}
void WindowServer::OnDisplayReady(Display* display, bool is_first) {
if (is_first)
delegate_->OnFirstDisplayReady();
bool wm_is_hosting_viz = !gpu_host_;
if (wm_is_hosting_viz) {
// Notify WM about the AcceleratedWidget if it is hosting viz.
for (auto& pair : tree_map_) {
if (pair.second->window_manager_state()) {
auto& wm_tree = pair.second;
wm_tree->OnAcceleratedWidgetAvailableForDisplay(display);
}
}
} else {
gpu_host_->OnAcceleratedWidgetAvailable(
display->platform_display()->GetAcceleratedWidget());
}
}
void WindowServer::OnDisplayDestroyed(Display* display) {
if (gpu_host_) {
gpu_host_->OnAcceleratedWidgetDestroyed(
display->platform_display()->GetAcceleratedWidget());
}
}
void WindowServer::OnNoMoreDisplays() {
delegate_->OnNoMoreDisplays();
}
WindowManagerState* WindowServer::GetWindowManagerState() {
return window_manager_window_tree_factory_->window_tree()
? window_manager_window_tree_factory_->window_tree()
->window_manager_state()
: nullptr;
}
VizHostProxy* WindowServer::GetVizHostProxy() {
return viz_host_proxy_.get();
}
void WindowServer::OnFirstSurfaceActivation(
const viz::SurfaceInfo& surface_info,
ServerWindow* window) {
DCHECK(host_frame_sink_manager_);
// This is only used for testing to observe that a window has a
// CompositorFrame.
if (!window_paint_callback_.is_null())
window_paint_callback_.Run(window);
Display* display = display_manager_->GetDisplayContaining(window);
if (IsWindowConsideredWindowManagerRoot(display, window)) {
// A new surface for a WindowManager root has been created. This is a
// special case because ServerWindows created by the WindowServer are not
// part of a WindowTree. Send the SurfaceId directly to FrameGenerator and
// claim the temporary reference for the display root.
display->platform_display()->GetFrameGenerator()->OnFirstSurfaceActivation(
surface_info);
host_frame_sink_manager_->AssignTemporaryReference(
surface_info.id(), display->root_window()->frame_sink_id());
return;
}
HandleTemporaryReferenceForNewSurface(surface_info.id(), window);
// We always use the owner of the window's id (even for an embedded window),
// because an embedded window's id is allocated by the parent's window tree.
WindowTree* window_tree = GetTreeWithId(window->owning_tree_id());
if (window_tree)
window_tree->ProcessWindowSurfaceChanged(window, surface_info);
}
bool WindowServer::GetFrameDecorations(
mojom::FrameDecorationValuesPtr* values) {
WindowManagerState* window_manager_state = GetWindowManagerState();
if (!window_manager_state)
return false;
if (values && window_manager_state->got_frame_decoration_values())
*values = window_manager_state->frame_decoration_values().Clone();
return window_manager_state->got_frame_decoration_values();
}
int64_t WindowServer::GetInternalDisplayId() {
return display_manager_->GetInternalDisplayId();
}
bool WindowServer::GetAndClearInFlightWindowManagerChange(
uint32_t window_manager_change_id,
InFlightWindowManagerChange* change) {
// There are valid reasons as to why we wouldn't know about the id. The
// most likely is the client disconnected before the response from the window
// manager came back.
auto iter = in_flight_wm_change_map_.find(window_manager_change_id);
if (iter == in_flight_wm_change_map_.end())
return false;
*change = iter->second;
in_flight_wm_change_map_.erase(iter);
return true;
}
void WindowServer::PrepareForOperation(Operation* op) {
// Should only ever have one change in flight.
CHECK(!current_operation_);
current_operation_ = op;
}
void WindowServer::FinishOperation() {
// PrepareForOperation/FinishOperation should be balanced.
CHECK(current_operation_);
current_operation_ = nullptr;
}
void WindowServer::UpdateNativeCursorFromMouseLocation(ServerWindow* window) {
UpdateNativeCursorFromMouseLocation(
display_manager_->GetWindowManagerDisplayRoot(window));
}
void WindowServer::UpdateNativeCursorFromMouseLocation(
WindowManagerDisplayRoot* display_root) {
if (!display_root)
return;
EventDispatcher* event_dispatcher =
display_root->window_manager_state()->event_dispatcher();
event_dispatcher->UpdateCursorProviderByLastKnownLocation();
}
void WindowServer::UpdateNativeCursorIfOver(ServerWindow* window) {
WindowManagerDisplayRoot* display_root =
display_manager_->GetWindowManagerDisplayRoot(window);
if (!display_root)
return;
EventDispatcher* event_dispatcher =
display_root->window_manager_state()->event_dispatcher();
if (window != event_dispatcher->GetWindowForMouseCursor())
return;
event_dispatcher->UpdateNonClientAreaForCurrentWindow();
}
void WindowServer::HandleTemporaryReferenceForNewSurface(
const viz::SurfaceId& surface_id,
ServerWindow* window) {
DCHECK(host_frame_sink_manager_);
// TODO(kylechar): Investigate adding tests for this.
const ClientSpecificId window_client_id = window->owning_tree_id();
// Find the root ServerWindow for the client that embeds |window|, which is
// the root of the client that embeds |surface_id|. The client that embeds
// |surface_id| created |window|, so |window| will have the client id of the
// embedder. The root window of the embedder will have been created by it's
// embedder, so the first ServerWindow with a different client id will be the
// root of the embedder.
ServerWindow* current = window->parent();
while (current && current->owning_tree_id() == window_client_id)
current = current->parent();
// The client that embeds |window| is expected to submit a CompositorFrame
// that references |surface_id|. Have the parent claim ownership of the
// temporary reference to |surface_id|. If the parent client crashes before it
// adds a surface reference then the GPU can cleanup temporary references. If
// no parent client embeds |window| then tell the GPU to drop the temporary
// reference immediately.
if (current) {
host_frame_sink_manager_->AssignTemporaryReference(
surface_id, current->frame_sink_id());
} else {
host_frame_sink_manager_->DropTemporaryReference(surface_id);
}
}
void WindowServer::CreateFrameSinkManager() {
DCHECK(host_frame_sink_manager_);
viz::mojom::FrameSinkManagerPtr frame_sink_manager;
viz::mojom::FrameSinkManagerRequest frame_sink_manager_request =
mojo::MakeRequest(&frame_sink_manager);
viz::mojom::FrameSinkManagerClientPtr frame_sink_manager_client;
viz::mojom::FrameSinkManagerClientRequest frame_sink_manager_client_request =
mojo::MakeRequest(&frame_sink_manager_client);
viz::mojom::FrameSinkManagerParamsPtr params =
viz::mojom::FrameSinkManagerParams::New();
params->restart_id = viz_restart_id_++;
base::Optional<uint32_t> activation_deadline_in_frames =
switches::GetDeadlineToSynchronizeSurfaces();
params->use_activation_deadline = activation_deadline_in_frames.has_value();
params->activation_deadline_in_frames =
activation_deadline_in_frames.value_or(0u);
params->frame_sink_manager = std::move(frame_sink_manager_request);
params->frame_sink_manager_client = frame_sink_manager_client.PassInterface();
gpu_host_->CreateFrameSinkManager(std::move(params));
host_frame_sink_manager_->BindAndSetManager(
std::move(frame_sink_manager_client_request), nullptr /* task_runner */,
std::move(frame_sink_manager));
}
ServerWindow* WindowServer::GetRootWindowForDrawn(const ServerWindow* window) {
Display* display = display_manager_->GetDisplayContaining(window);
return display ? display->root_window() : nullptr;
}
void WindowServer::OnWindowDestroyed(ServerWindow* window) {
ProcessWindowDeleted(window);
}
void WindowServer::OnWillChangeWindowHierarchy(ServerWindow* window,
ServerWindow* new_parent,
ServerWindow* old_parent) {
if (in_destructor_)
return;
ProcessWillChangeWindowHierarchy(window, new_parent, old_parent);
}
void WindowServer::OnWindowHierarchyChanged(ServerWindow* window,
ServerWindow* new_parent,
ServerWindow* old_parent) {
if (in_destructor_)
return;
WindowManagerDisplayRoot* display_root =
display_manager_->GetWindowManagerDisplayRoot(window);
if (display_root) {
display_root->window_manager_state()
->ReleaseCaptureBlockedByAnyModalWindow();
}
ProcessWindowHierarchyChanged(window, new_parent, old_parent);
if (old_parent) {
viz_host_proxy_->UnregisterFrameSinkHierarchy(old_parent->frame_sink_id(),
window->frame_sink_id());
}
if (new_parent) {
viz_host_proxy_->RegisterFrameSinkHierarchy(new_parent->frame_sink_id(),
window->frame_sink_id());
}
if (!pending_system_modal_windows_.windows().empty()) {
// Windows that are now in a display are put here, then removed. We do this
// in two passes to avoid removing from a list we're iterating over.
std::set<ServerWindow*> no_longer_pending;
for (ServerWindow* system_modal_window :
pending_system_modal_windows_.windows()) {
DCHECK_EQ(MODAL_TYPE_SYSTEM, system_modal_window->modal_type());
WindowManagerDisplayRoot* display_root =
display_manager_->GetWindowManagerDisplayRoot(system_modal_window);
if (display_root) {
no_longer_pending.insert(system_modal_window);
display_root->window_manager_state()->AddSystemModalWindow(window);
}
}
for (ServerWindow* system_modal_window : no_longer_pending)
pending_system_modal_windows_.Remove(system_modal_window);
}
WindowManagerDisplayRoot* old_display_root =
old_parent ? display_manager_->GetWindowManagerDisplayRoot(old_parent)
: nullptr;
WindowManagerDisplayRoot* new_display_root =
new_parent ? display_manager_->GetWindowManagerDisplayRoot(new_parent)
: nullptr;
UpdateNativeCursorFromMouseLocation(new_display_root);
if (old_display_root != new_display_root)
UpdateNativeCursorFromMouseLocation(old_display_root);
}
void WindowServer::OnWindowBoundsChanged(ServerWindow* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) {
if (in_destructor_)
return;
ProcessWindowBoundsChanged(window, old_bounds, new_bounds,
window->current_local_surface_id());
UpdateNativeCursorFromMouseLocation(window);
}
void WindowServer::OnWindowTransformChanged(
ServerWindow* window,
const gfx::Transform& old_transform,
const gfx::Transform& new_transform) {
if (in_destructor_)
return;
ProcessWindowTransformChanged(window, old_transform, new_transform);
UpdateNativeCursorFromMouseLocation(window);
}
void WindowServer::OnWindowClientAreaChanged(
ServerWindow* window,
const gfx::Insets& new_client_area,
const std::vector<gfx::Rect>& new_additional_client_areas) {
if (in_destructor_)
return;
ProcessClientAreaChanged(window, new_client_area,
new_additional_client_areas);
UpdateNativeCursorIfOver(window);
}
void WindowServer::OnWindowReordered(ServerWindow* window,
ServerWindow* relative,
mojom::OrderDirection direction) {
ProcessWindowReorder(window, relative, direction);
UpdateNativeCursorFromMouseLocation(window);
}
void WindowServer::OnWillChangeWindowVisibility(ServerWindow* window) {
if (in_destructor_)
return;
for (auto& pair : tree_map_) {
pair.second->ProcessWillChangeWindowVisibility(
window, IsOperationSource(pair.first));
}
}
void WindowServer::OnWindowOpacityChanged(ServerWindow* window,
float old_opacity,
float new_opacity) {
DCHECK(!in_destructor_);
for (auto& pair : tree_map_) {
pair.second->ProcessWindowOpacityChanged(window, old_opacity, new_opacity,
IsOperationSource(pair.first));
}
}
void WindowServer::OnWindowVisibilityChanged(ServerWindow* window) {
if (in_destructor_)
return;
WindowManagerDisplayRoot* display_root =
display_manager_->GetWindowManagerDisplayRoot(window);
if (display_root) {
display_root->window_manager_state()
->ReleaseCaptureBlockedByAnyModalWindow();
}
}
void WindowServer::OnWindowCursorChanged(ServerWindow* window,
const ui::CursorData& cursor) {
if (in_destructor_)
return;
ProcessWillChangeWindowCursor(window, cursor);
UpdateNativeCursorIfOver(window);
}
void WindowServer::OnWindowNonClientCursorChanged(
ServerWindow* window,
const ui::CursorData& cursor) {
if (in_destructor_)
return;
UpdateNativeCursorIfOver(window);
}
void WindowServer::OnWindowSharedPropertyChanged(
ServerWindow* window,
const std::string& name,
const std::vector<uint8_t>* new_data) {
for (auto& pair : tree_map_) {
pair.second->ProcessWindowPropertyChanged(window, name, new_data,
IsOperationSource(pair.first));
}
}
void WindowServer::OnWindowTextInputStateChanged(
ServerWindow* window,
const ui::TextInputState& state) {
Display* display = display_manager_->GetDisplayContaining(window);
display->UpdateTextInputState(window, state);
}
void WindowServer::OnTransientWindowAdded(ServerWindow* window,
ServerWindow* transient_child) {
for (auto& pair : tree_map_) {
pair.second->ProcessTransientWindowAdded(window, transient_child,
IsOperationSource(pair.first));
}
}
void WindowServer::OnTransientWindowRemoved(ServerWindow* window,
ServerWindow* transient_child) {
// If we're deleting a window, then this is a superfluous message.
if (current_operation_type() == OperationType::DELETE_WINDOW)
return;
for (auto& pair : tree_map_) {
pair.second->ProcessTransientWindowRemoved(window, transient_child,
IsOperationSource(pair.first));
}
}
void WindowServer::OnWindowModalTypeChanged(ServerWindow* window,
ModalType old_modal_type) {
WindowManagerDisplayRoot* display_root =
display_manager_->GetWindowManagerDisplayRoot(window);
if (window->modal_type() == MODAL_TYPE_SYSTEM) {
if (display_root)
display_root->window_manager_state()->AddSystemModalWindow(window);
else
pending_system_modal_windows_.Add(window);
} else {
pending_system_modal_windows_.Remove(window);
}
if (display_root && window->modal_type() != MODAL_TYPE_NONE) {
display_root->window_manager_state()
->ReleaseCaptureBlockedByAnyModalWindow();
}
}
void WindowServer::OnGpuServiceInitialized() {
delegate_->StartDisplayInit();
}
} // namespace ws
} // namespace ui