1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/wm/drag_window_resizer.h"
#include <utility>
#include "ash/display/mouse_cursor_event_filter.h"
#include "ash/shell.h"
#include "ash/wm/drag_window_controller.h"
#include "ash/wm/window_positioning_utils.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/base/hit_test.h"
#include "ui/base/ui_base_types.h"
#include "ui/compositor/layer.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/wm/core/coordinate_conversion.h"
#include "ui/wm/core/cursor_manager.h"
#include "ui/wm/core/shadow_controller.h"
#include "ui/wm/core/window_util.h"
namespace ash {
// static
DragWindowResizer* DragWindowResizer::instance_ = nullptr;
DragWindowResizer::~DragWindowResizer() {
Shell* shell = Shell::Get();
if (window_state_) {
window_state_->DeleteDragDetails();
shell->shadow_controller()->UpdateShadowForWindow(window_state_->window());
}
shell->mouse_cursor_filter()->set_mouse_warp_enabled(true);
shell->mouse_cursor_filter()->HideSharedEdgeIndicator();
if (instance_ == this)
instance_ = nullptr;
}
void DragWindowResizer::Drag(const gfx::PointF& location, int event_flags) {
base::WeakPtr<DragWindowResizer> resizer(weak_ptr_factory_.GetWeakPtr());
next_window_resizer_->Drag(location, event_flags);
if (!resizer)
return;
last_mouse_location_ = location;
// Show a phantom window for dragging in another root window.
if (display::Screen::GetScreen()->GetNumDisplays() > 1)
UpdateDragWindow();
else
drag_window_controller_.reset();
}
void DragWindowResizer::CompleteDrag() {
EndDragImpl();
next_window_resizer_->CompleteDrag();
}
void DragWindowResizer::RevertDrag() {
drag_window_controller_.reset();
next_window_resizer_->RevertDrag();
}
void DragWindowResizer::FlingOrSwipe(ui::GestureEvent* event) {
EndDragImpl();
next_window_resizer_->FlingOrSwipe(event);
}
DragWindowResizer::DragWindowResizer(
std::unique_ptr<WindowResizer> next_window_resizer,
WindowState* window_state)
: WindowResizer(window_state),
next_window_resizer_(std::move(next_window_resizer)) {
// The pointer should be confined in one display during resizing a window
// because the window cannot span two displays at the same time anyway. The
// exception is window/tab dragging operation. During that operation, mouse
// warp is set so that the user can move a window/tab to another display.
MouseCursorEventFilter* mouse_cursor_filter =
Shell::Get()->mouse_cursor_filter();
mouse_cursor_filter->set_mouse_warp_enabled(ShouldAllowMouseWarp());
if (ShouldAllowMouseWarp())
mouse_cursor_filter->ShowSharedEdgeIndicator(GetTarget()->GetRootWindow());
Shell::Get()->shadow_controller()->UpdateShadowForWindow(GetTarget());
instance_ = this;
}
void DragWindowResizer::UpdateDragWindow() {
if (details().window_component != HTCAPTION || !ShouldAllowMouseWarp())
return;
if (!drag_window_controller_) {
drag_window_controller_ = std::make_unique<DragWindowController>(
GetTarget(), details().source == wm::WINDOW_MOVE_SOURCE_TOUCH);
}
drag_window_controller_->Update();
}
bool DragWindowResizer::ShouldAllowMouseWarp() {
return details().window_component == HTCAPTION &&
!::wm::GetTransientParent(GetTarget()) &&
window_util::IsWindowUserPositionable(GetTarget());
}
void DragWindowResizer::EndDragImpl() {
drag_window_controller_.reset();
// Check if the destination is another display.
if (details().source == wm::WINDOW_MOVE_SOURCE_TOUCH)
return;
aura::Window* root_window = GetTarget()->GetRootWindow();
// The |Display| object returned by |CursorManager::GetDisplay| may be stale,
// but will have the correct id.
// TODO(oshima): Change the API so |GetDisplay| just returns a display id.
const int64_t dst_display_id =
Shell::Get()->cursor_manager()->GetDisplay().id();
display::Screen* screen = display::Screen::GetScreen();
if (dst_display_id == screen->GetDisplayNearestWindow(root_window).id())
return;
// Adjust the size and position so that it doesn't exceed the size of work
// area.
display::Display dst_display;
// TODO(crbug.com/1131071): It's possible that |dst_display_id| returned from
// CursorManager::GetDisplay().id() is an invalid display id thus
// |dst_display| may be invalid as well. This may cause crash later. To avoid
// crash, we early return here. However, |dst_display_id| should never be
// invalid.
if (!screen->GetDisplayWithDisplayId(dst_display_id, &dst_display))
return;
const gfx::Size& size = dst_display.work_area().size();
gfx::Rect bounds = GetTarget()->bounds();
if (bounds.width() > size.width()) {
int diff = bounds.width() - size.width();
bounds.set_x(bounds.x() + diff / 2);
bounds.set_width(size.width());
}
if (bounds.height() > size.height())
bounds.set_height(size.height());
gfx::Rect dst_bounds = bounds;
::wm::ConvertRectToScreen(GetTarget()->parent(), &dst_bounds);
// Adjust the position so that the cursor is on the window.
gfx::Point last_mouse_location_in_screen =
gfx::ToRoundedPoint(last_mouse_location_);
::wm::ConvertPointToScreen(GetTarget()->parent(),
&last_mouse_location_in_screen);
if (!dst_bounds.Contains(last_mouse_location_in_screen)) {
if (last_mouse_location_in_screen.x() < dst_bounds.x())
dst_bounds.set_x(last_mouse_location_in_screen.x());
else if (last_mouse_location_in_screen.x() > dst_bounds.right())
dst_bounds.set_x(last_mouse_location_in_screen.x() - dst_bounds.width());
}
AdjustBoundsToEnsureMinimumWindowVisibility(dst_display.bounds(),
&dst_bounds);
GetTarget()->SetBoundsInScreen(dst_bounds, dst_display);
}
} // namespace ash
|