blob: 3df58d117b50d198c71620dd45f7f5d67e279708 [file] [log] [blame]
// Copyright 2017 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 "ui/wm/core/ime_util_chromeos.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/mus/window_mus.h"
#include "ui/base/ui_base_switches.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/wm/core/coordinate_conversion.h"
namespace wm {
namespace {
void SetWindowBoundsInScreen(aura::Window* window,
const gfx::Rect& bounds_in_screen) {
window->SetBoundsInScreen(
bounds_in_screen,
display::Screen::GetScreen()->GetDisplayNearestView(window));
}
// Moves the window to ensure caret not in rect.
// Returns whether the window was moved or not.
void MoveWindowToEnsureCaretNotInRect(aura::Window* window,
const gfx::Rect& rect_in_screen) {
gfx::Rect original_window_bounds = window->GetBoundsInScreen();
if (window->GetProperty(kVirtualKeyboardRestoreBoundsKey)) {
original_window_bounds =
*window->GetProperty(kVirtualKeyboardRestoreBoundsKey);
}
// Calculate vertical window shift.
const int top_y =
std::max(rect_in_screen.y() - original_window_bounds.height(),
display::Screen::GetScreen()
->GetDisplayNearestView(window)
.work_area()
.y());
// No need to move the window up.
if (top_y >= original_window_bounds.y())
return;
// Set restore bounds and move the window.
window->SetProperty(kVirtualKeyboardRestoreBoundsKey,
new gfx::Rect(original_window_bounds));
gfx::Rect new_bounds_in_screen = original_window_bounds;
new_bounds_in_screen.set_y(top_y);
SetWindowBoundsInScreen(window, new_bounds_in_screen);
}
} // namespace
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Rect,
kVirtualKeyboardRestoreBoundsKey,
nullptr)
void RestoreWindowBoundsOnClientFocusLost(aura::Window* window) {
window->GetRootWindow()->ClearProperty(
aura::client::kEmbeddedWindowEnsureNotInRect);
// Get restore bounds of the window
gfx::Rect* vk_restore_bounds =
window->GetProperty(kVirtualKeyboardRestoreBoundsKey);
if (!vk_restore_bounds)
return;
// Restore the window bounds
// TODO(yhanada): Don't move the window if a user has moved it while the
// keyboard is shown.
if (window->GetBoundsInScreen() != *vk_restore_bounds) {
SetWindowBoundsInScreen(window, *vk_restore_bounds);
}
window->ClearProperty(wm::kVirtualKeyboardRestoreBoundsKey);
}
void EnsureWindowNotInRect(aura::Window* window,
const gfx::Rect& rect_in_screen) {
// If |window| is embedded, the move should happen at the embedding side.
if (auto* window_mus = aura::WindowMus::Get(window->GetRootWindow())) {
if (window_mus->window_mus_type() == aura::WindowMusType::EMBED) {
window->GetRootWindow()->SetProperty(
aura::client::kEmbeddedWindowEnsureNotInRect,
new gfx::Rect(rect_in_screen));
return;
}
}
gfx::Rect original_window_bounds = window->GetBoundsInScreen();
if (window->GetProperty(wm::kVirtualKeyboardRestoreBoundsKey)) {
original_window_bounds =
*window->GetProperty(wm::kVirtualKeyboardRestoreBoundsKey);
}
gfx::Rect hidden_window_bounds_in_screen =
gfx::IntersectRects(rect_in_screen, original_window_bounds);
if (hidden_window_bounds_in_screen.IsEmpty()) {
// The window isn't covered by the keyboard, restore the window position if
// necessary.
RestoreWindowBoundsOnClientFocusLost(window);
return;
}
MoveWindowToEnsureCaretNotInRect(window, rect_in_screen);
}
EnsureWindowNotInRectHelper::EnsureWindowNotInRectHelper(
aura::Window* embedding_root)
: embedding_root_(embedding_root) {
embedding_root_->AddObserver(this);
}
EnsureWindowNotInRectHelper::~EnsureWindowNotInRectHelper() {
if (embedding_root_)
embedding_root_->RemoveObserver(this);
}
void EnsureWindowNotInRectHelper::OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) {
DCHECK_EQ(embedding_root_, window);
if (key != aura::client::kEmbeddedWindowEnsureNotInRect)
return;
aura::Window* top_level = embedding_root_->GetToplevelWindow();
gfx::Rect* rect_in_screen = embedding_root_->GetProperty(
aura::client::kEmbeddedWindowEnsureNotInRect);
if (rect_in_screen)
EnsureWindowNotInRect(top_level, *rect_in_screen);
else
RestoreWindowBoundsOnClientFocusLost(top_level);
}
void EnsureWindowNotInRectHelper::OnWindowDestroyed(aura::Window* window) {
DCHECK_EQ(embedding_root_, window);
embedding_root_ = nullptr;
}
} // namespace wm