File: glic_window_controller_impl.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (372 lines) | stat: -rw-r--r-- 15,232 bytes parent folder | download | duplicates (3)
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
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_GLIC_WIDGET_GLIC_WINDOW_CONTROLLER_IMPL_H_
#define CHROME_BROWSER_GLIC_WIDGET_GLIC_WINDOW_CONTROLLER_IMPL_H_

#include <optional>
#include <vector>

#include "base/callback_list.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "base/scoped_observation.h"
#include "base/scoped_observation_traits.h"
#include "chrome/browser/glic/glic_enabling.h"
#include "chrome/browser/glic/host/glic.mojom.h"
#include "chrome/browser/glic/host/glic_web_client_access.h"
#include "chrome/browser/glic/host/host.h"
#include "chrome/browser/glic/widget/application_hotkey_delegate.h"
#include "chrome/browser/glic/widget/glic_window_config.h"
#include "chrome/browser/glic/widget/glic_window_controller.h"
#include "chrome/browser/glic/widget/glic_window_hotkey_delegate.h"
#include "chrome/browser/glic/widget/local_hotkey_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "components/web_modal/web_contents_modal_dialog_host.h"
#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/interaction/element_tracker.h"
#include "ui/display/display_observer.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"

class Browser;
class WindowFinder;
namespace gfx {
class Size;
class Point;
}  // namespace gfx

namespace glic {

class GlicEnabling;
class ScopedGlicButtonIndicator;
class GlicButton;

// This class owns and manages the glic window. This class has the same lifetime
// as the GlicKeyedService, so it exists if and only if the profile exists.
//
// See the |State| enum below for the lifecycle of the window. When the glic
// window is open |attached_browser_| indicates if the window is attached or
// standalone. See |IsAttached|
class GlicWindowControllerImpl
    : public display::DisplayObserver,
      public GlicWindowController,
      public views::WidgetObserver,
      public Host::Observer,
      public web_modal::WebContentsModalDialogManagerDelegate,
      public web_modal::WebContentsModalDialogHost {
 public:
  GlicWindowControllerImpl(const GlicWindowControllerImpl&) = delete;
  GlicWindowControllerImpl& operator=(const GlicWindowControllerImpl&) = delete;

  GlicWindowControllerImpl(Profile* profile,
                           signin::IdentityManager* identity_manager,
                           GlicKeyedService* service,
                           GlicEnabling* enabling);
  ~GlicWindowControllerImpl() override;

  // GlicWindowController implementation
  void Toggle(BrowserWindowInterface* browser,
              bool prevent_close,
              mojom::InvocationSource source) override;
  void ShowAfterSignIn(base::WeakPtr<Browser> browser) override;
  void ToggleWhenNotAlwaysDetached(Browser* new_attached_browser,
                                   bool prevent_close,
                                   mojom::InvocationSource source) override;
  void FocusIfOpen() override;
  void Attach() override;
  void Detach() override;
  void Shutdown() override;
  void Resize(const gfx::Size& size,
              base::TimeDelta duration,
              base::OnceClosure callback) override;
  void EnableDragResize(bool enabled) override;
  void MaybeSetWidgetCanResize() override;
  gfx::Size GetSize() override;
  void SetDraggableAreas(
      const std::vector<gfx::Rect>& draggable_areas) override;
  void SetMinimumWidgetSize(const gfx::Size& size) override;
  void Close() override;
  void CloseWithReason(views::Widget::ClosedReason reason) override;
  void ShowTitleBarContextMenuAt(gfx::Point event_loc) override;
  bool ShouldStartDrag(const gfx::Point& initial_press_loc,
                       const gfx::Point& mouse_location) override;
  void HandleWindowDragWithOffset(gfx::Vector2d mouse_offset) override;
  const mojom::PanelState& GetPanelState() const override;

  void AddStateObserver(StateObserver* observer) override;
  void RemoveStateObserver(StateObserver* observer) override;

  bool IsActive() override;
  bool IsShowing() const override;
  bool IsPanelOrFreShowing() const override;
  bool IsAttached() const override;
  bool IsDetached() const override;
  base::CallbackListSubscription AddWindowActivationChangedCallback(
      WindowActivationChangedCallback callback) override;
  void Preload() override;
  void PreloadFre() override;
  void Reload() override;
  bool IsWarmed() const override;
  base::WeakPtr<GlicWindowController> GetWeakPtr() override;

  GlicView* GetGlicView() override;
  base::WeakPtr<views::View> GetGlicViewAsView() override;
  GlicWidget* GetGlicWidget() override;
  content::WebContents* GetFreWebContents() override;

  Browser* attached_browser() override;
  State state() const override;
  GlicFreController* fre_controller() override;
  GlicWindowAnimator* window_animator() override;
  Profile* profile() override;
  bool IsDragging() override;
  gfx::Rect GetInitialBounds(Browser* browser) override;
  void ShowDetachedForTesting() override;
  void SetPreviousPositionForTesting(gfx::Point position) override;

  // views::WidgetObserver implementation, monitoring the glic window widget.
  void OnWidgetActivationChanged(views::Widget* widget, bool active) override;
  void OnWidgetDestroyed(views::Widget* widget) override;
  void OnWidgetBoundsChanged(views::Widget* widget,
                             const gfx::Rect& new_bounds) override;
  void OnWidgetUserResizeStarted() override;
  void OnWidgetUserResizeEnded() override;

  // display::DisplayObserver implementation
  void OnDisplayMetricsChanged(const display::Display& display,
                               uint32_t changed_metrics) override;

 private:
  Host& host() const;

  // Sets the floating attributes of the glic window.
  //
  // When set to true, the glic window is set to have a `kFloatingWindow`
  // z-order, and on the Mac is set to be "activation independent" (to allow the
  // user to interact with it without causing Chromium to be activated), and
  // visible on every space (including fullscreen ones).
  //
  // When set to false, the glic window is set to have a `kNormal` z-order, and
  // on the Mac, all special activation and visibility properties are cleared.
  void SetGlicWindowToFloatingMode(bool floating);

  // Return the default detached bounds which are just below the tab strip
  // button on the active browser.
  std::optional<gfx::Rect> GetInitialDetachedBoundsFromBrowser(
      Browser* browser,
      const gfx::Size& target_size);

  // Return the default detached bounds when there is no active browser. The
  // position is relative to the top right of the current display.
  gfx::Rect GetInitialDetachedBoundsNoBrowser(const gfx::Size& target_size);

  // Return the default bounds when attached to the browser which cover the tab
  // strip button on the active browser.
  gfx::Rect GetInitialAttachedBounds(Browser& browser);

  // Creates the glic view, waits for the web client to initialize, and then
  // shows the glic window. If `browser` is non-nullptr then glic will be
  // attached to the browser. Otherwise glic will be detached.
  void Show(Browser* browser, mojom::InvocationSource source);

  void SetupGlicWidget(Browser* browser);
  void SetupGlicWidgetAccessibilityText();

  // Host::Observer implementation.
  void WebClientInitializeFailed() override;
  void LoginPageCommitted() override;
  void ClientReadyToShow(const mojom::OpenPanelInfo& open_info) override;

  // Called once glic is completely loaded and any animations have finished.
  // This is the end of the opening process and |state_| will be set to kOpen.
  void GlicLoadedAndReadyToDisplay();

  void SetDraggingAreasAndWatchForMouseEvents();

  // Called when the Detach() animation ends.
  void DetachFinished();

  // Save the top-right corner position for re-opening.
  void SaveWidgetPosition(bool user_modified);

  // Clear the previous position if the widget would not be on an existing
  // display when shown.
  void MaybeResetPreviousPosition(const gfx::Size& target_size);

  // Determines the correct position for the glic window when attached to a
  // browser window. The top right of the widget should be placed here.
  gfx::Point GetTopRightPositionForAttachedGlicWindow(GlicButton* glic_button);

  // Runs an animation to move glic to its target position.
  // TODO(crbug.com/410629338): Reimplement attachment.
  void AttachToBrowser(Browser& browser, AttachChangeReason reason);

  // Keep part of glic window within the visible region.
  void AdjustPositionIfNeeded();

  // Handles end-of-drag:
  //  - If glic is within attachment distance of a browser window's glic button,
  //    attach the glic window to the button's position.
  //  - If glic is still detached and has moved to a display with a different
  //    work area size, possibly resize the window.
  void OnDragComplete();

  // Finds a browser within attachment distance of glic to toggle the attachment
  // indicator.
  void HandleGlicButtonIndicator();

  // Find and return a browser within attachment distance. Returns nullptr if no
  // browsers are within attachment distance.
  Browser* FindBrowserForAttachment();

  // Updates the position of the glic window to that of the glic button of
  // `browser`'s window. This position change is animated if `animate` is true.
  void MovePositionToBrowserGlicButton(const Browser& browser, bool animate);

  // Called when the move animation finishes when attaching.
  void AttachAnimationFinished();

  // This method should be called anytime:
  //  * state_ transitions to or from kClosed.
  //  * attached_browser_ changes.
  void NotifyIfPanelStateChanged();
  mojom::PanelState ComputePanelState() const;

  // When the attached browser is closed, this is invoked so we can clean up.
  void AttachedBrowserDidClose(BrowserWindowInterface* browser);

  // Returns true if a browser is occluded at point in screen coordinates.
  bool IsBrowserOccludedAtPoint(Browser* browser, gfx::Point point);

  // Return the last size Resize() was called with, or the default initial size
  // if Resize() hasn't been called. The return value is clamped to fit between
  // the minimum and maximum sizes.
  gfx::Size GetLastRequestedSizeClamped() const;

  // Possibly adjusts the size of the window appropriate for the current
  // display workspace, but only if it's different than the current target size.
  void MaybeAdjustSizeForDisplay(bool animate);

  // Modifies `state_` to the given new state.
  void SetWindowState(State new_state);

  // Returns true of the window is showing and the content is loaded.
  bool IsWindowOpenAndReady();

  // web_modal::WebContentsModalDialogManagerDelegate:
  web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost()
      override;

  // web_modal::WebContentsModalDialogHost:
  gfx::Size GetMaximumDialogSize() override;
  gfx::NativeView GetHostView() const override;
  gfx::Point GetDialogPosition(const gfx::Size& dialog_size) override;
  bool ShouldDialogBoundsConstrainedByHost() override;
  void AddObserver(web_modal::ModalDialogHostObserver* observer) override;
  void RemoveObserver(web_modal::ModalDialogHostObserver* observer) override;

  // Observes the glic widget.
  base::ScopedObservation<views::Widget, views::WidgetObserver>
      glic_widget_observation_{this};

  // Observes the display configuration.
  display::ScopedOptionalDisplayObserver display_observer_{this};

  // Used for observing closing of the pinned browser.
  std::optional<base::CallbackListSubscription> browser_close_subscription_;

  // List of callbacks to be notified when window activation has changed.
  base::RepeatingCallbackList<void(bool)> window_activation_callback_list_;

  const raw_ptr<Profile> profile_;

  // Contains the glic webview.
  std::unique_ptr<GlicWidget> glic_widget_;

  std::unique_ptr<GlicWindowAnimator> glic_window_animator_;

  // True if we've hit a login page (and have not yet shown).
  bool login_page_committed_ = false;

  // This member contains the last size that glic requested. This should be
  // reset every time glic is closed but is currently cached.
  std::optional<gfx::Size> glic_size_;

  // Contains the size of the draggable area zone for the glic widget.
  // This value gets sent from the web client; if it is ever null, the draggable
  // area will be set to a default value.
  std::optional<gfx::Rect> draggable_area_ = std::nullopt;

  // Whether the widget should be user resizable, kept here in case it's
  // specified before the widget is created.
  bool user_resizable_ = true;

  // Used to monitor key and mouse events from native window.
  class WindowEventObserver;
  std::unique_ptr<WindowEventObserver> window_event_observer_;

  // True while RunMoveLoop() has been called on a widget.
  bool in_move_loop_ = false;

  // This is the last panel state sent to observers. It should only be updated
  // in `NotifyIfPanelStateChanged`.
  mojom::PanelState panel_state_;

  raw_ptr<GlicWebClientAccess> web_client_;

  // Modified only by calling `SetWindowState`.
  State state_ = State::kClosed;

  // If State != kClosed, then the UI must either be associated with a browser
  // window, or standalone. That is tracked by this member.
  raw_ptr<Browser> attached_browser_ = nullptr;

  base::ObserverList<StateObserver> state_observers_;

  // Used by web modals to listens for glic window events, e.g. size change or
  // window close.
  base::ObserverList<web_modal::ModalDialogHostObserver>::Unchecked
      modal_dialog_host_observers_;

  // The announcement should happen the first time focus is lost after the FRE.
  bool do_focus_loss_announcement_ = false;

  // Whether the user is currently drag-resizing the widget.
  bool user_resizing_ = false;

  GlicWindowConfig window_config_;

  // The invocation source requesting the opening of the web client. Note that
  // this value is retained until it is consumed by the web client. Because
  // opening the glic window may not actually load the client, there's no
  // guarantee that this value is sent to the web client.
  std::optional<mojom::InvocationSource> opening_source_;

  std::optional<gfx::Point> previous_position_ = std::nullopt;

  std::unique_ptr<ScopedGlicButtonIndicator> scoped_glic_button_indicator_;

  std::unique_ptr<GlicFreController> fre_controller_;

  std::unique_ptr<WindowFinder> window_finder_;

  std::unique_ptr<LocalHotkeyManager> application_hotkey_manager_;
  std::unique_ptr<LocalHotkeyManager> glic_window_hotkey_manager_;

  raw_ptr<GlicKeyedService> glic_service_;  // Owns this.
  raw_ptr<GlicEnabling> enabling_;
  base::ScopedObservation<Host, Host::Observer> host_observation_{this};

  base::WeakPtrFactory<GlicWindowControllerImpl> weak_ptr_factory_{this};
};

}  // namespace glic

#endif  // CHROME_BROWSER_GLIC_WIDGET_GLIC_WINDOW_CONTROLLER_IMPL_H_