Skip to content

Commit

Permalink
wm_mode: Hook up the pie menu
Browse files Browse the repository at this point in the history
When the WM mode is active, a mouse or touch release triggers the
window selection. Once a window is selected, the pie menu should
be shown, and its bounds should be refreshed.

Demo: https://b.corp.google.com/issues/296462416#comment2

Fixed: b/296462416
Test: Manually, unit test

Change-Id: If3354e0fcca7289aac3f7017f3e81f4978687376
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4791312
Reviewed-by: James Cook <jamescook@chromium.org>
Commit-Queue: Ahmed Fakhry <afakhry@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1185244}
  • Loading branch information
Ahmed Fakhry authored and Chromium LUCI CQ committed Aug 18, 2023
1 parent 56c6a0d commit f3dc293
Show file tree
Hide file tree
Showing 7 changed files with 344 additions and 18 deletions.
3 changes: 3 additions & 0 deletions ash/resources/vector_icons/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,9 @@ aggregate_vector_icons("ash_vector_icons") {
"visibility.icon",
"visibility_off.icon",
"wallpaper.icon",
"wm_mode_gesture_move_to_desk.icon",
"wm_mode_gesture_resize.icon",
"wm_mode_gesture_snap.icon",
"wm_mode_off.icon",
"wm_mode_on.icon",
"zoom_in.icon",
Expand Down
38 changes: 38 additions & 0 deletions ash/resources/vector_icons/wm_mode_gesture_move_to_desk.icon
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

CANVAS_DIMENSIONS, 24,
MOVE_TO, 4, 20,
R_ARC_TO, 1.99f, 1.99f, 0, 0, 1, -1.42f, -0.57f,
ARC_TO, 1.99f, 1.99f, 0, 0, 1, 2, 18,
R_V_LINE_TO, -3,
R_H_LINE_TO, 2,
R_V_LINE_TO, 3,
R_H_LINE_TO, 16,
V_LINE_TO, 6,
H_LINE_TO, 4,
R_V_LINE_TO, 3,
H_LINE_TO, 2,
V_LINE_TO, 6,
R_CUBIC_TO, 0, -0.55f, 0.19f, -1.02f, 0.57f, -1.4f,
R_CUBIC_TO, 0.4f, -0.4f, 0.88f, -0.6f, 1.43f, -0.6f,
R_H_LINE_TO, 16,
R_CUBIC_TO, 0.55f, 0, 1.02f, 0.2f, 1.4f, 0.6f,
R_CUBIC_TO, 0.4f, 0.38f, 0.6f, 0.85f, 0.6f, 1.4f,
R_V_LINE_TO, 12,
R_CUBIC_TO, 0, 0.55f, -0.2f, 1.02f, -0.6f, 1.43f,
R_CUBIC_TO, -0.38f, 0.38f, -0.85f, 0.57f, -1.4f, 0.57f,
H_LINE_TO, 4,
CLOSE,
R_MOVE_TO, 7.5f, -3.5f,
R_LINE_TO, -1.4f, -1.45f,
LINE_TO, 12.18f, 13,
H_LINE_TO, 2,
R_V_LINE_TO, -2,
R_H_LINE_TO, 10.18f,
LINE_TO, 10.1f, 8.95f,
R_LINE_TO, 1.4f, -1.45f,
LINE_TO, 16, 12,
R_LINE_TO, -4.5f, 4.5f,
CLOSE
42 changes: 42 additions & 0 deletions ash/resources/vector_icons/wm_mode_gesture_resize.icon
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

CANVAS_DIMENSIONS, 24,
MOVE_TO, 5, 9,
R_V_LINE_TO, 5,
R_H_LINE_TO, 2,
R_V_LINE_TO, -3,
R_H_LINE_TO, 3,
V_LINE_TO, 9,
H_LINE_TO, 5,
CLOSE,
R_MOVE_TO, 14, 3,
R_V_LINE_TO, 5,
R_H_LINE_TO, -5,
R_V_LINE_TO, -2,
R_H_LINE_TO, 3,
R_V_LINE_TO, -3,
R_H_LINE_TO, 2,
CLOSE,
NEW_PATH,
MOVE_TO, 4, 20,
R_ARC_TO, 1.99f, 1.99f, 0, 0, 1, -1.42f, -0.57f,
ARC_TO, 1.99f, 1.99f, 0, 0, 1, 2, 18,
V_LINE_TO, 6,
R_CUBIC_TO, 0, -0.55f, 0.19f, -1.02f, 0.57f, -1.4f,
R_CUBIC_TO, 0.4f, -0.4f, 0.88f, -0.6f, 1.43f, -0.6f,
R_H_LINE_TO, 16,
R_CUBIC_TO, 0.55f, 0, 1.02f, 0.2f, 1.4f, 0.6f,
R_CUBIC_TO, 0.4f, 0.38f, 0.6f, 0.85f, 0.6f, 1.4f,
R_V_LINE_TO, 12,
R_CUBIC_TO, 0, 0.55f, -0.2f, 1.02f, -0.6f, 1.43f,
R_CUBIC_TO, -0.38f, 0.38f, -0.85f, 0.57f, -1.4f, 0.57f,
H_LINE_TO, 4,
CLOSE,
R_MOVE_TO, 0, -2,
R_H_LINE_TO, 16,
V_LINE_TO, 8,
H_LINE_TO, 4,
R_V_LINE_TO, 10,
CLOSE
32 changes: 32 additions & 0 deletions ash/resources/vector_icons/wm_mode_gesture_snap.icon
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

CANVAS_DIMENSIONS, 24,
MOVE_TO, 12, 7,
H_LINE_TO, 5,
R_V_LINE_TO, 10,
R_H_LINE_TO, 7,
V_LINE_TO, 7,
CLOSE,
NEW_PATH,
MOVE_TO, 2.58f, 19.43f,
R_CUBIC_TO, 0.4f, 0.38f, 0.88f, 0.57f, 1.43f, 0.57f,
R_H_LINE_TO, 16,
R_CUBIC_TO, 0.55f, 0, 1.02f, -0.19f, 1.4f, -0.57f,
R_CUBIC_TO, 0.4f, -0.4f, 0.6f, -0.87f, 0.6f, -1.42f,
V_LINE_TO, 6,
R_CUBIC_TO, 0, -0.55f, -0.2f, -1.02f, -0.6f, -1.4f,
R_CUBIC_TO, -0.38f, -0.4f, -0.85f, -0.6f, -1.4f, -0.6f,
H_LINE_TO, 4,
R_CUBIC_TO, -0.55f, 0, -1.02f, 0.2f, -1.42f, 0.6f,
CUBIC_TO, 2.19f, 4.98f, 2, 5.45f, 2, 6,
R_V_LINE_TO, 12,
R_CUBIC_TO, 0, 0.55f, 0.19f, 1.02f, 0.57f, 1.43f,
CLOSE,
MOVE_TO, 20, 6,
R_V_LINE_TO, 12,
H_LINE_TO, 4,
V_LINE_TO, 6,
R_H_LINE_TO, 16,
CLOSE
156 changes: 142 additions & 14 deletions ash/wm_mode/wm_mode_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@
#include "ash/capture_mode/capture_mode_util.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/public/cpp/window_finder.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/style/ash_color_id.h"
#include "ash/system/status_area_widget.h"
#include "ash/wm/desks/desks_util.h"
#include "ash/wm/window_dimmer.h"
#include "ash/wm_mode/pie_menu_view.h"
#include "ash/wm_mode/wm_mode_button_tray.h"
#include "base/auto_reset.h"
#include "base/check.h"
#include "base/check_op.h"
#include "third_party/skia/include/core/SkColor.h"
Expand All @@ -28,6 +31,14 @@ namespace ash {

namespace {

enum PieMenuButtonIds {
kSnapButtonId = 0,
kMoveToDeskButtonId = 1,
kResizeButtonId = 2,
};

constexpr gfx::Size kPieMenuSize{300, 300};

WmModeController* g_instance = nullptr;

// The color used to highlight a selected window on hover or tap.
Expand All @@ -45,6 +56,18 @@ std::unique_ptr<WindowDimmer> CreateDimmerForRoot(aura::Window* root) {
return dimmer;
}

gfx::Rect GetPieMenuScreenBounds(const gfx::Point& center_point_in_screen,
aura::Window* current_root) {
CHECK(current_root);

gfx::Rect bounds(
gfx::Point(center_point_in_screen.x() - kPieMenuSize.width() / 2,
center_point_in_screen.y() - kPieMenuSize.height() / 2),
kPieMenuSize);
bounds.AdjustToFit(current_root->GetBoundsInScreen());
return bounds;
}

} // namespace

WmModeController::WmModeController() {
Expand Down Expand Up @@ -84,7 +107,11 @@ void WmModeController::Toggle() {
this, ui::EventTarget::Priority::kSystem);
CreateLayer();
MaybeChangeRoot(capture_mode_util::GetPreferredRootWindow());
BuildPieMenu();
} else {
SetSelectedWindow(nullptr);
pie_menu_widget_.reset();
pie_menu_view_ = nullptr;
ReleaseLayer();
DCHECK(!layer());
current_root_ = nullptr;
Expand Down Expand Up @@ -125,6 +152,13 @@ void WmModeController::OnPaintLayer(const ui::PaintContext& context) {
canvas->FillRect(selected_window_->bounds(), kSelectedWindowHighlightColor);
}

void WmModeController::OnWindowDestroying(aura::Window* window) {
CHECK_EQ(window, selected_window_);
SetSelectedWindow(nullptr);
}

void WmModeController::OnPieMenuButtonPressed(int button_id) {}

bool WmModeController::IsRootWindowDimmedForTesting(aura::Window* root) const {
return dimmers_.contains(root);
}
Expand All @@ -151,11 +185,15 @@ void WmModeController::UpdateTrayButtons() {

void WmModeController::OnLocatedEvent(ui::LocatedEvent* event) {
auto* target = static_cast<aura::Window*>(event->target());

// Let events targeting the pie menu (if available) go through.
if (IsTargetingPieMenu(target)) {
return;
}

gfx::Point screen_location = event->root_location();
wm::ConvertPointToScreen(target->GetRootWindow(), &screen_location);

MaybeChangeRoot(capture_mode_util::GetPreferredRootWindow(screen_location));

// Let events on the WM Mode tray button go through.
auto* status_area_widget =
StatusAreaWidget::ForWindow(target->GetRootWindow());
Expand All @@ -167,19 +205,19 @@ void WmModeController::OnLocatedEvent(ui::LocatedEvent* event) {
event->StopPropagation();
event->SetHandled();

// Only consider top-most desk windows (i.e. ignore always-on-top, PIP,
// and Floated windows) for now.
auto* top_most_window = GetTopmostWindowAtPoint(screen_location, {});
if (top_most_window &&
!desks_util::GetDeskContainerForContext(top_most_window)) {
top_most_window = nullptr;
const bool is_release = event->type() == ui::ET_MOUSE_RELEASED ||
event->type() == ui::ET_TOUCH_RELEASED;
if (!is_release) {
return;
}

// Only repaint if there's a change in the selected window.
if (selected_window_ != top_most_window) {
selected_window_ = top_most_window;
layer()->SchedulePaint(layer()->bounds());
}
base::AutoReset<absl::optional<gfx::Point>> reset_release_location(
&last_release_event_screen_point_, screen_location);

MaybeChangeRoot(capture_mode_util::GetPreferredRootWindow(screen_location));

auto* top_most_window = GetTopMostWindowAtPoint(screen_location);
SetSelectedWindow(top_most_window);
}

void WmModeController::CreateLayer() {
Expand All @@ -201,9 +239,99 @@ void WmModeController::MaybeChangeRoot(aura::Window* new_root) {
return;

current_root_ = new_root;
auto* parent = new_root->GetChildById(kShellWindowId_OverlayContainer);
auto* parent = new_root->GetChildById(kShellWindowId_MenuContainer);
parent->layer()->Add(layer());
layer()->SetBounds(parent->bounds());

SetSelectedWindow(nullptr);
}

void WmModeController::SetSelectedWindow(aura::Window* window) {
if (selected_window_ != window) {
if (selected_window_) {
selected_window_->RemoveObserver(this);
}

selected_window_ = window;

if (selected_window_) {
selected_window_->AddObserver(this);
}

ScheduleRepaint();
}

MaybeRefreshPieMenu();
}

void WmModeController::ScheduleRepaint() {
CHECK(layer());
layer()->SchedulePaint(layer()->bounds());
}

void WmModeController::BuildPieMenu() {
DCHECK(!pie_menu_widget_);
DCHECK(current_root_);

pie_menu_widget_ = std::make_unique<views::Widget>();
views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
params.parent = current_root_->GetChildById(kShellWindowId_MenuContainer);
params.bounds = gfx::Rect(kPieMenuSize);
params.name = "WmModePieMenuWidget";
pie_menu_widget_->Init(std::move(params));
pie_menu_view_ = pie_menu_widget_->SetContentsView(
std::make_unique<PieMenuView>(/*delegate=*/this));

// TODO(b/252558235): Localize once approved.
pie_menu_view_->main_menu_container()->AddMenuButton(
kSnapButtonId, u"Snap window", &kWmModeGestureSnapIcon);
pie_menu_view_->main_menu_container()->AddMenuButton(
kMoveToDeskButtonId, u"Move to desk", &kWmModeGestureMoveToDeskIcon);
pie_menu_view_->main_menu_container()->AddMenuButton(
kResizeButtonId, u"Resize window", &kWmModeGestureResizeIcon);

// TODO(b/296464906): Add the sub menu buttons for the move-to-desk menu item.
}

bool WmModeController::IsTargetingPieMenu(aura::Window* event_target) const {
return pie_menu_widget_ && pie_menu_widget_->IsVisible() &&
pie_menu_widget_->GetNativeWindow()->Contains(event_target);
}

aura::Window* WmModeController::GetTopMostWindowAtPoint(
const gfx::Point& screen_location) const {
// Ignore the pie menu if it's available.
std::set<aura::Window*> windows_to_ignore;
if (pie_menu_widget_) {
windows_to_ignore.insert(pie_menu_widget_->GetNativeWindow());
}
auto* top_most_window =
GetTopmostWindowAtPoint(screen_location, windows_to_ignore);
// Only consider top-most desk windows (i.e. ignore always-on-top, PIP,
// and Floated windows) for now.
if (top_most_window &&
!desks_util::GetDeskContainerForContext(top_most_window)) {
top_most_window = nullptr;
}
return top_most_window;
}

void WmModeController::MaybeRefreshPieMenu() {
if (!pie_menu_widget_) {
return;
}

if (!selected_window_) {
pie_menu_widget_->Hide();
return;
}

pie_menu_widget_->SetBounds(GetPieMenuScreenBounds(
last_release_event_screen_point_.value_or(
selected_window_->GetBoundsInScreen().CenterPoint()),
current_root_));
pie_menu_widget_->Show();
}

} // namespace ash

0 comments on commit f3dc293

Please sign in to comment.