1 // Copyright 2014 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 "remoting/host/chromeos/mouse_cursor_monitor_aura.h"
9 #include "base/callback.h"
10 #include "base/location.h"
11 #include "remoting/host/chromeos/skia_bitmap_desktop_frame.h"
12 #include "third_party/webrtc/modules/desktop_capture/mouse_cursor.h"
13 #include "ui/aura/env.h"
14 #include "ui/aura/window.h"
15 #include "ui/aura/window_tree_host.h"
16 #include "ui/base/cursor/cursors_aura.h"
20 // Creates an empty webrtc::MouseCursor. The caller is responsible for
21 // destroying the returned cursor.
22 webrtc::MouseCursor
* CreateEmptyMouseCursor() {
23 return new webrtc::MouseCursor(
24 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(0, 0)),
25 webrtc::DesktopVector(0, 0));
32 MouseCursorMonitorAura::MouseCursorMonitorAura()
34 mode_(SHAPE_AND_POSITION
) {
37 void MouseCursorMonitorAura::Init(Callback
* callback
, Mode mode
) {
45 void MouseCursorMonitorAura::Capture() {
46 // Check if the cursor is different.
47 gfx::NativeCursor cursor
=
48 ash::Shell::GetPrimaryRootWindow()->GetHost()->last_cursor();
50 if (cursor
!= last_cursor_
) {
51 last_cursor_
= cursor
;
52 NotifyCursorChanged(cursor
);
55 // Check if we need to update the location.
56 if (mode_
== SHAPE_AND_POSITION
) {
57 gfx::Point position
= aura::Env::GetInstance()->last_mouse_location();
58 if (position
!= last_mouse_location_
) {
59 last_mouse_location_
= position
;
60 callback_
->OnMouseCursorPosition(
61 INSIDE
, webrtc::DesktopVector(position
.x(), position
.y()));
66 void MouseCursorMonitorAura::NotifyCursorChanged(const ui::Cursor
& cursor
) {
67 scoped_ptr
<SkBitmap
> cursor_bitmap(new SkBitmap());
68 gfx::Point cursor_hotspot
;
70 if (cursor
.native_type() == ui::kCursorNone
) {
71 callback_
->OnMouseCursor(CreateEmptyMouseCursor());
75 if (!ui::GetCursorBitmap(cursor
, cursor_bitmap
.get(), &cursor_hotspot
)) {
76 LOG(ERROR
) << "Failed to load bitmap for cursor type:"
77 << cursor
.native_type();
78 callback_
->OnMouseCursor(CreateEmptyMouseCursor());
82 // There is a bug (crbug.com/436993) in aura::GetCursorBitmap() such that it
83 // it would return a scale-factor-100 bitmap with a scale-factor-200 hotspot.
84 // This causes the hotspot to go out of range. As a result, we would need to
85 // manually downscale the hotspot.
86 float scale_factor
= cursor
.device_scale_factor();
87 cursor_hotspot
.SetPoint(cursor_hotspot
.x() / scale_factor
,
88 cursor_hotspot
.y() / scale_factor
);
90 if (cursor_hotspot
.x() >= cursor_bitmap
->width() ||
91 cursor_hotspot
.y() >= cursor_bitmap
->height()) {
92 LOG(WARNING
) << "Cursor hotspot is out of bounds for type: "
93 << cursor
.native_type() << ". Setting to (0,0) instead";
94 cursor_hotspot
.SetPoint(0, 0);
97 scoped_ptr
<webrtc::DesktopFrame
> image(
98 SkiaBitmapDesktopFrame::Create(cursor_bitmap
.Pass()));
99 scoped_ptr
<webrtc::MouseCursor
> cursor_shape(new webrtc::MouseCursor(
101 webrtc::DesktopVector(cursor_hotspot
.x(), cursor_hotspot
.y())));
103 callback_
->OnMouseCursor(cursor_shape
.release());
106 } // namespace remoting