1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/panels/panel.h"
7 #include "base/logging.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/app/chrome_command_ids.h"
11 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/browser/devtools/devtools_window.h"
13 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
14 #include "chrome/browser/extensions/api/tabs/tabs_windows_api.h"
15 #include "chrome/browser/extensions/api/tabs/windows_event_router.h"
16 #include "chrome/browser/extensions/extension_service.h"
17 #include "chrome/browser/extensions/extension_tab_util.h"
18 #include "chrome/browser/extensions/image_loader.h"
19 #include "chrome/browser/extensions/window_controller.h"
20 #include "chrome/browser/extensions/window_controller_list.h"
21 #include "chrome/browser/lifetime/application_lifetime.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/themes/theme_service.h"
24 #include "chrome/browser/themes/theme_service_factory.h"
25 #include "chrome/browser/ui/panels/native_panel.h"
26 #include "chrome/browser/ui/panels/panel_collection.h"
27 #include "chrome/browser/ui/panels/panel_host.h"
28 #include "chrome/browser/ui/panels/panel_manager.h"
29 #include "chrome/browser/ui/panels/stacked_panel_collection.h"
30 #include "chrome/browser/web_applications/web_app.h"
31 #include "content/public/browser/notification_service.h"
32 #include "content/public/browser/notification_source.h"
33 #include "content/public/browser/notification_types.h"
34 #include "content/public/browser/render_view_host.h"
35 #include "content/public/browser/user_metrics.h"
36 #include "content/public/browser/web_contents.h"
37 #include "extensions/browser/extension_system.h"
38 #include "extensions/common/constants.h"
39 #include "extensions/common/extension.h"
40 #include "extensions/common/manifest_handlers/icons_handler.h"
41 #include "ui/gfx/image/image.h"
42 #include "ui/gfx/rect.h"
44 using base::UserMetricsAction
;
45 using content::RenderViewHost
;
47 namespace panel_internal
{
49 class PanelExtensionWindowController
: public extensions::WindowController
{
51 PanelExtensionWindowController(Panel
* panel
, Profile
* profile
);
52 virtual ~PanelExtensionWindowController();
54 // Overridden from extensions::WindowController.
55 virtual int GetWindowId() const OVERRIDE
;
56 virtual std::string
GetWindowTypeText() const OVERRIDE
;
57 virtual base::DictionaryValue
* CreateWindowValueWithTabs(
58 const extensions::Extension
* extension
) const OVERRIDE
;
59 virtual base::DictionaryValue
* CreateTabValue(
60 const extensions::Extension
* extension
, int tab_index
) const OVERRIDE
;
61 virtual bool CanClose(Reason
* reason
) const OVERRIDE
;
62 virtual void SetFullscreenMode(bool is_fullscreen
,
63 const GURL
& extension_url
) const OVERRIDE
;
64 virtual bool IsVisibleToExtension(
65 const extensions::Extension
* extension
) const OVERRIDE
;
68 Panel
* panel_
; // Weak pointer. Owns us.
69 DISALLOW_COPY_AND_ASSIGN(PanelExtensionWindowController
);
72 PanelExtensionWindowController::PanelExtensionWindowController(
73 Panel
* panel
, Profile
* profile
)
74 : extensions::WindowController(panel
, profile
),
76 extensions::WindowControllerList::GetInstance()->AddExtensionWindow(this);
79 PanelExtensionWindowController::~PanelExtensionWindowController() {
80 extensions::WindowControllerList::GetInstance()->RemoveExtensionWindow(this);
83 int PanelExtensionWindowController::GetWindowId() const {
84 return static_cast<int>(panel_
->session_id().id());
87 std::string
PanelExtensionWindowController::GetWindowTypeText() const {
88 return extensions::tabs_constants::kWindowTypeValuePanel
;
91 base::DictionaryValue
*
92 PanelExtensionWindowController::CreateWindowValueWithTabs(
93 const extensions::Extension
* extension
) const {
94 base::DictionaryValue
* result
= CreateWindowValue();
96 DCHECK(IsVisibleToExtension(extension
));
97 base::DictionaryValue
* tab_value
= CreateTabValue(extension
, 0);
99 base::ListValue
* tab_list
= new base::ListValue();
100 tab_list
->Append(tab_value
);
101 result
->Set(extensions::tabs_constants::kTabsKey
, tab_list
);
106 base::DictionaryValue
* PanelExtensionWindowController::CreateTabValue(
107 const extensions::Extension
* extension
, int tab_index
) const {
111 content::WebContents
* web_contents
= panel_
->GetWebContents();
115 DCHECK(IsVisibleToExtension(extension
));
116 base::DictionaryValue
* tab_value
= new base::DictionaryValue();
117 tab_value
->SetInteger(extensions::tabs_constants::kIdKey
,
118 SessionID::IdForTab(web_contents
));
119 tab_value
->SetInteger(extensions::tabs_constants::kIndexKey
, 0);
120 tab_value
->SetInteger(extensions::tabs_constants::kWindowIdKey
,
121 SessionID::IdForWindowContainingTab(web_contents
));
122 tab_value
->SetString(
123 extensions::tabs_constants::kUrlKey
, web_contents
->GetURL().spec());
124 tab_value
->SetString(extensions::tabs_constants::kStatusKey
,
125 extensions::ExtensionTabUtil::GetTabStatusText(
126 web_contents
->IsLoading()));
127 tab_value
->SetBoolean(
128 extensions::tabs_constants::kActiveKey
, panel_
->IsActive());
129 tab_value
->SetBoolean(extensions::tabs_constants::kSelectedKey
, true);
130 tab_value
->SetBoolean(extensions::tabs_constants::kHighlightedKey
, true);
131 tab_value
->SetBoolean(extensions::tabs_constants::kPinnedKey
, false);
132 tab_value
->SetString(
133 extensions::tabs_constants::kTitleKey
, web_contents
->GetTitle());
134 tab_value
->SetBoolean(
135 extensions::tabs_constants::kIncognitoKey
,
136 web_contents
->GetBrowserContext()->IsOffTheRecord());
140 bool PanelExtensionWindowController::CanClose(Reason
* reason
) const {
144 void PanelExtensionWindowController::SetFullscreenMode(
145 bool is_fullscreen
, const GURL
& extension_url
) const {
146 // Do nothing. Panels cannot be fullscreen.
149 bool PanelExtensionWindowController::IsVisibleToExtension(
150 const extensions::Extension
* extension
) const {
151 return extension
->id() == panel_
->extension_id();
154 } // namespace panel_internal
157 DCHECK(!collection_
);
158 #if !defined(USE_AURA)
159 // Invoked by native panel destructor. Do not access native_panel_ here.
160 chrome::DecrementKeepAliveCount(); // Remove shutdown prevention.
164 PanelManager
* Panel::manager() const {
165 return PanelManager::GetInstance();
168 const std::string
Panel::extension_id() const {
169 return web_app::GetExtensionIdFromApplicationName(app_name_
);
172 CommandUpdater
* Panel::command_updater() {
173 return &command_updater_
;
176 Profile
* Panel::profile() const {
180 const extensions::Extension
* Panel::GetExtension() const {
181 ExtensionService
* extension_service
=
182 extensions::ExtensionSystem::Get(profile())->extension_service();
183 if (!extension_service
|| !extension_service
->is_ready())
185 return extension_service
->GetExtensionById(extension_id(), false);
188 content::WebContents
* Panel::GetWebContents() const {
189 return panel_host_
.get() ? panel_host_
->web_contents() : NULL
;
192 void Panel::SetExpansionState(ExpansionState new_state
) {
193 if (expansion_state_
== new_state
)
195 native_panel_
->PanelExpansionStateChanging(expansion_state_
, new_state
);
196 expansion_state_
= new_state
;
198 manager()->OnPanelExpansionStateChanged(this);
200 DCHECK(initialized_
&& collection_
!= NULL
);
201 native_panel_
->PreventActivationByOS(collection_
->IsPanelMinimized(this));
202 UpdateMinimizeRestoreButtonVisibility();
204 content::NotificationService::current()->Notify(
205 chrome::NOTIFICATION_PANEL_CHANGED_EXPANSION_STATE
,
206 content::Source
<Panel
>(this),
207 content::NotificationService::NoDetails());
210 bool Panel::IsDrawingAttention() const {
211 return native_panel_
->IsDrawingAttention();
214 void Panel::FullScreenModeChanged(bool is_full_screen
) {
215 native_panel_
->FullScreenModeChanged(is_full_screen
);
218 int Panel::TitleOnlyHeight() const {
219 return native_panel_
->TitleOnlyHeight();
222 bool Panel::CanShowMinimizeButton() const {
223 return collection_
&& collection_
->CanShowMinimizeButton(this);
226 bool Panel::CanShowRestoreButton() const {
227 return collection_
&& collection_
->CanShowRestoreButton(this);
230 bool Panel::IsActive() const {
231 return native_panel_
->IsPanelActive();
234 bool Panel::IsMaximized() const {
235 // Size of panels is managed by PanelManager, they are never 'zoomed'.
239 bool Panel::IsMinimized() const {
240 return !collection_
|| collection_
->IsPanelMinimized(this);
243 bool Panel::IsFullscreen() const {
247 gfx::NativeWindow
Panel::GetNativeWindow() {
248 return native_panel_
->GetNativePanelWindow();
251 gfx::Rect
Panel::GetRestoredBounds() const {
252 gfx::Rect bounds
= native_panel_
->GetPanelBounds();
253 bounds
.set_y(bounds
.bottom() - full_size_
.height());
254 bounds
.set_x(bounds
.right() - full_size_
.width());
255 bounds
.set_size(full_size_
);
259 ui::WindowShowState
Panel::GetRestoredState() const {
260 return ui::SHOW_STATE_NORMAL
;
263 gfx::Rect
Panel::GetBounds() const {
264 return native_panel_
->GetPanelBounds();
268 if (manager()->display_settings_provider()->is_full_screen() || !collection_
)
271 native_panel_
->ShowPanel();
278 void Panel::ShowInactive() {
279 if (manager()->display_settings_provider()->is_full_screen() || !collection_
)
282 native_panel_
->ShowPanelInactive();
285 // Close() may be called multiple times if the panel window is not ready to
286 // close on the first attempt.
287 void Panel::Close() {
288 native_panel_
->ClosePanel();
291 void Panel::Activate() {
295 collection_
->ActivatePanel(this);
296 native_panel_
->ActivatePanel();
299 void Panel::Deactivate() {
300 native_panel_
->DeactivatePanel();
303 void Panel::Maximize() {
307 void Panel::Minimize() {
309 collection_
->MinimizePanel(this);
312 bool Panel::IsMinimizedBySystem() const {
313 return native_panel_
->IsPanelMinimizedBySystem();
316 bool Panel::IsShownOnActiveDesktop() const {
317 return native_panel_
->IsPanelShownOnActiveDesktop();
320 void Panel::ShowShadow(bool show
) {
321 native_panel_
->ShowShadow(show
);
324 void Panel::Restore() {
326 collection_
->RestorePanel(this);
329 void Panel::SetBounds(const gfx::Rect
& bounds
) {
330 // Ignore bounds position as the panel manager controls all positioning.
333 collection_
->ResizePanelWindow(this, bounds
.size());
334 SetAutoResizable(false);
337 void Panel::FlashFrame(bool draw_attention
) {
338 if (IsDrawingAttention() == draw_attention
|| !collection_
)
341 // Don't draw attention for an active panel.
342 if (draw_attention
&& IsActive())
345 // Invoking native panel to draw attention must be done before informing the
346 // panel collection because it needs to check internal state of the panel to
347 // determine if the panel has been drawing attention.
348 native_panel_
->DrawAttention(draw_attention
);
349 collection_
->OnPanelAttentionStateChanged(this);
352 bool Panel::IsAlwaysOnTop() const {
353 return native_panel_
->IsPanelAlwaysOnTop();
356 void Panel::SetAlwaysOnTop(bool on_top
) {
357 native_panel_
->SetPanelAlwaysOnTop(on_top
);
360 void Panel::ExecuteCommandWithDisposition(int id
,
361 WindowOpenDisposition disposition
) {
362 DCHECK(command_updater_
.IsCommandEnabled(id
)) << "Invalid/disabled command "
365 if (!GetWebContents())
371 panel_host_
->Reload();
373 case IDC_RELOAD_IGNORING_CACHE
:
374 panel_host_
->ReloadIgnoringCache();
377 panel_host_
->StopLoading();
381 case IDC_CLOSE_WINDOW
:
382 content::RecordAction(UserMetricsAction("CloseWindow"));
386 content::RecordAction(UserMetricsAction("Exit"));
387 chrome::AttemptUserExit();
392 content::RecordAction(UserMetricsAction("Copy"));
393 native_panel_
->PanelCopy();
396 content::RecordAction(UserMetricsAction("Cut"));
397 native_panel_
->PanelCut();
400 content::RecordAction(UserMetricsAction("Paste"));
401 native_panel_
->PanelPaste();
406 panel_host_
->Zoom(content::PAGE_ZOOM_IN
);
408 case IDC_ZOOM_NORMAL
:
409 panel_host_
->Zoom(content::PAGE_ZOOM_RESET
);
412 panel_host_
->Zoom(content::PAGE_ZOOM_OUT
);
417 content::RecordAction(UserMetricsAction("DevTools_ToggleWindow"));
418 DevToolsWindow::OpenDevToolsWindow(
419 GetWebContents()->GetRenderViewHost(),
420 DevToolsToggleAction::Show());
422 case IDC_DEV_TOOLS_CONSOLE
:
423 content::RecordAction(UserMetricsAction("DevTools_ToggleConsole"));
424 DevToolsWindow::OpenDevToolsWindow(
425 GetWebContents()->GetRenderViewHost(),
426 DevToolsToggleAction::ShowConsole());
430 LOG(WARNING
) << "Received unimplemented command: " << id
;
435 void Panel::Observe(int type
,
436 const content::NotificationSource
& source
,
437 const content::NotificationDetails
& details
) {
439 case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED
:
440 ConfigureAutoResize(content::Source
<content::WebContents
>(source
).ptr());
442 case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED
:
443 if (content::Details
<extensions::UnloadedExtensionInfo
>(
444 details
)->extension
->id() == extension_id())
447 case chrome::NOTIFICATION_APP_TERMINATING
:
451 NOTREACHED() << "Received unexpected notification " << type
;
455 void Panel::OnTitlebarClicked(panel::ClickModifier modifier
) {
457 collection_
->OnPanelTitlebarClicked(this, modifier
);
459 // Normally the system activates a window when the titlebar is clicked.
460 // However, we prevent system activation of minimized panels, thus the
461 // activation may not have occurred. Also, some OSes (Windows) will
462 // activate a minimized panel on mouse-down regardless of our attempts to
463 // prevent system activation. Attention state is not cleared in that case.
464 // See Panel::OnActiveStateChanged().
465 // Therefore, we ensure activation and clearing of attention state if the
466 // panel has been expanded. If the panel is in a stack, the titlebar click
467 // might minimize the panel and we do not want to activate it to make it
469 // These are no-ops if no changes are needed.
476 void Panel::OnMinimizeButtonClicked(panel::ClickModifier modifier
) {
478 collection_
->OnMinimizeButtonClicked(this, modifier
);
481 void Panel::OnRestoreButtonClicked(panel::ClickModifier modifier
) {
482 // Clicking the restore button has the same behavior as clicking the titlebar.
483 OnTitlebarClicked(modifier
);
486 void Panel::OnWindowSizeAvailable() {
487 ConfigureAutoResize(GetWebContents());
490 void Panel::OnNativePanelClosed() {
491 // Ensure previously enqueued OnImageLoaded callbacks are ignored.
492 image_loader_ptr_factory_
.InvalidateWeakPtrs();
493 registrar_
.RemoveAll();
494 manager()->OnPanelClosed(this);
495 DCHECK(!collection_
);
498 StackedPanelCollection
* Panel::stack() const {
499 return collection_
&& collection_
->type() == PanelCollection::STACKED
?
500 static_cast<StackedPanelCollection
*>(collection_
) : NULL
;
503 panel::Resizability
Panel::CanResizeByMouse() const {
505 return panel::NOT_RESIZABLE
;
507 return collection_
->GetPanelResizability(this);
510 void Panel::Initialize(const GURL
& url
,
511 const gfx::Rect
& bounds
,
512 bool always_on_top
) {
513 DCHECK(!initialized_
);
514 DCHECK(!collection_
); // Cannot be added to a collection until fully created.
515 DCHECK_EQ(EXPANDED
, expansion_state_
);
516 DCHECK(!bounds
.IsEmpty());
518 full_size_
= bounds
.size();
519 native_panel_
= CreateNativePanel(this, bounds
, always_on_top
);
521 extension_window_controller_
.reset(
522 new panel_internal::PanelExtensionWindowController(this, profile_
));
526 // Set up hosting for web contents.
527 panel_host_
.reset(new PanelHost(this, profile_
));
528 panel_host_
->Init(url
);
529 content::WebContents
* web_contents
= GetWebContents();
530 // The contents might be NULL for most of our tests.
532 native_panel_
->AttachWebContents(web_contents
);
534 // Close when the extension is unloaded or the browser is exiting.
535 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED
,
536 content::Source
<Profile
>(profile_
));
537 registrar_
.Add(this, chrome::NOTIFICATION_APP_TERMINATING
,
538 content::NotificationService::AllSources());
539 registrar_
.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED
,
540 content::Source
<ThemeService
>(
541 ThemeServiceFactory::GetForProfile(profile_
)));
543 #if !defined(USE_AURA)
544 // Keep alive for AURA has been moved to panel_view.
545 // Prevent the browser process from shutting down while this window is open.
546 chrome::IncrementKeepAliveCount();
552 void Panel::SetPanelBounds(const gfx::Rect
& bounds
) {
553 if (bounds
!= native_panel_
->GetPanelBounds())
554 native_panel_
->SetPanelBounds(bounds
);
557 void Panel::SetPanelBoundsInstantly(const gfx::Rect
& bounds
) {
558 native_panel_
->SetPanelBoundsInstantly(bounds
);
561 void Panel::LimitSizeToWorkArea(const gfx::Rect
& work_area
) {
562 int max_width
= manager()->GetMaxPanelWidth(work_area
);
563 int max_height
= manager()->GetMaxPanelHeight(work_area
);
565 // If the custom max size is used, ensure that it does not exceed the display
567 if (max_size_policy_
== CUSTOM_MAX_SIZE
) {
568 int current_max_width
= max_size_
.width();
569 if (current_max_width
> max_width
)
570 max_width
= std::min(current_max_width
, work_area
.width());
571 int current_max_height
= max_size_
.height();
572 if (current_max_height
> max_height
)
573 max_height
= std::min(current_max_height
, work_area
.height());
576 SetSizeRange(min_size_
, gfx::Size(max_width
, max_height
));
578 // Ensure that full size does not exceed max size.
579 full_size_
= ClampSize(full_size_
);
582 void Panel::SetAutoResizable(bool resizable
) {
583 if (auto_resizable_
== resizable
)
586 auto_resizable_
= resizable
;
587 content::WebContents
* web_contents
= GetWebContents();
588 if (auto_resizable_
) {
590 EnableWebContentsAutoResize(web_contents
);
593 registrar_
.Remove(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED
,
594 content::Source
<content::WebContents
>(web_contents
));
596 // NULL might be returned if the tab has not been added.
597 RenderViewHost
* render_view_host
= web_contents
->GetRenderViewHost();
598 if (render_view_host
)
599 render_view_host
->DisableAutoResize(full_size_
);
604 void Panel::EnableWebContentsAutoResize(content::WebContents
* web_contents
) {
605 DCHECK(web_contents
);
606 ConfigureAutoResize(web_contents
);
608 // We also need to know when the render view host changes in order
609 // to turn on auto-resize notifications in the new render view host.
610 if (!registrar_
.IsRegistered(
611 this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED
,
612 content::Source
<content::WebContents
>(web_contents
))) {
615 content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED
,
616 content::Source
<content::WebContents
>(web_contents
));
620 void Panel::OnContentsAutoResized(const gfx::Size
& new_content_size
) {
621 DCHECK(auto_resizable_
);
625 gfx::Size new_window_size
=
626 native_panel_
->WindowSizeFromContentSize(new_content_size
);
628 // Ignore content auto resizes until window frame size is known.
629 // This reduces extra resizes when panel is first shown.
630 // After window frame size is known, it will trigger another content
632 if (new_content_size
== new_window_size
)
635 collection_
->ResizePanelWindow(this, new_window_size
);
638 void Panel::OnWindowResizedByMouse(const gfx::Rect
& new_bounds
) {
640 collection_
->OnPanelResizedByMouse(this, new_bounds
);
643 void Panel::SetSizeRange(const gfx::Size
& min_size
, const gfx::Size
& max_size
) {
644 if (min_size
== min_size_
&& max_size
== max_size_
)
647 DCHECK(min_size
.width() <= max_size
.width());
648 DCHECK(min_size
.height() <= max_size
.height());
649 min_size_
= min_size
;
650 max_size_
= max_size
;
652 ConfigureAutoResize(GetWebContents());
655 void Panel::IncreaseMaxSize(const gfx::Size
& desired_panel_size
) {
656 gfx::Size new_max_size
= max_size_
;
657 if (new_max_size
.width() < desired_panel_size
.width())
658 new_max_size
.set_width(desired_panel_size
.width());
659 if (new_max_size
.height() < desired_panel_size
.height())
660 new_max_size
.set_height(desired_panel_size
.height());
662 SetSizeRange(min_size_
, new_max_size
);
665 void Panel::HandleKeyboardEvent(const content::NativeWebKeyboardEvent
& event
) {
666 native_panel_
->HandlePanelKeyboardEvent(event
);
669 void Panel::SetPreviewMode(bool in_preview
) {
670 DCHECK_NE(in_preview_mode_
, in_preview
);
671 in_preview_mode_
= in_preview
;
674 void Panel::UpdateMinimizeRestoreButtonVisibility() {
675 native_panel_
->UpdatePanelMinimizeRestoreButtonVisibility();
678 gfx::Size
Panel::ClampSize(const gfx::Size
& size
) const {
680 // * cannot grow or shrink to go beyond [min_width, max_width]
681 int new_width
= size
.width();
682 if (new_width
> max_size_
.width())
683 new_width
= max_size_
.width();
684 if (new_width
< min_size_
.width())
685 new_width
= min_size_
.width();
688 // * cannot grow or shrink to go beyond [min_height, max_height]
689 int new_height
= size
.height();
690 if (new_height
> max_size_
.height())
691 new_height
= max_size_
.height();
692 if (new_height
< min_size_
.height())
693 new_height
= min_size_
.height();
695 return gfx::Size(new_width
, new_height
);
698 void Panel::OnActiveStateChanged(bool active
) {
699 // Clear attention state when an expanded panel becomes active.
700 // On some systems (e.g. Win), mouse-down activates a panel regardless of
701 // its expansion state. However, we don't want to clear draw attention if
702 // contents are not visible. In that scenario, if the mouse-down results
703 // in a mouse-click, draw attention will be cleared then.
704 // See Panel::OnTitlebarClicked().
705 if (active
&& IsDrawingAttention() && !IsMinimized())
709 collection_
->OnPanelActiveStateChanged(this);
711 // Send extension event about window changing active state.
712 extensions::TabsWindowsAPI
* tabs_windows_api
=
713 extensions::TabsWindowsAPI::Get(profile());
714 if (tabs_windows_api
) {
715 tabs_windows_api
->windows_event_router()->OnActiveWindowChanged(
716 active
? extension_window_controller_
.get() : NULL
);
719 content::NotificationService::current()->Notify(
720 chrome::NOTIFICATION_PANEL_CHANGED_ACTIVE_STATUS
,
721 content::Source
<Panel
>(this),
722 content::NotificationService::NoDetails());
725 void Panel::OnPanelStartUserResizing() {
726 SetAutoResizable(false);
727 SetPreviewMode(true);
728 max_size_policy_
= CUSTOM_MAX_SIZE
;
731 void Panel::OnPanelEndUserResizing() {
732 SetPreviewMode(false);
735 bool Panel::ShouldCloseWindow() {
739 void Panel::OnWindowClosing() {
740 if (GetWebContents()) {
741 native_panel_
->DetachWebContents(GetWebContents());
742 panel_host_
->DestroyWebContents();
746 bool Panel::ExecuteCommandIfEnabled(int id
) {
747 if (command_updater()->SupportsCommand(id
) &&
748 command_updater()->IsCommandEnabled(id
)) {
749 ExecuteCommandWithDisposition(id
, CURRENT_TAB
);
755 base::string16
Panel::GetWindowTitle() const {
756 content::WebContents
* contents
= GetWebContents();
757 base::string16 title
;
759 // |contents| can be NULL during the window's creation.
761 title
= contents
->GetTitle();
762 FormatTitleForDisplay(&title
);
766 title
= base::UTF8ToUTF16(app_name());
771 gfx::Image
Panel::GetCurrentPageIcon() const {
772 return panel_host_
->GetPageIcon();
775 void Panel::UpdateTitleBar() {
776 native_panel_
->UpdatePanelTitleBar();
779 void Panel::LoadingStateChanged(bool is_loading
) {
780 command_updater_
.UpdateCommandEnabled(IDC_STOP
, is_loading
);
781 native_panel_
->UpdatePanelLoadingAnimations(is_loading
);
785 void Panel::WebContentsFocused(content::WebContents
* contents
) {
786 native_panel_
->PanelWebContentsFocused(contents
);
789 void Panel::MoveByInstantly(const gfx::Vector2d
& delta_origin
) {
790 gfx::Rect bounds
= GetBounds();
791 bounds
.Offset(delta_origin
);
792 SetPanelBoundsInstantly(bounds
);
795 void Panel::SetWindowCornerStyle(panel::CornerStyle corner_style
) {
796 native_panel_
->SetWindowCornerStyle(corner_style
);
799 void Panel::MinimizeBySystem() {
800 native_panel_
->MinimizePanelBySystem();
803 Panel::Panel(Profile
* profile
, const std::string
& app_name
,
804 const gfx::Size
& min_size
, const gfx::Size
& max_size
)
805 : app_name_(app_name
),
811 max_size_policy_(DEFAULT_MAX_SIZE
),
812 auto_resizable_(false),
813 in_preview_mode_(false),
815 attention_mode_(USE_PANEL_ATTENTION
),
816 expansion_state_(EXPANDED
),
817 command_updater_(this),
818 image_loader_ptr_factory_(this) {
821 void Panel::OnImageLoaded(const gfx::Image
& image
) {
822 if (!image
.IsEmpty()) {
824 native_panel_
->UpdatePanelTitleBar();
827 content::NotificationService::current()->Notify(
828 chrome::NOTIFICATION_PANEL_APP_ICON_LOADED
,
829 content::Source
<Panel
>(this),
830 content::NotificationService::NoDetails());
833 void Panel::InitCommandState() {
834 // All supported commands whose state isn't set automagically some other way
835 // (like Stop during a page load) must have their state initialized here,
836 // otherwise they will be forever disabled.
838 // Navigation commands
839 command_updater_
.UpdateCommandEnabled(IDC_RELOAD
, true);
840 command_updater_
.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE
, true);
842 // Window management commands
843 command_updater_
.UpdateCommandEnabled(IDC_CLOSE_WINDOW
, true);
844 command_updater_
.UpdateCommandEnabled(IDC_EXIT
, true);
847 command_updater_
.UpdateCommandEnabled(IDC_ZOOM_MENU
, true);
848 command_updater_
.UpdateCommandEnabled(IDC_ZOOM_PLUS
, true);
849 command_updater_
.UpdateCommandEnabled(IDC_ZOOM_NORMAL
, true);
850 command_updater_
.UpdateCommandEnabled(IDC_ZOOM_MINUS
, true);
853 command_updater_
.UpdateCommandEnabled(IDC_COPY
, true);
854 command_updater_
.UpdateCommandEnabled(IDC_CUT
, true);
855 command_updater_
.UpdateCommandEnabled(IDC_PASTE
, true);
858 command_updater_
.UpdateCommandEnabled(IDC_DEV_TOOLS
, true);
859 command_updater_
.UpdateCommandEnabled(IDC_DEV_TOOLS_CONSOLE
, true);
862 void Panel::ConfigureAutoResize(content::WebContents
* web_contents
) {
863 if (!auto_resizable_
|| !web_contents
)
866 // NULL might be returned if the tab has not been added.
867 RenderViewHost
* render_view_host
= web_contents
->GetRenderViewHost();
868 if (!render_view_host
)
871 render_view_host
->EnableAutoResize(
873 native_panel_
->ContentSizeFromWindowSize(max_size_
));
876 void Panel::UpdateAppIcon() {
877 const extensions::Extension
* extension
= GetExtension();
881 extensions::ImageLoader
* loader
= extensions::ImageLoader::Get(profile());
882 loader
->LoadImageAsync(
884 extensions::IconsInfo::GetIconResource(
886 extension_misc::EXTENSION_ICON_SMALL
,
887 ExtensionIconSet::MATCH_BIGGER
),
888 gfx::Size(extension_misc::EXTENSION_ICON_SMALL
,
889 extension_misc::EXTENSION_ICON_SMALL
),
890 base::Bind(&Panel::OnImageLoaded
,
891 image_loader_ptr_factory_
.GetWeakPtr()));
895 void Panel::FormatTitleForDisplay(base::string16
* title
) {
896 size_t current_index
= 0;
898 while ((match_index
= title
->find(L
'\n', current_index
)) !=
899 base::string16::npos
) {
900 title
->replace(match_index
, 1, base::string16());
901 current_index
= match_index
;