File: tooltip_controller.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (235 lines) | stat: -rw-r--r-- 9,578 bytes parent folder | download | duplicates (6)
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_VIEWS_COREWM_TOOLTIP_CONTROLLER_H_
#define UI_VIEWS_COREWM_TOOLTIP_CONTROLLER_H_

#include <map>
#include <memory>
#include <string>
#include <string_view>

#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "ui/aura/client/cursor_client_observer.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_tracker.h"
#include "ui/events/event_handler.h"
#include "ui/gfx/geometry/point.h"
#include "ui/views/corewm/tooltip.h"
#include "ui/views/views_export.h"
#include "ui/wm/public/activation_change_observer.h"
#include "ui/wm/public/tooltip_client.h"

namespace aura {
class Window;
}

namespace gfx {
class Rect;
}  // namespace gfx

namespace wm {
class ActivationClient;
class TooltipObserver;
}  // namespace wm

namespace views::corewm {

class Tooltip;
class TooltipStateManager;

namespace test {
class TooltipControllerTestHelper;
}  // namespace test

// TooltipController listens for events that can have an impact on the
// tooltip state.
class VIEWS_EXPORT TooltipController
    : public wm::TooltipClient,
      public ui::EventHandler,
      public aura::client::CursorClientObserver,
      public aura::WindowObserver,
      public wm::ActivationChangeObserver {
 public:
  TooltipController(std::unique_ptr<Tooltip> tooltip,
                    wm::ActivationClient* activation_client);

  TooltipController(const TooltipController&) = delete;
  TooltipController& operator=(const TooltipController&) = delete;

  ~TooltipController() override;

  void AddObserver(wm::TooltipObserver* observer);
  void RemoveObserver(wm::TooltipObserver* observer);

  // Overridden from wm::TooltipClient.
  int GetMaxWidth(const gfx::Point& location) const override;
  void UpdateTooltip(aura::Window* target) override;
  void UpdateTooltipFromKeyboard(const gfx::Rect& bounds,
                                 aura::Window* target) override;
  bool IsTooltipSetFromKeyboard(aura::Window* target) override;
  void SetHideTooltipTimeout(aura::Window* target,
                             base::TimeDelta timeout) override;
  void SetTooltipsEnabled(bool enable) override;

  // Overridden from ui::EventHandler.
  void OnKeyEvent(ui::KeyEvent* event) override;
  void OnMouseEvent(ui::MouseEvent* event) override;
  void OnTouchEvent(ui::TouchEvent* event) override;
  void OnCancelMode(ui::CancelModeEvent* event) override;
  std::string_view GetLogContext() const override;

  // Overridden from aura::client::CursorClientObserver.
  void OnCursorVisibilityChanged(bool is_visible) override;

  // Overridden from aura::WindowObserver.
  void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
  void OnWindowDestroying(aura::Window* window) override;
  void OnWindowDestroyed(aura::Window* window) override;
  void OnWindowPropertyChanged(aura::Window* window,
                               const void* key,
                               intptr_t old) override;

  // Overridden from wm::ActivationChangeObserver.
  void OnWindowActivated(ActivationReason reason,
                         aura::Window* gained_active,
                         aura::Window* lost_active) override;

  // Updates tooltip triggered by keyboard with `anchor_point` value.
  // This should be called instead of UpdateTooltipFromKeyboard() when the
  // anchor point is already calculated (e.g. Exo).
  void UpdateTooltipFromKeyboardWithAnchorPoint(const gfx::Point& anchor_point,
                                                aura::Window* target);

  // Sets show tooltip delay for `target` window.
  void SetShowTooltipDelay(aura::Window* target, base::TimeDelta delay);

 private:
  friend class test::TooltipControllerTestHelper;

  // Resets the window and calls `TooltipStateManager::HideAndReset`.
  void HideAndReset();

  // Updates the tooltip if required (if there is any change in the tooltip
  // text, tooltip id or the aura::Window).
  void UpdateIfRequired(TooltipTrigger trigger);

  // Returns true if there's a drag-and-drop in progress.
  bool IsDragDropInProgress() const;

  // Returns true if the cursor is visible.
  bool IsCursorVisible() const;

  // Gets the delay after which the tooltip should be shown/hidden.
  base::TimeDelta GetShowTooltipDelay();
  base::TimeDelta GetHideTooltipDelay();

  // Sets observed window to |target| if it is different from existing window.
  // Calls RemoveObserver on the existing window if it is not NULL.
  // Calls AddObserver on the new window if it is not NULL.
  void SetObservedWindow(aura::Window* target);

  // Returns true if the tooltip id stored on the state manager and the one
  // stored on the window are different.
  bool IsTooltipIdUpdateNeeded() const;

  // Returns true if the tooltip text stored on the state manager and the one
  // stored on the window are different.
  bool IsTooltipTextUpdateNeeded() const;

  // Removes show/hide tooltip delay from `show_tooltip_delay_map_` and
  // `hide_tooltip_timeout_map_`.
  void RemoveTooltipDelayFromMap(aura::Window* window);

  // Stops tracking the window on which the cursor was when the mouse was
  // pressed if we're on another window or if a new tooltip is triggered by
  // keyboard.
  void ResetWindowAtMousePressedIfNeeded(aura::Window* target,
                                         bool force_reset);

  // To prevent the tooltip to show again after a mouse press event, we want
  // to hide it until the cursor moves to another window.
  bool ShouldHideBecauseMouseWasOncePressed();

  // Returns true if the current event is a duplicate event generated by a
  // pen/stylus hovering over the same window.
  bool IsDuplicatePenHoverEvent(ui::EventPointerType pointer_type);

  aura::Window* tooltip_window_at_mouse_press() {
    auto& windows = tooltip_window_at_mouse_press_tracker_.windows();
    return windows.empty() ? nullptr : windows[0];
  }

  // The window on which we are currently listening for events. When there's a
  // keyboard-triggered visible tooltip, its value is set to the tooltip parent
  // window. Otherwise, it's following the cursor.
  raw_ptr<aura::Window> observed_window_ = nullptr;

  // These fields are for tracking state when the user presses a mouse button.
  // The tooltip should stay hidden after a mouse press event on the view until
  // the cursor moves to another view.
  std::u16string tooltip_text_at_mouse_press_;
  // NOTE: this either has zero or one window.
  aura::WindowTracker tooltip_window_at_mouse_press_tracker_;

  // Location of the last events in |tooltip_window_|'s coordinates.
  // |last_mouse_loc_| and |last_focus_loc_| are used to position tooltips
  // triggered by either the mouse or the keyboard, respectively. We also
  // track |last_mouse_loc_| to be able to ignore spurious and/or redundant
  // events.
  gfx::Point last_mouse_loc_;
  gfx::Point last_touch_loc_;
  gfx::Point last_focus_loc_;

  // True if the current event is a duplicate event generated by hovering with a
  // pen/stylus. Hovering with a pen generates a constant stream of move events,
  // so duplicate pen events on the same window should be ignored to prevent the
  // tooltip's show timer from being restarted on each event.
  bool is_duplicate_pen_hover_event_ = false;
  // The last tooltip text that was shown when the pen was hovering.
  // TODO(crbug.com/40246278): Replace this with a unique tooltip identifier
  // when one is implemented. For now, the tooltip text is the closest thing to
  // a tooltip identifier there is.
  std::u16string last_pen_tooltip_text_;

  // Whether tooltips can be displayed or not.
  bool tooltips_enabled_ = true;

  // Whether tooltip should be skip delay before showing.
  // This may be set to true only for testing.
  // Do NOT override this value except from TooltipControllerTestHelper.
  bool skip_show_delay_for_testing_ = false;

  // The show delay before showing tooltip may differ for external app's
  // tooltip. This map specifies the show delay for each target window.
  // TODO(crbug.com/c/374244480): consider removing this when removing lacros
  // support code from //c/exo. This is only used by aura shell to show tooltips
  // with delays for external apps.
  std::map<aura::Window*, base::TimeDelta> show_tooltip_delay_map_;

  // Web content tooltips should be shown indefinitely and those added on Views
  // should be hidden automatically after a timeout. This map stores the timeout
  // value for each aura::Window.
  // TODO(bebeaudr): Currently, all Views tooltips are hidden after the same
  // timeout and all web content views should be shown indefinitely. If this
  // general rule is always true, then we don't need a complex map here. A set
  // of aura::Window* would be enough with an attribute named
  // "disabled_hide_timeout_views_set_" or something like that.
  std::map<aura::Window*, base::TimeDelta> hide_tooltip_timeout_map_;

  // We want to hide tooltips whenever our client window loses focus. This will
  // ensure that no tooltip stays visible when the user navigated away from
  // our client.
  raw_ptr<wm::ActivationClient> activation_client_;

  // The TooltipStateManager is responsible for keeping track of the current
  // tooltip state (its text, position, id, etc.) and to modify it when asked
  // by the TooltipController or the show/hide timers.
  std::unique_ptr<TooltipStateManager> state_manager_;
};

}  // namespace views::corewm

#endif  // UI_VIEWS_COREWM_TOOLTIP_CONTROLLER_H_