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.
4
5#include "ash/wm/ash_native_cursor_manager.h"
6
7#include "ash/display/cursor_window_controller.h"
8#include "ash/display/display_controller.h"
9#include "ash/shell.h"
10#include "base/logging.h"
11#include "ui/aura/env.h"
12#include "ui/aura/window_event_dispatcher.h"
13#include "ui/aura/window_tree_host.h"
14#include "ui/base/cursor/cursor.h"
15#include "ui/base/cursor/image_cursors.h"
16#include "ui/base/layout.h"
17
18namespace ash {
19namespace  {
20
21void SetCursorOnAllRootWindows(gfx::NativeCursor cursor) {
22  aura::Window::Windows root_windows =
23      Shell::GetInstance()->GetAllRootWindows();
24  for (aura::Window::Windows::iterator iter = root_windows.begin();
25       iter != root_windows.end(); ++iter)
26    (*iter)->GetHost()->SetCursor(cursor);
27#if defined(OS_CHROMEOS)
28  Shell::GetInstance()->display_controller()->
29      cursor_window_controller()->SetCursor(cursor);
30#endif
31}
32
33void NotifyCursorVisibilityChange(bool visible) {
34  aura::Window::Windows root_windows =
35      Shell::GetInstance()->GetAllRootWindows();
36  for (aura::Window::Windows::iterator iter = root_windows.begin();
37       iter != root_windows.end(); ++iter)
38    (*iter)->GetHost()->OnCursorVisibilityChanged(visible);
39#if defined(OS_CHROMEOS)
40  Shell::GetInstance()->display_controller()->cursor_window_controller()->
41      SetVisibility(visible);
42#endif
43}
44
45void NotifyMouseEventsEnableStateChange(bool enabled) {
46  aura::Window::Windows root_windows =
47      Shell::GetInstance()->GetAllRootWindows();
48  for (aura::Window::Windows::iterator iter = root_windows.begin();
49       iter != root_windows.end(); ++iter)
50    (*iter)->GetHost()->dispatcher()->OnMouseEventsEnableStateChanged(enabled);
51  // Mirror window never process events.
52}
53
54}  // namespace
55
56AshNativeCursorManager::AshNativeCursorManager()
57    : native_cursor_enabled_(true),
58      image_cursors_(new ui::ImageCursors) {
59}
60
61AshNativeCursorManager::~AshNativeCursorManager() {
62}
63
64
65void AshNativeCursorManager::SetNativeCursorEnabled(bool enabled) {
66  native_cursor_enabled_ = enabled;
67
68  ::wm::CursorManager* cursor_manager =
69      Shell::GetInstance()->cursor_manager();
70  SetCursor(cursor_manager->GetCursor(), cursor_manager);
71}
72
73void AshNativeCursorManager::SetDisplay(
74    const gfx::Display& display,
75    ::wm::NativeCursorManagerDelegate* delegate) {
76  DCHECK(display.is_valid());
77  // Use the platform's device scale factor instead of the display's, which
78  // might have been adjusted for the UI scale.
79  const float original_scale = Shell::GetInstance()->display_manager()->
80      GetDisplayInfo(display.id()).device_scale_factor();
81#if defined(OS_CHROMEOS)
82  // And use the nearest resource scale factor.
83  const float cursor_scale = ui::GetScaleForScaleFactor(
84      ui::GetSupportedScaleFactor(original_scale));
85#else
86  // TODO(oshima): crbug.com/143619
87  const float cursor_scale = original_scale;
88#endif
89  if (image_cursors_->SetDisplay(display, cursor_scale))
90    SetCursor(delegate->GetCursor(), delegate);
91#if defined(OS_CHROMEOS)
92  Shell::GetInstance()->display_controller()->cursor_window_controller()->
93      SetDisplay(display);
94#endif
95}
96
97void AshNativeCursorManager::SetCursor(
98    gfx::NativeCursor cursor,
99    ::wm::NativeCursorManagerDelegate* delegate) {
100  if (native_cursor_enabled_) {
101    image_cursors_->SetPlatformCursor(&cursor);
102  } else {
103    gfx::NativeCursor invisible_cursor(ui::kCursorNone);
104    image_cursors_->SetPlatformCursor(&invisible_cursor);
105    if (cursor == ui::kCursorCustom) {
106      cursor = invisible_cursor;
107    } else {
108      cursor.SetPlatformCursor(invisible_cursor.platform());
109    }
110  }
111  cursor.set_device_scale_factor(image_cursors_->GetScale());
112
113  delegate->CommitCursor(cursor);
114
115  if (delegate->IsCursorVisible())
116    SetCursorOnAllRootWindows(cursor);
117}
118
119void AshNativeCursorManager::SetCursorSet(
120    ui::CursorSetType cursor_set,
121    ::wm::NativeCursorManagerDelegate* delegate) {
122  image_cursors_->SetCursorSet(cursor_set);
123  delegate->CommitCursorSet(cursor_set);
124
125  // Sets the cursor to reflect the scale change immediately.
126  if (delegate->IsCursorVisible())
127    SetCursor(delegate->GetCursor(), delegate);
128
129#if defined(OS_CHROMEOS)
130  Shell::GetInstance()->display_controller()->cursor_window_controller()->
131      SetCursorSet(cursor_set);
132#endif
133}
134
135void AshNativeCursorManager::SetVisibility(
136    bool visible,
137    ::wm::NativeCursorManagerDelegate* delegate) {
138  delegate->CommitVisibility(visible);
139
140  if (visible) {
141    SetCursor(delegate->GetCursor(), delegate);
142  } else {
143    gfx::NativeCursor invisible_cursor(ui::kCursorNone);
144    image_cursors_->SetPlatformCursor(&invisible_cursor);
145    SetCursorOnAllRootWindows(invisible_cursor);
146  }
147
148  NotifyCursorVisibilityChange(visible);
149}
150
151void AshNativeCursorManager::SetMouseEventsEnabled(
152    bool enabled,
153    ::wm::NativeCursorManagerDelegate* delegate) {
154  delegate->CommitMouseEventsEnabled(enabled);
155
156  if (enabled) {
157    aura::Env::GetInstance()->set_last_mouse_location(
158        disabled_cursor_location_);
159  } else {
160    disabled_cursor_location_ = aura::Env::GetInstance()->last_mouse_location();
161  }
162
163  SetVisibility(delegate->IsCursorVisible(), delegate);
164  NotifyMouseEventsEnableStateChange(enabled);
165}
166
167}  // namespace ash
168