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 "ui/ozone/platform/drm/host/drm_cursor.h"
7 #include "base/thread_task_runner_handle.h"
8 #include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
9 #include "ui/gfx/geometry/point.h"
10 #include "ui/gfx/geometry/point_conversions.h"
11 #include "ui/gfx/geometry/point_f.h"
12 #include "ui/ozone/common/gpu/ozone_gpu_messages.h"
13 #include "ui/ozone/platform/drm/host/drm_window_host.h"
14 #include "ui/ozone/platform/drm/host/drm_window_host_manager.h"
16 #if defined(OS_CHROMEOS)
17 #include "ui/events/ozone/chromeos/cursor_controller.h"
22 DrmCursor::DrmCursor(DrmWindowHostManager
* window_manager
)
23 : window_manager_(window_manager
) {
26 DrmCursor::~DrmCursor() {
29 void DrmCursor::SetCursor(gfx::AcceleratedWidget window
,
30 PlatformCursor platform_cursor
) {
31 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
32 DCHECK_NE(window
, gfx::kNullAcceleratedWidget
);
34 scoped_refptr
<BitmapCursorOzone
> bitmap
=
35 BitmapCursorFactoryOzone::GetBitmapCursor(platform_cursor
);
37 base::AutoLock
lock(state_
.lock
);
38 if (state_
.window
!= window
|| state_
.bitmap
== bitmap
)
41 state_
.bitmap
= bitmap
;
43 SendCursorShowLocked();
46 void DrmCursor::OnWindowAdded(gfx::AcceleratedWidget window
,
47 const gfx::Rect
& bounds_in_screen
,
48 const gfx::Rect
& cursor_confined_bounds
) {
51 ui_task_runner_
= base::ThreadTaskRunnerHandle::Get();
53 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
54 base::AutoLock
lock(state_
.lock
);
56 if (state_
.window
== gfx::kNullAcceleratedWidget
) {
57 // First window added & cursor is not placed. Place it.
58 state_
.window
= window
;
59 state_
.display_bounds_in_screen
= bounds_in_screen
;
60 state_
.confined_bounds
= cursor_confined_bounds
;
61 SetCursorLocationLocked(cursor_confined_bounds
.CenterPoint());
65 void DrmCursor::OnWindowRemoved(gfx::AcceleratedWidget window
) {
66 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
67 base::AutoLock
lock(state_
.lock
);
69 if (state_
.window
== window
) {
70 // Try to find a new location for the cursor.
71 DrmWindowHost
* dest_window
= window_manager_
->GetPrimaryWindow();
74 state_
.window
= dest_window
->GetAcceleratedWidget();
75 state_
.display_bounds_in_screen
= dest_window
->GetBounds();
76 state_
.confined_bounds
= dest_window
->GetCursorConfinedBounds();
77 SetCursorLocationLocked(state_
.confined_bounds
.CenterPoint());
78 SendCursorShowLocked();
80 state_
.window
= gfx::kNullAcceleratedWidget
;
81 state_
.display_bounds_in_screen
= gfx::Rect();
82 state_
.confined_bounds
= gfx::Rect();
83 state_
.location
= gfx::Point();
88 void DrmCursor::CommitBoundsChange(
89 gfx::AcceleratedWidget window
,
90 const gfx::Rect
& new_display_bounds_in_screen
,
91 const gfx::Rect
& new_confined_bounds
) {
92 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
93 base::AutoLock
lock(state_
.lock
);
94 if (state_
.window
== window
) {
95 state_
.display_bounds_in_screen
= new_display_bounds_in_screen
;
96 state_
.confined_bounds
= new_confined_bounds
;
97 SetCursorLocationLocked(state_
.location
);
98 SendCursorShowLocked();
102 void DrmCursor::MoveCursorTo(gfx::AcceleratedWidget window
,
103 const gfx::PointF
& location
) {
104 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
105 base::AutoLock
lock(state_
.lock
);
106 gfx::AcceleratedWidget old_window
= state_
.window
;
108 if (window
!= old_window
) {
109 // When moving between displays, hide the cursor on the old display
110 // prior to showing it on the new display.
111 if (old_window
!= gfx::kNullAcceleratedWidget
)
112 SendCursorHideLocked();
114 DrmWindowHost
* drm_window_host
= window_manager_
->GetWindow(window
);
115 state_
.display_bounds_in_screen
= drm_window_host
->GetBounds();
116 state_
.confined_bounds
= drm_window_host
->GetCursorConfinedBounds();
117 state_
.window
= window
;
120 SetCursorLocationLocked(location
);
122 if (window
!= old_window
)
123 SendCursorShowLocked();
125 SendCursorMoveLocked();
128 void DrmCursor::MoveCursorTo(const gfx::PointF
& screen_location
) {
129 base::AutoLock
lock(state_
.lock
);
131 // TODO(spang): Moving between windows doesn't work here, but
132 // is not needed for current uses.
134 SetCursorLocationLocked(screen_location
-
135 state_
.display_bounds_in_screen
.OffsetFromOrigin());
137 SendCursorMoveLocked();
140 void DrmCursor::MoveCursor(const gfx::Vector2dF
& delta
) {
141 base::AutoLock
lock(state_
.lock
);
142 if (state_
.window
== gfx::kNullAcceleratedWidget
)
146 #if defined(OS_CHROMEOS)
147 gfx::Vector2dF transformed_delta
= delta
;
148 ui::CursorController::GetInstance()->ApplyCursorConfigForWindow(
149 state_
.window
, &transformed_delta
);
150 SetCursorLocationLocked(state_
.location
+ transformed_delta
);
152 SetCursorLocationLocked(state_
.location
+ delta
);
155 SendCursorMoveLocked();
158 bool DrmCursor::IsCursorVisible() {
159 base::AutoLock
lock(state_
.lock
);
160 return state_
.bitmap
;
163 gfx::PointF
DrmCursor::GetLocation() {
164 base::AutoLock
lock(state_
.lock
);
165 return state_
.location
+ state_
.display_bounds_in_screen
.OffsetFromOrigin();
168 gfx::Rect
DrmCursor::GetCursorConfinedBounds() {
169 base::AutoLock
lock(state_
.lock
);
170 return state_
.confined_bounds
+
171 state_
.display_bounds_in_screen
.OffsetFromOrigin();
174 void DrmCursor::OnChannelEstablished(
176 scoped_refptr
<base::SingleThreadTaskRunner
> send_runner
,
177 const base::Callback
<void(IPC::Message
*)>& send_callback
) {
179 if (!ui_task_runner_
)
180 ui_task_runner_
= base::ThreadTaskRunnerHandle::Get();
182 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
183 base::AutoLock
lock(state_
.lock
);
184 state_
.host_id
= host_id
;
185 state_
.send_runner
= send_runner
;
186 state_
.send_callback
= send_callback
;
187 // Initial set for this GPU process will happen after the window
188 // initializes, in CommitBoundsChange().
191 void DrmCursor::OnChannelDestroyed(int host_id
) {
192 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
193 base::AutoLock
lock(state_
.lock
);
194 if (state_
.host_id
== host_id
) {
196 state_
.send_runner
= NULL
;
197 state_
.send_callback
.Reset();
201 bool DrmCursor::OnMessageReceived(const IPC::Message
& message
) {
205 void DrmCursor::SetCursorLocationLocked(const gfx::PointF
& location
) {
206 state_
.lock
.AssertAcquired();
208 gfx::PointF clamped_location
= location
;
209 clamped_location
.SetToMax(state_
.confined_bounds
.origin());
210 // Right and bottom edges are exclusive.
211 clamped_location
.SetToMin(gfx::PointF(state_
.confined_bounds
.right() - 1,
212 state_
.confined_bounds
.bottom() - 1));
214 state_
.location
= clamped_location
;
217 gfx::Point
DrmCursor::GetBitmapLocationLocked() {
218 return gfx::ToFlooredPoint(state_
.location
) -
219 state_
.bitmap
->hotspot().OffsetFromOrigin();
222 bool DrmCursor::IsConnectedLocked() {
223 return !state_
.send_callback
.is_null();
226 void DrmCursor::SendCursorShowLocked() {
227 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
228 if (!state_
.bitmap
) {
229 SendCursorHideLocked();
232 SendLocked(new OzoneGpuMsg_CursorSet(state_
.window
, state_
.bitmap
->bitmaps(),
233 GetBitmapLocationLocked(),
234 state_
.bitmap
->frame_delay_ms()));
237 void DrmCursor::SendCursorHideLocked() {
238 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
239 SendLocked(new OzoneGpuMsg_CursorSet(state_
.window
, std::vector
<SkBitmap
>(),
243 void DrmCursor::SendCursorMoveLocked() {
247 new OzoneGpuMsg_CursorMove(state_
.window
, GetBitmapLocationLocked()));
250 void DrmCursor::SendLocked(IPC::Message
* message
) {
251 state_
.lock
.AssertAcquired();
253 if (IsConnectedLocked() &&
254 state_
.send_runner
->PostTask(FROM_HERE
,
255 base::Bind(state_
.send_callback
, message
)))
258 // Drop disconnected updates. DrmWindowHost will call CommitBoundsChange()
260 // we connect to initialize the cursor location.
264 DrmCursor::CursorState::CursorState()
265 : window(gfx::kNullAcceleratedWidget
), host_id(-1) {
268 DrmCursor::CursorState::~CursorState() {