1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137

ash / display / display_alignment_controller.h [blame]

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef ASH_DISPLAY_DISPLAY_ALIGNMENT_CONTROLLER_H_
#define ASH_DISPLAY_DISPLAY_ALIGNMENT_CONTROLLER_H_

#include <memory>

#include "ash/ash_export.h"
#include "ash/public/cpp/session/session_observer.h"
#include "ui/display/manager/display_manager_observer.h"
#include "ui/events/event_handler.h"
#include "ui/gfx/geometry/vector2d.h"

namespace base {
class OneShotTimer;
}  // namespace base

namespace ash {

class DisplayAlignmentIndicator;

// DisplayAlignmentController is responsible for creating new
// DisplayAlignmentIndicators when the activation criteria is met.
// TODO(1091497): Consider combining DisplayHighlightController and
// DisplayAlignmentController.
class ASH_EXPORT DisplayAlignmentController
    : public ui::EventHandler,
      public display::DisplayManagerObserver,
      public SessionObserver {
 public:
  enum class DisplayAlignmentState {
    // No indicators shown and mouse is not on edge
    kIdle,

    // Mouse is currently on one of the edges.
    kOnEdge,

    // The indicators are visible.
    kIndicatorsVisible,

    // A display is being dragged around in display layouts. Preview indicators
    // are being updated and shown.
    kLayoutPreview,

    // Screen is locked or there is only one display.
    kDisabled,
  };

  DisplayAlignmentController();
  DisplayAlignmentController(const DisplayAlignmentController&) = delete;
  DisplayAlignmentController& operator=(const DisplayAlignmentController&) =
      delete;
  ~DisplayAlignmentController() override;

  // display::DisplayManagerObserver
  void OnDidApplyDisplayChanges() override;
  void OnDisplaysInitialized() override;

  // ui::EventHandler:
  void OnMouseEvent(ui::MouseEvent* event) override;

  // SessionObserver:
  void OnLockStateChanged(bool locked) override;

  // Update positions of display alignment preview highlights. Display being
  // dragged is specified by |display_id|. |preview_indicators_| is
  // populated with indicators from this display and its neighbors as
  // it is not possible for |display_id| to change mid-drag.
  void DisplayDragged(int64_t display_id, int32_t delta_x, int32_t delta_y);

  void SetTimerForTesting(std::unique_ptr<base::OneShotTimer> timer);

  const std::vector<std::unique_ptr<DisplayAlignmentIndicator>>&
  GetActiveIndicatorsForTesting();

  int64_t GetDraggedDisplayIdForTesting() const;

 private:
  // Show all indicators on |src_display| and other indicators that shares
  // an edge with |src_display|. Indicators on other displays are shown without
  // pills. All indicators are created in this method and stored in
  // |active_indicators_| to be destroyed in ResetState().
  void ShowIndicators(const display::Display& src_display);

  // Clears all indicators, containers, timer, and resets the state back to
  // kIdle.
  void ResetState();

  // Used to transition to kDisable if required. Called whenever display
  // configuration or lock state updates.
  void RefreshState();

  // Updates, shows/hides preview indicators according to changes reported by
  // DisplayDragged().
  void ComputePreviewIndicators();

  // Stores all DisplayAlignmentIndicators currently being shown. All indicators
  // should either belong to or be a shared edge of display with
  // |triggered_display_id_|. Indicators are created upon activation in
  // ShowIndicators() or upon adjusting display layout in
  // ComputePreviewIndicators() and cleared in ResetState().
  std::vector<std::unique_ptr<DisplayAlignmentIndicator>> active_indicators_;

  // Timer used for both edge trigger timeouts and hiding indicators.
  std::unique_ptr<base::OneShotTimer> action_trigger_timer_;

  // Tracks current state of the controller. Mostly used to determine if action
  // is taken in OnMouseEvent();
  DisplayAlignmentState current_state_ = DisplayAlignmentState::kIdle;

  // Tracks if the screen is locked to disable highlights.
  bool is_locked_ = false;

  // Keeps track of the most recent display where the mouse hit the edge.
  // Prevents activating indicators when user hits edges of different displays.
  int64_t triggered_display_id_ = display::kInvalidDisplayId;

  // Number of times the mouse was on an edge of some display specified by
  // |triggered_display_id_| recently.
  int trigger_count_ = 0;

  // ID of display currently beign dragged. Cannot change from one valid
  // ID to another as dropping the dragged display causes changes to display
  // configuration, resetting this ID.
  int64_t dragged_display_id_;

  // The difference between dragged display's actual position and preview
  // position. Is an accumulation of |delta_x| and |delta_y| from
  // DisplayDragged(). The offset is reset when a configuration event occurs.
  gfx::Vector2d dragged_offset_;
};

}  // namespace ash

#endif  // ASH_DISPLAY_DISPLAY_ALIGNMENT_CONTROLLER_H_