Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / ui / panels / panel.cc
blob27207e8405f0b64580e94ec01c1ea91508eb69e0
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/window_controller.h"
19 #include "chrome/browser/extensions/window_controller_list.h"
20 #include "chrome/browser/lifetime/application_lifetime.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/sessions/session_tab_helper.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_registry.h"
38 #include "extensions/browser/extension_system.h"
39 #include "extensions/browser/image_loader.h"
40 #include "extensions/common/constants.h"
41 #include "extensions/common/extension.h"
42 #include "extensions/common/manifest_handlers/icons_handler.h"
43 #include "ui/gfx/geometry/rect.h"
44 #include "ui/gfx/image/image.h"
46 using base::UserMetricsAction;
47 using content::RenderViewHost;
49 namespace panel_internal {
51 class PanelExtensionWindowController : public extensions::WindowController {
52 public:
53 PanelExtensionWindowController(Panel* panel, Profile* profile);
54 ~PanelExtensionWindowController() override;
56 // Overridden from extensions::WindowController.
57 int GetWindowId() const override;
58 std::string GetWindowTypeText() const override;
59 base::DictionaryValue* CreateWindowValueWithTabs(
60 const extensions::Extension* extension) const override;
61 base::DictionaryValue* CreateTabValue(const extensions::Extension* extension,
62 int tab_index) const override;
63 bool CanClose(Reason* reason) const override;
64 void SetFullscreenMode(bool is_fullscreen,
65 const GURL& extension_url) const override;
66 bool IsVisibleToExtension(
67 const extensions::Extension* extension) const override;
69 private:
70 Panel* panel_; // Weak pointer. Owns us.
71 DISALLOW_COPY_AND_ASSIGN(PanelExtensionWindowController);
74 PanelExtensionWindowController::PanelExtensionWindowController(
75 Panel* panel, Profile* profile)
76 : extensions::WindowController(panel, profile),
77 panel_(panel) {
78 extensions::WindowControllerList::GetInstance()->AddExtensionWindow(this);
81 PanelExtensionWindowController::~PanelExtensionWindowController() {
82 extensions::WindowControllerList::GetInstance()->RemoveExtensionWindow(this);
85 int PanelExtensionWindowController::GetWindowId() const {
86 return static_cast<int>(panel_->session_id().id());
89 std::string PanelExtensionWindowController::GetWindowTypeText() const {
90 return extensions::tabs_constants::kWindowTypeValuePanel;
93 base::DictionaryValue*
94 PanelExtensionWindowController::CreateWindowValueWithTabs(
95 const extensions::Extension* extension) const {
96 base::DictionaryValue* result = CreateWindowValue();
98 DCHECK(IsVisibleToExtension(extension));
99 base::DictionaryValue* tab_value = CreateTabValue(extension, 0);
100 if (tab_value) {
101 base::ListValue* tab_list = new base::ListValue();
102 tab_list->Append(tab_value);
103 result->Set(extensions::tabs_constants::kTabsKey, tab_list);
105 return result;
108 base::DictionaryValue* PanelExtensionWindowController::CreateTabValue(
109 const extensions::Extension* extension, int tab_index) const {
110 if (tab_index > 0)
111 return NULL;
113 content::WebContents* web_contents = panel_->GetWebContents();
114 if (!web_contents)
115 return NULL;
117 DCHECK(IsVisibleToExtension(extension));
118 base::DictionaryValue* tab_value = new base::DictionaryValue();
119 tab_value->SetInteger(extensions::tabs_constants::kIdKey,
120 SessionTabHelper::IdForTab(web_contents));
121 tab_value->SetInteger(extensions::tabs_constants::kIndexKey, 0);
122 tab_value->SetInteger(
123 extensions::tabs_constants::kWindowIdKey,
124 SessionTabHelper::IdForWindowContainingTab(web_contents));
125 tab_value->SetString(
126 extensions::tabs_constants::kUrlKey, web_contents->GetURL().spec());
127 tab_value->SetString(extensions::tabs_constants::kStatusKey,
128 extensions::ExtensionTabUtil::GetTabStatusText(
129 web_contents->IsLoading()));
130 tab_value->SetBoolean(
131 extensions::tabs_constants::kActiveKey, panel_->IsActive());
132 tab_value->SetBoolean(extensions::tabs_constants::kSelectedKey, true);
133 tab_value->SetBoolean(extensions::tabs_constants::kHighlightedKey, true);
134 tab_value->SetBoolean(extensions::tabs_constants::kPinnedKey, false);
135 tab_value->SetString(
136 extensions::tabs_constants::kTitleKey, web_contents->GetTitle());
137 tab_value->SetBoolean(
138 extensions::tabs_constants::kIncognitoKey,
139 web_contents->GetBrowserContext()->IsOffTheRecord());
140 return tab_value;
143 bool PanelExtensionWindowController::CanClose(Reason* reason) const {
144 return true;
147 void PanelExtensionWindowController::SetFullscreenMode(
148 bool is_fullscreen, const GURL& extension_url) const {
149 // Do nothing. Panels cannot be fullscreen.
152 bool PanelExtensionWindowController::IsVisibleToExtension(
153 const extensions::Extension* extension) const {
154 return extension->id() == panel_->extension_id();
157 } // namespace panel_internal
159 Panel::~Panel() {
160 DCHECK(!collection_);
161 #if !defined(USE_AURA)
162 // Invoked by native panel destructor. Do not access native_panel_ here.
163 chrome::DecrementKeepAliveCount(); // Remove shutdown prevention.
164 #endif
167 PanelManager* Panel::manager() const {
168 return PanelManager::GetInstance();
171 const std::string Panel::extension_id() const {
172 return web_app::GetExtensionIdFromApplicationName(app_name_);
175 CommandUpdater* Panel::command_updater() {
176 return &command_updater_;
179 Profile* Panel::profile() const {
180 return profile_;
183 const extensions::Extension* Panel::GetExtension() const {
184 ExtensionService* extension_service =
185 extensions::ExtensionSystem::Get(profile())->extension_service();
186 if (!extension_service || !extension_service->is_ready())
187 return NULL;
188 return extension_service->GetExtensionById(extension_id(), false);
191 content::WebContents* Panel::GetWebContents() const {
192 return panel_host_.get() ? panel_host_->web_contents() : NULL;
195 void Panel::SetExpansionState(ExpansionState new_state) {
196 if (expansion_state_ == new_state)
197 return;
198 native_panel_->PanelExpansionStateChanging(expansion_state_, new_state);
199 expansion_state_ = new_state;
201 manager()->OnPanelExpansionStateChanged(this);
203 DCHECK(initialized_ && collection_ != NULL);
204 native_panel_->PreventActivationByOS(collection_->IsPanelMinimized(this));
205 UpdateMinimizeRestoreButtonVisibility();
207 content::NotificationService::current()->Notify(
208 chrome::NOTIFICATION_PANEL_CHANGED_EXPANSION_STATE,
209 content::Source<Panel>(this),
210 content::NotificationService::NoDetails());
213 bool Panel::IsDrawingAttention() const {
214 return native_panel_->IsDrawingAttention();
217 void Panel::FullScreenModeChanged(bool is_full_screen) {
218 native_panel_->FullScreenModeChanged(is_full_screen);
221 int Panel::TitleOnlyHeight() const {
222 return native_panel_->TitleOnlyHeight();
225 bool Panel::CanShowMinimizeButton() const {
226 return collection_ && collection_->CanShowMinimizeButton(this);
229 bool Panel::CanShowRestoreButton() const {
230 return collection_ && collection_->CanShowRestoreButton(this);
233 bool Panel::IsActive() const {
234 return native_panel_->IsPanelActive();
237 bool Panel::IsMaximized() const {
238 // Size of panels is managed by PanelManager, they are never 'zoomed'.
239 return false;
242 bool Panel::IsMinimized() const {
243 return !collection_ || collection_->IsPanelMinimized(this);
246 bool Panel::IsFullscreen() const {
247 return false;
250 gfx::NativeWindow Panel::GetNativeWindow() const {
251 return native_panel_->GetNativePanelWindow();
254 gfx::Rect Panel::GetRestoredBounds() const {
255 gfx::Rect bounds = native_panel_->GetPanelBounds();
256 bounds.set_y(bounds.bottom() - full_size_.height());
257 bounds.set_x(bounds.right() - full_size_.width());
258 bounds.set_size(full_size_);
259 return bounds;
262 ui::WindowShowState Panel::GetRestoredState() const {
263 return ui::SHOW_STATE_NORMAL;
266 gfx::Rect Panel::GetBounds() const {
267 return native_panel_->GetPanelBounds();
270 void Panel::Show() {
271 if (manager()->display_settings_provider()->is_full_screen() || !collection_)
272 return;
274 native_panel_->ShowPanel();
277 void Panel::Hide() {
278 // Not implemented.
281 void Panel::ShowInactive() {
282 if (manager()->display_settings_provider()->is_full_screen() || !collection_)
283 return;
285 native_panel_->ShowPanelInactive();
288 // Close() may be called multiple times if the panel window is not ready to
289 // close on the first attempt.
290 void Panel::Close() {
291 native_panel_->ClosePanel();
294 void Panel::Activate() {
295 if (!collection_)
296 return;
298 collection_->ActivatePanel(this);
299 native_panel_->ActivatePanel();
302 void Panel::Deactivate() {
303 native_panel_->DeactivatePanel();
306 void Panel::Maximize() {
307 Restore();
310 void Panel::Minimize() {
311 if (collection_)
312 collection_->MinimizePanel(this);
315 bool Panel::IsMinimizedBySystem() const {
316 return native_panel_->IsPanelMinimizedBySystem();
319 bool Panel::IsShownOnActiveDesktop() const {
320 return native_panel_->IsPanelShownOnActiveDesktop();
323 void Panel::ShowShadow(bool show) {
324 native_panel_->ShowShadow(show);
327 void Panel::Restore() {
328 if (collection_)
329 collection_->RestorePanel(this);
332 void Panel::SetBounds(const gfx::Rect& bounds) {
333 // Ignore bounds position as the panel manager controls all positioning.
334 if (!collection_)
335 return;
336 collection_->ResizePanelWindow(this, bounds.size());
337 SetAutoResizable(false);
340 void Panel::FlashFrame(bool draw_attention) {
341 if (IsDrawingAttention() == draw_attention || !collection_)
342 return;
344 // Don't draw attention for an active panel.
345 if (draw_attention && IsActive())
346 return;
348 // Invoking native panel to draw attention must be done before informing the
349 // panel collection because it needs to check internal state of the panel to
350 // determine if the panel has been drawing attention.
351 native_panel_->DrawAttention(draw_attention);
352 collection_->OnPanelAttentionStateChanged(this);
355 bool Panel::IsAlwaysOnTop() const {
356 return native_panel_->IsPanelAlwaysOnTop();
359 void Panel::SetAlwaysOnTop(bool on_top) {
360 native_panel_->SetPanelAlwaysOnTop(on_top);
363 void Panel::ExecuteCommandWithDisposition(int id,
364 WindowOpenDisposition disposition) {
365 DCHECK(command_updater_.IsCommandEnabled(id)) << "Invalid/disabled command "
366 << id;
368 if (!GetWebContents())
369 return;
371 switch (id) {
372 // Navigation
373 case IDC_RELOAD:
374 panel_host_->Reload();
375 break;
376 case IDC_RELOAD_IGNORING_CACHE:
377 panel_host_->ReloadIgnoringCache();
378 break;
379 case IDC_STOP:
380 panel_host_->StopLoading();
381 break;
383 // Window management
384 case IDC_CLOSE_WINDOW:
385 content::RecordAction(UserMetricsAction("CloseWindow"));
386 Close();
387 break;
388 case IDC_EXIT:
389 content::RecordAction(UserMetricsAction("Exit"));
390 chrome::AttemptUserExit();
391 break;
393 // Clipboard
394 case IDC_COPY:
395 content::RecordAction(UserMetricsAction("Copy"));
396 native_panel_->PanelCopy();
397 break;
398 case IDC_CUT:
399 content::RecordAction(UserMetricsAction("Cut"));
400 native_panel_->PanelCut();
401 break;
402 case IDC_PASTE:
403 content::RecordAction(UserMetricsAction("Paste"));
404 native_panel_->PanelPaste();
405 break;
407 // Zoom
408 case IDC_ZOOM_PLUS:
409 panel_host_->Zoom(content::PAGE_ZOOM_IN);
410 break;
411 case IDC_ZOOM_NORMAL:
412 panel_host_->Zoom(content::PAGE_ZOOM_RESET);
413 break;
414 case IDC_ZOOM_MINUS:
415 panel_host_->Zoom(content::PAGE_ZOOM_OUT);
416 break;
418 // DevTools
419 case IDC_DEV_TOOLS:
420 content::RecordAction(UserMetricsAction("DevTools_ToggleWindow"));
421 DevToolsWindow::OpenDevToolsWindow(GetWebContents(),
422 DevToolsToggleAction::Show());
423 break;
424 case IDC_DEV_TOOLS_CONSOLE:
425 content::RecordAction(UserMetricsAction("DevTools_ToggleConsole"));
426 DevToolsWindow::OpenDevToolsWindow(GetWebContents(),
427 DevToolsToggleAction::ShowConsole());
428 break;
430 default:
431 LOG(WARNING) << "Received unimplemented command: " << id;
432 break;
436 void Panel::Observe(int type,
437 const content::NotificationSource& source,
438 const content::NotificationDetails& details) {
439 switch (type) {
440 case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED:
441 ConfigureAutoResize(content::Source<content::WebContents>(source).ptr());
442 break;
443 case chrome::NOTIFICATION_APP_TERMINATING:
444 Close();
445 break;
446 default:
447 NOTREACHED() << "Received unexpected notification " << type;
451 void Panel::OnExtensionUnloaded(
452 content::BrowserContext* browser_context,
453 const extensions::Extension* extension,
454 extensions::UnloadedExtensionInfo::Reason reason) {
455 if (extension->id() == extension_id())
456 Close();
458 void Panel::OnTitlebarClicked(panel::ClickModifier modifier) {
459 if (collection_)
460 collection_->OnPanelTitlebarClicked(this, modifier);
462 // Normally the system activates a window when the titlebar is clicked.
463 // However, we prevent system activation of minimized panels, thus the
464 // activation may not have occurred. Also, some OSes (Windows) will
465 // activate a minimized panel on mouse-down regardless of our attempts to
466 // prevent system activation. Attention state is not cleared in that case.
467 // See Panel::OnActiveStateChanged().
468 // Therefore, we ensure activation and clearing of attention state if the
469 // panel has been expanded. If the panel is in a stack, the titlebar click
470 // might minimize the panel and we do not want to activate it to make it
471 // expand again.
472 // These are no-ops if no changes are needed.
473 if (IsMinimized())
474 return;
475 Activate();
476 FlashFrame(false);
479 void Panel::OnMinimizeButtonClicked(panel::ClickModifier modifier) {
480 if (collection_)
481 collection_->OnMinimizeButtonClicked(this, modifier);
484 void Panel::OnRestoreButtonClicked(panel::ClickModifier modifier) {
485 // Clicking the restore button has the same behavior as clicking the titlebar.
486 OnTitlebarClicked(modifier);
489 void Panel::OnWindowSizeAvailable() {
490 ConfigureAutoResize(GetWebContents());
493 void Panel::OnNativePanelClosed() {
494 // Ensure previously enqueued OnImageLoaded callbacks are ignored.
495 image_loader_ptr_factory_.InvalidateWeakPtrs();
496 registrar_.RemoveAll();
497 extension_registry_->RemoveObserver(this);
498 manager()->OnPanelClosed(this);
499 DCHECK(!collection_);
502 StackedPanelCollection* Panel::stack() const {
503 return collection_ && collection_->type() == PanelCollection::STACKED ?
504 static_cast<StackedPanelCollection*>(collection_) : NULL;
507 panel::Resizability Panel::CanResizeByMouse() const {
508 if (!collection_)
509 return panel::NOT_RESIZABLE;
511 return collection_->GetPanelResizability(this);
514 void Panel::Initialize(const GURL& url,
515 const gfx::Rect& bounds,
516 bool always_on_top) {
517 DCHECK(!initialized_);
518 DCHECK(!collection_); // Cannot be added to a collection until fully created.
519 DCHECK_EQ(EXPANDED, expansion_state_);
520 DCHECK(!bounds.IsEmpty());
521 initialized_ = true;
522 full_size_ = bounds.size();
523 native_panel_ = CreateNativePanel(this, bounds, always_on_top);
525 extension_window_controller_.reset(
526 new panel_internal::PanelExtensionWindowController(this, profile_));
528 InitCommandState();
530 // Set up hosting for web contents.
531 panel_host_.reset(new PanelHost(this, profile_));
532 panel_host_->Init(url);
533 content::WebContents* web_contents = GetWebContents();
534 // The contents might be NULL for most of our tests.
535 if (web_contents)
536 native_panel_->AttachWebContents(web_contents);
538 // Close when the extension is unloaded or the browser is exiting.
539 extension_registry_->AddObserver(this);
540 registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
541 content::NotificationService::AllSources());
542 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
543 content::Source<ThemeService>(
544 ThemeServiceFactory::GetForProfile(profile_)));
546 #if !defined(USE_AURA)
547 // Keep alive for AURA has been moved to panel_view.
548 // Prevent the browser process from shutting down while this window is open.
549 chrome::IncrementKeepAliveCount();
550 #endif
552 UpdateAppIcon();
555 void Panel::SetPanelBounds(const gfx::Rect& bounds) {
556 if (bounds != native_panel_->GetPanelBounds())
557 native_panel_->SetPanelBounds(bounds);
560 void Panel::SetPanelBoundsInstantly(const gfx::Rect& bounds) {
561 native_panel_->SetPanelBoundsInstantly(bounds);
564 void Panel::LimitSizeToWorkArea(const gfx::Rect& work_area) {
565 int max_width = manager()->GetMaxPanelWidth(work_area);
566 int max_height = manager()->GetMaxPanelHeight(work_area);
568 // If the custom max size is used, ensure that it does not exceed the display
569 // area.
570 if (max_size_policy_ == CUSTOM_MAX_SIZE) {
571 int current_max_width = max_size_.width();
572 if (current_max_width > max_width)
573 max_width = std::min(current_max_width, work_area.width());
574 int current_max_height = max_size_.height();
575 if (current_max_height > max_height)
576 max_height = std::min(current_max_height, work_area.height());
579 SetSizeRange(min_size_, gfx::Size(max_width, max_height));
581 // Ensure that full size does not exceed max size.
582 full_size_ = ClampSize(full_size_);
585 void Panel::SetAutoResizable(bool resizable) {
586 if (auto_resizable_ == resizable)
587 return;
589 auto_resizable_ = resizable;
590 content::WebContents* web_contents = GetWebContents();
591 if (auto_resizable_) {
592 if (web_contents)
593 EnableWebContentsAutoResize(web_contents);
594 } else {
595 if (web_contents) {
596 registrar_.Remove(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
597 content::Source<content::WebContents>(web_contents));
599 // NULL might be returned if the tab has not been added.
600 RenderViewHost* render_view_host = web_contents->GetRenderViewHost();
601 if (render_view_host)
602 render_view_host->DisableAutoResize(full_size_);
607 void Panel::EnableWebContentsAutoResize(content::WebContents* web_contents) {
608 DCHECK(web_contents);
609 ConfigureAutoResize(web_contents);
611 // We also need to know when the render view host changes in order
612 // to turn on auto-resize notifications in the new render view host.
613 if (!registrar_.IsRegistered(
614 this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
615 content::Source<content::WebContents>(web_contents))) {
616 registrar_.Add(
617 this,
618 content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
619 content::Source<content::WebContents>(web_contents));
623 void Panel::OnContentsAutoResized(const gfx::Size& new_content_size) {
624 DCHECK(auto_resizable_);
625 if (!collection_)
626 return;
628 gfx::Size new_window_size =
629 native_panel_->WindowSizeFromContentSize(new_content_size);
631 // Ignore content auto resizes until window frame size is known.
632 // This reduces extra resizes when panel is first shown.
633 // After window frame size is known, it will trigger another content
634 // auto resize.
635 if (new_content_size == new_window_size)
636 return;
638 collection_->ResizePanelWindow(this, new_window_size);
641 void Panel::OnWindowResizedByMouse(const gfx::Rect& new_bounds) {
642 if (collection_)
643 collection_->OnPanelResizedByMouse(this, new_bounds);
646 void Panel::SetSizeRange(const gfx::Size& min_size, const gfx::Size& max_size) {
647 if (min_size == min_size_ && max_size == max_size_)
648 return;
650 DCHECK(min_size.width() <= max_size.width());
651 DCHECK(min_size.height() <= max_size.height());
652 min_size_ = min_size;
653 max_size_ = max_size;
655 ConfigureAutoResize(GetWebContents());
658 void Panel::IncreaseMaxSize(const gfx::Size& desired_panel_size) {
659 gfx::Size new_max_size = max_size_;
660 if (new_max_size.width() < desired_panel_size.width())
661 new_max_size.set_width(desired_panel_size.width());
662 if (new_max_size.height() < desired_panel_size.height())
663 new_max_size.set_height(desired_panel_size.height());
665 SetSizeRange(min_size_, new_max_size);
668 void Panel::HandleKeyboardEvent(const content::NativeWebKeyboardEvent& event) {
669 native_panel_->HandlePanelKeyboardEvent(event);
672 void Panel::SetPreviewMode(bool in_preview) {
673 DCHECK_NE(in_preview_mode_, in_preview);
674 in_preview_mode_ = in_preview;
677 void Panel::UpdateMinimizeRestoreButtonVisibility() {
678 native_panel_->UpdatePanelMinimizeRestoreButtonVisibility();
681 gfx::Size Panel::ClampSize(const gfx::Size& size) const {
682 // The panel width:
683 // * cannot grow or shrink to go beyond [min_width, max_width]
684 int new_width = size.width();
685 if (new_width > max_size_.width())
686 new_width = max_size_.width();
687 if (new_width < min_size_.width())
688 new_width = min_size_.width();
690 // The panel height:
691 // * cannot grow or shrink to go beyond [min_height, max_height]
692 int new_height = size.height();
693 if (new_height > max_size_.height())
694 new_height = max_size_.height();
695 if (new_height < min_size_.height())
696 new_height = min_size_.height();
698 return gfx::Size(new_width, new_height);
701 void Panel::OnActiveStateChanged(bool active) {
702 // Clear attention state when an expanded panel becomes active.
703 // On some systems (e.g. Win), mouse-down activates a panel regardless of
704 // its expansion state. However, we don't want to clear draw attention if
705 // contents are not visible. In that scenario, if the mouse-down results
706 // in a mouse-click, draw attention will be cleared then.
707 // See Panel::OnTitlebarClicked().
708 if (active && IsDrawingAttention() && !IsMinimized())
709 FlashFrame(false);
711 if (collection_)
712 collection_->OnPanelActiveStateChanged(this);
714 // Send extension event about window changing active state.
715 extensions::TabsWindowsAPI* tabs_windows_api =
716 extensions::TabsWindowsAPI::Get(profile());
717 if (tabs_windows_api) {
718 tabs_windows_api->windows_event_router()->OnActiveWindowChanged(
719 active ? extension_window_controller_.get() : NULL);
722 content::NotificationService::current()->Notify(
723 chrome::NOTIFICATION_PANEL_CHANGED_ACTIVE_STATUS,
724 content::Source<Panel>(this),
725 content::NotificationService::NoDetails());
728 void Panel::OnPanelStartUserResizing() {
729 SetAutoResizable(false);
730 SetPreviewMode(true);
731 max_size_policy_ = CUSTOM_MAX_SIZE;
734 void Panel::OnPanelEndUserResizing() {
735 SetPreviewMode(false);
738 bool Panel::ShouldCloseWindow() {
739 return true;
742 void Panel::OnWindowClosing() {
743 if (GetWebContents()) {
744 native_panel_->DetachWebContents(GetWebContents());
745 panel_host_->DestroyWebContents();
749 bool Panel::ExecuteCommandIfEnabled(int id) {
750 if (command_updater()->SupportsCommand(id) &&
751 command_updater()->IsCommandEnabled(id)) {
752 ExecuteCommandWithDisposition(id, CURRENT_TAB);
753 return true;
755 return false;
758 base::string16 Panel::GetWindowTitle() const {
759 content::WebContents* contents = GetWebContents();
760 base::string16 title;
762 // |contents| can be NULL during the window's creation.
763 if (contents) {
764 title = contents->GetTitle();
765 FormatTitleForDisplay(&title);
768 if (title.empty())
769 title = base::UTF8ToUTF16(app_name());
771 return title;
774 gfx::Image Panel::GetCurrentPageIcon() const {
775 return panel_host_.get() ? panel_host_->GetPageIcon() : gfx::Image();
778 void Panel::UpdateTitleBar() {
779 native_panel_->UpdatePanelTitleBar();
782 void Panel::LoadingStateChanged(bool is_loading) {
783 command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading);
784 native_panel_->UpdatePanelLoadingAnimations(is_loading);
785 UpdateTitleBar();
788 void Panel::WebContentsFocused(content::WebContents* contents) {
789 native_panel_->PanelWebContentsFocused(contents);
792 void Panel::MoveByInstantly(const gfx::Vector2d& delta_origin) {
793 gfx::Rect bounds = GetBounds();
794 bounds.Offset(delta_origin);
795 SetPanelBoundsInstantly(bounds);
798 void Panel::SetWindowCornerStyle(panel::CornerStyle corner_style) {
799 native_panel_->SetWindowCornerStyle(corner_style);
802 void Panel::MinimizeBySystem() {
803 native_panel_->MinimizePanelBySystem();
806 Panel::Panel(Profile* profile,
807 const std::string& app_name,
808 const gfx::Size& min_size,
809 const gfx::Size& max_size)
810 : app_name_(app_name),
811 profile_(profile),
812 collection_(NULL),
813 initialized_(false),
814 min_size_(min_size),
815 max_size_(max_size),
816 max_size_policy_(DEFAULT_MAX_SIZE),
817 auto_resizable_(false),
818 in_preview_mode_(false),
819 native_panel_(NULL),
820 attention_mode_(USE_PANEL_ATTENTION),
821 expansion_state_(EXPANDED),
822 command_updater_(this),
823 extension_registry_(extensions::ExtensionRegistry::Get(profile_)),
824 image_loader_ptr_factory_(this) {
827 void Panel::OnImageLoaded(const gfx::Image& image) {
828 if (!image.IsEmpty()) {
829 app_icon_ = image;
830 native_panel_->UpdatePanelTitleBar();
833 content::NotificationService::current()->Notify(
834 chrome::NOTIFICATION_PANEL_APP_ICON_LOADED,
835 content::Source<Panel>(this),
836 content::NotificationService::NoDetails());
839 void Panel::InitCommandState() {
840 // All supported commands whose state isn't set automagically some other way
841 // (like Stop during a page load) must have their state initialized here,
842 // otherwise they will be forever disabled.
844 // Navigation commands
845 command_updater_.UpdateCommandEnabled(IDC_RELOAD, true);
846 command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE, true);
848 // Window management commands
849 command_updater_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true);
850 command_updater_.UpdateCommandEnabled(IDC_EXIT, true);
852 // Zoom
853 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MENU, true);
854 command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true);
855 command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, true);
856 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true);
858 // Clipboard
859 command_updater_.UpdateCommandEnabled(IDC_COPY, true);
860 command_updater_.UpdateCommandEnabled(IDC_CUT, true);
861 command_updater_.UpdateCommandEnabled(IDC_PASTE, true);
863 // DevTools
864 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS, true);
865 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_CONSOLE, true);
868 void Panel::ConfigureAutoResize(content::WebContents* web_contents) {
869 if (!auto_resizable_ || !web_contents)
870 return;
872 // NULL might be returned if the tab has not been added.
873 RenderViewHost* render_view_host = web_contents->GetRenderViewHost();
874 if (!render_view_host)
875 return;
877 render_view_host->EnableAutoResize(
878 min_size_,
879 native_panel_->ContentSizeFromWindowSize(max_size_));
882 void Panel::UpdateAppIcon() {
883 const extensions::Extension* extension = GetExtension();
884 if (!extension)
885 return;
887 extensions::ImageLoader* loader = extensions::ImageLoader::Get(profile());
888 loader->LoadImageAsync(
889 extension,
890 extensions::IconsInfo::GetIconResource(
891 extension,
892 extension_misc::EXTENSION_ICON_SMALL,
893 ExtensionIconSet::MATCH_BIGGER),
894 gfx::Size(extension_misc::EXTENSION_ICON_SMALL,
895 extension_misc::EXTENSION_ICON_SMALL),
896 base::Bind(&Panel::OnImageLoaded,
897 image_loader_ptr_factory_.GetWeakPtr()));
900 // static
901 void Panel::FormatTitleForDisplay(base::string16* title) {
902 size_t current_index = 0;
903 size_t match_index;
904 while ((match_index = title->find(L'\n', current_index)) !=
905 base::string16::npos) {
906 title->replace(match_index, 1, base::string16());
907 current_index = match_index;