summaryrefslogtreecommitdiff
path: root/chromium/components/mus/public/cpp/lib
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/components/mus/public/cpp/lib')
-rw-r--r--chromium/components/mus/public/cpp/lib/DEPS3
-rw-r--r--chromium/components/mus/public/cpp/lib/command_buffer_client_impl.cc370
-rw-r--r--chromium/components/mus/public/cpp/lib/command_buffer_client_impl.h117
-rw-r--r--chromium/components/mus/public/cpp/lib/context_provider.cc61
-rw-r--r--chromium/components/mus/public/cpp/lib/gles2_context.cc109
-rw-r--r--chromium/components/mus/public/cpp/lib/in_flight_change.cc220
-rw-r--r--chromium/components/mus/public/cpp/lib/in_flight_change.h298
-rw-r--r--chromium/components/mus/public/cpp/lib/output_surface.cc70
-rw-r--r--chromium/components/mus/public/cpp/lib/property_type_converters.cc207
-rw-r--r--chromium/components/mus/public/cpp/lib/scoped_window_ptr.cc44
-rw-r--r--chromium/components/mus/public/cpp/lib/window.cc891
-rw-r--r--chromium/components/mus/public/cpp/lib/window_observer.cc18
-rw-r--r--chromium/components/mus/public/cpp/lib/window_private.cc31
-rw-r--r--chromium/components/mus/public/cpp/lib/window_private.h100
-rw-r--r--chromium/components/mus/public/cpp/lib/window_surface.cc69
-rw-r--r--chromium/components/mus/public/cpp/lib/window_tree_client.cc1181
-rw-r--r--chromium/components/mus/public/cpp/lib/window_tree_client_delegate.cc11
-rw-r--r--chromium/components/mus/public/cpp/lib/window_tree_host_factory.cc32
18 files changed, 3832 insertions, 0 deletions
diff --git a/chromium/components/mus/public/cpp/lib/DEPS b/chromium/components/mus/public/cpp/lib/DEPS
new file mode 100644
index 00000000000..c635ea6f5e4
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+mojo/gpu"
+]
diff --git a/chromium/components/mus/public/cpp/lib/command_buffer_client_impl.cc b/chromium/components/mus/public/cpp/lib/command_buffer_client_impl.cc
new file mode 100644
index 00000000000..062c3f78477
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/command_buffer_client_impl.cc
@@ -0,0 +1,370 @@
+// 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 "components/mus/public/cpp/lib/command_buffer_client_impl.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <limits>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/process/process_handle.h"
+#include "base/threading/thread_restrictions.h"
+#include "components/mus/common/gpu_type_converters.h"
+#include "components/mus/common/mojo_buffer_backing.h"
+#include "components/mus/common/mojo_gpu_memory_buffer.h"
+#include "gpu/command_buffer/client/gpu_control_client.h"
+#include "gpu/command_buffer/common/command_buffer_id.h"
+#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
+#include "gpu/command_buffer/common/sync_token.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+
+namespace mus {
+
+namespace {
+
+bool CreateAndMapSharedBuffer(size_t size,
+ mojo::ScopedSharedBufferMapping* mapping,
+ mojo::ScopedSharedBufferHandle* handle) {
+ *handle = mojo::SharedBufferHandle::Create(size);
+ if (!handle->is_valid())
+ return false;
+
+ *mapping = (*handle)->Map(size);
+ if (!*mapping)
+ return false;
+
+ return true;
+}
+
+void MakeProgressCallback(gpu::CommandBuffer::State* output,
+ const gpu::CommandBuffer::State& input) {
+ *output = input;
+}
+
+void InitializeCallback(mus::mojom::CommandBufferInitializeResultPtr* output,
+ mus::mojom::CommandBufferInitializeResultPtr input) {
+ *output = std::move(input);
+}
+
+} // namespace
+
+CommandBufferClientImpl::CommandBufferClientImpl(
+ const std::vector<int32_t>& attribs,
+ mus::mojom::CommandBufferPtr command_buffer_ptr)
+ : gpu_control_client_(nullptr),
+ destroyed_(false),
+ attribs_(attribs),
+ client_binding_(this),
+ command_buffer_(std::move(command_buffer_ptr)),
+ command_buffer_id_(),
+ last_put_offset_(-1),
+ next_transfer_buffer_id_(0),
+ next_image_id_(0),
+ next_fence_sync_release_(1),
+ flushed_fence_sync_release_(0) {
+ command_buffer_.set_connection_error_handler(
+ base::Bind(&CommandBufferClientImpl::Destroyed, base::Unretained(this),
+ gpu::error::kUnknown, gpu::error::kLostContext));
+}
+
+CommandBufferClientImpl::~CommandBufferClientImpl() {}
+
+bool CommandBufferClientImpl::Initialize() {
+ const size_t kSharedStateSize = sizeof(gpu::CommandBufferSharedState);
+ mojo::ScopedSharedBufferHandle handle;
+ bool result =
+ CreateAndMapSharedBuffer(kSharedStateSize, &shared_state_, &handle);
+ if (!result)
+ return false;
+
+ shared_state()->Initialize();
+
+ mus::mojom::CommandBufferClientPtr client_ptr;
+ client_binding_.Bind(GetProxy(&client_ptr));
+
+ mus::mojom::CommandBufferInitializeResultPtr initialize_result;
+ command_buffer_->Initialize(
+ std::move(client_ptr), std::move(handle),
+ mojo::Array<int32_t>::From(attribs_),
+ base::Bind(&InitializeCallback, &initialize_result));
+
+ base::ThreadRestrictions::ScopedAllowWait wait;
+ if (!command_buffer_.WaitForIncomingResponse()) {
+ VLOG(1) << "Channel encountered error while creating command buffer.";
+ return false;
+ }
+
+ if (!initialize_result) {
+ VLOG(1) << "Command buffer cannot be initialized successfully.";
+ return false;
+ }
+
+ DCHECK_EQ(gpu::CommandBufferNamespace::MOJO,
+ initialize_result->command_buffer_namespace);
+ command_buffer_id_ = gpu::CommandBufferId::FromUnsafeValue(
+ initialize_result->command_buffer_id);
+ capabilities_ = initialize_result->capabilities;
+ return true;
+}
+
+gpu::CommandBuffer::State CommandBufferClientImpl::GetLastState() {
+ return last_state_;
+}
+
+int32_t CommandBufferClientImpl::GetLastToken() {
+ TryUpdateState();
+ return last_state_.token;
+}
+
+void CommandBufferClientImpl::Flush(int32_t put_offset) {
+ if (last_put_offset_ == put_offset)
+ return;
+
+ last_put_offset_ = put_offset;
+ command_buffer_->Flush(put_offset);
+ flushed_fence_sync_release_ = next_fence_sync_release_ - 1;
+}
+
+void CommandBufferClientImpl::OrderingBarrier(int32_t put_offset) {
+ // TODO(jamesr): Implement this more efficiently.
+ Flush(put_offset);
+}
+
+void CommandBufferClientImpl::WaitForTokenInRange(int32_t start, int32_t end) {
+ TryUpdateState();
+ while (!InRange(start, end, last_state_.token) &&
+ last_state_.error == gpu::error::kNoError) {
+ MakeProgressAndUpdateState();
+ }
+}
+
+void CommandBufferClientImpl::WaitForGetOffsetInRange(int32_t start,
+ int32_t end) {
+ TryUpdateState();
+ while (!InRange(start, end, last_state_.get_offset) &&
+ last_state_.error == gpu::error::kNoError) {
+ MakeProgressAndUpdateState();
+ }
+}
+
+void CommandBufferClientImpl::SetGetBuffer(int32_t shm_id) {
+ command_buffer_->SetGetBuffer(shm_id);
+ last_put_offset_ = -1;
+}
+
+scoped_refptr<gpu::Buffer> CommandBufferClientImpl::CreateTransferBuffer(
+ size_t size,
+ int32_t* id) {
+ if (size >= std::numeric_limits<uint32_t>::max())
+ return NULL;
+
+ mojo::ScopedSharedBufferMapping mapping;
+ mojo::ScopedSharedBufferHandle handle;
+ if (!CreateAndMapSharedBuffer(size, &mapping, &handle)) {
+ if (last_state_.error == gpu::error::kNoError)
+ last_state_.error = gpu::error::kLostContext;
+ return NULL;
+ }
+
+ *id = ++next_transfer_buffer_id_;
+
+ command_buffer_->RegisterTransferBuffer(*id, std::move(handle),
+ static_cast<uint32_t>(size));
+
+ std::unique_ptr<gpu::BufferBacking> backing(
+ new mus::MojoBufferBacking(std::move(mapping), size));
+ scoped_refptr<gpu::Buffer> buffer(new gpu::Buffer(std::move(backing)));
+ return buffer;
+}
+
+void CommandBufferClientImpl::DestroyTransferBuffer(int32_t id) {
+ command_buffer_->DestroyTransferBuffer(id);
+}
+
+void CommandBufferClientImpl::SetGpuControlClient(gpu::GpuControlClient* c) {
+ gpu_control_client_ = c;
+}
+
+gpu::Capabilities CommandBufferClientImpl::GetCapabilities() {
+ return capabilities_;
+}
+
+int32_t CommandBufferClientImpl::CreateImage(ClientBuffer buffer,
+ size_t width,
+ size_t height,
+ unsigned internalformat) {
+ int32_t new_id = ++next_image_id_;
+
+ gfx::Size size(static_cast<int32_t>(width), static_cast<int32_t>(height));
+
+ mus::MojoGpuMemoryBufferImpl* gpu_memory_buffer =
+ mus::MojoGpuMemoryBufferImpl::FromClientBuffer(buffer);
+ gfx::GpuMemoryBufferHandle handle = gpu_memory_buffer->GetHandle();
+
+ bool requires_sync_point = false;
+ if (handle.type != gfx::SHARED_MEMORY_BUFFER) {
+ requires_sync_point = true;
+ NOTIMPLEMENTED();
+ return -1;
+ }
+
+ base::SharedMemoryHandle dupd_handle =
+ base::SharedMemory::DuplicateHandle(handle.handle);
+#if defined(OS_WIN)
+ HANDLE platform_handle = dupd_handle.GetHandle();
+#else
+ int platform_handle = dupd_handle.fd;
+#endif
+
+ mojo::ScopedHandle scoped_handle = mojo::WrapPlatformFile(platform_handle);
+ command_buffer_->CreateImage(
+ new_id, std::move(scoped_handle), handle.type, std::move(size),
+ static_cast<int32_t>(gpu_memory_buffer->GetFormat()), internalformat);
+ if (requires_sync_point) {
+ NOTIMPLEMENTED();
+ // TODO(jam): need to support this if we support types other than
+ // SHARED_MEMORY_BUFFER.
+ // gpu_memory_buffer_manager->SetDestructionSyncPoint(gpu_memory_buffer,
+ // InsertSyncPoint());
+ }
+
+ return new_id;
+}
+
+void CommandBufferClientImpl::DestroyImage(int32_t id) {
+ command_buffer_->DestroyImage(id);
+}
+
+int32_t CommandBufferClientImpl::CreateGpuMemoryBufferImage(
+ size_t width,
+ size_t height,
+ unsigned internalformat,
+ unsigned usage) {
+ std::unique_ptr<gfx::GpuMemoryBuffer> buffer(
+ mus::MojoGpuMemoryBufferImpl::Create(
+ gfx::Size(static_cast<int>(width), static_cast<int>(height)),
+ gpu::DefaultBufferFormatForImageFormat(internalformat),
+ gfx::BufferUsage::SCANOUT));
+ if (!buffer)
+ return -1;
+
+ return CreateImage(buffer->AsClientBuffer(), width, height, internalformat);
+}
+
+int32_t CommandBufferClientImpl::GetImageGpuMemoryBufferId(unsigned image_id) {
+ // TODO(erikchen): Once this class supports IOSurface GpuMemoryBuffer backed
+ // images, it will also need to keep a local cache from image id to
+ // GpuMemoryBuffer id.
+ NOTIMPLEMENTED();
+ return -1;
+}
+
+void CommandBufferClientImpl::SignalQuery(uint32_t query,
+ const base::Closure& callback) {
+ // TODO(piman)
+ NOTIMPLEMENTED();
+}
+
+void CommandBufferClientImpl::Destroyed(int32_t lost_reason, int32_t error) {
+ if (destroyed_)
+ return;
+ last_state_.context_lost_reason =
+ static_cast<gpu::error::ContextLostReason>(lost_reason);
+ last_state_.error = static_cast<gpu::error::Error>(error);
+ if (gpu_control_client_)
+ gpu_control_client_->OnGpuControlLostContext();
+ destroyed_ = true;
+}
+
+void CommandBufferClientImpl::SignalAck(uint32_t id) {}
+
+void CommandBufferClientImpl::SwapBuffersCompleted(int32_t result) {}
+
+void CommandBufferClientImpl::UpdateState(
+ const gpu::CommandBuffer::State& state) {}
+
+void CommandBufferClientImpl::UpdateVSyncParameters(int64_t timebase,
+ int64_t interval) {}
+
+void CommandBufferClientImpl::TryUpdateState() {
+ if (last_state_.error == gpu::error::kNoError)
+ shared_state()->Read(&last_state_);
+}
+
+void CommandBufferClientImpl::MakeProgressAndUpdateState() {
+ gpu::CommandBuffer::State state;
+ command_buffer_->MakeProgress(last_state_.get_offset,
+ base::Bind(&MakeProgressCallback, &state));
+
+ base::ThreadRestrictions::ScopedAllowWait wait;
+ if (!command_buffer_.WaitForIncomingResponse()) {
+ VLOG(1) << "Channel encountered error while waiting for command buffer.";
+ // TODO(piman): is it ok for this to re-enter?
+ Destroyed(gpu::error::kUnknown, gpu::error::kLostContext);
+ return;
+ }
+
+ if (state.generation - last_state_.generation < 0x80000000U)
+ last_state_ = state;
+}
+
+void CommandBufferClientImpl::SetLock(base::Lock* lock) {}
+
+void CommandBufferClientImpl::EnsureWorkVisible() {
+ // This is only relevant for out-of-process command buffers.
+}
+
+gpu::CommandBufferNamespace CommandBufferClientImpl::GetNamespaceID() const {
+ return gpu::CommandBufferNamespace::MOJO;
+}
+
+gpu::CommandBufferId CommandBufferClientImpl::GetCommandBufferID() const {
+ return command_buffer_id_;
+}
+
+int32_t CommandBufferClientImpl::GetExtraCommandBufferData() const {
+ return 0;
+}
+
+uint64_t CommandBufferClientImpl::GenerateFenceSyncRelease() {
+ return next_fence_sync_release_++;
+}
+
+bool CommandBufferClientImpl::IsFenceSyncRelease(uint64_t release) {
+ return release != 0 && release < next_fence_sync_release_;
+}
+
+bool CommandBufferClientImpl::IsFenceSyncFlushed(uint64_t release) {
+ return release != 0 && release <= flushed_fence_sync_release_;
+}
+
+bool CommandBufferClientImpl::IsFenceSyncFlushReceived(uint64_t release) {
+ return IsFenceSyncFlushed(release);
+}
+
+void CommandBufferClientImpl::SignalSyncToken(const gpu::SyncToken& sync_token,
+ const base::Closure& callback) {
+ // TODO(dyen)
+ NOTIMPLEMENTED();
+}
+
+bool CommandBufferClientImpl::CanWaitUnverifiedSyncToken(
+ const gpu::SyncToken* sync_token) {
+ // Right now, MOJO_LOCAL is only used by trusted code, so it is safe to wait
+ // on a sync token in MOJO_LOCAL command buffer.
+ if (sync_token->namespace_id() == gpu::CommandBufferNamespace::MOJO_LOCAL)
+ return true;
+
+ // It is also safe to wait on the same context.
+ if (sync_token->namespace_id() == gpu::CommandBufferNamespace::MOJO &&
+ sync_token->command_buffer_id() == GetCommandBufferID())
+ return true;
+
+ return false;
+}
+
+} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/command_buffer_client_impl.h b/chromium/components/mus/public/cpp/lib/command_buffer_client_impl.h
new file mode 100644
index 00000000000..80a46e93b7f
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/command_buffer_client_impl.h
@@ -0,0 +1,117 @@
+// 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.
+
+#ifndef COMPONENTS_MUS_PUBLIC_CPP_LIB_COMMAND_BUFFER_CLIENT_IMPL_H_
+#define COMPONENTS_MUS_PUBLIC_CPP_LIB_COMMAND_BUFFER_CLIENT_IMPL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "components/mus/public/interfaces/command_buffer.mojom.h"
+#include "gpu/command_buffer/client/gpu_control.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/command_buffer/common/command_buffer_id.h"
+#include "gpu/command_buffer/common/command_buffer_shared.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace base {
+class RunLoop;
+}
+
+namespace mus {
+class CommandBufferClientImpl;
+
+class CommandBufferClientImpl : public mus::mojom::CommandBufferClient,
+ public gpu::CommandBuffer,
+ public gpu::GpuControl {
+ public:
+ explicit CommandBufferClientImpl(
+ const std::vector<int32_t>& attribs,
+ mus::mojom::CommandBufferPtr command_buffer_ptr);
+ ~CommandBufferClientImpl() override;
+ bool Initialize();
+
+ // CommandBuffer implementation:
+ State GetLastState() override;
+ int32_t GetLastToken() override;
+ void Flush(int32_t put_offset) override;
+ void OrderingBarrier(int32_t put_offset) override;
+ void WaitForTokenInRange(int32_t start, int32_t end) override;
+ void WaitForGetOffsetInRange(int32_t start, int32_t end) override;
+ void SetGetBuffer(int32_t shm_id) override;
+ scoped_refptr<gpu::Buffer> CreateTransferBuffer(size_t size,
+ int32_t* id) override;
+ void DestroyTransferBuffer(int32_t id) override;
+
+ // gpu::GpuControl implementation:
+ void SetGpuControlClient(gpu::GpuControlClient*) override;
+ gpu::Capabilities GetCapabilities() override;
+ int32_t CreateImage(ClientBuffer buffer,
+ size_t width,
+ size_t height,
+ unsigned internalformat) override;
+ void DestroyImage(int32_t id) override;
+ int32_t CreateGpuMemoryBufferImage(size_t width,
+ size_t height,
+ unsigned internalformat,
+ unsigned usage) override;
+ int32_t GetImageGpuMemoryBufferId(unsigned image_id) override;
+ void SignalQuery(uint32_t query, const base::Closure& callback) override;
+ void SetLock(base::Lock*) override;
+ void EnsureWorkVisible() override;
+ gpu::CommandBufferNamespace GetNamespaceID() const override;
+ gpu::CommandBufferId GetCommandBufferID() const override;
+ int32_t GetExtraCommandBufferData() const override;
+ uint64_t GenerateFenceSyncRelease() override;
+ bool IsFenceSyncRelease(uint64_t release) override;
+ bool IsFenceSyncFlushed(uint64_t release) override;
+ bool IsFenceSyncFlushReceived(uint64_t release) override;
+ void SignalSyncToken(const gpu::SyncToken& sync_token,
+ const base::Closure& callback) override;
+ bool CanWaitUnverifiedSyncToken(const gpu::SyncToken* sync_token) override;
+
+ private:
+ // mus::mojom::CommandBufferClient implementation:
+ void Destroyed(int32_t lost_reason, int32_t error) override;
+ void SignalAck(uint32_t id) override;
+ void SwapBuffersCompleted(int32_t result) override;
+ void UpdateState(const gpu::CommandBuffer::State& state) override;
+ void UpdateVSyncParameters(int64_t timebase, int64_t interval) override;
+
+ void TryUpdateState();
+ void MakeProgressAndUpdateState();
+
+ gpu::CommandBufferSharedState* shared_state() const {
+ return reinterpret_cast<gpu::CommandBufferSharedState*>(
+ shared_state_.get());
+ }
+
+ gpu::GpuControlClient* gpu_control_client_;
+ bool destroyed_;
+ std::vector<int32_t> attribs_;
+ mojo::Binding<mus::mojom::CommandBufferClient> client_binding_;
+ mus::mojom::CommandBufferPtr command_buffer_;
+
+ gpu::CommandBufferId command_buffer_id_;
+ gpu::Capabilities capabilities_;
+ State last_state_;
+ mojo::ScopedSharedBufferMapping shared_state_;
+ int32_t last_put_offset_;
+ int32_t next_transfer_buffer_id_;
+
+ // Image IDs are allocated in sequence.
+ int next_image_id_;
+
+ uint64_t next_fence_sync_release_;
+ uint64_t flushed_fence_sync_release_;
+};
+
+} // mus
+
+#endif // COMPONENTS_MUS_PUBLIC_CPP_LIB_COMMAND_BUFFER_CLIENT_IMPL_H_
diff --git a/chromium/components/mus/public/cpp/lib/context_provider.cc b/chromium/components/mus/public/cpp/lib/context_provider.cc
new file mode 100644
index 00000000000..02717112dd7
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/context_provider.cc
@@ -0,0 +1,61 @@
+// 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 "components/mus/public/cpp/context_provider.h"
+
+#include <stdint.h>
+
+#include "base/logging.h"
+#include "components/mus/public/cpp/gles2_context.h"
+#include "services/shell/public/cpp/connector.h"
+
+namespace mus {
+
+ContextProvider::ContextProvider(shell::Connector* connector)
+ : connector_(connector->Clone()) {}
+
+bool ContextProvider::BindToCurrentThread() {
+ if (connector_) {
+ context_ = GLES2Context::CreateOffscreenContext(std::vector<int32_t>(),
+ connector_.get());
+ // We don't need the connector anymore, so release it.
+ connector_.reset();
+ }
+ return !!context_;
+}
+
+gpu::gles2::GLES2Interface* ContextProvider::ContextGL() {
+ return context_->interface();
+}
+
+gpu::ContextSupport* ContextProvider::ContextSupport() {
+ if (!context_)
+ return NULL;
+ return context_->context_support();
+}
+
+class GrContext* ContextProvider::GrContext() {
+ return NULL;
+}
+
+void ContextProvider::InvalidateGrContext(uint32_t state) {}
+
+gpu::Capabilities ContextProvider::ContextCapabilities() {
+ gpu::Capabilities capabilities;
+ // Enabled the CHROMIUM_image extension to use GpuMemoryBuffers. The
+ // implementation of which is used in CommandBufferDriver.
+ capabilities.image = true;
+ return capabilities;
+}
+
+base::Lock* ContextProvider::GetLock() {
+ // This context provider is not used on multiple threads.
+ NOTREACHED();
+ return nullptr;
+}
+
+ContextProvider::~ContextProvider() {
+}
+
+} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/gles2_context.cc b/chromium/components/mus/public/cpp/lib/gles2_context.cc
new file mode 100644
index 00000000000..84363b15cfe
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/gles2_context.cc
@@ -0,0 +1,109 @@
+// 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 "components/mus/public/cpp/gles2_context.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <utility>
+
+#include "components/mus/common/gpu_service.h"
+#include "components/mus/public/cpp/lib/command_buffer_client_impl.h"
+#include "components/mus/public/interfaces/command_buffer.mojom.h"
+#include "components/mus/public/interfaces/gpu_service.mojom.h"
+#include "gpu/command_buffer/client/gles2_cmd_helper.h"
+#include "gpu/command_buffer/client/shared_memory_limits.h"
+#include "gpu/command_buffer/client/transfer_buffer.h"
+#include "gpu/ipc/client/command_buffer_proxy_impl.h"
+#include "mojo/public/cpp/system/core.h"
+#include "services/shell/public/cpp/connector.h"
+#include "url/gurl.h"
+
+namespace mus {
+
+GLES2Context::GLES2Context() {}
+
+GLES2Context::~GLES2Context() {}
+
+bool GLES2Context::Initialize(const std::vector<int32_t>& attribs,
+ shell::Connector* connector) {
+ gpu::CommandBuffer* command_buffer = nullptr;
+ gpu::GpuControl* gpu_control = nullptr;
+ // TODO(penghuang): Use type gpu::gles2::ContextCreationAttribHelper for
+ // attribs.
+ if (!mus::GpuService::UseChromeGpuCommandBuffer()) {
+ mojom::GpuPtr gpu;
+ connector->ConnectToInterface("mojo:mus", &gpu);
+ mojom::CommandBufferPtr command_buffer_ptr;
+ gpu->CreateOffscreenGLES2Context(GetProxy(&command_buffer_ptr));
+ command_buffer_client_impl_.reset(
+ new CommandBufferClientImpl(attribs, std::move(command_buffer_ptr)));
+ if (!command_buffer_client_impl_->Initialize())
+ return false;
+ command_buffer = command_buffer_client_impl_.get();
+ gpu_control = command_buffer_client_impl_.get();
+ } else {
+ scoped_refptr<gpu::GpuChannelHost> gpu_channel_host =
+ GpuService::GetInstance()->EstablishGpuChannelSync();
+ if (!gpu_channel_host)
+ return false;
+ gpu::SurfaceHandle surface_handle = gfx::kNullAcceleratedWidget;
+ // TODO(penghuang): support shared group.
+ gpu::CommandBufferProxyImpl* shared_command_buffer = nullptr;
+ gpu::GpuStreamId stream_id = gpu::GpuStreamId::GPU_STREAM_DEFAULT;
+ gpu::GpuStreamPriority stream_priority = gpu::GpuStreamPriority::NORMAL;
+ gpu::gles2::ContextCreationAttribHelper attributes;
+ // TODO(penghuang): figure a useful active_url.
+ GURL active_url;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ base::ThreadTaskRunnerHandle::Get();
+ if (!attributes.Parse(attribs))
+ return false;
+ command_buffer_proxy_impl_ = gpu::CommandBufferProxyImpl::Create(
+ std::move(gpu_channel_host), surface_handle, shared_command_buffer,
+ stream_id, stream_priority, attributes, active_url,
+ std::move(task_runner));
+ if (!command_buffer_proxy_impl_)
+ return false;
+ command_buffer = command_buffer_proxy_impl_.get();
+ gpu_control = command_buffer_proxy_impl_.get();
+ }
+
+ constexpr gpu::SharedMemoryLimits default_limits;
+ gles2_helper_.reset(new gpu::gles2::GLES2CmdHelper(command_buffer));
+ if (!gles2_helper_->Initialize(default_limits.command_buffer_size))
+ return false;
+ gles2_helper_->SetAutomaticFlushes(false);
+ transfer_buffer_.reset(new gpu::TransferBuffer(gles2_helper_.get()));
+ gpu::Capabilities capabilities = gpu_control->GetCapabilities();
+ bool bind_generates_resource =
+ !!capabilities.bind_generates_resource_chromium;
+ // TODO(piman): Some contexts (such as compositor) want this to be true, so
+ // this needs to be a public parameter.
+ bool lose_context_when_out_of_memory = false;
+ bool support_client_side_arrays = false;
+ implementation_.reset(new gpu::gles2::GLES2Implementation(
+ gles2_helper_.get(), NULL, transfer_buffer_.get(),
+ bind_generates_resource, lose_context_when_out_of_memory,
+ support_client_side_arrays, gpu_control));
+ if (!implementation_->Initialize(default_limits.start_transfer_buffer_size,
+ default_limits.min_transfer_buffer_size,
+ default_limits.max_transfer_buffer_size,
+ default_limits.mapped_memory_reclaim_limit))
+ return false;
+ return true;
+}
+
+// static
+std::unique_ptr<GLES2Context> GLES2Context::CreateOffscreenContext(
+ const std::vector<int32_t>& attribs,
+ shell::Connector* connector) {
+ std::unique_ptr<GLES2Context> gles2_context(new GLES2Context);
+ if (!gles2_context->Initialize(attribs, connector))
+ gles2_context.reset();
+ return gles2_context;
+}
+
+} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/in_flight_change.cc b/chromium/components/mus/public/cpp/lib/in_flight_change.cc
new file mode 100644
index 00000000000..04878742350
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/in_flight_change.cc
@@ -0,0 +1,220 @@
+// Copyright 2015 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 "components/mus/public/cpp/lib/in_flight_change.h"
+
+#include "components/mus/public/cpp/lib/window_private.h"
+#include "components/mus/public/cpp/window_tree_client.h"
+
+namespace mus {
+
+// InFlightChange -------------------------------------------------------------
+
+InFlightChange::InFlightChange(Window* window, ChangeType type)
+ : window_(window), change_type_(type) {}
+
+InFlightChange::~InFlightChange() {}
+
+bool InFlightChange::Matches(const InFlightChange& change) const {
+ DCHECK(change.window_ == window_ && change.change_type_ == change_type_);
+ return true;
+}
+
+void InFlightChange::ChangeFailed() {}
+
+// InFlightBoundsChange -------------------------------------------------------
+
+InFlightBoundsChange::InFlightBoundsChange(Window* window,
+ const gfx::Rect& revert_bounds)
+ : InFlightChange(window, ChangeType::BOUNDS),
+ revert_bounds_(revert_bounds) {}
+
+void InFlightBoundsChange::SetRevertValueFrom(const InFlightChange& change) {
+ revert_bounds_ =
+ static_cast<const InFlightBoundsChange&>(change).revert_bounds_;
+}
+
+void InFlightBoundsChange::Revert() {
+ WindowPrivate(window()).LocalSetBounds(window()->bounds(), revert_bounds_);
+}
+
+// CrashInFlightChange --------------------------------------------------------
+
+CrashInFlightChange::CrashInFlightChange(Window* window, ChangeType type)
+ : InFlightChange(window, type) {}
+
+CrashInFlightChange::~CrashInFlightChange() {}
+
+void CrashInFlightChange::SetRevertValueFrom(const InFlightChange& change) {
+ CHECK(false);
+}
+
+void CrashInFlightChange::ChangeFailed() {
+ DLOG(ERROR) << "changed failed, type=" << static_cast<int>(change_type());
+ CHECK(false);
+}
+
+void CrashInFlightChange::Revert() {
+ CHECK(false);
+}
+
+// InFlightWindowChange -------------------------------------------------------
+
+InFlightWindowTreeClientChange::InFlightWindowTreeClientChange(
+ WindowTreeClient* client,
+ Window* revert_value,
+ ChangeType type)
+ : InFlightChange(nullptr, type),
+ client_(client),
+ revert_window_(nullptr) {
+ SetRevertWindow(revert_value);
+}
+
+InFlightWindowTreeClientChange::~InFlightWindowTreeClientChange() {
+ SetRevertWindow(nullptr);
+}
+
+void InFlightWindowTreeClientChange::SetRevertValueFrom(
+ const InFlightChange& change) {
+ SetRevertWindow(static_cast<const InFlightWindowTreeClientChange&>(change)
+ .revert_window_);
+}
+
+void InFlightWindowTreeClientChange::SetRevertWindow(Window* window) {
+ if (revert_window_)
+ revert_window_->RemoveObserver(this);
+ revert_window_ = window;
+ if (revert_window_)
+ revert_window_->AddObserver(this);
+}
+
+void InFlightWindowTreeClientChange::OnWindowDestroying(Window* window) {
+ SetRevertWindow(nullptr);
+}
+
+// InFlightCaptureChange ------------------------------------------------------
+
+InFlightCaptureChange::InFlightCaptureChange(
+ WindowTreeClient* client, Window* revert_value)
+ : InFlightWindowTreeClientChange(client,
+ revert_value,
+ ChangeType::CAPTURE) {}
+
+InFlightCaptureChange::~InFlightCaptureChange() {}
+
+void InFlightCaptureChange::Revert() {
+ client()->LocalSetCapture(revert_window());
+}
+
+// InFlightFocusChange --------------------------------------------------------
+
+InFlightFocusChange::InFlightFocusChange(
+ WindowTreeClient* client,
+ Window* revert_value)
+ : InFlightWindowTreeClientChange(client,
+ revert_value,
+ ChangeType::FOCUS) {}
+
+InFlightFocusChange::~InFlightFocusChange() {}
+
+void InFlightFocusChange::Revert() {
+ client()->LocalSetFocus(revert_window());
+}
+
+// InFlightPropertyChange -----------------------------------------------------
+
+InFlightPropertyChange::InFlightPropertyChange(
+ Window* window,
+ const std::string& property_name,
+ const mojo::Array<uint8_t>& revert_value)
+ : InFlightChange(window, ChangeType::PROPERTY),
+ property_name_(property_name),
+ revert_value_(revert_value.Clone()) {}
+
+InFlightPropertyChange::~InFlightPropertyChange() {}
+
+bool InFlightPropertyChange::Matches(const InFlightChange& change) const {
+ return static_cast<const InFlightPropertyChange&>(change).property_name_ ==
+ property_name_;
+}
+
+void InFlightPropertyChange::SetRevertValueFrom(const InFlightChange& change) {
+ revert_value_ =
+ static_cast<const InFlightPropertyChange&>(change).revert_value_.Clone();
+}
+
+void InFlightPropertyChange::Revert() {
+ WindowPrivate(window())
+ .LocalSetSharedProperty(property_name_, std::move(revert_value_));
+}
+
+// InFlightPredefinedCursorChange ---------------------------------------------
+
+InFlightPredefinedCursorChange::InFlightPredefinedCursorChange(
+ Window* window,
+ mojom::Cursor revert_value)
+ : InFlightChange(window, ChangeType::PREDEFINED_CURSOR),
+ revert_cursor_(revert_value) {}
+
+InFlightPredefinedCursorChange::~InFlightPredefinedCursorChange() {}
+
+void InFlightPredefinedCursorChange::SetRevertValueFrom(
+ const InFlightChange& change) {
+ revert_cursor_ =
+ static_cast<const InFlightPredefinedCursorChange&>(change).revert_cursor_;
+}
+
+void InFlightPredefinedCursorChange::Revert() {
+ WindowPrivate(window()).LocalSetPredefinedCursor(revert_cursor_);
+}
+
+// InFlightVisibleChange -------------------------------------------------------
+
+InFlightVisibleChange::InFlightVisibleChange(Window* window,
+ bool revert_value)
+ : InFlightChange(window, ChangeType::VISIBLE),
+ revert_visible_(revert_value) {}
+
+InFlightVisibleChange::~InFlightVisibleChange() {}
+
+void InFlightVisibleChange::SetRevertValueFrom(const InFlightChange& change) {
+ revert_visible_ =
+ static_cast<const InFlightVisibleChange&>(change).revert_visible_;
+}
+
+void InFlightVisibleChange::Revert() {
+ WindowPrivate(window()).LocalSetVisible(revert_visible_);
+}
+
+// InFlightOpacityChange -------------------------------------------------------
+
+InFlightOpacityChange::InFlightOpacityChange(Window* window, float revert_value)
+ : InFlightChange(window, ChangeType::OPACITY),
+ revert_opacity_(revert_value) {}
+
+InFlightOpacityChange::~InFlightOpacityChange() {}
+
+void InFlightOpacityChange::SetRevertValueFrom(const InFlightChange& change) {
+ revert_opacity_ =
+ static_cast<const InFlightOpacityChange&>(change).revert_opacity_;
+}
+
+void InFlightOpacityChange::Revert() {
+ WindowPrivate(window()).LocalSetOpacity(revert_opacity_);
+}
+
+// InFlightSetModalChange ------------------------------------------------------
+
+InFlightSetModalChange::InFlightSetModalChange(Window* window)
+ : InFlightChange(window, ChangeType::SET_MODAL) {}
+
+InFlightSetModalChange::~InFlightSetModalChange() {}
+
+void InFlightSetModalChange::SetRevertValueFrom(const InFlightChange& change) {}
+
+void InFlightSetModalChange::Revert() {
+ WindowPrivate(window()).LocalUnsetModal();
+}
+
+} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/in_flight_change.h b/chromium/components/mus/public/cpp/lib/in_flight_change.h
new file mode 100644
index 00000000000..bf77fc6e6b1
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/in_flight_change.h
@@ -0,0 +1,298 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_MUS_PUBLIC_CPP_LIB_IN_FLIGHT_CHANGE_H_
+#define COMPONENTS_MUS_PUBLIC_CPP_LIB_IN_FLIGHT_CHANGE_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "components/mus/public/cpp/window_observer.h"
+#include "mojo/public/cpp/bindings/array.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace mus {
+
+namespace mojom {
+enum class Cursor : int32_t;
+}
+
+class Window;
+class WindowTreeClient;
+
+enum class ChangeType {
+ ADD_CHILD,
+ ADD_TRANSIENT_WINDOW,
+ BOUNDS,
+ CAPTURE,
+ DELETE_WINDOW,
+ FOCUS,
+ NEW_WINDOW,
+ NEW_TOP_LEVEL_WINDOW,
+ OPACITY,
+ PREDEFINED_CURSOR,
+ PROPERTY,
+ REMOVE_CHILD,
+ REMOVE_TRANSIENT_WINDOW_FROM_PARENT,
+ REORDER,
+ SET_MODAL,
+ VISIBLE,
+};
+
+// InFlightChange is used to track function calls to the server and take the
+// appropriate action when the call fails, or the same property changes while
+// waiting for the response. When a function is called on the server an
+// InFlightChange is created. The function call is complete when
+// OnChangeCompleted() is received from the server. The following may occur
+// while waiting for a response:
+// . A new value is encountered from the server. For example, the bounds of
+// a window is locally changed and while waiting for the ack
+// OnWindowBoundsChanged() is received.
+// When this happens SetRevertValueFrom() is invoked on the InFlightChange.
+// The expectation is SetRevertValueFrom() takes the value to revert from the
+// supplied change.
+// . While waiting for the ack the property is again modified locally. When
+// this happens a new InFlightChange is created. Once the ack for the first
+// call is received, and the server rejected the change ChangeFailed() is
+// invoked on the first change followed by SetRevertValueFrom() on the second
+// InFlightChange. This allows the new change to update the value to revert
+// should the second call fail.
+// . If the server responds that the call failed and there is not another
+// InFlightChange for the same window outstanding, then ChangeFailed() is
+// invoked followed by Revert(). The expectation is Revert() sets the
+// appropriate value back on the Window.
+//
+// In general there are two classes of changes:
+// 1. We are the only side allowed to make the change.
+// 2. The change can also be applied by another client. For example, the
+// window manager may change the bounds as well as the local client.
+//
+// For (1) use CrashInFlightChange. As the name implies this change CHECKs that
+// the change succeeded. Use the following pattern for this. This code goes
+// where the change is sent to the server (in WindowTreeClient):
+// const uint32_t change_id =
+// ScheduleInFlightChange(base::WrapUnique(new CrashInFlightChange(
+// window, ChangeType::REORDER)));
+//
+// For (2) use the same pattern as (1), but in the on change callback from the
+// server (e.g. OnWindowBoundsChanged()) add the following:
+// // value_from_server is the value supplied from the server. It corresponds
+// // to the value of the property at the time the server processed the
+// // change. If the local change fails, this is the value reverted to.
+// InFlightBoundsChange new_change(window, value_from_server);
+// if (ApplyServerChangeToExistingInFlightChange(new_change)) {
+// // There was an in flight change for the same property. The in flight
+// // change takes the value to revert from |new_change|.
+// return;
+// }
+//
+// // else case is no flight in change and the new value can be applied
+// // immediately.
+// WindowPrivate(window).LocalSetValue(new_value_from_server);
+//
+class InFlightChange {
+ public:
+ InFlightChange(Window* window, ChangeType type);
+ virtual ~InFlightChange();
+
+ // NOTE: for properties not associated with any window window is null.
+ Window* window() { return window_; }
+ const Window* window() const { return window_; }
+ ChangeType change_type() const { return change_type_; }
+
+ // Returns true if the two changes are considered the same. This is only
+ // invoked if the window id and ChangeType match.
+ virtual bool Matches(const InFlightChange& change) const;
+
+ // Called in two cases:
+ // . When the corresponding property on the server changes. In this case
+ // |change| corresponds to the value from the server.
+ // . When |change| unsuccesfully completes.
+ virtual void SetRevertValueFrom(const InFlightChange& change) = 0;
+
+ // The change failed. Normally you need not take any action here as Revert()
+ // is called as appropriate.
+ virtual void ChangeFailed();
+
+ // The change failed and there is no pending change of the same type
+ // outstanding, revert the value.
+ virtual void Revert() = 0;
+
+ private:
+ Window* window_;
+ const ChangeType change_type_;
+};
+
+class InFlightBoundsChange : public InFlightChange {
+ public:
+ InFlightBoundsChange(Window* window, const gfx::Rect& revert_bounds);
+
+ // InFlightChange:
+ void SetRevertValueFrom(const InFlightChange& change) override;
+ void Revert() override;
+
+ private:
+ gfx::Rect revert_bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(InFlightBoundsChange);
+};
+
+// Inflight change that crashes on failure. This is useful for changes that are
+// expected to always complete.
+class CrashInFlightChange : public InFlightChange {
+ public:
+ CrashInFlightChange(Window* window, ChangeType type);
+ ~CrashInFlightChange() override;
+
+ // InFlightChange:
+ void SetRevertValueFrom(const InFlightChange& change) override;
+ void ChangeFailed() override;
+ void Revert() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CrashInFlightChange);
+};
+
+// Use this class for properties that are specific to the client, and not a
+// particular window. For example, only a single window can have focus, so focus
+// is specific to the client.
+//
+// This does not implement InFlightChange::Revert, subclasses must implement
+// that to update the WindowTreeClient.
+class InFlightWindowTreeClientChange : public InFlightChange,
+ public WindowObserver {
+ public:
+ InFlightWindowTreeClientChange(WindowTreeClient* client,
+ Window* revert_value,
+ ChangeType type);
+ ~InFlightWindowTreeClientChange() override;
+
+ // InFlightChange:
+ void SetRevertValueFrom(const InFlightChange& change) override;
+
+ protected:
+ WindowTreeClient* client() { return client_; }
+ Window* revert_window() { return revert_window_; }
+
+ private:
+ void SetRevertWindow(Window* window);
+
+ // WindowObserver:
+ void OnWindowDestroying(Window* window) override;
+
+ WindowTreeClient* client_;
+ Window* revert_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(InFlightWindowTreeClientChange);
+};
+
+class InFlightCaptureChange : public InFlightWindowTreeClientChange {
+ public:
+ InFlightCaptureChange(WindowTreeClient* client, Window* revert_value);
+ ~InFlightCaptureChange() override;
+
+ // InFlightChange:
+ void Revert() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InFlightCaptureChange);
+};
+
+class InFlightFocusChange : public InFlightWindowTreeClientChange {
+ public:
+ InFlightFocusChange(WindowTreeClient* client, Window* revert_value);
+ ~InFlightFocusChange() override;
+
+ // InFlightChange:
+ void Revert() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InFlightFocusChange);
+};
+
+class InFlightPropertyChange : public InFlightChange {
+ public:
+ InFlightPropertyChange(Window* window,
+ const std::string& property_name,
+ const mojo::Array<uint8_t>& revert_value);
+ ~InFlightPropertyChange() override;
+
+ // InFlightChange:
+ bool Matches(const InFlightChange& change) const override;
+ void SetRevertValueFrom(const InFlightChange& change) override;
+ void Revert() override;
+
+ private:
+ const std::string property_name_;
+ mojo::Array<uint8_t> revert_value_;
+
+ DISALLOW_COPY_AND_ASSIGN(InFlightPropertyChange);
+};
+
+class InFlightPredefinedCursorChange : public InFlightChange {
+ public:
+ InFlightPredefinedCursorChange(Window* window, mojom::Cursor revert_value);
+ ~InFlightPredefinedCursorChange() override;
+
+ // InFlightChange:
+ void SetRevertValueFrom(const InFlightChange& change) override;
+ void Revert() override;
+
+ private:
+ mojom::Cursor revert_cursor_;
+
+ DISALLOW_COPY_AND_ASSIGN(InFlightPredefinedCursorChange);
+};
+
+class InFlightVisibleChange : public InFlightChange {
+ public:
+ InFlightVisibleChange(Window* window, const bool revert_value);
+ ~InFlightVisibleChange() override;
+
+ // InFlightChange:
+ void SetRevertValueFrom(const InFlightChange& change) override;
+ void Revert() override;
+
+ private:
+ bool revert_visible_;
+
+ DISALLOW_COPY_AND_ASSIGN(InFlightVisibleChange);
+};
+
+class InFlightOpacityChange : public InFlightChange {
+ public:
+ InFlightOpacityChange(Window* window, float revert_value);
+ ~InFlightOpacityChange() override;
+
+ // InFlightChange:
+ void SetRevertValueFrom(const InFlightChange& change) override;
+ void Revert() override;
+
+ private:
+ float revert_opacity_;
+
+ DISALLOW_COPY_AND_ASSIGN(InFlightOpacityChange);
+};
+
+class InFlightSetModalChange : public InFlightChange {
+ public:
+ explicit InFlightSetModalChange(Window* window);
+ ~InFlightSetModalChange() override;
+
+ // InFlightChange:
+ void SetRevertValueFrom(const InFlightChange& change) override;
+ void Revert() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InFlightSetModalChange);
+};
+
+} // namespace mus
+
+#endif // COMPONENTS_MUS_PUBLIC_CPP_LIB_IN_FLIGHT_CHANGE_H_
diff --git a/chromium/components/mus/public/cpp/lib/output_surface.cc b/chromium/components/mus/public/cpp/lib/output_surface.cc
new file mode 100644
index 00000000000..86462ec95f4
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/output_surface.cc
@@ -0,0 +1,70 @@
+// 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 "components/mus/public/cpp/output_surface.h"
+
+#include "base/bind.h"
+#include "cc/output/compositor_frame.h"
+#include "cc/output/compositor_frame_ack.h"
+#include "cc/output/output_surface_client.h"
+#include "components/mus/public/cpp/window_surface.h"
+
+namespace mus {
+
+OutputSurface::OutputSurface(
+ const scoped_refptr<cc::ContextProvider>& context_provider,
+ std::unique_ptr<mus::WindowSurface> surface)
+ : cc::OutputSurface(context_provider, nullptr, nullptr),
+ surface_(std::move(surface)) {
+ capabilities_.delegated_rendering = true;
+}
+
+OutputSurface::~OutputSurface() {}
+
+bool OutputSurface::BindToClient(cc::OutputSurfaceClient* client) {
+ surface_->BindToThread();
+ surface_->set_client(this);
+ return cc::OutputSurface::BindToClient(client);
+}
+
+void OutputSurface::DetachFromClient() {
+ surface_.reset();
+ cc::OutputSurface::DetachFromClient();
+}
+
+void OutputSurface::BindFramebuffer() {
+ // This is a delegating output surface, no framebuffer/direct drawing support.
+ NOTREACHED();
+}
+
+uint32_t OutputSurface::GetFramebufferCopyTextureFormat() {
+ // This is a delegating output surface, no framebuffer/direct drawing support.
+ NOTREACHED();
+ return 0;
+}
+
+void OutputSurface::SwapBuffers(cc::CompositorFrame frame) {
+ // TODO(fsamuel, rjkroege): We should probably throttle compositor frames.
+ client_->DidSwapBuffers();
+ // OutputSurface owns WindowSurface, and so if OutputSurface is
+ // destroyed then SubmitCompositorFrame's callback will never get called.
+ // Thus, base::Unretained is safe here.
+ surface_->SubmitCompositorFrame(
+ std::move(frame),
+ base::Bind(&OutputSurface::SwapBuffersComplete, base::Unretained(this)));
+}
+
+void OutputSurface::OnResourcesReturned(
+ mus::WindowSurface* surface,
+ mojo::Array<cc::ReturnedResource> resources) {
+ cc::CompositorFrameAck cfa;
+ cfa.resources = resources.To<cc::ReturnedResourceArray>();
+ ReclaimResources(&cfa);
+}
+
+void OutputSurface::SwapBuffersComplete() {
+ client_->DidSwapBuffersComplete();
+}
+
+} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/property_type_converters.cc b/chromium/components/mus/public/cpp/lib/property_type_converters.cc
new file mode 100644
index 00000000000..17cacf1f249
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/property_type_converters.cc
@@ -0,0 +1,207 @@
+// Copyright 2015 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 "components/mus/public/cpp/property_type_converters.h"
+
+#include <stdint.h>
+
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace {
+
+// Maximum allowed height or width of a bitmap, in pixels. This limit prevents
+// malformed bitmap headers from causing arbitrarily large memory allocations
+// for pixel data.
+const int kMaxBitmapSize = 4096;
+
+} // namespace
+
+namespace mojo {
+
+// static
+std::vector<uint8_t> TypeConverter<std::vector<uint8_t>, gfx::Rect>::Convert(
+ const gfx::Rect& input) {
+ std::vector<uint8_t> vec(16);
+ vec[0] = (input.x() >> 24) & 0xFF;
+ vec[1] = (input.x() >> 16) & 0xFF;
+ vec[2] = (input.x() >> 8) & 0xFF;
+ vec[3] = input.x() & 0xFF;
+ vec[4] = (input.y() >> 24) & 0xFF;
+ vec[5] = (input.y() >> 16) & 0xFF;
+ vec[6] = (input.y() >> 8) & 0xFF;
+ vec[7] = input.y() & 0xFF;
+ vec[8] = (input.width() >> 24) & 0xFF;
+ vec[9] = (input.width() >> 16) & 0xFF;
+ vec[10] = (input.width() >> 8) & 0xFF;
+ vec[11] = input.width() & 0xFF;
+ vec[12] = (input.height() >> 24) & 0xFF;
+ vec[13] = (input.height() >> 16) & 0xFF;
+ vec[14] = (input.height() >> 8) & 0xFF;
+ vec[15] = input.height() & 0xFF;
+ return vec;
+}
+
+// static
+gfx::Rect TypeConverter<gfx::Rect, std::vector<uint8_t>>::Convert(
+ const std::vector<uint8_t>& input) {
+ return gfx::Rect(
+ input[0] << 24 | input[1] << 16 | input[2] << 8 | input[3],
+ input[4] << 24 | input[5] << 16 | input[6] << 8 | input[7],
+ input[8] << 24 | input[9] << 16 | input[10] << 8 | input[11],
+ input[12] << 24 | input[13] << 16 | input[14] << 8 | input[15]);
+}
+
+// static
+std::vector<uint8_t> TypeConverter<std::vector<uint8_t>, gfx::Size>::Convert(
+ const gfx::Size& input) {
+ std::vector<uint8_t> vec(8);
+ vec[0] = (input.width() >> 24) & 0xFF;
+ vec[1] = (input.width() >> 16) & 0xFF;
+ vec[2] = (input.width() >> 8) & 0xFF;
+ vec[3] = input.width() & 0xFF;
+ vec[4] = (input.height() >> 24) & 0xFF;
+ vec[5] = (input.height() >> 16) & 0xFF;
+ vec[6] = (input.height() >> 8) & 0xFF;
+ vec[7] = input.height() & 0xFF;
+ return vec;
+}
+
+// static
+gfx::Size TypeConverter<gfx::Size, std::vector<uint8_t>>::Convert(
+ const std::vector<uint8_t>& input) {
+ return gfx::Size(input[0] << 24 | input[1] << 16 | input[2] << 8 | input[3],
+ input[4] << 24 | input[5] << 16 | input[6] << 8 | input[7]);
+}
+
+// static
+std::vector<uint8_t> TypeConverter<std::vector<uint8_t>, int32_t>::Convert(
+ const int32_t& input) {
+ std::vector<uint8_t> vec(4);
+ vec[0] = (input >> 24) & 0xFF;
+ vec[1] = (input >> 16) & 0xFF;
+ vec[2] = (input >> 8) & 0xFF;
+ vec[3] = input & 0xFF;
+ return vec;
+}
+
+// static
+int32_t TypeConverter<int32_t, std::vector<uint8_t>>::Convert(
+ const std::vector<uint8_t>& input) {
+ return input[0] << 24 | input[1] << 16 | input[2] << 8 | input[3];
+}
+
+// static
+std::vector<uint8_t>
+TypeConverter<std::vector<uint8_t>, base::string16>::Convert(
+ const base::string16& input) {
+ return ConvertTo<std::vector<uint8_t>>(base::UTF16ToUTF8(input));
+}
+
+// static
+base::string16 TypeConverter<base::string16, std::vector<uint8_t>>::Convert(
+ const std::vector<uint8_t>& input) {
+ return base::UTF8ToUTF16(ConvertTo<std::string>(input));
+}
+
+// static
+std::vector<uint8_t> TypeConverter<std::vector<uint8_t>, std::string>::Convert(
+ const std::string& input) {
+ return std::vector<uint8_t>(input.begin(), input.end());
+}
+
+// static
+std::string TypeConverter<std::string, std::vector<uint8_t>>::Convert(
+ const std::vector<uint8_t>& input) {
+ return std::string(input.begin(), input.end());
+}
+
+// static
+std::vector<uint8_t> TypeConverter<std::vector<uint8_t>, SkBitmap>::Convert(
+ const SkBitmap& input) {
+ // Empty images are valid to serialize and are represented by an empty vector.
+ if (input.isNull())
+ return std::vector<uint8_t>();
+
+ // Only RGBA 8888 bitmaps with premultiplied alpha are supported.
+ if (input.colorType() != kBGRA_8888_SkColorType ||
+ input.alphaType() != kPremul_SkAlphaType) {
+ NOTREACHED();
+ return std::vector<uint8_t>();
+ }
+
+ // Sanity check the bitmap size.
+ int width = input.width();
+ int height = input.height();
+ if (width < 0 || width > kMaxBitmapSize || height < 0 ||
+ height > kMaxBitmapSize) {
+ NOTREACHED();
+ return std::vector<uint8_t>();
+ }
+
+ // Serialize the bitmap. The size is restricted so only 2 bytes are required
+ // per dimension.
+ std::vector<uint8_t> vec(4 + input.getSize());
+ vec[0] = (width >> 8) & 0xFF;
+ vec[1] = width & 0xFF;
+ vec[2] = (height >> 8) & 0xFF;
+ vec[3] = height & 0xFF;
+ if (!input.copyPixelsTo(&vec[4], input.getSize()))
+ return std::vector<uint8_t>();
+ return vec;
+}
+
+// static
+SkBitmap TypeConverter<SkBitmap, std::vector<uint8_t>>::Convert(
+ const std::vector<uint8_t>& input) {
+ // Empty images are represented by empty vectors.
+ if (input.empty())
+ return SkBitmap();
+
+ // Read and sanity check size.
+ int width = input[0] << 8 | input[1];
+ int height = input[2] << 8 | input[3];
+ if (width < 0 || width > kMaxBitmapSize || height < 0 ||
+ height > kMaxBitmapSize) {
+ NOTREACHED();
+ return SkBitmap();
+ }
+
+ // Try to allocate a bitmap of the appropriate size.
+ SkBitmap bitmap;
+ if (!bitmap.tryAllocPixels(SkImageInfo::Make(
+ width, height, kBGRA_8888_SkColorType, kPremul_SkAlphaType))) {
+ return SkBitmap();
+ }
+
+ // Ensure the vector contains the right amount of data.
+ if (input.size() != bitmap.getSize() + 4) {
+ NOTREACHED();
+ return SkBitmap();
+ }
+
+ // Read the pixel data.
+ SkAutoLockPixels lock(bitmap);
+ memcpy(bitmap.getPixels(), &input[4], bitmap.getSize());
+ return bitmap;
+}
+
+// static
+std::vector<uint8_t> TypeConverter<std::vector<uint8_t>, bool>::Convert(
+ bool input) {
+ std::vector<uint8_t> vec(1);
+ vec[0] = input ? 1 : 0;
+ return vec;
+}
+
+// static
+bool TypeConverter<bool, std::vector<uint8_t>>::Convert(
+ const std::vector<uint8_t>& input) {
+ // Empty vectors are interpreted as false.
+ return !input.empty() && (input[0] == 1);
+}
+
+} // namespace mojo
diff --git a/chromium/components/mus/public/cpp/lib/scoped_window_ptr.cc b/chromium/components/mus/public/cpp/lib/scoped_window_ptr.cc
new file mode 100644
index 00000000000..360da1ff4b5
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/scoped_window_ptr.cc
@@ -0,0 +1,44 @@
+// Copyright 2015 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 "components/mus/public/cpp/scoped_window_ptr.h"
+
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_observer.h"
+#include "components/mus/public/cpp/window_tree_client.h"
+
+namespace mus {
+
+ScopedWindowPtr::ScopedWindowPtr(Window* window) : window_(window) {
+ window_->AddObserver(this);
+}
+
+ScopedWindowPtr::~ScopedWindowPtr() {
+ if (window_)
+ DeleteWindowOrWindowManager(window_);
+ DetachFromWindow();
+}
+
+// static
+void ScopedWindowPtr::DeleteWindowOrWindowManager(Window* window) {
+ if (window->window_tree()->GetRoots().count(window) > 0)
+ delete window->window_tree();
+ else
+ window->Destroy();
+}
+
+void ScopedWindowPtr::DetachFromWindow() {
+ if (!window_)
+ return;
+
+ window_->RemoveObserver(this);
+ window_ = nullptr;
+}
+
+void ScopedWindowPtr::OnWindowDestroying(Window* window) {
+ DCHECK_EQ(window_, window);
+ DetachFromWindow();
+}
+
+} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/window.cc b/chromium/components/mus/public/cpp/lib/window.cc
new file mode 100644
index 00000000000..83785c4544e
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/window.cc
@@ -0,0 +1,891 @@
+// 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 "components/mus/public/cpp/window.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <set>
+#include <string>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "components/mus/common/transient_window_utils.h"
+#include "components/mus/public/cpp/lib/window_private.h"
+#include "components/mus/public/cpp/property_type_converters.h"
+#include "components/mus/public/cpp/window_observer.h"
+#include "components/mus/public/cpp/window_property.h"
+#include "components/mus/public/cpp/window_surface.h"
+#include "components/mus/public/cpp/window_tracker.h"
+#include "components/mus/public/cpp/window_tree_client.h"
+#include "components/mus/public/interfaces/window_manager.mojom.h"
+#include "ui/display/display.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace mus {
+
+namespace {
+
+void NotifyWindowTreeChangeAtReceiver(
+ Window* receiver,
+ const WindowObserver::TreeChangeParams& params,
+ bool change_applied) {
+ WindowObserver::TreeChangeParams local_params = params;
+ local_params.receiver = receiver;
+ if (change_applied) {
+ FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(receiver).observers(),
+ OnTreeChanged(local_params));
+ } else {
+ FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(receiver).observers(),
+ OnTreeChanging(local_params));
+ }
+}
+
+void NotifyWindowTreeChangeUp(Window* start_at,
+ const WindowObserver::TreeChangeParams& params,
+ bool change_applied) {
+ for (Window* current = start_at; current; current = current->parent())
+ NotifyWindowTreeChangeAtReceiver(current, params, change_applied);
+}
+
+void NotifyWindowTreeChangeDown(Window* start_at,
+ const WindowObserver::TreeChangeParams& params,
+ bool change_applied) {
+ NotifyWindowTreeChangeAtReceiver(start_at, params, change_applied);
+ Window::Children::const_iterator it = start_at->children().begin();
+ for (; it != start_at->children().end(); ++it)
+ NotifyWindowTreeChangeDown(*it, params, change_applied);
+}
+
+void NotifyWindowTreeChange(const WindowObserver::TreeChangeParams& params,
+ bool change_applied) {
+ NotifyWindowTreeChangeDown(params.target, params, change_applied);
+ if (params.old_parent)
+ NotifyWindowTreeChangeUp(params.old_parent, params, change_applied);
+ if (params.new_parent)
+ NotifyWindowTreeChangeUp(params.new_parent, params, change_applied);
+}
+
+class ScopedTreeNotifier {
+ public:
+ ScopedTreeNotifier(Window* target, Window* old_parent, Window* new_parent) {
+ params_.target = target;
+ params_.old_parent = old_parent;
+ params_.new_parent = new_parent;
+ NotifyWindowTreeChange(params_, false);
+ }
+ ~ScopedTreeNotifier() { NotifyWindowTreeChange(params_, true); }
+
+ private:
+ WindowObserver::TreeChangeParams params_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedTreeNotifier);
+};
+
+void RemoveChildImpl(Window* child, Window::Children* children) {
+ Window::Children::iterator it =
+ std::find(children->begin(), children->end(), child);
+ if (it != children->end()) {
+ children->erase(it);
+ WindowPrivate(child).ClearParent();
+ }
+}
+
+class OrderChangedNotifier {
+ public:
+ OrderChangedNotifier(Window* window,
+ Window* relative_window,
+ mojom::OrderDirection direction)
+ : window_(window),
+ relative_window_(relative_window),
+ direction_(direction) {}
+
+ ~OrderChangedNotifier() {}
+
+ void NotifyWindowReordering() {
+ FOR_EACH_OBSERVER(
+ WindowObserver, *WindowPrivate(window_).observers(),
+ OnWindowReordering(window_, relative_window_, direction_));
+ }
+
+ void NotifyWindowReordered() {
+ FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(window_).observers(),
+ OnWindowReordered(window_, relative_window_, direction_));
+ }
+
+ private:
+ Window* window_;
+ Window* relative_window_;
+ mojom::OrderDirection direction_;
+
+ DISALLOW_COPY_AND_ASSIGN(OrderChangedNotifier);
+};
+
+class ScopedSetBoundsNotifier {
+ public:
+ ScopedSetBoundsNotifier(Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds)
+ : window_(window), old_bounds_(old_bounds), new_bounds_(new_bounds) {
+ FOR_EACH_OBSERVER(
+ WindowObserver, *WindowPrivate(window_).observers(),
+ OnWindowBoundsChanging(window_, old_bounds_, new_bounds_));
+ }
+ ~ScopedSetBoundsNotifier() {
+ FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(window_).observers(),
+ OnWindowBoundsChanged(window_, old_bounds_, new_bounds_));
+ }
+
+ private:
+ Window* window_;
+ const gfx::Rect old_bounds_;
+ const gfx::Rect new_bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedSetBoundsNotifier);
+};
+
+// Some operations are only permitted in the client that created the window.
+bool OwnsWindow(WindowTreeClient* client, Window* window) {
+ return !client || client->OwnsWindow(window);
+}
+
+bool IsClientRoot(Window* window) {
+ return window->window_tree() &&
+ window->window_tree()->GetRoots().count(window) > 0;
+}
+
+bool OwnsWindowOrIsRoot(Window* window) {
+ return OwnsWindow(window->window_tree(), window) || IsClientRoot(window);
+}
+
+void EmptyEmbedCallback(bool result) {}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// Window, public:
+
+void Window::Destroy() {
+ if (!OwnsWindowOrIsRoot(this))
+ return;
+
+ if (client_)
+ client_->DestroyWindow(this);
+ while (!children_.empty()) {
+ Window* child = children_.front();
+ if (!OwnsWindow(client_, child)) {
+ WindowPrivate(child).ClearParent();
+ children_.erase(children_.begin());
+ } else {
+ child->Destroy();
+ DCHECK(std::find(children_.begin(), children_.end(), child) ==
+ children_.end());
+ }
+ }
+ LocalDestroy();
+}
+
+void Window::SetBounds(const gfx::Rect& bounds) {
+ if (!OwnsWindowOrIsRoot(this))
+ return;
+ if (bounds_ == bounds)
+ return;
+ if (client_)
+ client_->SetBounds(this, bounds_, bounds);
+ LocalSetBounds(bounds_, bounds);
+}
+
+gfx::Rect Window::GetBoundsInRoot() const {
+ gfx::Vector2d offset;
+ for (const Window* w = parent(); w != nullptr; w = w->parent())
+ offset += w->bounds().OffsetFromOrigin();
+ return bounds() + offset;
+}
+
+void Window::SetClientArea(
+ const gfx::Insets& client_area,
+ const std::vector<gfx::Rect>& additional_client_areas) {
+ if (!OwnsWindowOrIsRoot(this))
+ return;
+
+ if (client_)
+ client_->SetClientArea(server_id_, client_area,
+ additional_client_areas);
+ LocalSetClientArea(client_area, additional_client_areas);
+}
+
+void Window::SetHitTestMask(const gfx::Rect& mask) {
+ if (!OwnsWindowOrIsRoot(this))
+ return;
+
+ if (hit_test_mask_ && *hit_test_mask_ == mask)
+ return;
+
+ if (client_)
+ client_->SetHitTestMask(server_id_, mask);
+ hit_test_mask_.reset(new gfx::Rect(mask));
+}
+
+void Window::ClearHitTestMask() {
+ if (!OwnsWindowOrIsRoot(this))
+ return;
+
+ if (!hit_test_mask_)
+ return;
+
+ if (client_)
+ client_->ClearHitTestMask(server_id_);
+ hit_test_mask_.reset();
+}
+
+void Window::SetVisible(bool value) {
+ if (visible_ == value)
+ return;
+
+ if (client_)
+ client_->SetVisible(this, value);
+ LocalSetVisible(value);
+}
+
+void Window::SetOpacity(float opacity) {
+ if (client_)
+ client_->SetOpacity(this, opacity);
+ LocalSetOpacity(opacity);
+}
+
+void Window::SetPredefinedCursor(mus::mojom::Cursor cursor_id) {
+ if (cursor_id_ == cursor_id)
+ return;
+
+ if (client_)
+ client_->SetPredefinedCursor(server_id_, cursor_id);
+ LocalSetPredefinedCursor(cursor_id);
+}
+
+bool Window::IsDrawn() const {
+ if (!visible_)
+ return false;
+ return parent_ ? parent_->IsDrawn() : parent_drawn_;
+}
+
+std::unique_ptr<WindowSurface> Window::RequestSurface(mojom::SurfaceType type) {
+ std::unique_ptr<WindowSurfaceBinding> surface_binding;
+ std::unique_ptr<WindowSurface> surface =
+ WindowSurface::Create(&surface_binding);
+ AttachSurface(type, std::move(surface_binding));
+ return surface;
+}
+
+void Window::AttachSurface(
+ mojom::SurfaceType type,
+ std::unique_ptr<WindowSurfaceBinding> surface_binding) {
+ window_tree()->AttachSurface(
+ server_id_, type, std::move(surface_binding->surface_request_),
+ mojo::MakeProxy(std::move(surface_binding->surface_client_)));
+}
+
+void Window::ClearSharedProperty(const std::string& name) {
+ SetSharedPropertyInternal(name, nullptr);
+}
+
+bool Window::HasSharedProperty(const std::string& name) const {
+ return properties_.count(name) > 0;
+}
+
+void Window::AddObserver(WindowObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void Window::RemoveObserver(WindowObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+const Window* Window::GetRoot() const {
+ const Window* root = this;
+ for (const Window* parent = this; parent; parent = parent->parent())
+ root = parent;
+ return root;
+}
+
+void Window::AddChild(Window* child) {
+ // TODO(beng): not necessarily valid to all clients, but possibly to the
+ // embeddee in an embedder-embeddee relationship.
+ if (client_)
+ CHECK_EQ(child->client_, client_);
+ // Roots can not be added as children of other windows.
+ if (window_tree() && window_tree()->IsRoot(child))
+ return;
+ LocalAddChild(child);
+ if (client_)
+ client_->AddChild(this, child->server_id());
+}
+
+void Window::RemoveChild(Window* child) {
+ // TODO(beng): not necessarily valid to all clients, but possibly to the
+ // embeddee in an embedder-embeddee relationship.
+ if (client_)
+ CHECK_EQ(child->client_, client_);
+ LocalRemoveChild(child);
+ if (client_)
+ client_->RemoveChild(this, child->server_id());
+}
+
+void Window::Reorder(Window* relative, mojom::OrderDirection direction) {
+ if (!LocalReorder(relative, direction))
+ return;
+ if (client_)
+ client_->Reorder(this, relative->server_id(), direction);
+}
+
+void Window::MoveToFront() {
+ if (!parent_ || parent_->children_.back() == this)
+ return;
+ Reorder(parent_->children_.back(), mojom::OrderDirection::ABOVE);
+}
+
+void Window::MoveToBack() {
+ if (!parent_ || parent_->children_.front() == this)
+ return;
+ Reorder(parent_->children_.front(), mojom::OrderDirection::BELOW);
+}
+
+bool Window::Contains(const Window* child) const {
+ if (!child)
+ return false;
+ if (child == this)
+ return true;
+ if (client_)
+ CHECK_EQ(child->client_, client_);
+ for (const Window* p = child->parent(); p; p = p->parent()) {
+ if (p == this)
+ return true;
+ }
+ return false;
+}
+
+void Window::AddTransientWindow(Window* transient_window) {
+ // A system modal window cannot become a transient child.
+ DCHECK(!transient_window->is_modal() || transient_window->transient_parent());
+
+ if (client_)
+ CHECK_EQ(transient_window->client_, client_);
+ LocalAddTransientWindow(transient_window);
+ if (client_)
+ client_->AddTransientWindow(this, transient_window->server_id());
+}
+
+void Window::RemoveTransientWindow(Window* transient_window) {
+ if (client_)
+ CHECK_EQ(transient_window->window_tree(), client_);
+ LocalRemoveTransientWindow(transient_window);
+ if (client_)
+ client_->RemoveTransientWindowFromParent(transient_window);
+}
+
+void Window::SetModal() {
+ if (is_modal_)
+ return;
+
+ LocalSetModal();
+ if (client_)
+ client_->SetModal(this);
+}
+
+Window* Window::GetChildByLocalId(int id) {
+ if (id == local_id_)
+ return this;
+ // TODO(beng): this could be improved depending on how we decide to own
+ // windows.
+ for (Window* child : children_) {
+ Window* matching_child = child->GetChildByLocalId(id);
+ if (matching_child)
+ return matching_child;
+ }
+ return nullptr;
+}
+
+void Window::SetTextInputState(mojo::TextInputStatePtr state) {
+ if (client_)
+ client_->SetWindowTextInputState(server_id_, std::move(state));
+}
+
+void Window::SetImeVisibility(bool visible, mojo::TextInputStatePtr state) {
+ // SetImeVisibility() shouldn't be used if the window is not editable.
+ DCHECK(state.is_null() || state->type != mojo::TextInputType::NONE);
+ if (client_)
+ client_->SetImeVisibility(server_id_, visible, std::move(state));
+}
+
+bool Window::HasCapture() const {
+ return client_ && client_->GetCaptureWindow() == this;
+}
+
+void Window::SetCapture() {
+ if (client_)
+ client_->SetCapture(this);
+}
+
+void Window::ReleaseCapture() {
+ if (client_)
+ client_->ReleaseCapture(this);
+}
+
+void Window::SetFocus() {
+ if (client_ && IsDrawn())
+ client_->SetFocus(this);
+}
+
+bool Window::HasFocus() const {
+ return client_ && client_->GetFocusedWindow() == this;
+}
+
+void Window::SetCanFocus(bool can_focus) {
+ if (client_)
+ client_->SetCanFocus(server_id_, can_focus);
+}
+
+void Window::Embed(mus::mojom::WindowTreeClientPtr client, uint32_t flags) {
+ Embed(std::move(client), base::Bind(&EmptyEmbedCallback), flags);
+}
+
+void Window::Embed(mus::mojom::WindowTreeClientPtr client,
+ const EmbedCallback& callback,
+ uint32_t flags) {
+ if (PrepareForEmbed())
+ client_->Embed(server_id_, std::move(client), flags, callback);
+ else
+ callback.Run(false);
+}
+
+void Window::RequestClose() {
+ if (client_)
+ client_->RequestClose(this);
+}
+
+std::string Window::GetName() const {
+ if (HasSharedProperty(mojom::WindowManager::kName_Property))
+ return GetSharedProperty<std::string>(mojom::WindowManager::kName_Property);
+
+ return std::string();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Window, protected:
+
+Window::Window() : Window(nullptr, static_cast<Id>(-1)) {}
+
+Window::~Window() {
+ FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroying(this));
+ if (client_)
+ client_->OnWindowDestroying(this);
+
+ if (HasFocus()) {
+ // The focused window is being removed. When this happens the server
+ // advances focus. We don't want to randomly pick a Window to get focus, so
+ // we update local state only, and wait for the next focus change from the
+ // server.
+ client_->LocalSetFocus(nullptr);
+ }
+
+ // Remove from transient parent.
+ if (transient_parent_)
+ transient_parent_->LocalRemoveTransientWindow(this);
+
+ // Remove transient children.
+ while (!transient_children_.empty()) {
+ Window* transient_child = transient_children_.front();
+ LocalRemoveTransientWindow(transient_child);
+ transient_child->LocalDestroy();
+ DCHECK(transient_children_.empty() ||
+ transient_children_.front() != transient_child);
+ }
+
+ if (parent_)
+ parent_->LocalRemoveChild(this);
+
+ // We may still have children. This can happen if the embedder destroys the
+ // root while we're still alive.
+ while (!children_.empty()) {
+ Window* child = children_.front();
+ LocalRemoveChild(child);
+ DCHECK(children_.empty() || children_.front() != child);
+ }
+
+ // Clear properties.
+ for (auto& pair : prop_map_) {
+ if (pair.second.deallocator)
+ (*pair.second.deallocator)(pair.second.value);
+ }
+ prop_map_.clear();
+
+ FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroyed(this));
+
+ // Invoke after observers so that can clean up any internal state observers
+ // may have changed.
+ if (window_tree())
+ window_tree()->OnWindowDestroyed(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Window, private:
+
+Window::Window(WindowTreeClient* client, Id id)
+ : client_(client),
+ server_id_(id),
+ parent_(nullptr),
+ stacking_target_(nullptr),
+ transient_parent_(nullptr),
+ is_modal_(false),
+ // Matches aura, see aura::Window for details.
+ observers_(base::ObserverList<WindowObserver>::NOTIFY_EXISTING_ONLY),
+ input_event_handler_(nullptr),
+ visible_(false),
+ opacity_(1.0f),
+ display_id_(display::Display::kInvalidDisplayID),
+ cursor_id_(mojom::Cursor::CURSOR_NULL),
+ parent_drawn_(false) {}
+
+void Window::SetSharedPropertyInternal(const std::string& name,
+ const std::vector<uint8_t>* value) {
+ if (!OwnsWindowOrIsRoot(this))
+ return;
+
+ if (client_) {
+ mojo::Array<uint8_t> transport_value(nullptr);
+ if (value) {
+ transport_value.resize(value->size());
+ if (value->size())
+ memcpy(&transport_value.front(), &(value->front()), value->size());
+ }
+ // TODO: add test coverage of this (450303).
+ client_->SetProperty(this, name, std::move(transport_value));
+ }
+ LocalSetSharedProperty(name, value);
+}
+
+int64_t Window::SetLocalPropertyInternal(const void* key,
+ const char* name,
+ PropertyDeallocator deallocator,
+ int64_t value,
+ int64_t default_value) {
+ int64_t old = GetLocalPropertyInternal(key, default_value);
+ if (value == default_value) {
+ prop_map_.erase(key);
+ } else {
+ Value prop_value;
+ prop_value.name = name;
+ prop_value.value = value;
+ prop_value.deallocator = deallocator;
+ prop_map_[key] = prop_value;
+ }
+ FOR_EACH_OBSERVER(WindowObserver, observers_,
+ OnWindowLocalPropertyChanged(this, key, old));
+ return old;
+}
+
+int64_t Window::GetLocalPropertyInternal(const void* key,
+ int64_t default_value) const {
+ std::map<const void*, Value>::const_iterator iter = prop_map_.find(key);
+ if (iter == prop_map_.end())
+ return default_value;
+ return iter->second.value;
+}
+
+void Window::LocalDestroy() {
+ delete this;
+}
+
+void Window::LocalAddChild(Window* child) {
+ ScopedTreeNotifier notifier(child, child->parent(), this);
+ if (child->parent())
+ RemoveChildImpl(child, &child->parent_->children_);
+ children_.push_back(child);
+ child->parent_ = this;
+ child->display_id_ = display_id_;
+}
+
+void Window::LocalRemoveChild(Window* child) {
+ DCHECK_EQ(this, child->parent());
+ ScopedTreeNotifier notifier(child, this, nullptr);
+ RemoveChildImpl(child, &children_);
+}
+
+void Window::LocalAddTransientWindow(Window* transient_window) {
+ if (transient_window->transient_parent())
+ RemoveTransientWindowImpl(transient_window);
+ transient_children_.push_back(transient_window);
+ transient_window->transient_parent_ = this;
+
+ // Restack |transient_window| properly above its transient parent, if they
+ // share the same parent.
+ if (transient_window->parent() == parent())
+ RestackTransientDescendants(this, &GetStackingTarget,
+ &ReorderWithoutNotification);
+
+ // TODO(fsamuel): We might want a notification here.
+}
+
+void Window::LocalRemoveTransientWindow(Window* transient_window) {
+ DCHECK_EQ(this, transient_window->transient_parent());
+ RemoveTransientWindowImpl(transient_window);
+ // TODO(fsamuel): We might want a notification here.
+}
+
+void Window::LocalSetModal() {
+ is_modal_ = true;
+}
+
+bool Window::LocalReorder(Window* relative, mojom::OrderDirection direction) {
+ OrderChangedNotifier notifier(this, relative, direction);
+ return ReorderImpl(this, relative, direction, &notifier);
+}
+
+void Window::LocalSetBounds(const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) {
+ // If this client owns the window, then it should be the only one to change
+ // the bounds.
+ DCHECK(!OwnsWindow(client_, this) || old_bounds == bounds_);
+ ScopedSetBoundsNotifier notifier(this, old_bounds, new_bounds);
+ bounds_ = new_bounds;
+}
+
+void Window::LocalSetClientArea(
+ const gfx::Insets& new_client_area,
+ const std::vector<gfx::Rect>& additional_client_areas) {
+ const std::vector<gfx::Rect> old_additional_client_areas =
+ additional_client_areas_;
+ const gfx::Insets old_client_area = client_area_;
+ client_area_ = new_client_area;
+ additional_client_areas_ = additional_client_areas;
+ FOR_EACH_OBSERVER(WindowObserver, observers_,
+ OnWindowClientAreaChanged(this, old_client_area,
+ old_additional_client_areas));
+}
+
+void Window::LocalSetDisplay(int64_t display_id) {
+ display_id_ = display_id;
+ // TODO(sad): Notify observers (of this window, and of the descendant windows)
+ // when a window moves from one display into another. https://crbug.com/614887
+}
+
+void Window::LocalSetParentDrawn(bool value) {
+ if (parent_drawn_ == value)
+ return;
+
+ // As IsDrawn() is derived from |visible_| and |parent_drawn_|, only send
+ // drawn notification is the value of IsDrawn() is really changing.
+ if (IsDrawn() == value) {
+ parent_drawn_ = value;
+ return;
+ }
+ FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDrawnChanging(this));
+ parent_drawn_ = value;
+ FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDrawnChanged(this));
+}
+
+void Window::LocalSetVisible(bool visible) {
+ if (visible_ == visible)
+ return;
+
+ FOR_EACH_OBSERVER(WindowObserver, observers_,
+ OnWindowVisibilityChanging(this));
+ visible_ = visible;
+ NotifyWindowVisibilityChanged(this);
+}
+
+void Window::LocalSetOpacity(float opacity) {
+ if (opacity_ == opacity)
+ return;
+
+ float old_opacity = opacity_;
+ opacity_ = opacity;
+ FOR_EACH_OBSERVER(WindowObserver, observers_,
+ OnWindowOpacityChanged(this, old_opacity, opacity_));
+}
+
+void Window::LocalSetPredefinedCursor(mojom::Cursor cursor_id) {
+ if (cursor_id_ == cursor_id)
+ return;
+
+ cursor_id_ = cursor_id;
+ FOR_EACH_OBSERVER(WindowObserver, observers_,
+ OnWindowPredefinedCursorChanged(this, cursor_id));
+}
+
+void Window::LocalSetSharedProperty(const std::string& name,
+ const std::vector<uint8_t>* value) {
+ std::vector<uint8_t> old_value;
+ std::vector<uint8_t>* old_value_ptr = nullptr;
+ auto it = properties_.find(name);
+ if (it != properties_.end()) {
+ old_value = it->second;
+ old_value_ptr = &old_value;
+
+ if (value && old_value == *value)
+ return;
+ } else if (!value) {
+ // This property isn't set in |properties_| and |value| is nullptr, so
+ // there's no change.
+ return;
+ }
+
+ if (value) {
+ properties_[name] = *value;
+ } else if (it != properties_.end()) {
+ properties_.erase(it);
+ }
+
+ FOR_EACH_OBSERVER(
+ WindowObserver, observers_,
+ OnWindowSharedPropertyChanged(this, name, old_value_ptr, value));
+}
+
+void Window::NotifyWindowStackingChanged() {
+ if (stacking_target_) {
+ Children::const_iterator window_i = std::find(
+ parent()->children().begin(), parent()->children().end(), this);
+ DCHECK(window_i != parent()->children().end());
+ if (window_i != parent()->children().begin() &&
+ (*(window_i - 1) == stacking_target_))
+ return;
+ }
+ RestackTransientDescendants(this, &GetStackingTarget,
+ &ReorderWithoutNotification);
+}
+
+void Window::NotifyWindowVisibilityChanged(Window* target) {
+ if (!NotifyWindowVisibilityChangedDown(target)) {
+ return; // |this| has been deleted.
+ }
+ NotifyWindowVisibilityChangedUp(target);
+}
+
+bool Window::NotifyWindowVisibilityChangedAtReceiver(Window* target) {
+ // |this| may be deleted during a call to OnWindowVisibilityChanged() on one
+ // of the observers. We create an local observer for that. In that case we
+ // exit without further access to any members.
+ WindowTracker tracker;
+ tracker.Add(this);
+ FOR_EACH_OBSERVER(WindowObserver, observers_,
+ OnWindowVisibilityChanged(target));
+ return tracker.Contains(this);
+}
+
+bool Window::NotifyWindowVisibilityChangedDown(Window* target) {
+ if (!NotifyWindowVisibilityChangedAtReceiver(target))
+ return false; // |this| was deleted.
+ std::set<const Window*> child_already_processed;
+ bool child_destroyed = false;
+ do {
+ child_destroyed = false;
+ for (Window::Children::const_iterator it = children_.begin();
+ it != children_.end(); ++it) {
+ if (!child_already_processed.insert(*it).second)
+ continue;
+ if (!(*it)->NotifyWindowVisibilityChangedDown(target)) {
+ // |*it| was deleted, |it| is invalid and |children_| has changed. We
+ // exit the current for-loop and enter a new one.
+ child_destroyed = true;
+ break;
+ }
+ }
+ } while (child_destroyed);
+ return true;
+}
+
+void Window::NotifyWindowVisibilityChangedUp(Window* target) {
+ // Start with the parent as we already notified |this|
+ // in NotifyWindowVisibilityChangedDown.
+ for (Window* window = parent(); window; window = window->parent()) {
+ bool ret = window->NotifyWindowVisibilityChangedAtReceiver(target);
+ DCHECK(ret);
+ }
+}
+
+bool Window::PrepareForEmbed() {
+ if (!OwnsWindow(client_, this))
+ return false;
+
+ while (!children_.empty())
+ RemoveChild(children_[0]);
+ return true;
+}
+
+void Window::RemoveTransientWindowImpl(Window* transient_window) {
+ Window::Children::iterator it = std::find(
+ transient_children_.begin(), transient_children_.end(), transient_window);
+ if (it != transient_children_.end()) {
+ transient_children_.erase(it);
+ transient_window->transient_parent_ = nullptr;
+ }
+ // If |transient_window| and its former transient parent share the same
+ // parent, |transient_window| should be restacked properly so it is not among
+ // transient children of its former parent, anymore.
+ if (parent() == transient_window->parent())
+ RestackTransientDescendants(this, &GetStackingTarget,
+ &ReorderWithoutNotification);
+
+ // TOOD(fsamuel): We might want to notify observers here.
+}
+
+// static
+void Window::ReorderWithoutNotification(Window* window,
+ Window* relative,
+ mojom::OrderDirection direction) {
+ ReorderImpl(window, relative, direction, nullptr);
+}
+
+// static
+// Returns true if the order actually changed.
+bool Window::ReorderImpl(Window* window,
+ Window* relative,
+ mojom::OrderDirection direction,
+ OrderChangedNotifier* notifier) {
+ DCHECK(relative);
+ DCHECK_NE(window, relative);
+ DCHECK_EQ(window->parent(), relative->parent());
+ DCHECK(window->parent());
+
+ if (!AdjustStackingForTransientWindows(&window, &relative, &direction,
+ window->stacking_target_))
+ return false;
+
+ const size_t child_i = std::find(window->parent_->children_.begin(),
+ window->parent_->children_.end(), window) -
+ window->parent_->children_.begin();
+ const size_t target_i =
+ std::find(window->parent_->children_.begin(),
+ window->parent_->children_.end(), relative) -
+ window->parent_->children_.begin();
+ if ((direction == mojom::OrderDirection::ABOVE && child_i == target_i + 1) ||
+ (direction == mojom::OrderDirection::BELOW && child_i + 1 == target_i)) {
+ return false;
+ }
+
+ if (notifier)
+ notifier->NotifyWindowReordering();
+
+ const size_t dest_i = direction == mojom::OrderDirection::ABOVE
+ ? (child_i < target_i ? target_i : target_i + 1)
+ : (child_i < target_i ? target_i - 1 : target_i);
+ window->parent_->children_.erase(window->parent_->children_.begin() +
+ child_i);
+ window->parent_->children_.insert(window->parent_->children_.begin() + dest_i,
+ window);
+
+ window->NotifyWindowStackingChanged();
+
+ if (notifier)
+ notifier->NotifyWindowReordered();
+
+ return true;
+}
+
+// static
+Window** Window::GetStackingTarget(Window* window) {
+ return &window->stacking_target_;
+}
+} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/window_observer.cc b/chromium/components/mus/public/cpp/lib/window_observer.cc
new file mode 100644
index 00000000000..26e65078f77
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/window_observer.cc
@@ -0,0 +1,18 @@
+// 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 "components/mus/public/cpp/window_observer.h"
+
+namespace mus {
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowObserver, public:
+
+WindowObserver::TreeChangeParams::TreeChangeParams()
+ : target(nullptr),
+ old_parent(nullptr),
+ new_parent(nullptr),
+ receiver(nullptr) {}
+
+} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/window_private.cc b/chromium/components/mus/public/cpp/lib/window_private.cc
new file mode 100644
index 00000000000..11c7ebeefae
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/window_private.cc
@@ -0,0 +1,31 @@
+// 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 "components/mus/public/cpp/lib/window_private.h"
+
+namespace mus {
+
+WindowPrivate::WindowPrivate(Window* window) : window_(window) {
+ CHECK(window);
+}
+
+WindowPrivate::~WindowPrivate() {}
+
+// static
+Window* WindowPrivate::LocalCreate() {
+ return new Window;
+}
+
+void WindowPrivate::LocalSetSharedProperty(const std::string& name,
+ mojo::Array<uint8_t> new_data) {
+ std::vector<uint8_t> data;
+ std::vector<uint8_t>* data_ptr = nullptr;
+ if (!new_data.is_null()) {
+ data = new_data.To<std::vector<uint8_t>>();
+ data_ptr = &data;
+ }
+ LocalSetSharedProperty(name, data_ptr);
+}
+
+} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/window_private.h b/chromium/components/mus/public/cpp/lib/window_private.h
new file mode 100644
index 00000000000..4b2640e8b37
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/window_private.h
@@ -0,0 +1,100 @@
+// 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.
+
+#ifndef COMPONENTS_MUS_PUBLIC_CPP_LIB_WINDOW_PRIVATE_H_
+#define COMPONENTS_MUS_PUBLIC_CPP_LIB_WINDOW_PRIVATE_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/macros.h"
+#include "components/mus/public/cpp/window.h"
+#include "mojo/public/cpp/bindings/array.h"
+
+namespace mus {
+
+// This class is a friend of a Window and contains functions to mutate internal
+// state of Window.
+class WindowPrivate {
+ public:
+ explicit WindowPrivate(Window* window);
+ ~WindowPrivate();
+
+ // Creates and returns a new Window. Caller owns the return value.
+ static Window* LocalCreate();
+
+ base::ObserverList<WindowObserver>* observers() {
+ return &window_->observers_;
+ }
+
+ void ClearParent() { window_->parent_ = nullptr; }
+
+ void ClearTransientParent() { window_->transient_parent_ = nullptr; }
+
+ void set_visible(bool visible) { window_->visible_ = visible; }
+
+ void set_parent_drawn(bool drawn) { window_->parent_drawn_ = drawn; }
+ bool parent_drawn() { return window_->parent_drawn_; }
+
+ void set_server_id(Id id) { window_->server_id_ = id; }
+ Id server_id() { return window_->server_id_; }
+
+ void set_client(WindowTreeClient* client) {
+ window_->client_ = client;
+ }
+
+ void set_properties(const std::map<std::string, std::vector<uint8_t>>& data) {
+ window_->properties_ = data;
+ }
+
+ void LocalSetDisplay(int64_t new_display) {
+ window_->LocalSetDisplay(new_display);
+ }
+
+ void LocalDestroy() { window_->LocalDestroy(); }
+ void LocalAddChild(Window* child) { window_->LocalAddChild(child); }
+ void LocalRemoveChild(Window* child) { window_->LocalRemoveChild(child); }
+ void LocalAddTransientWindow(Window* child) {
+ window_->LocalAddTransientWindow(child);
+ }
+ void LocalRemoveTransientWindow(Window* child) {
+ window_->LocalRemoveTransientWindow(child);
+ }
+ void LocalUnsetModal() { window_->is_modal_ = false; }
+ void LocalReorder(Window* relative, mojom::OrderDirection direction) {
+ window_->LocalReorder(relative, direction);
+ }
+ void LocalSetBounds(const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) {
+ window_->LocalSetBounds(old_bounds, new_bounds);
+ }
+ void LocalSetClientArea(
+ const gfx::Insets& client_area,
+ const std::vector<gfx::Rect>& additional_client_areas) {
+ window_->LocalSetClientArea(client_area, additional_client_areas);
+ }
+ void LocalSetParentDrawn(bool drawn) { window_->LocalSetParentDrawn(drawn); }
+ void LocalSetVisible(bool visible) { window_->LocalSetVisible(visible); }
+ void LocalSetOpacity(float opacity) { window_->LocalSetOpacity(opacity); }
+ void LocalSetPredefinedCursor(mojom::Cursor cursor) {
+ window_->LocalSetPredefinedCursor(cursor);
+ }
+ void LocalSetSharedProperty(const std::string& name,
+ mojo::Array<uint8_t> new_data);
+ void LocalSetSharedProperty(const std::string& name,
+ const std::vector<uint8_t>* data) {
+ window_->LocalSetSharedProperty(name, data);
+ }
+ void NotifyWindowStackingChanged() { window_->NotifyWindowStackingChanged(); }
+
+ private:
+ Window* window_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowPrivate);
+};
+
+} // namespace mus
+
+#endif // COMPONENTS_MUS_PUBLIC_CPP_LIB_WINDOW_PRIVATE_H_
diff --git a/chromium/components/mus/public/cpp/lib/window_surface.cc b/chromium/components/mus/public/cpp/lib/window_surface.cc
new file mode 100644
index 00000000000..1f0b840a102
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/window_surface.cc
@@ -0,0 +1,69 @@
+// Copyright 2015 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 "components/mus/public/cpp/window_surface.h"
+
+#include "base/memory/ptr_util.h"
+#include "components/mus/public/cpp/window_surface_client.h"
+
+namespace mus {
+
+// static
+std::unique_ptr<WindowSurface> WindowSurface::Create(
+ std::unique_ptr<WindowSurfaceBinding>* surface_binding) {
+ mojom::SurfacePtr surface;
+ mojom::SurfaceClientPtr surface_client;
+ mojo::InterfaceRequest<mojom::SurfaceClient> surface_client_request =
+ GetProxy(&surface_client);
+
+ surface_binding->reset(new WindowSurfaceBinding(
+ GetProxy(&surface), surface_client.PassInterface()));
+ return base::WrapUnique(new WindowSurface(surface.PassInterface(),
+ std::move(surface_client_request)));
+}
+
+WindowSurface::~WindowSurface() {}
+
+void WindowSurface::BindToThread() {
+ DCHECK(!thread_checker_);
+ thread_checker_.reset(new base::ThreadChecker());
+ surface_.Bind(std::move(surface_info_));
+ client_binding_.reset(new mojo::Binding<mojom::SurfaceClient>(
+ this, std::move(client_request_)));
+}
+
+void WindowSurface::SubmitCompositorFrame(cc::CompositorFrame frame,
+ const base::Closure& callback) {
+ DCHECK(thread_checker_);
+ DCHECK(thread_checker_->CalledOnValidThread());
+ if (!surface_)
+ return;
+ surface_->SubmitCompositorFrame(std::move(frame), callback);
+}
+
+WindowSurface::WindowSurface(
+ mojo::InterfacePtrInfo<mojom::Surface> surface_info,
+ mojo::InterfaceRequest<mojom::SurfaceClient> client_request)
+ : client_(nullptr),
+ surface_info_(std::move(surface_info)),
+ client_request_(std::move(client_request)) {}
+
+void WindowSurface::ReturnResources(
+ mojo::Array<cc::ReturnedResource> resources) {
+ DCHECK(thread_checker_);
+ DCHECK(thread_checker_->CalledOnValidThread());
+ if (!client_)
+ return;
+ client_->OnResourcesReturned(this, std::move(resources));
+}
+
+WindowSurfaceBinding::~WindowSurfaceBinding() {}
+
+WindowSurfaceBinding::WindowSurfaceBinding(
+ mojo::InterfaceRequest<mojom::Surface> surface_request,
+ mojo::InterfacePtrInfo<mojom::SurfaceClient> surface_client)
+ : surface_request_(std::move(surface_request)),
+ surface_client_(std::move(surface_client)) {}
+
+} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/window_tree_client.cc b/chromium/components/mus/public/cpp/lib/window_tree_client.cc
new file mode 100644
index 00000000000..7a43101ff6a
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/window_tree_client.cc
@@ -0,0 +1,1181 @@
+// 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 "components/mus/public/cpp/window_tree_client.h"
+
+#include <stddef.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "components/mus/common/util.h"
+#include "components/mus/public/cpp/input_event_handler.h"
+#include "components/mus/public/cpp/lib/in_flight_change.h"
+#include "components/mus/public/cpp/lib/window_private.h"
+#include "components/mus/public/cpp/window_manager_delegate.h"
+#include "components/mus/public/cpp/window_observer.h"
+#include "components/mus/public/cpp/window_tracker.h"
+#include "components/mus/public/cpp/window_tree_client_delegate.h"
+#include "components/mus/public/cpp/window_tree_client_observer.h"
+#include "components/mus/public/interfaces/window_manager_window_tree_factory.mojom.h"
+#include "services/shell/public/cpp/connector.h"
+#include "ui/display/mojo/display_type_converters.h"
+#include "ui/events/event.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace mus {
+
+void DeleteWindowTreeClient(WindowTreeClient* client) { delete client; }
+
+Id MakeTransportId(ClientSpecificId client_id, ClientSpecificId local_id) {
+ return (client_id << 16) | local_id;
+}
+
+Id server_id(Window* window) {
+ return WindowPrivate(window).server_id();
+}
+
+// Helper called to construct a local window object from transport data.
+Window* AddWindowToClient(WindowTreeClient* client,
+ Window* parent,
+ const mojom::WindowDataPtr& window_data) {
+ // We don't use the ctor that takes a WindowTreeClient here, since it will
+ // call back to the service and attempt to create a new window.
+ Window* window = WindowPrivate::LocalCreate();
+ WindowPrivate private_window(window);
+ private_window.set_client(client);
+ private_window.set_server_id(window_data->window_id);
+ private_window.set_visible(window_data->visible);
+ private_window.set_properties(
+ window_data->properties
+ .To<std::map<std::string, std::vector<uint8_t>>>());
+ client->AddWindow(window);
+ private_window.LocalSetBounds(gfx::Rect(), window_data->bounds);
+ if (parent)
+ WindowPrivate(parent).LocalAddChild(window);
+ return window;
+}
+
+Window* BuildWindowTree(WindowTreeClient* client,
+ const mojo::Array<mojom::WindowDataPtr>& windows,
+ Window* initial_parent) {
+ std::vector<Window*> parents;
+ Window* root = NULL;
+ Window* last_window = NULL;
+ if (initial_parent)
+ parents.push_back(initial_parent);
+ for (size_t i = 0; i < windows.size(); ++i) {
+ if (last_window && windows[i]->parent_id == server_id(last_window)) {
+ parents.push_back(last_window);
+ } else if (!parents.empty()) {
+ while (server_id(parents.back()) != windows[i]->parent_id)
+ parents.pop_back();
+ }
+ Window* window = AddWindowToClient(
+ client, !parents.empty() ? parents.back() : NULL, windows[i]);
+ if (!last_window)
+ root = window;
+ last_window = window;
+ }
+ return root;
+}
+
+WindowTreeClient::WindowTreeClient(
+ WindowTreeClientDelegate* delegate,
+ WindowManagerDelegate* window_manager_delegate,
+ mojo::InterfaceRequest<mojom::WindowTreeClient> request)
+ : client_id_(0),
+ next_window_id_(1),
+ next_change_id_(1),
+ delegate_(delegate),
+ window_manager_delegate_(window_manager_delegate),
+ capture_window_(nullptr),
+ focused_window_(nullptr),
+ binding_(this),
+ tree_(nullptr),
+ delete_on_no_roots_(!window_manager_delegate),
+ in_destructor_(false),
+ weak_factory_(this) {
+ // Allow for a null request in tests.
+ if (request.is_pending())
+ binding_.Bind(std::move(request));
+ if (window_manager_delegate)
+ window_manager_delegate->SetWindowManagerClient(this);
+}
+
+WindowTreeClient::~WindowTreeClient() {
+ in_destructor_ = true;
+
+ std::vector<Window*> non_owned;
+ WindowTracker tracker;
+ while (!windows_.empty()) {
+ IdToWindowMap::iterator it = windows_.begin();
+ if (OwnsWindow(it->second)) {
+ it->second->Destroy();
+ } else {
+ tracker.Add(it->second);
+ windows_.erase(it);
+ }
+ }
+
+ // Delete the non-owned windows last. In the typical case these are roots. The
+ // exception is the window manager and embed roots, which may know about
+ // other random windows that it doesn't own.
+ // NOTE: we manually delete as we're a friend.
+ while (!tracker.windows().empty())
+ delete tracker.windows().front();
+
+ FOR_EACH_OBSERVER(WindowTreeClientObserver, observers_,
+ OnWillDestroyClient(this));
+
+ delegate_->OnWindowTreeClientDestroyed(this);
+}
+
+void WindowTreeClient::ConnectViaWindowTreeFactory(
+ shell::Connector* connector) {
+ // Clients created with no root shouldn't delete automatically.
+ delete_on_no_roots_ = false;
+
+ // The client id doesn't really matter, we use 101 purely for debugging.
+ client_id_ = 101;
+
+ mojom::WindowTreeFactoryPtr factory;
+ connector->ConnectToInterface("mojo:mus", &factory);
+ mojom::WindowTreePtr window_tree;
+ factory->CreateWindowTree(GetProxy(&window_tree),
+ binding_.CreateInterfacePtrAndBind());
+ SetWindowTree(std::move(window_tree));
+}
+
+void WindowTreeClient::ConnectAsWindowManager(shell::Connector* connector) {
+ DCHECK(window_manager_delegate_);
+
+ mojom::WindowManagerWindowTreeFactoryPtr factory;
+ connector->ConnectToInterface("mojo:mus", &factory);
+ mojom::WindowTreePtr window_tree;
+ factory->CreateWindowTree(GetProxy(&window_tree),
+ binding_.CreateInterfacePtrAndBind());
+ SetWindowTree(std::move(window_tree));
+}
+
+void WindowTreeClient::WaitForEmbed() {
+ DCHECK(roots_.empty());
+ // OnEmbed() is the first function called.
+ binding_.WaitForIncomingMethodCall();
+ // TODO(sky): deal with pipe being closed before we get OnEmbed().
+}
+
+void WindowTreeClient::DestroyWindow(Window* window) {
+ DCHECK(tree_);
+ const uint32_t change_id = ScheduleInFlightChange(base::WrapUnique(
+ new CrashInFlightChange(window, ChangeType::DELETE_WINDOW)));
+ tree_->DeleteWindow(change_id, server_id(window));
+}
+
+void WindowTreeClient::AddChild(Window* parent, Id child_id) {
+ DCHECK(tree_);
+ const uint32_t change_id = ScheduleInFlightChange(
+ base::WrapUnique(new CrashInFlightChange(parent, ChangeType::ADD_CHILD)));
+ tree_->AddWindow(change_id, parent->server_id(), child_id);
+}
+
+void WindowTreeClient::RemoveChild(Window* parent, Id child_id) {
+ DCHECK(tree_);
+ const uint32_t change_id = ScheduleInFlightChange(base::WrapUnique(
+ new CrashInFlightChange(parent, ChangeType::REMOVE_CHILD)));
+ tree_->RemoveWindowFromParent(change_id, child_id);
+}
+
+void WindowTreeClient::AddTransientWindow(Window* window,
+ Id transient_window_id) {
+ DCHECK(tree_);
+ const uint32_t change_id = ScheduleInFlightChange(base::WrapUnique(
+ new CrashInFlightChange(window, ChangeType::ADD_TRANSIENT_WINDOW)));
+ tree_->AddTransientWindow(change_id, server_id(window), transient_window_id);
+}
+
+void WindowTreeClient::RemoveTransientWindowFromParent(Window* window) {
+ DCHECK(tree_);
+ const uint32_t change_id =
+ ScheduleInFlightChange(base::WrapUnique(new CrashInFlightChange(
+ window, ChangeType::REMOVE_TRANSIENT_WINDOW_FROM_PARENT)));
+ tree_->RemoveTransientWindowFromParent(change_id, server_id(window));
+}
+
+void WindowTreeClient::SetModal(Window* window) {
+ DCHECK(tree_);
+ const uint32_t change_id = ScheduleInFlightChange(
+ base::WrapUnique(new InFlightSetModalChange(window)));
+ tree_->SetModal(change_id, server_id(window));
+}
+
+void WindowTreeClient::Reorder(Window* window,
+ Id relative_window_id,
+ mojom::OrderDirection direction) {
+ DCHECK(tree_);
+ const uint32_t change_id = ScheduleInFlightChange(
+ base::WrapUnique(new CrashInFlightChange(window, ChangeType::REORDER)));
+ tree_->ReorderWindow(change_id, server_id(window), relative_window_id,
+ direction);
+}
+
+bool WindowTreeClient::OwnsWindow(Window* window) const {
+ // Windows created via CreateTopLevelWindow() are not owned by us, but have
+ // our client id.
+ return HiWord(server_id(window)) == client_id_ &&
+ roots_.count(window) == 0;
+}
+
+void WindowTreeClient::SetBounds(Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& bounds) {
+ DCHECK(tree_);
+ const uint32_t change_id = ScheduleInFlightChange(
+ base::WrapUnique(new InFlightBoundsChange(window, old_bounds)));
+ tree_->SetWindowBounds(change_id, server_id(window), bounds);
+}
+
+void WindowTreeClient::SetCapture(Window* window) {
+ // In order for us to get here we had to have exposed a window, which implies
+ // we got a client.
+ DCHECK(tree_);
+ if (capture_window_ == window)
+ return;
+ const uint32_t change_id = ScheduleInFlightChange(
+ base::WrapUnique(new InFlightCaptureChange(this, capture_window_)));
+ tree_->SetCapture(change_id, server_id(window));
+ LocalSetCapture(window);
+}
+
+void WindowTreeClient::ReleaseCapture(Window* window) {
+ // In order for us to get here we had to have exposed a window, which implies
+ // we got a client.
+ DCHECK(tree_);
+ if (capture_window_ != window)
+ return;
+ const uint32_t change_id = ScheduleInFlightChange(
+ base::WrapUnique(new InFlightCaptureChange(this, window)));
+ tree_->ReleaseCapture(change_id, server_id(window));
+ LocalSetCapture(nullptr);
+}
+
+void WindowTreeClient::SetClientArea(
+ Id window_id,
+ const gfx::Insets& client_area,
+ const std::vector<gfx::Rect>& additional_client_areas) {
+ DCHECK(tree_);
+ tree_->SetClientArea(window_id, client_area, additional_client_areas);
+}
+
+void WindowTreeClient::SetHitTestMask(Id window_id, const gfx::Rect& mask) {
+ DCHECK(tree_);
+ tree_->SetHitTestMask(window_id, mask);
+}
+
+void WindowTreeClient::ClearHitTestMask(Id window_id) {
+ DCHECK(tree_);
+ tree_->SetHitTestMask(window_id, {});
+}
+
+void WindowTreeClient::SetFocus(Window* window) {
+ // In order for us to get here we had to have exposed a window, which implies
+ // we got a client.
+ DCHECK(tree_);
+ const uint32_t change_id = ScheduleInFlightChange(
+ base::WrapUnique(new InFlightFocusChange(this, focused_window_)));
+ tree_->SetFocus(change_id, window ? server_id(window) : 0);
+ LocalSetFocus(window);
+}
+
+void WindowTreeClient::SetCanFocus(Id window_id, bool can_focus) {
+ DCHECK(tree_);
+ tree_->SetCanFocus(window_id, can_focus);
+}
+
+void WindowTreeClient::SetPredefinedCursor(Id window_id,
+ mus::mojom::Cursor cursor_id) {
+ DCHECK(tree_);
+
+ Window* window = GetWindowByServerId(window_id);
+ if (!window)
+ return;
+
+ // We make an inflight change thing here.
+ const uint32_t change_id = ScheduleInFlightChange(base::WrapUnique(
+ new InFlightPredefinedCursorChange(window, window->predefined_cursor())));
+ tree_->SetPredefinedCursor(change_id, window_id, cursor_id);
+}
+
+void WindowTreeClient::SetVisible(Window* window, bool visible) {
+ DCHECK(tree_);
+ const uint32_t change_id = ScheduleInFlightChange(
+ base::WrapUnique(new InFlightVisibleChange(window, !visible)));
+ tree_->SetWindowVisibility(change_id, server_id(window), visible);
+}
+
+void WindowTreeClient::SetOpacity(Window* window, float opacity) {
+ DCHECK(tree_);
+ const uint32_t change_id = ScheduleInFlightChange(
+ base::WrapUnique(new InFlightOpacityChange(window, window->opacity())));
+ tree_->SetWindowOpacity(change_id, server_id(window), opacity);
+}
+
+void WindowTreeClient::SetProperty(Window* window,
+ const std::string& name,
+ mojo::Array<uint8_t> data) {
+ DCHECK(tree_);
+
+ mojo::Array<uint8_t> old_value(nullptr);
+ if (window->HasSharedProperty(name))
+ old_value = mojo::Array<uint8_t>::From(window->properties_[name]);
+
+ const uint32_t change_id = ScheduleInFlightChange(
+ base::WrapUnique(new InFlightPropertyChange(window, name, old_value)));
+ tree_->SetWindowProperty(change_id, server_id(window), mojo::String(name),
+ std::move(data));
+}
+
+void WindowTreeClient::SetWindowTextInputState(
+ Id window_id,
+ mojo::TextInputStatePtr state) {
+ DCHECK(tree_);
+ tree_->SetWindowTextInputState(window_id, std::move(state));
+}
+
+void WindowTreeClient::SetImeVisibility(Id window_id,
+ bool visible,
+ mojo::TextInputStatePtr state) {
+ DCHECK(tree_);
+ tree_->SetImeVisibility(window_id, visible, std::move(state));
+}
+
+void WindowTreeClient::Embed(Id window_id,
+ mojom::WindowTreeClientPtr client,
+ uint32_t flags,
+ const mojom::WindowTree::EmbedCallback& callback) {
+ DCHECK(tree_);
+ tree_->Embed(window_id, std::move(client), flags, callback);
+}
+
+void WindowTreeClient::RequestClose(Window* window) {
+ if (window_manager_internal_client_)
+ window_manager_internal_client_->WmRequestClose(server_id(window));
+}
+
+void WindowTreeClient::AttachSurface(
+ Id window_id,
+ mojom::SurfaceType type,
+ mojo::InterfaceRequest<mojom::Surface> surface,
+ mojom::SurfaceClientPtr client) {
+ DCHECK(tree_);
+ tree_->AttachSurface(window_id, type, std::move(surface), std::move(client));
+}
+
+void WindowTreeClient::LocalSetCapture(Window* window) {
+ if (capture_window_ == window)
+ return;
+ Window* lost_capture = capture_window_;
+ capture_window_ = window;
+ if (lost_capture) {
+ FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(lost_capture).observers(),
+ OnWindowLostCapture(lost_capture));
+ }
+}
+
+void WindowTreeClient::LocalSetFocus(Window* focused) {
+ Window* blurred = focused_window_;
+ // Update |focused_window_| before calling any of the observers, so that the
+ // observers get the correct result from calling |Window::HasFocus()|,
+ // |WindowTreeClient::GetFocusedWindow()| etc.
+ focused_window_ = focused;
+ if (blurred) {
+ FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(blurred).observers(),
+ OnWindowFocusChanged(focused, blurred));
+ }
+ if (focused) {
+ FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(focused).observers(),
+ OnWindowFocusChanged(focused, blurred));
+ }
+ FOR_EACH_OBSERVER(WindowTreeClientObserver, observers_,
+ OnWindowTreeFocusChanged(focused, blurred));
+}
+
+void WindowTreeClient::AddWindow(Window* window) {
+ DCHECK(windows_.find(server_id(window)) == windows_.end());
+ windows_[server_id(window)] = window;
+}
+
+void WindowTreeClient::OnWindowDestroying(Window* window) {
+ if (window == capture_window_) {
+ // Normally the queue updates itself upon window destruction. However since
+ // |window| is being destroyed, it will not be possible to notify its
+ // observers of the lost capture. Update local state now.
+ LocalSetCapture(nullptr);
+ }
+ // For |focused_window_| window destruction clears the entire focus state.
+}
+
+void WindowTreeClient::OnWindowDestroyed(Window* window) {
+ windows_.erase(server_id(window));
+
+ for (auto& entry : embedded_windows_) {
+ auto it = entry.second.find(window);
+ if (it != entry.second.end()) {
+ entry.second.erase(it);
+ break;
+ }
+ }
+
+ // Remove any InFlightChanges associated with the window.
+ std::set<uint32_t> in_flight_change_ids_to_remove;
+ for (const auto& pair : in_flight_map_) {
+ if (pair.second->window() == window)
+ in_flight_change_ids_to_remove.insert(pair.first);
+ }
+ for (auto change_id : in_flight_change_ids_to_remove)
+ in_flight_map_.erase(change_id);
+
+ if (roots_.erase(window) > 0 && roots_.empty() && delete_on_no_roots_ &&
+ !in_destructor_) {
+ delete this;
+ }
+}
+
+Window* WindowTreeClient::GetWindowByServerId(Id id) {
+ IdToWindowMap::const_iterator it = windows_.find(id);
+ return it != windows_.end() ? it->second : NULL;
+}
+
+InFlightChange* WindowTreeClient::GetOldestInFlightChangeMatching(
+ const InFlightChange& change) {
+ for (const auto& pair : in_flight_map_) {
+ if (pair.second->window() == change.window() &&
+ pair.second->change_type() == change.change_type() &&
+ pair.second->Matches(change)) {
+ return pair.second.get();
+ }
+ }
+ return nullptr;
+}
+
+uint32_t WindowTreeClient::ScheduleInFlightChange(
+ std::unique_ptr<InFlightChange> change) {
+ DCHECK(!change->window() ||
+ windows_.count(change->window()->server_id()) > 0);
+ const uint32_t change_id = next_change_id_++;
+ in_flight_map_[change_id] = std::move(change);
+ return change_id;
+}
+
+bool WindowTreeClient::ApplyServerChangeToExistingInFlightChange(
+ const InFlightChange& change) {
+ InFlightChange* existing_change = GetOldestInFlightChangeMatching(change);
+ if (!existing_change)
+ return false;
+
+ existing_change->SetRevertValueFrom(change);
+ return true;
+}
+
+Window* WindowTreeClient::NewWindowImpl(
+ NewWindowType type,
+ const Window::SharedProperties* properties) {
+ DCHECK(tree_);
+ Window* window =
+ new Window(this, MakeTransportId(client_id_, next_window_id_++));
+ if (properties)
+ window->properties_ = *properties;
+ AddWindow(window);
+
+ const uint32_t change_id = ScheduleInFlightChange(base::WrapUnique(
+ new CrashInFlightChange(window, type == NewWindowType::CHILD
+ ? ChangeType::NEW_WINDOW
+ : ChangeType::NEW_TOP_LEVEL_WINDOW)));
+ mojo::Map<mojo::String, mojo::Array<uint8_t>> transport_properties;
+ if (properties) {
+ transport_properties =
+ mojo::Map<mojo::String, mojo::Array<uint8_t>>::From(*properties);
+ }
+ if (type == NewWindowType::CHILD) {
+ tree_->NewWindow(change_id, server_id(window),
+ std::move(transport_properties));
+ } else {
+ roots_.insert(window);
+ tree_->NewTopLevelWindow(change_id, server_id(window),
+ std::move(transport_properties));
+ }
+ return window;
+}
+
+void WindowTreeClient::SetWindowTree(mojom::WindowTreePtr window_tree_ptr) {
+ tree_ptr_ = std::move(window_tree_ptr);
+ tree_ = tree_ptr_.get();
+
+ tree_ptr_->GetCursorLocationMemory(
+ base::Bind(&WindowTreeClient::OnReceivedCursorLocationMemory,
+ weak_factory_.GetWeakPtr()));
+
+ tree_ptr_.set_connection_error_handler(base::Bind(
+ &WindowTreeClient::OnConnectionLost, weak_factory_.GetWeakPtr()));
+
+ if (window_manager_delegate_) {
+ tree_ptr_->GetWindowManagerClient(GetProxy(&window_manager_internal_client_,
+ tree_ptr_.associated_group()));
+ }
+}
+
+void WindowTreeClient::OnConnectionLost() {
+ delete this;
+}
+
+void WindowTreeClient::OnEmbedImpl(mojom::WindowTree* window_tree,
+ ClientSpecificId client_id,
+ mojom::WindowDataPtr root_data,
+ int64_t display_id,
+ Id focused_window_id,
+ bool drawn) {
+ // WARNING: this is only called if WindowTreeClient was created as the
+ // result of an embedding.
+ tree_ = window_tree;
+ client_id_ = client_id;
+
+ DCHECK(roots_.empty());
+ Window* root = AddWindowToClient(this, nullptr, root_data);
+ WindowPrivate(root).LocalSetDisplay(display_id);
+ roots_.insert(root);
+
+ focused_window_ = GetWindowByServerId(focused_window_id);
+
+ WindowPrivate(root).LocalSetParentDrawn(drawn);
+
+ delegate_->OnEmbed(root);
+
+ if (focused_window_) {
+ FOR_EACH_OBSERVER(WindowTreeClientObserver, observers_,
+ OnWindowTreeFocusChanged(focused_window_, nullptr));
+ }
+}
+
+void WindowTreeClient::WmNewDisplayAddedImpl(const display::Display& display,
+ mojom::WindowDataPtr root_data,
+ bool parent_drawn) {
+ DCHECK(window_manager_delegate_);
+
+ Window* root = AddWindowToClient(this, nullptr, root_data);
+ WindowPrivate(root).LocalSetDisplay(display.id());
+ WindowPrivate(root).LocalSetParentDrawn(parent_drawn);
+ roots_.insert(root);
+
+ window_manager_delegate_->OnWmNewDisplay(root, display);
+}
+
+void WindowTreeClient::OnReceivedCursorLocationMemory(
+ mojo::ScopedSharedBufferHandle handle) {
+ cursor_location_mapping_ = handle->Map(sizeof(base::subtle::Atomic32));
+ DCHECK(cursor_location_mapping_);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowTreeClient, WindowTreeClient implementation:
+
+void WindowTreeClient::SetDeleteOnNoRoots(bool value) {
+ delete_on_no_roots_ = value;
+}
+
+const std::set<Window*>& WindowTreeClient::GetRoots() {
+ return roots_;
+}
+
+Window* WindowTreeClient::GetFocusedWindow() {
+ return focused_window_;
+}
+
+void WindowTreeClient::ClearFocus() {
+ if (!focused_window_)
+ return;
+
+ SetFocus(nullptr);
+}
+
+gfx::Point WindowTreeClient::GetCursorScreenPoint() {
+ // We raced initialization. Return (0, 0).
+ if (!cursor_location_memory())
+ return gfx::Point();
+
+ base::subtle::Atomic32 location =
+ base::subtle::NoBarrier_Load(cursor_location_memory());
+ return gfx::Point(static_cast<int16_t>(location >> 16),
+ static_cast<int16_t>(location & 0xFFFF));
+}
+
+void WindowTreeClient::SetEventObserver(mojom::EventMatcherPtr matcher) {
+ if (matcher.is_null()) {
+ has_event_observer_ = false;
+ tree_->SetEventObserver(nullptr, 0u);
+ } else {
+ has_event_observer_ = true;
+ event_observer_id_++;
+ tree_->SetEventObserver(std::move(matcher), event_observer_id_);
+ }
+}
+
+Window* WindowTreeClient::NewWindow(
+ const Window::SharedProperties* properties) {
+ return NewWindowImpl(NewWindowType::CHILD, properties);
+}
+
+Window* WindowTreeClient::NewTopLevelWindow(
+ const Window::SharedProperties* properties) {
+ Window* window = NewWindowImpl(NewWindowType::TOP_LEVEL, properties);
+ // Assume newly created top level windows are drawn by default, otherwise
+ // requests to focus will fail. We will get the real value in
+ // OnTopLevelCreated().
+ window->LocalSetParentDrawn(true);
+ return window;
+}
+
+#if !defined(NDEBUG)
+std::string WindowTreeClient::GetDebugWindowHierarchy() const {
+ std::string result;
+ for (Window* root : roots_)
+ BuildDebugInfo(std::string(), root, &result);
+ return result;
+}
+
+void WindowTreeClient::BuildDebugInfo(const std::string& depth,
+ Window* window,
+ std::string* result) const {
+ std::string name = window->GetName();
+ *result += base::StringPrintf(
+ "%sid=%d visible=%s bounds=%d,%d %dx%d %s\n", depth.c_str(),
+ window->server_id(), window->visible() ? "true" : "false",
+ window->bounds().x(), window->bounds().y(), window->bounds().width(),
+ window->bounds().height(), !name.empty() ? name.c_str() : "(no name)");
+ for (Window* child : window->children())
+ BuildDebugInfo(depth + " ", child, result);
+}
+#endif // !defined(NDEBUG)
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowTreeClient, WindowTreeClient implementation:
+
+void WindowTreeClient::AddObserver(WindowTreeClientObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void WindowTreeClient::RemoveObserver(WindowTreeClientObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void WindowTreeClient::OnEmbed(ClientSpecificId client_id,
+ mojom::WindowDataPtr root_data,
+ mojom::WindowTreePtr tree,
+ int64_t display_id,
+ Id focused_window_id,
+ bool drawn) {
+ DCHECK(!tree_ptr_);
+ tree_ptr_ = std::move(tree);
+ tree_ptr_.set_connection_error_handler(
+ base::Bind(&DeleteWindowTreeClient, this));
+
+ if (window_manager_delegate_) {
+ tree_ptr_->GetWindowManagerClient(GetProxy(&window_manager_internal_client_,
+ tree_ptr_.associated_group()));
+ }
+
+ OnEmbedImpl(tree_ptr_.get(), client_id, std::move(root_data), display_id,
+ focused_window_id, drawn);
+}
+
+void WindowTreeClient::OnEmbeddedAppDisconnected(Id window_id) {
+ Window* window = GetWindowByServerId(window_id);
+ if (window) {
+ FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(window).observers(),
+ OnWindowEmbeddedAppDisconnected(window));
+ }
+}
+
+void WindowTreeClient::OnUnembed(Id window_id) {
+ Window* window = GetWindowByServerId(window_id);
+ if (!window)
+ return;
+
+ delegate_->OnUnembed(window);
+ WindowPrivate(window).LocalDestroy();
+}
+
+void WindowTreeClient::OnLostCapture(Id window_id) {
+ Window* window = GetWindowByServerId(window_id);
+ if (!window)
+ return;
+
+ InFlightCaptureChange reset_change(this, nullptr);
+ if (ApplyServerChangeToExistingInFlightChange(reset_change))
+ return;
+
+ LocalSetCapture(nullptr);
+}
+
+void WindowTreeClient::OnTopLevelCreated(uint32_t change_id,
+ mojom::WindowDataPtr data,
+ int64_t display_id,
+ bool drawn) {
+ // The server ack'd the top level window we created and supplied the state
+ // of the window at the time the server created it. For properties we do not
+ // have changes in flight for we can update them immediately. For properties
+ // with changes in flight we set the revert value from the server.
+
+ if (!in_flight_map_.count(change_id)) {
+ // The window may have been destroyed locally before the server could finish
+ // creating the window, and before the server received the notification that
+ // the window has been destroyed.
+ return;
+ }
+ std::unique_ptr<InFlightChange> change(std::move(in_flight_map_[change_id]));
+ in_flight_map_.erase(change_id);
+
+ Window* window = change->window();
+ WindowPrivate window_private(window);
+
+ // Drawn state and display-id always come from the server (they can't be
+ // modified locally).
+ window_private.LocalSetParentDrawn(drawn);
+ window_private.LocalSetDisplay(display_id);
+
+ // The default visibilty is false, we only need update visibility if it
+ // differs from that.
+ if (data->visible) {
+ InFlightVisibleChange visible_change(window, data->visible);
+ InFlightChange* current_change =
+ GetOldestInFlightChangeMatching(visible_change);
+ if (current_change)
+ current_change->SetRevertValueFrom(visible_change);
+ else
+ window_private.LocalSetVisible(true);
+ }
+
+ const gfx::Rect bounds(data->bounds);
+ {
+ InFlightBoundsChange bounds_change(window, bounds);
+ InFlightChange* current_change =
+ GetOldestInFlightChangeMatching(bounds_change);
+ if (current_change)
+ current_change->SetRevertValueFrom(bounds_change);
+ else if (window->bounds() != bounds)
+ window_private.LocalSetBounds(window->bounds(), bounds);
+ }
+
+ // There is currently no API to bulk set properties, so we iterate over each
+ // property individually.
+ Window::SharedProperties properties =
+ data->properties.To<std::map<std::string, std::vector<uint8_t>>>();
+ for (const auto& pair : properties) {
+ InFlightPropertyChange property_change(
+ window, pair.first, mojo::Array<uint8_t>::From(pair.second));
+ InFlightChange* current_change =
+ GetOldestInFlightChangeMatching(property_change);
+ if (current_change)
+ current_change->SetRevertValueFrom(property_change);
+ else
+ window_private.LocalSetSharedProperty(pair.first, &(pair.second));
+ }
+
+ // Top level windows should not have a parent.
+ DCHECK_EQ(0u, data->parent_id);
+}
+
+void WindowTreeClient::OnWindowBoundsChanged(Id window_id,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) {
+ Window* window = GetWindowByServerId(window_id);
+ if (!window)
+ return;
+
+ InFlightBoundsChange new_change(window, new_bounds);
+ if (ApplyServerChangeToExistingInFlightChange(new_change))
+ return;
+
+ WindowPrivate(window).LocalSetBounds(old_bounds, new_bounds);
+}
+
+void WindowTreeClient::OnClientAreaChanged(
+ uint32_t window_id,
+ const gfx::Insets& new_client_area,
+ mojo::Array<gfx::Rect> new_additional_client_areas) {
+ Window* window = GetWindowByServerId(window_id);
+ if (window) {
+ WindowPrivate(window).LocalSetClientArea(
+ new_client_area,
+ new_additional_client_areas.To<std::vector<gfx::Rect>>());
+ }
+}
+
+void WindowTreeClient::OnTransientWindowAdded(
+ uint32_t window_id,
+ uint32_t transient_window_id) {
+ Window* window = GetWindowByServerId(window_id);
+ Window* transient_window = GetWindowByServerId(transient_window_id);
+ // window or transient_window or both may be null if a local delete occurs
+ // with an in flight add from the server.
+ if (window && transient_window)
+ WindowPrivate(window).LocalAddTransientWindow(transient_window);
+}
+
+void WindowTreeClient::OnTransientWindowRemoved(
+ uint32_t window_id,
+ uint32_t transient_window_id) {
+ Window* window = GetWindowByServerId(window_id);
+ Window* transient_window = GetWindowByServerId(transient_window_id);
+ // window or transient_window or both may be null if a local delete occurs
+ // with an in flight delete from the server.
+ if (window && transient_window)
+ WindowPrivate(window).LocalRemoveTransientWindow(transient_window);
+}
+
+void WindowTreeClient::OnWindowHierarchyChanged(
+ Id window_id,
+ Id old_parent_id,
+ Id new_parent_id,
+ mojo::Array<mojom::WindowDataPtr> windows) {
+ Window* initial_parent =
+ windows.size() ? GetWindowByServerId(windows[0]->parent_id) : NULL;
+
+ const bool was_window_known = GetWindowByServerId(window_id) != nullptr;
+
+ BuildWindowTree(this, windows, initial_parent);
+
+ // If the window was not known, then BuildWindowTree() will have created it
+ // and parented the window.
+ if (!was_window_known)
+ return;
+
+ Window* new_parent = GetWindowByServerId(new_parent_id);
+ Window* old_parent = GetWindowByServerId(old_parent_id);
+ Window* window = GetWindowByServerId(window_id);
+ if (new_parent)
+ WindowPrivate(new_parent).LocalAddChild(window);
+ else
+ WindowPrivate(old_parent).LocalRemoveChild(window);
+}
+
+void WindowTreeClient::OnWindowReordered(Id window_id,
+ Id relative_window_id,
+ mojom::OrderDirection direction) {
+ Window* window = GetWindowByServerId(window_id);
+ Window* relative_window = GetWindowByServerId(relative_window_id);
+ if (window && relative_window)
+ WindowPrivate(window).LocalReorder(relative_window, direction);
+}
+
+void WindowTreeClient::OnWindowDeleted(Id window_id) {
+ Window* window = GetWindowByServerId(window_id);
+ if (window)
+ WindowPrivate(window).LocalDestroy();
+}
+
+Window* WindowTreeClient::GetCaptureWindow() {
+ return capture_window_;
+}
+
+void WindowTreeClient::OnWindowVisibilityChanged(Id window_id,
+ bool visible) {
+ Window* window = GetWindowByServerId(window_id);
+ if (!window)
+ return;
+
+ InFlightVisibleChange new_change(window, visible);
+ if (ApplyServerChangeToExistingInFlightChange(new_change))
+ return;
+
+ WindowPrivate(window).LocalSetVisible(visible);
+}
+
+void WindowTreeClient::OnWindowOpacityChanged(Id window_id,
+ float old_opacity,
+ float new_opacity) {
+ Window* window = GetWindowByServerId(window_id);
+ if (!window)
+ return;
+
+ InFlightOpacityChange new_change(window, new_opacity);
+ if (ApplyServerChangeToExistingInFlightChange(new_change))
+ return;
+
+ WindowPrivate(window).LocalSetOpacity(new_opacity);
+}
+
+void WindowTreeClient::OnWindowParentDrawnStateChanged(Id window_id,
+ bool drawn) {
+ Window* window = GetWindowByServerId(window_id);
+ if (window)
+ WindowPrivate(window).LocalSetParentDrawn(drawn);
+}
+
+void WindowTreeClient::OnWindowSharedPropertyChanged(
+ Id window_id,
+ const mojo::String& name,
+ mojo::Array<uint8_t> new_data) {
+ Window* window = GetWindowByServerId(window_id);
+ if (!window)
+ return;
+
+ InFlightPropertyChange new_change(window, name, new_data);
+ if (ApplyServerChangeToExistingInFlightChange(new_change))
+ return;
+
+ WindowPrivate(window).LocalSetSharedProperty(name, std::move(new_data));
+}
+
+void WindowTreeClient::OnWindowInputEvent(uint32_t event_id,
+ Id window_id,
+ std::unique_ptr<ui::Event> event,
+ uint32_t event_observer_id) {
+ DCHECK(event);
+ Window* window = GetWindowByServerId(window_id); // May be null.
+
+ // Non-zero event_observer_id means it matched an event observer on the
+ // server.
+ if (event_observer_id != 0 && has_event_observer_ &&
+ event_observer_id == event_observer_id_)
+ delegate_->OnEventObserved(*event.get(), window);
+
+ if (!window || !window->input_event_handler_) {
+ tree_->OnWindowInputEventAck(event_id, mojom::EventResult::UNHANDLED);
+ return;
+ }
+
+ std::unique_ptr<base::Callback<void(mojom::EventResult)>> ack_callback(
+ new base::Callback<void(mojom::EventResult)>(
+ base::Bind(&mojom::WindowTree::OnWindowInputEventAck,
+ base::Unretained(tree_), event_id)));
+
+ // TODO(moshayedi): crbug.com/617222. No need to convert to ui::MouseEvent or
+ // ui::TouchEvent once we have proper support for pointer events.
+ if (event->IsMousePointerEvent()) {
+ window->input_event_handler_->OnWindowInputEvent(
+ window, ui::MouseEvent(*event->AsPointerEvent()), &ack_callback);
+ } else if (event->IsTouchPointerEvent()) {
+ window->input_event_handler_->OnWindowInputEvent(
+ window, ui::TouchEvent(*event->AsPointerEvent()), &ack_callback);
+ } else {
+ window->input_event_handler_->OnWindowInputEvent(window, *event.get(),
+ &ack_callback);
+ }
+
+ // The handler did not take ownership of the callback, so we send the ack,
+ // marking the event as not consumed.
+ if (ack_callback)
+ ack_callback->Run(mojom::EventResult::UNHANDLED);
+}
+
+void WindowTreeClient::OnEventObserved(std::unique_ptr<ui::Event> event,
+ uint32_t event_observer_id) {
+ DCHECK(event);
+ if (has_event_observer_ && event_observer_id == event_observer_id_)
+ delegate_->OnEventObserved(*event.get(), nullptr /* target */);
+}
+
+void WindowTreeClient::OnWindowFocused(Id focused_window_id) {
+ Window* focused_window = GetWindowByServerId(focused_window_id);
+ InFlightFocusChange new_change(this, focused_window);
+ if (ApplyServerChangeToExistingInFlightChange(new_change))
+ return;
+
+ LocalSetFocus(focused_window);
+}
+
+void WindowTreeClient::OnWindowPredefinedCursorChanged(
+ Id window_id,
+ mojom::Cursor cursor) {
+ Window* window = GetWindowByServerId(window_id);
+ if (!window)
+ return;
+
+ InFlightPredefinedCursorChange new_change(window, cursor);
+ if (ApplyServerChangeToExistingInFlightChange(new_change))
+ return;
+
+ WindowPrivate(window).LocalSetPredefinedCursor(cursor);
+}
+
+void WindowTreeClient::OnChangeCompleted(uint32_t change_id, bool success) {
+ std::unique_ptr<InFlightChange> change(std::move(in_flight_map_[change_id]));
+ in_flight_map_.erase(change_id);
+ if (!change)
+ return;
+
+ if (!success)
+ change->ChangeFailed();
+
+ InFlightChange* next_change = GetOldestInFlightChangeMatching(*change);
+ if (next_change) {
+ if (!success)
+ next_change->SetRevertValueFrom(*change);
+ } else if (!success) {
+ change->Revert();
+ }
+}
+
+void WindowTreeClient::GetWindowManager(
+ mojo::AssociatedInterfaceRequest<WindowManager> internal) {
+ window_manager_internal_.reset(
+ new mojo::AssociatedBinding<mojom::WindowManager>(this,
+ std::move(internal)));
+}
+
+void WindowTreeClient::RequestClose(uint32_t window_id) {
+ Window* window = GetWindowByServerId(window_id);
+ if (!window || !IsRoot(window))
+ return;
+
+ FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(window).observers(),
+ OnRequestClose(window));
+}
+
+void WindowTreeClient::OnConnect(ClientSpecificId client_id) {
+ client_id_ = client_id;
+}
+
+void WindowTreeClient::WmNewDisplayAdded(mojom::DisplayPtr display,
+ mojom::WindowDataPtr root_data,
+ bool parent_drawn) {
+ WmNewDisplayAddedImpl(display.To<display::Display>(), std::move(root_data),
+ parent_drawn);
+}
+
+void WindowTreeClient::WmSetBounds(uint32_t change_id,
+ Id window_id,
+ const gfx::Rect& transit_bounds) {
+ Window* window = GetWindowByServerId(window_id);
+ bool result = false;
+ if (window) {
+ DCHECK(window_manager_delegate_);
+ gfx::Rect bounds = transit_bounds;
+ result = window_manager_delegate_->OnWmSetBounds(window, &bounds);
+ if (result) {
+ // If the resulting bounds differ return false. Returning false ensures
+ // the client applies the bounds we set below.
+ result = bounds == transit_bounds;
+ window->SetBounds(bounds);
+ }
+ }
+ if (window_manager_internal_client_)
+ window_manager_internal_client_->WmResponse(change_id, result);
+}
+
+void WindowTreeClient::WmSetProperty(uint32_t change_id,
+ Id window_id,
+ const mojo::String& name,
+ mojo::Array<uint8_t> transit_data) {
+ Window* window = GetWindowByServerId(window_id);
+ bool result = false;
+ if (window) {
+ DCHECK(window_manager_delegate_);
+ std::unique_ptr<std::vector<uint8_t>> data;
+ if (!transit_data.is_null()) {
+ data.reset(
+ new std::vector<uint8_t>(transit_data.To<std::vector<uint8_t>>()));
+ }
+ result = window_manager_delegate_->OnWmSetProperty(window, name, &data);
+ if (result) {
+ // If the resulting bounds differ return false. Returning false ensures
+ // the client applies the bounds we set below.
+ window->SetSharedPropertyInternal(name, data.get());
+ }
+ }
+ if (window_manager_internal_client_)
+ window_manager_internal_client_->WmResponse(change_id, result);
+}
+
+void WindowTreeClient::WmCreateTopLevelWindow(
+ uint32_t change_id,
+ ClientSpecificId requesting_client_id,
+ mojo::Map<mojo::String, mojo::Array<uint8_t>> transport_properties) {
+ std::map<std::string, std::vector<uint8_t>> properties =
+ transport_properties.To<std::map<std::string, std::vector<uint8_t>>>();
+ Window* window =
+ window_manager_delegate_->OnWmCreateTopLevelWindow(&properties);
+ embedded_windows_[requesting_client_id].insert(window);
+ if (window_manager_internal_client_) {
+ window_manager_internal_client_->OnWmCreatedTopLevelWindow(
+ change_id, server_id(window));
+ }
+}
+
+void WindowTreeClient::WmClientJankinessChanged(ClientSpecificId client_id,
+ bool janky) {
+ if (window_manager_delegate_) {
+ auto it = embedded_windows_.find(client_id);
+ CHECK(it != embedded_windows_.end());
+ window_manager_delegate_->OnWmClientJankinessChanged(
+ embedded_windows_[client_id], janky);
+ }
+}
+
+void WindowTreeClient::OnAccelerator(uint32_t id,
+ std::unique_ptr<ui::Event> event) {
+ DCHECK(event);
+ window_manager_delegate_->OnAccelerator(id, *event.get());
+}
+
+void WindowTreeClient::SetFrameDecorationValues(
+ mojom::FrameDecorationValuesPtr values) {
+ if (window_manager_internal_client_) {
+ window_manager_internal_client_->WmSetFrameDecorationValues(
+ std::move(values));
+ }
+}
+
+void WindowTreeClient::SetNonClientCursor(Window* window,
+ mus::mojom::Cursor cursor_id) {
+ window_manager_internal_client_->WmSetNonClientCursor(server_id(window),
+ cursor_id);
+}
+
+void WindowTreeClient::AddAccelerator(
+ uint32_t id,
+ mojom::EventMatcherPtr event_matcher,
+ const base::Callback<void(bool)>& callback) {
+ if (window_manager_internal_client_) {
+ window_manager_internal_client_->AddAccelerator(
+ id, std::move(event_matcher), callback);
+ }
+}
+
+void WindowTreeClient::RemoveAccelerator(uint32_t id) {
+ if (window_manager_internal_client_) {
+ window_manager_internal_client_->RemoveAccelerator(id);
+ }
+}
+
+void WindowTreeClient::AddActivationParent(Window* window) {
+ if (window_manager_internal_client_)
+ window_manager_internal_client_->AddActivationParent(server_id(window));
+}
+
+void WindowTreeClient::RemoveActivationParent(Window* window) {
+ if (window_manager_internal_client_)
+ window_manager_internal_client_->RemoveActivationParent(server_id(window));
+}
+
+void WindowTreeClient::ActivateNextWindow() {
+ if (window_manager_internal_client_)
+ window_manager_internal_client_->ActivateNextWindow();
+}
+
+void WindowTreeClient::SetUnderlaySurfaceOffsetAndExtendedHitArea(
+ Window* window,
+ const gfx::Vector2d& offset,
+ const gfx::Insets& hit_area) {
+ if (window_manager_internal_client_) {
+ window_manager_internal_client_->SetUnderlaySurfaceOffsetAndExtendedHitArea(
+ server_id(window), offset.x(), offset.y(), hit_area);
+ }
+}
+
+} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/window_tree_client_delegate.cc b/chromium/components/mus/public/cpp/lib/window_tree_client_delegate.cc
new file mode 100644
index 00000000000..ed53012b227
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/window_tree_client_delegate.cc
@@ -0,0 +1,11 @@
+// Copyright 2015 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 "components/mus/public/cpp/window_tree_client_delegate.h"
+
+namespace mus {
+
+void WindowTreeClientDelegate::OnUnembed(Window* root) {}
+
+} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/window_tree_host_factory.cc b/chromium/components/mus/public/cpp/lib/window_tree_host_factory.cc
new file mode 100644
index 00000000000..0d55bae13fe
--- /dev/null
+++ b/chromium/components/mus/public/cpp/lib/window_tree_host_factory.cc
@@ -0,0 +1,32 @@
+// Copyright 2015 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 "components/mus/public/cpp/window_tree_host_factory.h"
+
+#include "components/mus/public/cpp/window_tree_client.h"
+#include "components/mus/public/cpp/window_tree_client_delegate.h"
+#include "services/shell/public/cpp/connector.h"
+
+namespace mus {
+
+void CreateWindowTreeHost(mojom::WindowTreeHostFactory* factory,
+ WindowTreeClientDelegate* delegate,
+ mojom::WindowTreeHostPtr* host,
+ WindowManagerDelegate* window_manager_delegate) {
+ mojom::WindowTreeClientPtr tree_client;
+ new WindowTreeClient(delegate, window_manager_delegate,
+ GetProxy(&tree_client));
+ factory->CreateWindowTreeHost(GetProxy(host), std::move(tree_client));
+}
+
+void CreateWindowTreeHost(shell::Connector* connector,
+ WindowTreeClientDelegate* delegate,
+ mojom::WindowTreeHostPtr* host,
+ WindowManagerDelegate* window_manager_delegate) {
+ mojom::WindowTreeHostFactoryPtr factory;
+ connector->ConnectToInterface("mojo:mus", &factory);
+ CreateWindowTreeHost(factory.get(), delegate, host, window_manager_delegate);
+}
+
+} // namespace mus