chromium/ash/utility/cursor_setter.cc

// Copyright 2023 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/utility/cursor_setter.h"

#include "ash/display/screen_orientation_controller.h"
#include "ash/shell.h"

namespace ash {

CursorSetter::CursorSetter()
    : cursor_manager_(Shell::Get()->cursor_manager()),
      original_cursor_(cursor_manager_->GetCursor()),
      original_cursor_visible_(cursor_manager_->IsCursorVisible()),
      original_cursor_locked_(cursor_manager_->IsCursorLocked()) {
  if (!cursor_manager_->IsMouseEventsEnabled()) {
    cursor_manager_->EnableMouseEvents();
  }
}

CursorSetter::~CursorSetter() {
  custom_cursor_params_.reset();
  ResetCursor();
}

void CursorSetter::UpdateCursor(aura::Window* root_window,
                                const ui::Cursor& cursor,
                                std::optional<int> custom_type_id) {
  if (original_cursor_locked_) {
    return;
  }

  if (in_cursor_update_) {
    return;
  }

  base::AutoReset<bool> auto_reset_in_cursor_update(&in_cursor_update_, true);
  const ui::mojom::CursorType new_cursor_type = cursor.type();
  const float device_scale_factor = display::Screen::GetScreen()
                                        ->GetDisplayNearestWindow(root_window)
                                        .device_scale_factor();
  const chromeos::OrientationType orientation = GetCurrentScreenOrientation();
  if (!DidCursorChange(new_cursor_type, device_scale_factor, orientation,
                       custom_type_id)) {
    return;
  }

  if (new_cursor_type == ui::mojom::CursorType::kCustom) {
    custom_cursor_params_ = CustomCursorParams{
        custom_type_id.value(), device_scale_factor, orientation};
  }

  if (cursor_manager_->IsCursorLocked()) {
    cursor_manager_->UnlockCursor();
  }
  if (new_cursor_type == ui::mojom::CursorType::kNone) {
    cursor_manager_->HideCursor();
  } else {
    cursor_manager_->SetCursor(cursor);
    cursor_manager_->ShowCursor();
  }
  cursor_manager_->LockCursor();
  was_cursor_reset_to_original_ = false;
}

void CursorSetter::HideCursor() {
  if (original_cursor_locked_ || !IsCursorVisible()) {
    return;
  }

  if (cursor_manager_->IsCursorLocked()) {
    cursor_manager_->UnlockCursor();
  }

  cursor_manager_->HideCursor();
  cursor_manager_->LockCursor();
  was_cursor_reset_to_original_ = false;
}

void CursorSetter::ResetCursor() {
  // Only unlock the cursor if it wasn't locked before.
  if (original_cursor_locked_) {
    return;
  }

  // Only reset cursor if it hasn't been reset before.
  if (was_cursor_reset_to_original_) {
    return;
  }

  if (cursor_manager_->IsCursorLocked()) {
    cursor_manager_->UnlockCursor();
  }
  cursor_manager_->SetCursor(original_cursor_);
  if (original_cursor_visible_) {
    cursor_manager_->ShowCursor();
  } else {
    cursor_manager_->HideCursor();
  }
  was_cursor_reset_to_original_ = true;
}

bool CursorSetter::IsCursorVisible() const {
  return cursor_manager_->IsCursorVisible();
}

bool CursorSetter::IsUsingCustomCursor(int custom_type_id) const {
  return cursor_manager_->GetCursor().type() ==
             ui::mojom::CursorType::kCustom &&
         custom_cursor_params_->id == custom_type_id;
}

bool CursorSetter::DidCursorChange(
    ui::mojom::CursorType new_cursor_type,
    float device_scale_factor,
    chromeos::OrientationType orientation,
    const std::optional<int> custom_type_id) const {
  const ui::mojom::CursorType current_cursor_type =
      cursor_manager_->GetCursor().type();

  if (current_cursor_type != new_cursor_type) {
    return true;
  }

  // We use `kNone` as a signal to hide the cursor. See `UpdateCursor()`.
  bool visibility_changed = cursor_manager_->IsCursorVisible() !=
                            (new_cursor_type != ui::mojom::CursorType::kNone);

  if (visibility_changed) {
    return true;
  }

  if (current_cursor_type == ui::mojom::CursorType::kCustom) {
    CHECK(custom_type_id);
    return (custom_cursor_params_ != CustomCursorParams{custom_type_id.value(),
                                                        device_scale_factor,
                                                        orientation});
  }

  return false;
}

}  // namespace ash