1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/wm/partial_screenshot_view.h"
9 #include "ash/display/mouse_cursor_event_filter.h"
10 #include "ash/screenshot_delegate.h"
11 #include "ash/shell.h"
12 #include "ash/shell_window_ids.h"
13 #include "ash/wm/overlay_event_filter.h"
14 #include "ui/aura/client/capture_client.h"
15 #include "ui/aura/root_window.h"
16 #include "ui/base/cursor/cursor.h"
17 #include "ui/base/events/event.h"
18 #include "ui/gfx/canvas.h"
19 #include "ui/gfx/rect.h"
20 #include "ui/views/view.h"
21 #include "ui/views/widget/widget.h"
22 #include "ui/views/widget/widget_observer.h"
26 // A self-owned object to handle the cancel and the finish of current partial
27 // screenshot session.
28 class PartialScreenshotView::OverlayDelegate
29 : public internal::OverlayEventFilter::Delegate
,
30 public views::WidgetObserver
{
33 Shell::GetInstance()->overlay_filter()->Activate(this);
36 void RegisterWidget(views::Widget
* widget
) {
37 widgets_
.push_back(widget
);
38 widget
->AddObserver(this);
41 // Overridden from OverlayEventFilter::Delegate:
42 virtual void Cancel() OVERRIDE
{
43 // Make sure the mouse_warp_mode allows warping. It can be stopped by a
44 // partial screenshot view.
45 internal::MouseCursorEventFilter
* mouse_cursor_filter
=
46 Shell::GetInstance()->mouse_cursor_filter();
47 mouse_cursor_filter
->set_mouse_warp_mode(
48 internal::MouseCursorEventFilter::WARP_ALWAYS
);
49 for (size_t i
= 0; i
< widgets_
.size(); ++i
)
53 virtual bool IsCancelingKeyEvent(ui::KeyEvent
* event
) OVERRIDE
{
54 return event
->key_code() == ui::VKEY_ESCAPE
;
57 virtual aura::Window
* GetWindow() OVERRIDE
{
58 // Just returns NULL because this class does not handle key events in
59 // OverlayEventFilter, except for cancel keys.
63 // Overridden from views::WidgetObserver:
64 virtual void OnWidgetDestroying(views::Widget
* widget
) OVERRIDE
{
65 widget
->RemoveObserver(this);
66 widgets_
.erase(std::remove(widgets_
.begin(), widgets_
.end(), widget
));
72 virtual ~OverlayDelegate() {
73 Shell::GetInstance()->overlay_filter()->Deactivate();
76 std::vector
<views::Widget
*> widgets_
;
78 DISALLOW_COPY_AND_ASSIGN(OverlayDelegate
);
82 std::vector
<PartialScreenshotView
*>
83 PartialScreenshotView::StartPartialScreenshot(
84 ScreenshotDelegate
* screenshot_delegate
) {
85 std::vector
<PartialScreenshotView
*> views
;
86 OverlayDelegate
* overlay_delegate
= new OverlayDelegate();
87 Shell::RootWindowList root_windows
= Shell::GetAllRootWindows();
88 for (Shell::RootWindowList::iterator it
= root_windows
.begin();
89 it
!= root_windows
.end(); ++it
) {
90 PartialScreenshotView
* new_view
= new PartialScreenshotView(
91 overlay_delegate
, screenshot_delegate
);
93 views
.push_back(new_view
);
98 PartialScreenshotView::PartialScreenshotView(
99 PartialScreenshotView::OverlayDelegate
* overlay_delegate
,
100 ScreenshotDelegate
* screenshot_delegate
)
101 : is_dragging_(false),
102 overlay_delegate_(overlay_delegate
),
103 screenshot_delegate_(screenshot_delegate
) {
106 PartialScreenshotView::~PartialScreenshotView() {
107 overlay_delegate_
= NULL
;
108 screenshot_delegate_
= NULL
;
111 void PartialScreenshotView::Init(aura::RootWindow
* root_window
) {
112 views::Widget
* widget
= new views::Widget
;
113 views::Widget::InitParams
params(
114 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS
);
115 params
.transparent
= true;
116 params
.delegate
= this;
117 // The partial screenshot rectangle has to be at the real top of
119 params
.parent
= Shell::GetContainer(
121 internal::kShellWindowId_OverlayContainer
);
123 widget
->Init(params
);
124 widget
->SetContentsView(this);
125 widget
->SetBounds(root_window
->GetBoundsInScreen());
126 widget
->GetNativeView()->SetName("PartialScreenshotView");
127 widget
->StackAtTop();
129 // Releases the mouse capture to let mouse events come to the view. This
130 // will close the context menu.
131 aura::client::CaptureClient
* capture_client
=
132 aura::client::GetCaptureClient(root_window
);
133 if (capture_client
->GetCaptureWindow())
134 capture_client
->ReleaseCapture(capture_client
->GetCaptureWindow());
136 overlay_delegate_
->RegisterWidget(widget
);
139 gfx::Rect
PartialScreenshotView::GetScreenshotRect() const {
140 int left
= std::min(start_position_
.x(), current_position_
.x());
141 int top
= std::min(start_position_
.y(), current_position_
.y());
142 int width
= ::abs(start_position_
.x() - current_position_
.x());
143 int height
= ::abs(start_position_
.y() - current_position_
.y());
144 return gfx::Rect(left
, top
, width
, height
);
147 void PartialScreenshotView::OnSelectionStarted(const gfx::Point
& position
) {
148 start_position_
= position
;
151 void PartialScreenshotView::OnSelectionChanged(const gfx::Point
& position
) {
152 if (is_dragging_
&& current_position_
== position
)
154 current_position_
= position
;
159 void PartialScreenshotView::OnSelectionFinished() {
160 overlay_delegate_
->Cancel();
164 is_dragging_
= false;
165 if (screenshot_delegate_
) {
166 aura::RootWindow
*root_window
=
167 GetWidget()->GetNativeWindow()->GetRootWindow();
168 screenshot_delegate_
->HandleTakePartialScreenshot(
170 gfx::IntersectRects(root_window
->bounds(), GetScreenshotRect()));
174 gfx::NativeCursor
PartialScreenshotView::GetCursor(
175 const ui::MouseEvent
& event
) {
176 // Always use "crosshair" cursor.
177 return ui::kCursorCross
;
180 void PartialScreenshotView::OnPaint(gfx::Canvas
* canvas
) {
182 // Screenshot area representation: black rectangle with white
183 // rectangle inside. To avoid capturing these rectangles when mouse
184 // release, they should be outside of the actual capturing area.
185 gfx::Rect screenshot_rect
= GetScreenshotRect();
186 screenshot_rect
.Inset(-1, -1, -1, -1);
187 canvas
->DrawRect(screenshot_rect
, SK_ColorWHITE
);
188 screenshot_rect
.Inset(-1, -1, -1, -1);
189 canvas
->DrawRect(screenshot_rect
, SK_ColorBLACK
);
193 bool PartialScreenshotView::OnMousePressed(const ui::MouseEvent
& event
) {
194 // Prevent moving across displays during drag. Capturing a screenshot across
195 // the displays is not supported yet.
196 // TODO(mukai): remove this restriction.
197 internal::MouseCursorEventFilter
* mouse_cursor_filter
=
198 Shell::GetInstance()->mouse_cursor_filter();
199 mouse_cursor_filter
->set_mouse_warp_mode(
200 internal::MouseCursorEventFilter::WARP_NONE
);
201 OnSelectionStarted(event
.location());
205 bool PartialScreenshotView::OnMouseDragged(const ui::MouseEvent
& event
) {
206 OnSelectionChanged(event
.location());
210 bool PartialScreenshotView::OnMouseWheel(const ui::MouseWheelEvent
& event
) {
211 // Do nothing but do not propagate events futhermore.
215 void PartialScreenshotView::OnMouseReleased(const ui::MouseEvent
& event
) {
216 OnSelectionFinished();
219 void PartialScreenshotView::OnMouseCaptureLost() {
220 is_dragging_
= false;
221 OnSelectionFinished();
224 void PartialScreenshotView::OnGestureEvent(ui::GestureEvent
* event
) {
225 switch(event
->type()) {
226 case ui::ET_GESTURE_TAP_DOWN
:
227 OnSelectionStarted(event
->location());
229 case ui::ET_GESTURE_SCROLL_UPDATE
:
230 OnSelectionChanged(event
->location());
232 case ui::ET_GESTURE_SCROLL_END
:
233 case ui::ET_SCROLL_FLING_START
:
234 OnSelectionFinished();