blob: 61ae21e2fef4ff35369998a967c49e092f75f3e0 [file] [log] [blame]
// Copyright 2016 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 "ash/mus/root_window_controller.h"
#include <stdint.h>
#include <algorithm>
#include <map>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include "ash/common/shelf/shelf_layout_manager.h"
#include "ash/common/wm/container_finder.h"
#include "ash/common/wm/dock/docked_window_layout_manager.h"
#include "ash/common/wm/panels/panel_layout_manager.h"
#include "ash/common/wm/root_window_layout_manager.h"
#include "ash/mus/bridge/wm_root_window_controller_mus.h"
#include "ash/mus/bridge/wm_shelf_mus.h"
#include "ash/mus/bridge/wm_shell_mus.h"
#include "ash/mus/bridge/wm_window_mus.h"
#include "ash/mus/non_client_frame_controller.h"
#include "ash/mus/property_util.h"
#include "ash/mus/screen_mus.h"
#include "ash/mus/window_manager.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/wm/stacking_controller.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "mojo/public/cpp/bindings/type_converter.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/ui/common/switches.h"
#include "services/ui/common/util.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/mus/property_converter.h"
#include "ui/aura/mus/property_utils.h"
#include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/mus/window_tree_host_mus.h"
#include "ui/aura/window.h"
#include "ui/base/ui_base_types.h"
#include "ui/display/display_list.h"
namespace ash {
namespace mus {
namespace {
bool IsFullscreen(aura::PropertyConverter* property_converter,
const std::vector<uint8_t>& transport_data) {
using ui::mojom::WindowManager;
aura::PropertyConverter::PrimitiveType show_state = 0;
return property_converter->GetPropertyValueFromTransportValue(
WindowManager::kShowState_Property, transport_data, &show_state) &&
(static_cast<ui::WindowShowState>(show_state) ==
ui::SHOW_STATE_FULLSCREEN);
}
} // namespace
RootWindowController::RootWindowController(
WindowManager* window_manager,
std::unique_ptr<aura::WindowTreeHostMus> window_tree_host,
const display::Display& display)
: window_manager_(window_manager),
window_tree_host_(std::move(window_tree_host)),
window_count_(0),
display_(display),
wm_shelf_(base::MakeUnique<WmShelfMus>()) {
wm_root_window_controller_ = base::MakeUnique<WmRootWindowControllerMus>(
window_manager_->shell(), this);
wm_root_window_controller_->CreateContainers();
wm_root_window_controller_->CreateLayoutManagers();
parenting_client_ = base::MakeUnique<StackingController>();
aura::client::SetWindowParentingClient(root(), parenting_client_.get());
disconnected_app_handler_.reset(new DisconnectedAppHandler(root()));
// Force a layout of the root, and its children, RootWindowLayout handles
// both.
wm_root_window_controller_->root_window_layout_manager()->OnWindowResized();
for (size_t i = 0; i < kNumActivatableShellWindowIds; ++i) {
window_manager_->window_manager_client()->AddActivationParent(
GetWindowByShellWindowId(kActivatableShellWindowIds[i])->aura_window());
}
}
RootWindowController::~RootWindowController() {
Shutdown();
// Destroy WindowTreeHost last as it owns the root Window.
wm_shelf_.reset();
wm_root_window_controller_.reset();
window_tree_host_.reset();
}
void RootWindowController::Shutdown() {
// NOTE: Shutdown() may be called multiple times.
wm_root_window_controller_->ResetRootForNewWindowsIfNecessary();
wm_root_window_controller_->CloseChildWindows();
}
service_manager::Connector* RootWindowController::GetConnector() {
return window_manager_->connector();
}
aura::Window* RootWindowController::root() {
return window_tree_host_->window();
}
const aura::Window* RootWindowController::root() const {
return window_tree_host_->window();
}
aura::Window* RootWindowController::NewTopLevelWindow(
ui::mojom::WindowType window_type,
std::map<std::string, std::vector<uint8_t>>* properties) {
// TODO(sky): constrain and validate properties.
int32_t container_id = kShellWindowId_Invalid;
aura::Window* context = nullptr;
aura::Window* container_window = nullptr;
if (GetInitialContainerId(*properties, &container_id))
container_window = GetWindowByShellWindowId(container_id)->aura_window();
else
context = root();
gfx::Rect bounds = CalculateDefaultBounds(container_window, properties);
window_count_++;
const bool provide_non_client_frame =
window_type == ui::mojom::WindowType::WINDOW ||
window_type == ui::mojom::WindowType::PANEL;
if (provide_non_client_frame) {
(*properties)[ui::mojom::kWaitForUnderlay_Property].clear();
// See NonClientFrameController for details on lifetime.
NonClientFrameController* non_client_frame_controller =
new NonClientFrameController(container_window, context, bounds,
window_type, properties, window_manager_);
return non_client_frame_controller->window();
}
aura::Window* window = new aura::Window(nullptr);
aura::SetWindowType(window, window_type);
// Apply properties before Init(), that way they are sent to the server at
// the time the window is created.
aura::PropertyConverter* property_converter =
window_manager_->property_converter();
for (auto& property_pair : *properties) {
property_converter->SetPropertyFromTransportValue(
window, property_pair.first, &property_pair.second);
}
window->Init(ui::LAYER_TEXTURED);
window->SetBounds(bounds);
if (container_window) {
container_window->AddChild(window);
} else {
WmWindowMus* root = WmWindowMus::Get(this->root());
gfx::Point origin =
wm_root_window_controller_->ConvertPointToScreen(root, gfx::Point());
gfx::Rect bounds_in_screen(origin, bounds.size());
static_cast<WmWindowMus*>(
ash::wm::GetDefaultParent(WmWindowMus::Get(context),
WmWindowMus::Get(window), bounds_in_screen))
->aura_window()
->AddChild(window);
}
return window;
}
WmWindowMus* RootWindowController::GetWindowByShellWindowId(int id) {
return WmWindowMus::AsWmWindowMus(
WmWindowMus::Get(root())->GetChildByShellWindowId(id));
}
void RootWindowController::SetWorkAreaInests(const gfx::Insets& insets) {
gfx::Rect old_work_area = display_.work_area();
display_.UpdateWorkAreaFromInsets(insets);
if (old_work_area == display_.work_area())
return;
window_manager_->screen()->display_list().UpdateDisplay(display_);
// Push new display insets to service:ui if we have a connection.
auto* display_controller = window_manager_->GetDisplayController();
if (display_controller)
display_controller->SetDisplayWorkArea(display_.id(),
display_.bounds().size(), insets);
}
void RootWindowController::SetDisplay(const display::Display& display) {
DCHECK_EQ(display.id(), display_.id());
display_ = display;
window_manager_->screen()->display_list().UpdateDisplay(display_);
}
gfx::Rect RootWindowController::CalculateDefaultBounds(
aura::Window* container_window,
const std::map<std::string, std::vector<uint8_t>>* properties) const {
gfx::Rect requested_bounds;
if (GetInitialBounds(*properties, &requested_bounds))
return requested_bounds;
auto show_state_iter =
properties->find(ui::mojom::WindowManager::kShowState_Property);
if (show_state_iter != properties->end()) {
if (IsFullscreen(window_manager_->property_converter(),
show_state_iter->second)) {
gfx::Rect bounds(0, 0, root()->bounds().width(),
root()->bounds().height());
if (!container_window) {
bounds.Offset(display_.bounds().origin().x(),
display_.bounds().origin().y());
}
return bounds;
}
}
int width, height;
gfx::Size pref;
if (GetWindowPreferredSize(*properties, &pref) && !pref.IsEmpty()) {
// TODO(sky): likely want to constrain more than root size.
const gfx::Size max_size = root()->bounds().size();
width = std::max(0, std::min(max_size.width(), pref.width()));
height = std::max(0, std::min(max_size.height(), pref.height()));
} else {
width = root()->bounds().width() - 240;
height = root()->bounds().height() - 240;
}
return gfx::Rect(40 + (window_count_ % 4) * 40, 40 + (window_count_ % 4) * 40,
width, height);
}
} // namespace mus
} // namespace ash