File: element_tracker_views.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 (219 lines) | stat: -rw-r--r-- 8,797 bytes parent folder | download | duplicates (7)
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
// Copyright 2021 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_INTERACTION_ELEMENT_TRACKER_VIEWS_H_
#define UI_VIEWS_INTERACTION_ELEMENT_TRACKER_VIEWS_H_

#include <map>
#include <string>
#include <vector>

#include "base/functional/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/no_destructor.h"
#include "base/scoped_multi_source_observation.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/base/interaction/element_tracker.h"
#include "ui/views/view_utils.h"
#include "ui/views/views_export.h"

namespace views {

class View;
class Widget;

// Wraps a View in an ui::TrackedElement.
class VIEWS_EXPORT TrackedElementViews : public ui::TrackedElement {
 public:
  TrackedElementViews(View* view,
                      ui::ElementIdentifier identifier,
                      ui::ElementContext context);
  ~TrackedElementViews() override;

  View* view() { return view_; }
  const View* view() const { return view_; }

  // TrackedElement:
  gfx::Rect GetScreenBounds() const override;
  std::string ToString() const override;

  DECLARE_FRAMEWORK_SPECIFIC_METADATA()

 private:
  const raw_ptr<View> view_;
};

// Manages TrackedElements associated with View objects.
class VIEWS_EXPORT ElementTrackerViews {
 public:
  using ViewList = std::vector<View*>;

  // Returns the context to use for `primary_widget`, which will be a logical
  // top-level widget, or null to use the default computation. Used e.g. to
  // ensure that all system widgets on ChromeOS share a context.
  using ContextOverrideCallback =
      base::RepeatingCallback<ui::ElementContext(Widget* primary_widget)>;

  // Changes the computation of contexts for some or all widgets. See
  // `ContextOverrideCallback` for details.
  static void SetContextOverrideCallback(ContextOverrideCallback callback);

  // Gets the global instance of the tracker for Views.
  static ElementTrackerViews* GetInstance();

  // Returns the context associated with a particular View. The context will be
  // the same across all Views associated with a root Widget (such as an
  // application window), or as specified by the current
  // `ContextOverrideCallback` if one is set.
  static ui::ElementContext GetContextForView(View* view);

  // Returns the context associated with a particular Widget. The context will
  // be the same across all Widgets associated with a root Widget (such as an
  // application window), or as specified by the current
  // `ContextOverrideCallback` if one is set.
  static ui::ElementContext GetContextForWidget(Widget* widget);

  // ----------
  // The following methods retrieve Views directly without having to retrieve a
  // TrackedElement from ElementTracker, call, AsA<>, etc. Use if you know that
  // the element(s) in question are guaranteed to be Views.

  // Returns the corresponding TrackedElementViews for the given view, or
  // null if none exists. Note that views which are not visible or not added to
  // a Widget may not have associated elements, and that the returned object
  // may be transient.
  //
  // For the non-const version, if `assign_temporary_id` is set and `view` does
  // not have an identifier, ui::ElementTracker::kTemporaryIdentifier will be
  // assigned.
  TrackedElementViews* GetElementForView(View* view,
                                         bool assign_temporary_id = false);
  const TrackedElementViews* GetElementForView(const View* view) const;

  // Returns either the unique View matching the given `id` in the given
  // `context`, or null if there is none.
  //
  // Use if you are sure there's at most one matching element in the context
  // and that (if present) the element is a View; will DCHECK/crash otherwise.
  View* GetUniqueView(ui::ElementIdentifier id, ui::ElementContext context);

  // Convenience method that calls GetUniqueView() and then safely converts the
  // result to `T`, which must be a View subclass with metadata. Fails if a View
  // is found but is not of the expected subtype.
  template <class T>
  T* GetUniqueViewAs(ui::ElementIdentifier id, ui::ElementContext context);

  // Returns the first View with the given `id` in the given `context`; null if
  // none is found. Ignores all other Views and any matching elements that are
  // not Views.
  //
  // Use when you just need *a* View in the given context, and don't care if
  // there's more than one.
  View* GetFirstMatchingView(ui::ElementIdentifier id,
                             ui::ElementContext context);

  // Convenience method that calls GetFirstMatchingView() and then safely
  // converts the result to `T`, which must be a view subclass with metadata.
  // Fails if a View is found but is not of the expected subtype.
  template <class T>
  T* GetFirstMatchingViewAs(ui::ElementIdentifier id,
                            ui::ElementContext context);

  // Returns a list of all visible Views with identifier `id` in `context`.
  // The list may be empty. Ignores any non-Views elements which might match.
  ViewList GetAllMatchingViews(ui::ElementIdentifier id,
                               ui::ElementContext context);

  // Returns a list of all visible Views with identifier `id` in any context.
  // Order is not guaranteed. Ignores any non-Views elements with the same
  // identifier.
  ViewList GetAllMatchingViewsInAnyContext(ui::ElementIdentifier id);

  // Returns a widget that matches the given context. A valid
  // TrackedElementViews must exist within the widget.
  Widget* GetWidgetForContext(ui::ElementContext context);

  // ----------
  // Notifies listeners that a specific custom event has occurred for the given
  // view. Calls GetElementForView(view, true) under the hood; returns false if
  // an element cannot be found or created for the view (e.g. in the case where
  // it is not visible or associated with a widget).
  bool NotifyCustomEvent(ui::CustomElementEventType event_type, View* view);

  // ----------
  // The following methods are used by View and derived classes to send events
  // to ElementTracker. ElementTrackerViews maintains additional observers and
  // states that make sure shown and hidden events get sent at the correct
  // times.

  // Called by View after the kUniqueElementKey property is set.
  void RegisterView(ui::ElementIdentifier element_id, View* view);

  // Called by View if the kUniqueElementKey property is changed from a non-null
  // value.
  void UnregisterView(ui::ElementIdentifier element_id, View* view);

  // Called by a View when the user activates it (clicks a button, selects a
  // menu item, etc.)
  void NotifyViewActivated(ui::ElementIdentifier element_id, View* view);

 private:
  friend class base::NoDestructor<ElementTrackerViews>;
  FRIEND_TEST_ALL_PREFIXES(ElementTrackerViewsTest, CleansUpWidgetTrackers);
  class ElementDataViews;
  class WidgetTracker;

  ElementTrackerViews();
  ~ElementTrackerViews();

  // Returns the current `ContextOverrideCallback`, which may be null.
  static ContextOverrideCallback& GetContextOverrideCallback();

  // We do not get notified at the View level if a view's widget has not yet
  // been shown. We need this notification to know when the view is actually
  // visible to the user. So if a view is added to the tracker or is added to
  // a widget, and its widget is not visible, we watch it until it is (or it is
  // destroyed).
  void MaybeTrackWidget(Widget* widget);

  // Keep track of widgets for which we've received an
  // OnWidgetVisibilityChanged(true) event for but which are still reporting
  // IsVisible() = false. This happens because visibility of native window in
  // Aura is not exactly synced with our event reporting.
  bool IsWidgetVisible(const Widget* widget) const;

  std::map<ui::ElementIdentifier, ElementDataViews> element_data_;
  std::map<const Widget*, WidgetTracker> widget_trackers_;
};

// Template implementations.

template <class T>
T* ElementTrackerViews::GetUniqueViewAs(ui::ElementIdentifier id,
                                        ui::ElementContext context) {
  views::View* const view = GetUniqueView(id, context);
  if (!view) {
    return nullptr;
  }
  T* const result = views::AsViewClass<T>(view);
  DCHECK(result);
  return result;
}

template <class T>
T* ElementTrackerViews::GetFirstMatchingViewAs(ui::ElementIdentifier id,
                                               ui::ElementContext context) {
  views::View* const view = GetFirstMatchingView(id, context);
  if (!view) {
    return nullptr;
  }
  T* const result = views::AsViewClass<T>(view);
  DCHECK(result);
  return result;
}

}  // namespace views

#endif  // UI_VIEWS_INTERACTION_ELEMENT_TRACKER_VIEWS_H_