| // Copyright 2025 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/glic/widget/glic_side_panel_ui.h" |
| |
| #include "base/notimplemented.h" |
| #include "chrome/browser/glic/public/glic_instance.h" |
| #include "chrome/browser/glic/service/glic_ui_embedder.h" |
| #include "chrome/browser/glic/widget/application_hotkey_delegate.h" |
| #include "chrome/browser/glic/widget/glic_inactive_side_panel_ui.h" |
| #include "chrome/browser/glic/widget/glic_panel_hotkey_delegate.h" |
| #include "chrome/browser/glic/widget/glic_view.h" |
| #include "chrome/browser/glic/widget/glic_widget.h" |
| #include "chrome/browser/ui/browser_window/public/browser_window_features.h" |
| #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" |
| #include "chrome/browser/ui/tabs/public/tab_features.h" |
| #include "chrome/browser/ui/views/frame/browser_view.h" |
| #include "chrome/browser/ui/views/side_panel/side_panel.h" |
| #include "chrome/browser/ui/views/side_panel/side_panel_coordinator.h" |
| #include "chrome/browser/ui/views/side_panel/side_panel_entry.h" |
| #include "components/tabs/public/tab_interface.h" |
| #include "components/viz/common/frame_sinks/copy_output_result.h" |
| #include "content/public/browser/render_widget_host_view.h" |
| #include "content/public/browser/web_contents.h" |
| #include "ui/views/view.h" |
| |
| namespace glic { |
| |
| GlicSidePanelUi::GlicSidePanelUi(Profile* profile, |
| base::WeakPtr<tabs::TabInterface> tab, |
| GlicUiEmbedder::Delegate& delegate) |
| : profile_(profile), tab_(tab), delegate_(delegate) { |
| auto* glic_side_panel_coordinator = GetGlicSidePanelCoordinator(); |
| if (!glic_side_panel_coordinator) { |
| return; |
| } |
| |
| application_hotkey_manager_ = |
| MakeApplicationHotkeyManager(weak_ptr_factory_.GetWeakPtr()); |
| glic_panel_hotkey_manager_ = |
| MakeGlicWindowHotkeyManager(weak_ptr_factory_.GetWeakPtr()); |
| |
| panel_visibility_subscription_ = |
| glic_side_panel_coordinator->AddStateCallback( |
| base::BindRepeating(&GlicSidePanelUi::SidePanelStateChanged, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| glic_side_panel_coordinator->SetContentsView(CreateView(profile_)); |
| panel_state_.kind = mojom::PanelState_Kind::kAttached; |
| } |
| |
| std::unique_ptr<views::View> GlicSidePanelUi::CreateView(Profile* profile) { |
| auto glic_view = |
| std::make_unique<GlicView>(profile, GlicWidget::GetInitialSize(), |
| glic_panel_hotkey_manager_->GetWeakPtr()); |
| glic_view->SetWebContents(delegate_->host().webui_contents()); |
| glic_view->UpdateBackgroundColor(); |
| glic_view_ = glic_view->GetWeakPtr(); |
| return glic_view; |
| } |
| |
| GlicSidePanelUi::~GlicSidePanelUi() = default; |
| |
| Host::EmbedderDelegate* GlicSidePanelUi::GetHostEmbedderDelegate() { |
| return this; |
| } |
| |
| mojom::PanelState GlicSidePanelUi::GetPanelState() const { |
| return panel_state_; |
| } |
| |
| gfx::Size GlicSidePanelUi::GetPanelSize() { |
| if (!glic_view_) { |
| return {}; |
| } |
| return glic_view_->size(); |
| } |
| |
| void GlicSidePanelUi::Resize(const gfx::Size& size, |
| base::TimeDelta duration, |
| base::OnceClosure callback) { |
| NOTIMPLEMENTED(); |
| std::move(callback).Run(); |
| } |
| |
| void GlicSidePanelUi::SetDraggableAreas( |
| const std::vector<gfx::Rect>& draggable_areas) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void GlicSidePanelUi::EnableDragResize(bool enabled) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void GlicSidePanelUi::Attach() { |
| // The Side Panel Ui is already attached, do nothing. |
| } |
| |
| void GlicSidePanelUi::Detach() { |
| if (!tab_) { |
| return; |
| } |
| delegate_->Detach(tab_.get()); |
| } |
| |
| void GlicSidePanelUi::SetMinimumWidgetSize(const gfx::Size& size) { |
| NOTIMPLEMENTED(); |
| } |
| |
| bool GlicSidePanelUi::IsShowing() const { |
| auto* glic_side_panel_coordinator = GetGlicSidePanelCoordinator(); |
| if (!glic_side_panel_coordinator) { |
| return false; |
| } |
| return glic_side_panel_coordinator->IsShowing(); |
| } |
| |
| void GlicSidePanelUi::Focus() { |
| if (auto* web_contents = delegate_->host().webui_contents()) { |
| web_contents->Focus(); |
| } |
| } |
| |
| void GlicSidePanelUi::SidePanelStateChanged( |
| GlicSidePanelCoordinator::State state) { |
| // Showing only happens through glic entrypoint, hiding can also be triggered |
| // by side panel coordinator when replacing glic with another entry. |
| if (state != GlicSidePanelCoordinator::State::kShown && tab_) { |
| delegate_->WillCloseFor(tab_.get()); |
| } |
| } |
| |
| void GlicSidePanelUi::SwitchConversation( |
| glic::mojom::ConversationInfoPtr info, |
| mojom::WebClientHandler::SwitchConversationCallback callback) { |
| delegate_->SwitchConversation(ShowOptions::ForSidePanel(*tab_), |
| std::move(info), std::move(callback)); |
| } |
| |
| void GlicSidePanelUi::Show() { |
| auto* glic_side_panel_coordinator = GetGlicSidePanelCoordinator(); |
| if (!glic_side_panel_coordinator) { |
| return; |
| } |
| panel_state_.kind = mojom::PanelState_Kind::kAttached; |
| delegate_->NotifyPanelStateChanged(); |
| application_hotkey_manager_->InitializeAccelerators(); |
| glic_panel_hotkey_manager_->InitializeAccelerators(); |
| glic_side_panel_coordinator->Show(); |
| } |
| |
| void GlicSidePanelUi::Close() { |
| auto* glic_side_panel_coordinator = GetGlicSidePanelCoordinator(); |
| if (!glic_side_panel_coordinator || !IsShowing()) { |
| return; |
| } |
| panel_state_.kind = mojom::PanelState_Kind::kHidden; |
| delegate_->NotifyPanelStateChanged(); |
| glic_side_panel_coordinator->Close(); |
| } |
| |
| void GlicSidePanelUi::ClosePanel() { |
| Close(); |
| } |
| |
| std::unique_ptr<GlicUiEmbedder> GlicSidePanelUi::CreateInactiveEmbedder() |
| const { |
| return GlicInactiveSidePanelUi::CreateForVisibleTab( |
| tab_, delegate_->host().webui_contents(), delegate_.get()); |
| } |
| |
| void GlicSidePanelUi::FocusIfOpen() { |
| if (IsShowing()) { |
| Focus(); |
| } |
| } |
| |
| bool GlicSidePanelUi::HasFocus() { |
| if (!glic_view_) { |
| return false; |
| } |
| return glic_view_->HasFocus(); |
| } |
| |
| bool GlicSidePanelUi::ActivateBrowser() { |
| if (!tab_) { |
| return false; |
| } |
| tab_->GetContents()->Focus(); |
| return true; |
| } |
| |
| void GlicSidePanelUi::ShowTitleBarContextMenuAt(gfx::Point event_loc) { |
| // This is floaty-specific. It doesn't make sense in side panel. |
| } |
| |
| base::WeakPtr<views::View> GlicSidePanelUi::GetView() { |
| return glic_view_; |
| } |
| |
| GlicSidePanelCoordinator* GlicSidePanelUi::GetGlicSidePanelCoordinator() const { |
| if (!tab_ || !tab_->GetTabFeatures()) { |
| return nullptr; |
| } |
| return tab_->GetTabFeatures()->glic_side_panel_coordinator(); |
| } |
| |
| } // namespace glic |