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_
|