blob: 9f226a9f8d99c6d5bab5380c98f1c6e4a66ac995 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/mus/mus_app.h"
#include <set>
#include "base/memory/weak_ptr.h"
#include "base/stl_util.h"
#include "base/threading/platform_thread.h"
#include "build/build_config.h"
#include "components/mus/common/args.h"
#include "components/mus/gles2/gpu_impl.h"
#include "components/mus/ws/display.h"
#include "components/mus/ws/display_binding.h"
#include "components/mus/ws/display_manager.h"
#include "components/mus/ws/user_display_manager.h"
#include "components/mus/ws/window_server.h"
#include "components/mus/ws/window_tree.h"
#include "components/mus/ws/window_tree_binding.h"
#include "components/mus/ws/window_tree_factory.h"
#include "components/mus/ws/window_tree_host_factory.h"
#include "components/resource_provider/public/cpp/resource_loader.h"
#include "mojo/public/c/system/main.h"
#include "mojo/services/tracing/public/cpp/tracing_impl.h"
#include "mojo/shell/public/cpp/connection.h"
#include "mojo/shell/public/cpp/connector.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_paths.h"
#include "ui/events/event_switches.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/gl/gl_surface.h"
#if defined(USE_X11)
#include <X11/Xlib.h>
#include "base/command_line.h"
#include "ui/platform_window/x11/x11_window.h"
#elif defined(USE_OZONE)
#include "ui/ozone/public/ozone_platform.h"
#endif
using mojo::Connection;
using mojo::InterfaceRequest;
using mus::mojom::WindowTreeHostFactory;
using mus::mojom::Gpu;
namespace mus {
namespace {
const char kResourceFileStrings[] = "mus_app_resources_strings.pak";
const char kResourceFile100[] = "mus_app_resources_100.pak";
const char kResourceFile200[] = "mus_app_resources_200.pak";
} // namespace
// TODO(sky): this is a pretty typical pattern, make it easier to do.
struct MandolineUIServicesApp::PendingRequest {
mojo::Connection* connection;
scoped_ptr<mojo::InterfaceRequest<mojom::WindowTreeFactory>> wtf_request;
};
struct MandolineUIServicesApp::UserState {
scoped_ptr<ws::WindowTreeFactory> window_tree_factory;
scoped_ptr<ws::WindowTreeHostFactory> window_tree_host_factory;
};
MandolineUIServicesApp::MandolineUIServicesApp() {}
MandolineUIServicesApp::~MandolineUIServicesApp() {
if (platform_display_init_params_.gpu_state)
platform_display_init_params_.gpu_state->StopThreads();
// Destroy |window_server_| first, since it depends on |event_source_|.
window_server_.reset();
}
void MandolineUIServicesApp::InitializeResources(mojo::Connector* connector) {
if (ui::ResourceBundle::HasSharedInstance())
return;
std::set<std::string> resource_paths;
resource_paths.insert(kResourceFileStrings);
resource_paths.insert(kResourceFile100);
resource_paths.insert(kResourceFile200);
resource_provider::ResourceLoader resource_loader(connector, resource_paths);
if (!resource_loader.BlockUntilLoaded())
return;
CHECK(resource_loader.loaded());
ui::RegisterPathProvider();
// Initialize resource bundle with 1x and 2x cursor bitmaps.
ui::ResourceBundle::InitSharedInstanceWithPakFileRegion(
resource_loader.ReleaseFile(kResourceFileStrings),
base::MemoryMappedFile::Region::kWholeFile);
ui::ResourceBundle::GetSharedInstance().AddDataPackFromFile(
resource_loader.ReleaseFile(kResourceFile100), ui::SCALE_FACTOR_100P);
ui::ResourceBundle::GetSharedInstance().AddDataPackFromFile(
resource_loader.ReleaseFile(kResourceFile200), ui::SCALE_FACTOR_200P);
}
MandolineUIServicesApp::UserState* MandolineUIServicesApp::GetUserState(
mojo::Connection* connection) {
const ws::UserId& user_id = connection->GetRemoteIdentity().user_id();
auto it = user_id_to_user_state_.find(user_id);
if (it != user_id_to_user_state_.end())
return it->second.get();
user_id_to_user_state_[user_id] = make_scoped_ptr(new UserState);
return user_id_to_user_state_[user_id].get();
}
void MandolineUIServicesApp::AddUserIfNecessary(mojo::Connection* connection) {
window_server_->user_id_tracker()->AddUserId(
connection->GetRemoteIdentity().user_id());
}
void MandolineUIServicesApp::Initialize(mojo::Connector* connector,
const mojo::Identity& identity,
uint32_t id) {
platform_display_init_params_.connector = connector;
platform_display_init_params_.surfaces_state = new SurfacesState;
base::PlatformThread::SetName("mus");
#if defined(USE_X11)
XInitThreads();
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(kUseX11TestConfig)) {
ui::test::SetUseOverrideRedirectWindowByDefault(true);
}
#endif
InitializeResources(connector);
#if defined(USE_OZONE)
// The ozone platform can provide its own event source. So initialize the
// platform before creating the default event source.
// TODO(rjkroege): Add tracing here.
// Because GL libraries need to be initialized before entering the sandbox,
// in MUS, |InitializeForUI| will load the GL libraries.
ui::OzonePlatform::InitializeForUI();
#endif
// TODO(rjkroege): Enter sandbox here before we start threads in GpuState
// http://crbug.com/584532
#if !defined(OS_ANDROID)
event_source_ = ui::PlatformEventSource::CreateDefault();
#endif
// TODO(rjkroege): It is possible that we might want to generalize the
// GpuState object.
platform_display_init_params_.gpu_state = new GpuState();
window_server_.reset(
new ws::WindowServer(this, platform_display_init_params_.surfaces_state));
tracing_.Initialize(connector, identity.name());
}
bool MandolineUIServicesApp::AcceptConnection(Connection* connection) {
connection->AddInterface<Gpu>(this);
connection->AddInterface<mojom::DisplayManager>(this);
connection->AddInterface<mojom::UserAccessManager>(this);
connection->AddInterface<WindowTreeHostFactory>(this);
connection->AddInterface<mojom::WindowManagerFactoryService>(this);
connection->AddInterface<mojom::WindowTreeFactory>(this);
return true;
}
void MandolineUIServicesApp::ShellConnectionLost() {
// TODO: This should exit cleanly.
_exit(1);
}
void MandolineUIServicesApp::OnFirstDisplayReady() {
PendingRequests requests;
requests.swap(pending_requests_);
for (auto& request : requests)
Create(request->connection, std::move(*request->wtf_request));
}
void MandolineUIServicesApp::OnNoMoreDisplays() {
base::MessageLoop::current()->QuitWhenIdle();
}
scoped_ptr<ws::WindowTreeBinding>
MandolineUIServicesApp::CreateWindowTreeBindingForEmbedAtWindow(
ws::WindowServer* window_server,
ws::WindowTree* tree,
mojom::WindowTreeRequest tree_request,
mojom::WindowTreeClientPtr client) {
return make_scoped_ptr(new ws::DefaultWindowTreeBinding(
tree, window_server, std::move(tree_request), std::move(client)));
}
void MandolineUIServicesApp::CreateDefaultDisplays() {
// Display manages its own lifetime.
ws::Display* host_impl =
new ws::Display(window_server_.get(), platform_display_init_params_);
host_impl->Init(nullptr);
}
void MandolineUIServicesApp::Create(mojo::Connection* connection,
mojom::DisplayManagerRequest request) {
window_server_->display_manager()
->GetUserDisplayManager(connection->GetRemoteIdentity().user_id())
->AddDisplayManagerBinding(std::move(request));
}
void MandolineUIServicesApp::Create(mojo::Connection* connection,
mojom::UserAccessManagerRequest request) {
window_server_->user_id_tracker()->Bind(std::move(request));
}
void MandolineUIServicesApp::Create(
mojo::Connection* connection,
mojom::WindowManagerFactoryServiceRequest request) {
AddUserIfNecessary(connection);
window_server_->window_manager_factory_registry()->Register(
connection->GetRemoteIdentity().user_id(), std::move(request));
}
void MandolineUIServicesApp::Create(Connection* connection,
mojom::WindowTreeFactoryRequest request) {
AddUserIfNecessary(connection);
if (!window_server_->display_manager()->has_displays()) {
scoped_ptr<PendingRequest> pending_request(new PendingRequest);
pending_request->connection = connection;
pending_request->wtf_request.reset(
new mojo::InterfaceRequest<mojom::WindowTreeFactory>(
std::move(request)));
pending_requests_.push_back(std::move(pending_request));
return;
}
AddUserIfNecessary(connection);
UserState* user_state = GetUserState(connection);
if (!user_state->window_tree_factory) {
user_state->window_tree_factory.reset(new ws::WindowTreeFactory(
window_server_.get(), connection->GetRemoteIdentity().user_id()));
}
user_state->window_tree_factory->AddBinding(std::move(request));
}
void MandolineUIServicesApp::Create(
Connection* connection,
mojom::WindowTreeHostFactoryRequest request) {
UserState* user_state = GetUserState(connection);
if (!user_state->window_tree_host_factory) {
user_state->window_tree_host_factory.reset(new ws::WindowTreeHostFactory(
window_server_.get(), connection->GetRemoteIdentity().user_id(),
platform_display_init_params_));
}
user_state->window_tree_host_factory->AddBinding(std::move(request));
}
void MandolineUIServicesApp::Create(mojo::Connection* connection,
mojom::GpuRequest request) {
DCHECK(platform_display_init_params_.gpu_state);
new GpuImpl(std::move(request), platform_display_init_params_.gpu_state);
}
} // namespace mus