diff options
author | flackr@chromium.org <flackr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-26 05:33:29 +0000 |
---|---|---|
committer | flackr@chromium.org <flackr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-26 05:33:29 +0000 |
commit | 5b602190c3a6b949cfb74157e8b7c1ecf61bed36 (patch) | |
tree | a9a140196363fac1152c1520c57a7111c8787084 /ash | |
parent | 9c233029a88b2b529a119f951361cb803987d5c1 (diff) | |
download | chromium_src-5b602190c3a6b949cfb74157e8b7c1ecf61bed36.zip chromium_src-5b602190c3a6b949cfb74157e8b7c1ecf61bed36.tar.gz chromium_src-5b602190c3a6b949cfb74157e8b7c1ecf61bed36.tar.bz2 |
Create a separate callout widget per panel which displays over each icon.
BUG=162960
TEST=PanelManagerLayoutTest.MinimizeRestorePanel, PanelManagerLayoutTest.MultiplePanelCallout, RootWindowControllerTest.MoveWindows_Basic
Review URL: https://chromiumcodereview.appspot.com/12282046
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@184593 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r-- | ash/root_window_controller.cc | 24 | ||||
-rw-r--r-- | ash/wm/panel_layout_manager.cc | 136 | ||||
-rw-r--r-- | ash/wm/panel_layout_manager.h | 38 | ||||
-rw-r--r-- | ash/wm/panel_layout_manager_unittest.cc | 38 |
4 files changed, 128 insertions, 108 deletions
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc index 71c9101..dcb3bab 100644 --- a/ash/root_window_controller.cc +++ b/ash/root_window_controller.cc @@ -134,16 +134,20 @@ void ReparentAllWindows(aura::RootWindow* src, aura::RootWindow* dst) { aura::Window* src_container = Shell::GetContainer(src, id); aura::Window* dst_container = Shell::GetContainer(dst, id); - aura::Window::Windows children = src_container->children(); - for (aura::Window::Windows::iterator iter = children.begin(); - iter != children.end(); ++iter) { - aura::Window* window = *iter; - // Don't move modal screen. - if (internal::SystemModalContainerLayoutManager::IsModalBackground( - window)) - continue; - - ReparentWindow(window, dst_container); + while (!src_container->children().empty()) { + // Restart iteration from the source container windows each time as they + // may change as a result of moving other windows. + aura::Window::Windows::const_iterator iter = + src_container->children().begin(); + while (iter != src_container->children().end() && + internal::SystemModalContainerLayoutManager::IsModalBackground( + *iter)) { + ++iter; + } + // If the entire window list is modal background windows then stop. + if (iter == src_container->children().end()) + break; + ReparentWindow(*iter, dst_container); } } } diff --git a/ash/wm/panel_layout_manager.cc b/ash/wm/panel_layout_manager.cc index b7b6fc4..54df0c2 100644 --- a/ash/wm/panel_layout_manager.cc +++ b/ash/wm/panel_layout_manager.cc @@ -128,32 +128,14 @@ PanelLayoutManager::PanelLayoutManager(aura::Window* panel_container) dragged_panel_(NULL), launcher_(NULL), last_active_panel_(NULL), - callout_widget_(new views::Widget), weak_factory_(this) { DCHECK(panel_container); - views::Widget::InitParams params; - params.type = views::Widget::InitParams::TYPE_POPUP; - params.transparent = true; - params.can_activate = false; - params.keep_on_top = true; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.parent = panel_container_; - params.bounds = ScreenAsh::ConvertRectToScreen(panel_container_, gfx::Rect()); - params.bounds.set_width(kArrowWidth); - params.bounds.set_height(kArrowHeight); - // Why do we need this and can_activate = false? - callout_widget_->set_focus_on_creation(false); - callout_widget_->Init(params); - DCHECK_EQ(callout_widget_->GetNativeView()->GetRootWindow(), - panel_container_->GetRootWindow()); - views::View* content_view = new views::View; - content_view->set_background(new CalloutWidgetBackground); - callout_widget_->SetContentsView(content_view); aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())-> AddObserver(this); } PanelLayoutManager::~PanelLayoutManager() { + Shutdown(); if (launcher_) launcher_->RemoveIconObserver(this); aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())-> @@ -161,7 +143,11 @@ PanelLayoutManager::~PanelLayoutManager() { } void PanelLayoutManager::Shutdown() { - callout_widget_.reset(); + for (PanelList::iterator iter = panel_windows_.begin(); + iter != panel_windows_.end(); ++iter) { + delete iter->callout_widget; + } + panel_windows_.clear(); } void PanelLayoutManager::StartDragging(aura::Window* panel) { @@ -200,9 +186,12 @@ void PanelLayoutManager::OnWindowResized() { } void PanelLayoutManager::OnWindowAddedToLayout(aura::Window* child) { - if (callout_widget_ && child == callout_widget_->GetNativeWindow()) + if (child->type() == aura::client::WINDOW_TYPE_POPUP) return; - panel_windows_.push_back(child); + PanelInfo panel_info; + panel_info.window = child; + panel_info.callout_widget = CreateCalloutWidget(); + panel_windows_.push_back(panel_info); child->AddObserver(this); Relayout(); } @@ -211,10 +200,14 @@ void PanelLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) { } void PanelLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) { + if (child->type() == aura::client::WINDOW_TYPE_POPUP) + return; PanelList::iterator found = std::find(panel_windows_.begin(), panel_windows_.end(), child); - if (found != panel_windows_.end()) + if (found != panel_windows_.end()) { + delete found->callout_widget; panel_windows_.erase(found); + } child->RemoveObserver(this); if (dragged_panel_ == child) @@ -251,12 +244,13 @@ void PanelLayoutManager::SetChildBounds(aura::Window* child, for (new_position = panel_windows_.begin(); new_position != panel_windows_.end(); ++new_position) { - const gfx::Rect& bounds = (*new_position)->bounds(); + const gfx::Rect& bounds = (*new_position).window->bounds(); if (bounds.x() + bounds.width()/2 <= requested_bounds.x()) break; } if (new_position != dragged_panel_iter) { + PanelInfo dragged_panel_info = *dragged_panel_iter; panel_windows_.erase(dragged_panel_iter); - panel_windows_.insert(new_position, dragged_panel_); + panel_windows_.insert(new_position, dragged_panel_info); } } @@ -306,10 +300,8 @@ void PanelLayoutManager::OnWindowActivated(aura::Window* gained_active, gained_active->type() == aura::client::WINDOW_TYPE_PANEL && gained_active->parent() == panel_container_) { UpdateStacking(gained_active); - UpdateCallout(gained_active); - } else { - UpdateCallout(NULL); } + UpdateCallouts(); } //////////////////////////////////////////////////////////////////////////////// @@ -345,7 +337,7 @@ void PanelLayoutManager::Relayout() { std::vector<VisiblePanelPositionInfo> visible_panels; for (PanelList::iterator iter = panel_windows_.begin(); iter != panel_windows_.end(); ++iter) { - aura::Window* panel = *iter; + aura::Window* panel = iter->window; if (!panel->IsVisible() || panel == dragged_panel_) continue; @@ -407,7 +399,7 @@ void PanelLayoutManager::Relayout() { } UpdateStacking(active_panel); - UpdateCallout(active_panel); + UpdateCallouts(); } void PanelLayoutManager::UpdateStacking(aura::Window* active_panel) { @@ -429,9 +421,9 @@ void PanelLayoutManager::UpdateStacking(aura::Window* active_panel) { std::map<int, aura::Window*> window_ordering; for (PanelList::const_iterator it = panel_windows_.begin(); it != panel_windows_.end(); ++it) { - gfx::Rect bounds = (*it)->bounds(); + gfx::Rect bounds = it->window->bounds(); window_ordering.insert(std::make_pair(bounds.x() + bounds.width() / 2, - *it)); + it->window)); } aura::Window* previous_panel = NULL; @@ -456,41 +448,57 @@ void PanelLayoutManager::UpdateStacking(aura::Window* active_panel) { last_active_panel_ = active_panel; } -void PanelLayoutManager::UpdateCallout(aura::Window* active_panel) { - weak_factory_.InvalidateWeakPtrs(); - // TODO(dcheng): This doesn't account for panels in overflow. They should have - // a callout as well. - if (!active_panel || - launcher_->GetScreenBoundsOfItemIconForWindow(active_panel).IsEmpty()) { - if (callout_widget_) - callout_widget_->Hide(); - return; +void PanelLayoutManager::UpdateCallouts() { + for (PanelList::iterator iter = panel_windows_.begin(); + iter != panel_windows_.end(); ++iter) { + aura::Window* panel = iter->window; + views::Widget* callout_widget = iter->callout_widget; + + gfx::Rect bounds = panel->GetBoundsInRootWindow(); + gfx::Rect icon_bounds = + launcher_->GetScreenBoundsOfItemIconForWindow(panel); + if (icon_bounds.IsEmpty() || !panel->IsVisible() || + panel == dragged_panel_) { + callout_widget->Hide(); + continue; + } + + gfx::Rect callout_bounds = callout_widget->GetWindowBoundsInScreen(); + callout_bounds.set_x( + icon_bounds.x() + (icon_bounds.width() - callout_bounds.width()) / 2); + callout_bounds.set_y(bounds.bottom()); + callout_bounds = ScreenAsh::ConvertRectFromScreen( + callout_widget->GetNativeWindow()->parent(), + callout_bounds); + + SetChildBoundsDirect(callout_widget->GetNativeWindow(), callout_bounds); + panel_container_->StackChildAbove(callout_widget->GetNativeWindow(), + panel); + callout_widget->Show(); } - MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&PanelLayoutManager::ShowCalloutHelper, - weak_factory_.GetWeakPtr(), - active_panel)); } -void PanelLayoutManager::ShowCalloutHelper(aura::Window* active_panel) { - if (!callout_widget_) - return; - DCHECK(active_panel); - gfx::Rect bounds = active_panel->GetBoundsInRootWindow(); - gfx::Rect icon_bounds = - launcher_->GetScreenBoundsOfItemIconForWindow(active_panel); - gfx::Rect callout_bounds = callout_widget_->GetWindowBoundsInScreen(); - callout_bounds.set_x( - icon_bounds.x() + (icon_bounds.width() - callout_bounds.width()) / 2); - callout_bounds.set_y(bounds.bottom()); - callout_bounds = ScreenAsh::ConvertRectFromScreen( - callout_widget_->GetNativeWindow()->parent(), - callout_bounds); - - SetChildBoundsDirect(callout_widget_->GetNativeWindow(), callout_bounds); - panel_container_->StackChildAtTop(callout_widget_->GetNativeWindow()); - callout_widget_->Show(); +views::Widget* PanelLayoutManager::CreateCalloutWidget() { + views::Widget* callout_widget = new views::Widget; + views::Widget::InitParams params; + params.type = views::Widget::InitParams::TYPE_POPUP; + params.transparent = true; + params.can_activate = false; + params.keep_on_top = true; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.parent = panel_container_; + params.bounds = ScreenAsh::ConvertRectToScreen(panel_container_, gfx::Rect()); + params.bounds.set_width(kArrowWidth); + params.bounds.set_height(kArrowHeight); + // Why do we need this and can_activate = false? + callout_widget->set_focus_on_creation(false); + callout_widget->Init(params); + DCHECK_EQ(callout_widget->GetNativeView()->GetRootWindow(), + panel_container_->GetRootWindow()); + views::View* content_view = new views::View; + content_view->set_background(new CalloutWidgetBackground); + callout_widget->SetContentsView(content_view); + return callout_widget; } } // namespace internal diff --git a/ash/wm/panel_layout_manager.h b/ash/wm/panel_layout_manager.h index 9c94fef..ec032a1 100644 --- a/ash/wm/panel_layout_manager.h +++ b/ash/wm/panel_layout_manager.h @@ -91,7 +91,25 @@ class ASH_EXPORT PanelLayoutManager friend class PanelLayoutManagerTest; friend class PanelWindowResizerTest; - typedef std::list<aura::Window*> PanelList; + views::Widget* CreateCalloutWidget(); + + struct PanelInfo{ + PanelInfo() : window(NULL), callout_widget(NULL) {} + + bool operator==(const aura::Window* other_window) const { + return window == other_window; + } + + // A weak pointer to the panel window. + aura::Window* window; + // The callout widget for this panel. This pointer must be managed + // manually as this structure is used in a std::list. See + // http://www.chromium.org/developers/smart-pointer-guidelines + views::Widget* callout_widget; + + }; + + typedef std::list<PanelInfo> PanelList; void MinimizePanel(aura::Window* panel); void RestorePanel(aura::Window* panel); @@ -103,20 +121,8 @@ class ASH_EXPORT PanelLayoutManager // changes or a panel is moved). void UpdateStacking(aura::Window* active_panel); - // Trigger a delayed task to update the callout. We use this because - // otherwise, ShadowController::OnWindowPropertyChanged may be invoked after - // we've already updated the callout, causing the drop shadow to be stacked on - // top of the callout rather than the other way around. - // TODO(dcheng): Possibly a bug in the shadow controller. If a window is - // focused but not stacked at the top, I don't think its shadow should be - // drawn on top of "higher" windows. - void UpdateCallout(aura::Window* active_window); - - // Don't call this directly. Only UpdateCallout() should call this method. - void ShowCalloutHelper(aura::Window* active_panel); - - // For testing. - views::Widget* callout_widget() const { return callout_widget_.get(); } + // Update the callout arrows for all managed panels. + void UpdateCallouts(); // Parent window associated with this layout manager. aura::Window* panel_container_; @@ -131,8 +137,6 @@ class ASH_EXPORT PanelLayoutManager // The last active panel. Used to maintain stacking even if no panels are // currently focused. aura::Window* last_active_panel_; - // Manage the callout for the focused panel, if any. - scoped_ptr<views::Widget> callout_widget_; base::WeakPtrFactory<PanelLayoutManager> weak_factory_; DISALLOW_COPY_AND_ASSIGN(PanelLayoutManager); diff --git a/ash/wm/panel_layout_manager_unittest.cc b/ash/wm/panel_layout_manager_unittest.cc index 9a3c218..48170f7 100644 --- a/ash/wm/panel_layout_manager_unittest.cc +++ b/ash/wm/panel_layout_manager_unittest.cc @@ -72,12 +72,16 @@ class PanelLayoutManagerTest : public test::AshTestBase { internal::kShellWindowId_PanelContainer); } - void GetCalloutWidget(views::Widget** widget) { + void GetCalloutWidgetForPanel(aura::Window* panel, views::Widget** widget) { PanelLayoutManager* manager = static_cast<PanelLayoutManager*>(GetPanelContainer()->layout_manager()); - ASSERT_TRUE(manager); - ASSERT_TRUE(manager->callout_widget()); - *widget = manager->callout_widget(); + DCHECK(manager); + PanelLayoutManager::PanelList::iterator found = std::find( + manager->panel_windows_.begin(), manager->panel_windows_.end(), + panel); + DCHECK(found != manager->panel_windows_.end()); + DCHECK(found->callout_widget); + *widget = found->callout_widget; } void PanelInScreen(aura::Window* panel) { @@ -127,7 +131,7 @@ class PanelLayoutManagerTest : public test::AshTestBase { // Flush the message loop, since callout updates use a delayed task. MessageLoop::current()->RunUntilIdle(); views::Widget* widget = NULL; - GetCalloutWidget(&widget); + GetCalloutWidgetForPanel(panel, &widget); Launcher* launcher = Launcher::ForPrimaryDisplay(); gfx::Rect icon_bounds = launcher->GetScreenBoundsOfItemIconForWindow(panel); @@ -141,9 +145,9 @@ class PanelLayoutManagerTest : public test::AshTestBase { 1); } - bool IsCalloutVisible() { + bool IsPanelCalloutVisible(aura::Window* panel) { views::Widget* widget = NULL; - GetCalloutWidget(&widget); + GetCalloutWidgetForPanel(panel, &widget); return widget->IsVisible(); } @@ -238,7 +242,10 @@ TEST_F(PanelLayoutManagerTest, MultiplePanelCallout) { scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds)); scoped_ptr<aura::Window> w4(CreateNormalWindow()); - EXPECT_FALSE(IsCalloutVisible()); + launcher_view_test()->RunMessageLoopUntilAnimationsDone(); + EXPECT_TRUE(IsPanelCalloutVisible(w1.get())); + EXPECT_TRUE(IsPanelCalloutVisible(w2.get())); + EXPECT_TRUE(IsPanelCalloutVisible(w3.get())); wm::ActivateWindow(w1.get()); EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w1.get())); wm::ActivateWindow(w2.get()); @@ -246,14 +253,11 @@ TEST_F(PanelLayoutManagerTest, MultiplePanelCallout) { wm::ActivateWindow(w3.get()); EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w3.get())); wm::ActivateWindow(w4.get()); - EXPECT_FALSE(IsCalloutVisible()); wm::ActivateWindow(w3.get()); EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w3.get())); w3.reset(); if (views::corewm::UseFocusController()) EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w2.get())); - else - EXPECT_FALSE(IsCalloutVisible()); } // Tests removing panels. @@ -359,20 +363,20 @@ TEST_F(PanelLayoutManagerTest, MinimizeRestorePanel) { // Activate the window, ensure callout is visible. wm::ActivateWindow(window.get()); RunAllPendingInMessageLoop(); - EXPECT_TRUE(IsCalloutVisible()); + EXPECT_TRUE(IsPanelCalloutVisible(window.get())); // Minimize the panel, callout should be hidden. window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED); RunAllPendingInMessageLoop(); - EXPECT_FALSE(IsCalloutVisible()); - // Restore the pantel; panel should not be activated by default and callout - // should be hidden. + EXPECT_FALSE(IsPanelCalloutVisible(window.get())); + // Restore the pantel; panel should not be activated by default but callout + // should be visible. window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); RunAllPendingInMessageLoop(); - EXPECT_FALSE(IsCalloutVisible()); + EXPECT_TRUE(IsPanelCalloutVisible(window.get())); // Activate the window, ensure callout is visible. wm::ActivateWindow(window.get()); RunAllPendingInMessageLoop(); - EXPECT_TRUE(IsCalloutVisible()); + EXPECT_TRUE(IsPanelCalloutVisible(window.get())); } TEST_F(PanelLayoutManagerTest, PanelMoveBetweenMultipleDisplays) { |