blob: 9032d1f1f4ee8fe94dd02a5f17b9d66b8fa4bb9b [file] [log] [blame]
// Copyright 2018 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/wm/window_finder.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/shell.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_grid.h"
#include "ash/wm/overview/overview_session.h"
#include "ash/wm/root_window_finder.h"
#include "services/ws/window_service.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/window.h"
#include "ui/aura/window_targeter.h"
#include "ui/events/event.h"
namespace {
// Returns true if |window| is considered to be a toplevel window.
bool IsTopLevelWindow(aura::Window* window) {
// ui::LAYER_TEXTURED is for non-mash environment. For Mash, browser windows
// are not with LAYER_TEXTURED but have a remote client.
return window->layer()->type() == ui::LAYER_TEXTURED ||
ws::WindowService::IsProxyWindow(window);
}
// Returns true if |window| can be a target at |screen_point| by |targeter|.
// If |targeter| is null, it will check with Window::GetEventHandlerForPoint().
bool IsWindowTargeted(aura::Window* window,
const gfx::Point& screen_point,
aura::WindowTargeter* targeter) {
aura::client::ScreenPositionClient* client =
aura::client::GetScreenPositionClient(window->GetRootWindow());
gfx::Point local_point = screen_point;
if (targeter) {
client->ConvertPointFromScreen(window->parent(), &local_point);
// TODO(mukai): consider the hittest differences between mouse and touch.
gfx::Point point_in_root = local_point;
aura::Window::ConvertPointToTarget(window, window->GetRootWindow(),
&point_in_root);
ui::MouseEvent event(ui::ET_MOUSE_MOVED, local_point, point_in_root,
base::TimeTicks::Now(), 0, 0);
return targeter->SubtreeShouldBeExploredForEvent(window, event);
}
// TODO(mukai): maybe we can remove this, simply return false if targeter does
// not exist.
client->ConvertPointFromScreen(window, &local_point);
return window->GetEventHandlerForPoint(local_point);
}
// Get the toplevel window at |screen_point| among the descendants of |window|.
aura::Window* GetTopmostWindowAtPointWithinWindow(
const gfx::Point& screen_point,
aura::Window* window,
aura::WindowTargeter* targeter,
const std::set<aura::Window*> ignore,
aura::Window** real_topmost) {
if (!window->IsVisible())
return nullptr;
if (window->id() == ash::kShellWindowId_PhantomWindow ||
window->id() == ash::kShellWindowId_OverlayContainer ||
window->id() == ash::kShellWindowId_MouseCursorContainer)
return nullptr;
if (IsTopLevelWindow(window)) {
if (IsWindowTargeted(window, screen_point, targeter)) {
if (real_topmost && !(*real_topmost))
*real_topmost = window;
return (ignore.find(window) == ignore.end()) ? window : nullptr;
}
return nullptr;
}
for (aura::Window::Windows::const_reverse_iterator i =
window->children().rbegin();
i != window->children().rend(); ++i) {
aura::WindowTargeter* child_targeter =
(*i)->targeter() ? (*i)->targeter() : targeter;
aura::Window* result = GetTopmostWindowAtPointWithinWindow(
screen_point, *i, child_targeter, ignore, real_topmost);
if (result)
return result;
}
return nullptr;
}
// Finds the top level window in overview that contains |screen_point| while
// ignoring |ignore|. Returns nullptr if there is no such window. Note the
// returned window might be a minimized window that's currently showing in
// overview.
aura::Window* GetToplevelWindowInOverviewAtPoint(
const gfx::Point& screen_point,
const std::set<aura::Window*>& ignore) {
ash::OverviewController* overview_controller =
ash::Shell::Get()->overview_controller();
if (!overview_controller->IsSelecting())
return nullptr;
ash::OverviewGrid* grid =
overview_controller->overview_session()->GetGridWithRootWindow(
ash::wm::GetRootWindowAt(screen_point));
if (!grid)
return nullptr;
aura::Window* window = grid->GetTargetWindowOnLocation(
gfx::PointF(screen_point), /*ignored_item=*/nullptr);
if (!window)
return nullptr;
window = window->GetToplevelWindow();
return (ignore.find(window) == ignore.end()) ? window : nullptr;
}
} // namespace
namespace ash {
namespace wm {
aura::Window* GetTopmostWindowAtPoint(const gfx::Point& screen_point,
const std::set<aura::Window*>& ignore,
aura::Window** real_topmost) {
if (real_topmost)
*real_topmost = nullptr;
aura::Window* root = GetRootWindowAt(screen_point);
// GetTopmostWindowAtPointWithinWindow() always needs to be called to update
// |real_topmost| correctly.
aura::Window* topmost_window = GetTopmostWindowAtPointWithinWindow(
screen_point, root, root->targeter(), ignore, real_topmost);
aura::Window* overview_window =
GetToplevelWindowInOverviewAtPoint(screen_point, ignore);
return overview_window ? overview_window : topmost_window;
}
} // namespace wm
} // namespace ash