#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/host/context/glic_screenshot_capturer.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/public/glic_enabling.h"
#include "chrome/browser/glic/public/glic_instance.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_event_observer.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 "chrome/browser/ui/views/side_panel/side_panel_entry.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 glic {
class GlicEnabling;
class GlicView;
class GlicWindowAnimator;
class ScopedGlicButtonIndicator;
class GlicInstanceMetrics;
class GlicWindowControllerImpl
: public display::DisplayObserver,
public GlicWindowControllerInterface,
public views::WidgetObserver,
public Host::EmbedderDelegate,
public Host::Observer,
public web_modal::WebContentsModalDialogManagerDelegate,
public web_modal::WebContentsModalDialogHost,
public GlicWindowEventObserver::Delegate,
public LocalHotkeyManager::Panel {
public:
GlicWindowControllerImpl(const GlicWindowControllerImpl&) = delete;
GlicWindowControllerImpl& operator=(const GlicWindowControllerImpl&) = delete;
GlicWindowControllerImpl(Profile* profile,
signin::IdentityManager* identity_manager,
GlicKeyedService* service,
GlicEnabling* enabling);
~GlicWindowControllerImpl() override;
void Toggle(BrowserWindowInterface* browser,
bool prevent_close,
mojom::InvocationSource source,
std::optional<std::string> prompt_suggestion) override;
void ShowAfterSignIn(base::WeakPtr<Browser> browser) override;
void FocusIfOpen() override;
void Shutdown() override;
void MaybeSetWidgetCanResize() override;
gfx::Size GetPanelSize() override;
void Close() override;
void CloseInstanceWithFrame(
content::RenderFrameHost* render_frame_host) override;
void CloseAndShutdownInstanceWithFrame(
content::RenderFrameHost* render_frame_host) override;
void AddStateObserver(StateObserver* observer) override;
void RemoveStateObserver(StateObserver* observer) override;
void AddGlobalStateObserver(PanelStateObserver* observer) override;
void RemoveGlobalStateObserver(PanelStateObserver* observer) override;
bool IsPanelShowingForBrowser(
const BrowserWindowInterface& bwi) const override;
bool IsActive() override;
bool IsAttached() override;
bool IsAttached() const;
bool IsDetached() const override;
base::CallbackListSubscription AddWindowActivationChangedCallback(
WindowActivationChangedCallback callback) override;
base::CallbackListSubscription AddGlobalShowHideCallback(
base::RepeatingClosure callback) override;
void Preload() override;
void Reload(content::RenderFrameHost* render_frame_host) override;
bool IsWarmed() const override;
base::WeakPtr<GlicWindowControllerInterface> GetWeakPtr() override;
GlicWindowAnimator* window_animator() override;
void OnDragComplete() override;
base::WeakPtr<views::View> GetView() override;
GlicWidget* GetGlicWidget() const override;
Browser* attached_browser() override;
State state() const override;
Profile* profile() override;
gfx::Rect GetInitialBounds(Browser* browser) override;
void ShowDetachedForTesting() override;
void SetPreviousPositionForTesting(gfx::Point position) override;
std::unique_ptr<views::View> CreateViewForSidePanel(
tabs::TabInterface& tab) override;
void SidePanelShown(BrowserWindowInterface* browser) override;
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;
void Resize(const gfx::Size& size,
base::TimeDelta duration,
base::OnceClosure callback) override;
void SetDraggableAreas(
const std::vector<gfx::Rect>& draggable_areas) override;
void EnableDragResize(bool enabled) override;
void Attach() override;
void Detach() override;
void ClosePanel() override;
void SetMinimumWidgetSize(const gfx::Size& size) override;
bool IsShowing() const override;
void SwitchConversation(
glic::mojom::ConversationInfoPtr info,
mojom::WebClientHandler::SwitchConversationCallback callback) override;
void CaptureScreenshot(
glic::mojom::WebClientHandler::CaptureScreenshotCallback callback)
override;
mojom::PanelState GetPanelState() override;
void OnDisplayMetricsChanged(const display::Display& display,
uint32_t changed_metrics) override;
bool HasFocus() override;
bool ActivateBrowser() override;
void ShowTitleBarContextMenuAt(gfx::Point event_loc) override;
HostManager& host_manager() override;
std::vector<GlicInstance*> GetInstances() override;
GlicInstance* GetInstanceForTab(const tabs::TabInterface* tab) const override;
Host& host() override;
const InstanceId& id() const override;
std::optional<std::string> conversation_id() const override;
base::TimeTicks GetLastActiveTime() const override;
base::CallbackListSubscription RegisterStateChange(
StateChangeCallback callback) override;
base::CallbackListSubscription
AddActiveInstanceChangedCallbackAndNotifyImmediately(
ActiveInstanceChangedCallback callback) override;
GlicInstance* GetActiveInstance() override;
GlicWindowAnimator* GetWindowAnimatorForTesting();
GlicView* GetGlicViewForTesting() const { return GetGlicView(); }
glic::GlicInstanceMetrics* instance_metrics() override;
private:
void CloseWithReason(views::Widget::ClosedReason reason);
GlicView* GetGlicView() const;
void ToggleWhenNotAlwaysDetached(
Browser* new_attached_browser,
bool prevent_close,
mojom::InvocationSource source,
std::optional<std::string> prompt_suggestion);
void SetGlicWindowToFloatingMode(bool floating);
void MaybeResetPanelPostionOnShow(mojom::InvocationSource source);
void Show(Browser* browser,
mojom::InvocationSource source,
std::optional<std::string> prompt_suggestion);
bool BeforeViewCreated(Browser* browser,
mojom::InvocationSource source,
std::optional<std::string> prompt_suggestion);
void AfterViewShown();
void SetupAndShowGlicWidget(Browser* browser);
void SetupGlicWidgetAccessibilityText();
void ResetAndHidePanel();
void WebClientInitializeFailed() override;
void LoginPageCommitted() override;
void ClientReadyToShow(const mojom::OpenPanelInfo& open_info) override;
void OnViewChanged(mojom::CurrentView view) override;
void ContextAccessIndicatorChanged(bool enabled) override;
void GlicLoadedAndReadyToDisplay();
void SetDraggingAreasAndWatchForMouseEvents();
void SaveWidgetPosition(bool user_modified);
void MaybeResetPreviousPosition(const gfx::Size& target_size);
void AttachToBrowser(Browser& browser, AttachChangeReason reason);
void AttachToBrowserAndShow(Browser& browser, AttachChangeReason reason);
void HandleGlicButtonIndicator();
BrowserWindowInterface* FindBrowserForAttachment();
void AttachAnimationFinished();
void NotifyIfPanelStateChanged();
mojom::PanelState ComputePanelState() const;
void AttachedBrowserDidClose(BrowserWindowInterface* browser);
bool IsBrowserOccludedAtPoint(BrowserWindowInterface* browser,
gfx::Point point);
void MaybeAdjustSizeForDisplay(bool animate);
void SetWindowState(State new_state);
bool IsWindowOpenAndReady();
web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost(
content::WebContents* web_contents) override;
gfx::Size GetMaximumDialogSize() override;
gfx::NativeView GetHostView() const override;
gfx::Point GetDialogPosition(const gfx::Size& dialog_size) override;
bool ShouldConstrainDialogBoundsByHost() override;
void AddObserver(web_modal::ModalDialogHostObserver* observer) override;
void RemoveObserver(web_modal::ModalDialogHostObserver* observer) override;
void MaybeSendConversationViewRequest();
void MaybeSendActuationViewRequest();
void MaybeSendViewChangeRequest(mojom::InvocationSource source);
bool InvocationSourceMatchesCurrentView(mojom::InvocationSource source);
using StateChangeCallbackList =
base::RepeatingCallbackList<void(bool, mojom::CurrentView view)>;
StateChangeCallbackList state_change_callback_list_;
base::ScopedObservation<views::Widget, views::WidgetObserver>
glic_widget_observation_{this};
display::ScopedOptionalDisplayObserver display_observer_{this};
std::optional<base::CallbackListSubscription> browser_close_subscription_;
base::RepeatingCallbackList<void(bool)> window_activation_callback_list_;
void HandleWindowDragWithOffset(gfx::Vector2d mouse_offset);
const raw_ptr<Profile> profile_;
base::ObserverList<StateObserver> state_observers_;
Host host_;
std::unique_ptr<HostManager> host_manager_;
std::unique_ptr<views::WidgetDelegate> glic_delegate_;
std::unique_ptr<GlicWidget> glic_widget_;
raw_ptr<GlicView> glic_view_;
std::unique_ptr<GlicWindowAnimator> glic_window_animator_;
std::unique_ptr<GlicWindowEventObserver> window_event_observer_;
bool login_page_committed_ = false;
std::optional<gfx::Size> glic_size_;
bool user_resizable_ = true;
mojom::PanelState panel_state_;
raw_ptr<GlicWebClientAccess> web_client_;
State state_ = State::kClosed;
raw_ptr<Browser> attached_browser_ = nullptr;
base::ObserverList<web_modal::ModalDialogHostObserver>::Unchecked
modal_dialog_host_observers_;
bool do_focus_loss_announcement_ = false;
bool user_resizing_ = false;
GlicWindowConfig window_config_;
std::optional<mojom::InvocationSource> opening_source_;
std::optional<std::string> prompt_suggestion_;
std::optional<gfx::Point> previous_position_ = std::nullopt;
std::unique_ptr<ScopedGlicButtonIndicator> scoped_glic_button_indicator_;
std::unique_ptr<WindowFinder> window_finder_;
std::unique_ptr<LocalHotkeyManager> application_hotkey_manager_;
std::unique_ptr<LocalHotkeyManager> glic_panel_hotkey_manager_;
raw_ptr<GlicKeyedService> glic_service_;
raw_ptr<GlicEnabling> enabling_;
base::ScopedObservation<Host, Host::Observer> host_observation_{this};
const InstanceId id_;
std::unique_ptr<GlicScreenshotCapturer> screenshot_capturer_;
base::WeakPtrFactory<GlicWindowControllerImpl> weak_ptr_factory_{this};
};
}
#endif