This source file includes following definitions.
- ComparePanelsByPosition
- ComparerNumberOfPanelsInStack
- CompareDetachedPanels
- GetInstance
- SetDisplaySettingsProviderForTesting
- ShouldUsePanels
- IsPanelStackingEnabled
- CanUseSystemMinimize
- auto_sizing_enabled_
- GetDefaultDetachedPanelOrigin
- OnDisplayChanged
- OnFullScreenModeChanged
- GetMaxPanelWidth
- GetMaxPanelHeight
- CreatePanel
- GetCollectionForNewPanel
- OnPanelClosed
- CreateStack
- RemoveStack
- StartDragging
- Drag
- EndDragging
- StartResizingByMouse
- ResizeByMouse
- EndResizingByMouse
- OnPanelExpansionStateChanged
- MovePanelToCollection
- ShouldBringUpTitlebars
- BringUpOrDownTitlebars
- CloseAll
- num_panels
- panels
- GetDetachedAndStackedPanels
- SetMouseWatcher
- OnPanelAnimationEnded
#include "chrome/browser/ui/panels/panel_manager.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/ui/panels/detached_panel_collection.h"
#include "chrome/browser/ui/panels/docked_panel_collection.h"
#include "chrome/browser/ui/panels/panel_drag_controller.h"
#include "chrome/browser/ui/panels/panel_mouse_watcher.h"
#include "chrome/browser/ui/panels/panel_resize_controller.h"
#include "chrome/browser/ui/panels/stacked_panel_collection.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#if defined(USE_X11) && !defined(OS_CHROMEOS)
#include "base/environment.h"
#include "base/nix/xdg_util.h"
#include "ui/base/x/x11_util.h"
#endif
#if defined(OS_WIN)
#include "win8/util/win8_util.h"
#endif
namespace {
#if defined(OS_CHROMEOS)
const double kPanelMaxWidthFactor = 0.80;
#else
const double kPanelMaxWidthFactor = 0.35;
#endif
const double kPanelMaxHeightFactor = 0.5;
const double kPanelDefaultWidthToHeightRatio = 1.62;
DisplaySettingsProvider* display_settings_provider_for_testing;
bool ComparePanelsByPosition(Panel* panel1, Panel* panel2) {
gfx::Rect bounds1 = panel1->GetBounds();
gfx::Rect bounds2 = panel2->GetBounds();
if (bounds1.x() > bounds2.x())
return true;
if (bounds1.x() < bounds2.x())
return false;
return bounds1.y() < bounds2.y();
}
bool ComparerNumberOfPanelsInStack(StackedPanelCollection* stack1,
StackedPanelCollection* stack2) {
int num_panels_in_stack1 = stack1->num_panels();
int num_panels_in_stack2 = stack2->num_panels();
if (num_panels_in_stack1 > num_panels_in_stack2)
return true;
if (num_panels_in_stack1 < num_panels_in_stack2)
return false;
DCHECK(num_panels_in_stack1);
return ComparePanelsByPosition(stack1->top_panel(), stack2->top_panel());
}
bool CompareDetachedPanels(Panel* panel1, Panel* panel2) {
return ComparePanelsByPosition(panel1, panel2);
}
}
bool PanelManager::shorten_time_intervals_ = false;
PanelManager* PanelManager::GetInstance() {
static base::LazyInstance<PanelManager> instance = LAZY_INSTANCE_INITIALIZER;
return instance.Pointer();
}
void PanelManager::SetDisplaySettingsProviderForTesting(
DisplaySettingsProvider* provider) {
display_settings_provider_for_testing = provider;
}
bool PanelManager::ShouldUsePanels(const std::string& extension_id) {
#if defined(USE_X11) && !defined(OS_CHROMEOS)
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePanels))
return true;
ui::WindowManagerName wm_type = ui::GuessWindowManager();
if (wm_type != ui::WM_COMPIZ &&
wm_type != ui::WM_ICE_WM &&
wm_type != ui::WM_KWIN &&
wm_type != ui::WM_METACITY &&
wm_type != ui::WM_MUFFIN &&
wm_type != ui::WM_MUTTER &&
wm_type != ui::WM_XFWM4) {
return false;
}
#endif
#if defined(OS_WIN)
if (win8::IsSingleWindowMetroMode())
return false;
#endif
chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
channel == chrome::VersionInfo::CHANNEL_BETA) {
return CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnablePanels) ||
extension_id == std::string("nckgahadagoaajjgafhacjanaoiihapd") ||
extension_id == std::string("ljclpkphhpbpinifbeabbhlfddcpfdde") ||
extension_id == std::string("ppleadejekpmccmnpjdimmlfljlkdfej") ||
extension_id == std::string("eggnbpckecmjlblplehfpjjdhhidfdoj");
}
return true;
}
bool PanelManager::IsPanelStackingEnabled() {
#if defined(OS_LINUX) && !defined(TOOLKIT_GTK)
return false;
#else
return true;
#endif
}
bool PanelManager::CanUseSystemMinimize() {
#if defined(USE_X11) && !defined(OS_CHROMEOS)
static base::nix::DesktopEnvironment desktop_env =
base::nix::DESKTOP_ENVIRONMENT_OTHER;
if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_OTHER) {
scoped_ptr<base::Environment> env(base::Environment::Create());
desktop_env = base::nix::GetDesktopEnvironment(env.get());
}
return desktop_env != base::nix::DESKTOP_ENVIRONMENT_UNITY;
#else
return true;
#endif
}
PanelManager::PanelManager()
: panel_mouse_watcher_(PanelMouseWatcher::Create()),
auto_sizing_enabled_(true) {
if (display_settings_provider_for_testing)
display_settings_provider_.reset(display_settings_provider_for_testing);
else
display_settings_provider_.reset(DisplaySettingsProvider::Create());
display_settings_provider_->AddDisplayObserver(this);
detached_collection_.reset(new DetachedPanelCollection(this));
docked_collection_.reset(new DockedPanelCollection(this));
drag_controller_.reset(new PanelDragController(this));
resize_controller_.reset(new PanelResizeController(this));
}
PanelManager::~PanelManager() {
display_settings_provider_->RemoveDisplayObserver(this);
docked_collection_.reset();
}
gfx::Point PanelManager::GetDefaultDetachedPanelOrigin() {
return detached_collection_->GetDefaultPanelOrigin();
}
void PanelManager::OnDisplayChanged() {
docked_collection_->OnDisplayChanged();
detached_collection_->OnDisplayChanged();
for (Stacks::const_iterator iter = stacks_.begin();
iter != stacks_.end(); iter++)
(*iter)->OnDisplayChanged();
}
void PanelManager::OnFullScreenModeChanged(bool is_full_screen) {
std::vector<Panel*> all_panels = panels();
for (std::vector<Panel*>::const_iterator iter = all_panels.begin();
iter != all_panels.end(); ++iter) {
(*iter)->FullScreenModeChanged(is_full_screen);
}
}
int PanelManager::GetMaxPanelWidth(const gfx::Rect& work_area) const {
return static_cast<int>(work_area.width() * kPanelMaxWidthFactor);
}
int PanelManager::GetMaxPanelHeight(const gfx::Rect& work_area) const {
return static_cast<int>(work_area.height() * kPanelMaxHeightFactor);
}
Panel* PanelManager::CreatePanel(const std::string& app_name,
Profile* profile,
const GURL& url,
const gfx::Rect& requested_bounds,
CreateMode mode) {
if (num_panels() == 0) {
display_settings_provider_->OnDisplaySettingsChanged();
display_settings_provider_->AddFullScreenObserver(this);
}
int width = requested_bounds.width();
int height = requested_bounds.height();
if (width == 0)
width = height * kPanelDefaultWidthToHeightRatio;
else if (height == 0)
height = width / kPanelDefaultWidthToHeightRatio;
gfx::Rect work_area =
display_settings_provider_->GetWorkAreaMatching(requested_bounds);
gfx::Size min_size(panel::kPanelMinWidth, panel::kPanelMinHeight);
gfx::Size max_size(GetMaxPanelWidth(work_area), GetMaxPanelHeight(work_area));
if (width < min_size.width())
width = min_size.width();
else if (width > max_size.width())
width = max_size.width();
if (height < min_size.height())
height = min_size.height();
else if (height > max_size.height())
height = max_size.height();
Panel* panel = new Panel(profile, app_name, min_size, max_size);
gfx::Rect adjusted_requested_bounds(
requested_bounds.x(), requested_bounds.y(), width, height);
PanelCollection::PositioningMask positioning_mask;
PanelCollection* collection = GetCollectionForNewPanel(
panel, adjusted_requested_bounds, mode, &positioning_mask);
gfx::Rect bounds = collection->GetInitialPanelBounds(
adjusted_requested_bounds);
bounds.AdjustToFit(work_area);
panel->Initialize(url, bounds, collection->UsesAlwaysOnTopPanels());
if (auto_sizing_enabled() && requested_bounds.width() == 0 &&
requested_bounds.height() == 0) {
panel->SetAutoResizable(true);
}
collection->AddPanel(panel, positioning_mask);
collection->UpdatePanelOnCollectionChange(panel);
return panel;
}
PanelCollection* PanelManager::GetCollectionForNewPanel(
Panel* new_panel,
const gfx::Rect& bounds,
CreateMode mode,
PanelCollection::PositioningMask* positioning_mask) {
if (mode == CREATE_AS_DOCKED) {
*positioning_mask = PanelCollection::DELAY_LAYOUT_REFRESH;
return docked_collection_.get();
}
DCHECK_EQ(CREATE_AS_DETACHED, mode);
*positioning_mask = PanelCollection::DEFAULT_POSITION;
if (!IsPanelStackingEnabled())
return detached_collection_.get();
if (!stacks_.empty()) {
stacks_.sort(ComparerNumberOfPanelsInStack);
for (Stacks::const_iterator iter = stacks_.begin();
iter != stacks_.end(); iter++) {
StackedPanelCollection* stack = *iter;
Panel* panel = stack->bottom_panel();
if (panel->profile() != new_panel->profile() ||
panel->extension_id() != new_panel->extension_id())
continue;
if (stack->IsMinimized())
continue;
if (!panel->IsShownOnActiveDesktop())
continue;
if (bounds.height() <= stack->GetMaximiumAvailableBottomSpace()) {
*positioning_mask = static_cast<PanelCollection::PositioningMask>(
*positioning_mask | PanelCollection::COLLAPSE_TO_FIT);
return stack;
}
}
}
if (detached_collection_->num_panels()) {
detached_collection_->SortPanels(CompareDetachedPanels);
for (DetachedPanelCollection::Panels::const_iterator iter =
detached_collection_->panels().begin();
iter != detached_collection_->panels().end(); ++iter) {
Panel* panel = *iter;
if (panel->profile() != new_panel->profile() ||
panel->extension_id() != new_panel->extension_id())
continue;
if (panel->IsMinimizedBySystem())
continue;
if (!panel->IsShownOnActiveDesktop())
continue;
gfx::Rect work_area =
display_settings_provider_->GetWorkAreaMatching(panel->GetBounds());
int max_available_space =
work_area.bottom() - panel->GetBounds().y() -
(panel->IsActive() ? panel->GetBounds().height()
: panel::kTitlebarHeight);
if (bounds.height() <= max_available_space) {
StackedPanelCollection* new_stack = CreateStack();
MovePanelToCollection(panel,
new_stack,
PanelCollection::DEFAULT_POSITION);
*positioning_mask = static_cast<PanelCollection::PositioningMask>(
*positioning_mask | PanelCollection::COLLAPSE_TO_FIT);
return new_stack;
}
}
}
return detached_collection_.get();
}
void PanelManager::OnPanelClosed(Panel* panel) {
if (num_panels() == 1) {
display_settings_provider_->RemoveFullScreenObserver(this);
}
drag_controller_->OnPanelClosed(panel);
resize_controller_->OnPanelClosed(panel);
PanelCollection* collection = panel->collection();
collection->RemovePanel(panel, PanelCollection::PANEL_CLOSED);
if (collection->type() == PanelCollection::STACKED) {
StackedPanelCollection* stack =
static_cast<StackedPanelCollection*>(collection);
DCHECK_GE(stack->num_panels(), 1);
if (stack->num_panels() == 1) {
Panel* top_panel = stack->top_panel();
MovePanelToCollection(top_panel,
detached_collection(),
PanelCollection::DEFAULT_POSITION);
if (top_panel->expansion_state() != Panel::EXPANDED)
top_panel->SetExpansionState(Panel::EXPANDED);
RemoveStack(stack);
}
}
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PANEL_CLOSED,
content::Source<Panel>(panel),
content::NotificationService::NoDetails());
}
StackedPanelCollection* PanelManager::CreateStack() {
StackedPanelCollection* stack = new StackedPanelCollection(this);
stacks_.push_back(stack);
return stack;
}
void PanelManager::RemoveStack(StackedPanelCollection* stack) {
DCHECK_EQ(0, stack->num_panels());
stacks_.remove(stack);
stack->CloseAll();
delete stack;
}
void PanelManager::StartDragging(Panel* panel,
const gfx::Point& mouse_location) {
drag_controller_->StartDragging(panel, mouse_location);
}
void PanelManager::Drag(const gfx::Point& mouse_location) {
drag_controller_->Drag(mouse_location);
}
void PanelManager::EndDragging(bool cancelled) {
drag_controller_->EndDragging(cancelled);
}
void PanelManager::StartResizingByMouse(Panel* panel,
const gfx::Point& mouse_location,
panel::ResizingSides sides) {
if (panel->CanResizeByMouse() != panel::NOT_RESIZABLE &&
sides != panel::RESIZE_NONE)
resize_controller_->StartResizing(panel, mouse_location, sides);
}
void PanelManager::ResizeByMouse(const gfx::Point& mouse_location) {
if (resize_controller_->IsResizing())
resize_controller_->Resize(mouse_location);
}
void PanelManager::EndResizingByMouse(bool cancelled) {
if (resize_controller_->IsResizing()) {
Panel* resized_panel = resize_controller_->EndResizing(cancelled);
if (!cancelled && resized_panel->collection())
resized_panel->collection()->RefreshLayout();
}
}
void PanelManager::OnPanelExpansionStateChanged(Panel* panel) {
panel->collection()->OnPanelExpansionStateChanged(panel);
}
void PanelManager::MovePanelToCollection(
Panel* panel,
PanelCollection* target_collection,
PanelCollection::PositioningMask positioning_mask) {
DCHECK(panel);
PanelCollection* current_collection = panel->collection();
DCHECK(current_collection);
DCHECK_NE(current_collection, target_collection);
current_collection->RemovePanel(panel,
PanelCollection::PANEL_CHANGED_COLLECTION);
target_collection->AddPanel(panel, positioning_mask);
target_collection->UpdatePanelOnCollectionChange(panel);
panel->SetAlwaysOnTop(target_collection->UsesAlwaysOnTopPanels());
}
bool PanelManager::ShouldBringUpTitlebars(int mouse_x, int mouse_y) const {
return docked_collection_->ShouldBringUpTitlebars(mouse_x, mouse_y);
}
void PanelManager::BringUpOrDownTitlebars(bool bring_up) {
docked_collection_->BringUpOrDownTitlebars(bring_up);
}
void PanelManager::CloseAll() {
DCHECK(!drag_controller_->is_dragging());
detached_collection_->CloseAll();
docked_collection_->CloseAll();
}
int PanelManager::num_panels() const {
int count = detached_collection_->num_panels() +
docked_collection_->num_panels();
for (Stacks::const_iterator iter = stacks_.begin();
iter != stacks_.end(); iter++)
count += (*iter)->num_panels();
return count;
}
std::vector<Panel*> PanelManager::panels() const {
std::vector<Panel*> panels;
for (DetachedPanelCollection::Panels::const_iterator iter =
detached_collection_->panels().begin();
iter != detached_collection_->panels().end(); ++iter)
panels.push_back(*iter);
for (DockedPanelCollection::Panels::const_iterator iter =
docked_collection_->panels().begin();
iter != docked_collection_->panels().end(); ++iter)
panels.push_back(*iter);
for (Stacks::const_iterator stack_iter = stacks_.begin();
stack_iter != stacks_.end(); stack_iter++) {
for (StackedPanelCollection::Panels::const_iterator iter =
(*stack_iter)->panels().begin();
iter != (*stack_iter)->panels().end(); ++iter) {
panels.push_back(*iter);
}
}
return panels;
}
std::vector<Panel*> PanelManager::GetDetachedAndStackedPanels() const {
std::vector<Panel*> panels;
for (DetachedPanelCollection::Panels::const_iterator iter =
detached_collection_->panels().begin();
iter != detached_collection_->panels().end(); ++iter)
panels.push_back(*iter);
for (Stacks::const_iterator stack_iter = stacks_.begin();
stack_iter != stacks_.end(); stack_iter++) {
for (StackedPanelCollection::Panels::const_iterator iter =
(*stack_iter)->panels().begin();
iter != (*stack_iter)->panels().end(); ++iter) {
panels.push_back(*iter);
}
}
return panels;
}
void PanelManager::SetMouseWatcher(PanelMouseWatcher* watcher) {
panel_mouse_watcher_.reset(watcher);
}
void PanelManager::OnPanelAnimationEnded(Panel* panel) {
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PANEL_BOUNDS_ANIMATIONS_FINISHED,
content::Source<Panel>(panel),
content::NotificationService::NoDetails());
}