Index: ash/wm/panel_layout_manager.cc |
diff --git a/ash/wm/panel_layout_manager.cc b/ash/wm/panel_layout_manager.cc |
index f741154d787135c96e46942cac6ff7950de64b6f..4ab7032c2953446a95d9cab06ba598500f292ec1 100644 |
--- a/ash/wm/panel_layout_manager.cc |
+++ b/ash/wm/panel_layout_manager.cc |
@@ -10,6 +10,7 @@ |
#include "ash/shell.h" |
#include "ash/wm/property_util.h" |
#include "base/auto_reset.h" |
+#include "ui/aura/client/activation_client.h" |
#include "ui/aura/client/aura_constants.h" |
#include "ui/aura/root_window.h" |
#include "ui/aura/window.h" |
@@ -32,18 +33,20 @@ namespace internal { |
//////////////////////////////////////////////////////////////////////////////// |
// PanelLayoutManager public implementation: |
- |
PanelLayoutManager::PanelLayoutManager(aura::Window* panel_container) |
: panel_container_(panel_container), |
in_layout_(false), |
dragged_panel_(NULL), |
- launcher_(NULL) { |
+ launcher_(NULL), |
+ last_active_panel_(NULL) { |
DCHECK(panel_container); |
+ Shell::GetRootWindow()->AddObserver(this); |
} |
PanelLayoutManager::~PanelLayoutManager() { |
if (launcher_) |
launcher_->RemoveIconObserver(this); |
+ Shell::GetRootWindow()->RemoveObserver(this); |
} |
void PanelLayoutManager::StartDragging(aura::Window* panel) { |
@@ -92,7 +95,6 @@ void PanelLayoutManager::ToggleMinimize(aura::Window* panel) { |
//////////////////////////////////////////////////////////////////////////////// |
// PanelLayoutManager, aura::LayoutManager implementation: |
- |
void PanelLayoutManager::OnWindowResized() { |
Relayout(); |
} |
@@ -111,6 +113,9 @@ void PanelLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) { |
if (dragged_panel_ == child) |
dragged_panel_ = NULL; |
+ if (last_active_panel_ == child) |
+ last_active_panel_ = NULL; |
+ |
Relayout(); |
} |
@@ -156,15 +161,27 @@ void PanelLayoutManager::SetChildBounds(aura::Window* child, |
} |
//////////////////////////////////////////////////////////////////////////////// |
-// PanelLayoutManager, aura::LauncherIconObserver implementation: |
- |
+// PanelLayoutManager, ash::LauncherIconObserver implementation: |
void PanelLayoutManager::OnLauncherIconPositionsChanged() { |
Relayout(); |
} |
//////////////////////////////////////////////////////////////////////////////// |
-// PanelLayoutManager private implementation: |
+// PanelLayoutManager, aura::WindowObserver implementation: |
+void PanelLayoutManager::OnWindowPropertyChanged(aura::Window* window, |
+ const void* key, |
+ intptr_t old) { |
+ if (key == aura::client::kRootWindowActiveWindowKey) { |
+ aura::Window* active = window->GetProperty( |
+ aura::client::kRootWindowActiveWindowKey); |
+ if (active && active->type() == aura::client::WINDOW_TYPE_PANEL) |
+ UpdateStacking(active); |
+ } |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// PanelLayoutManager private implementation: |
void PanelLayoutManager::Relayout() { |
if (in_layout_) |
return; |
@@ -172,31 +189,87 @@ void PanelLayoutManager::Relayout() { |
ash::Shell* shell = ash::Shell::GetInstance(); |
+ aura::Window* active_panel = NULL; |
for (PanelList::iterator iter = panel_windows_.begin(); |
iter != panel_windows_.end(); ++iter) { |
- aura::Window* panel_win = *iter; |
- if (!panel_win->IsVisible() || panel_win == dragged_panel_) |
+ aura::Window* panel = *iter; |
+ if (!panel->IsVisible() || panel == dragged_panel_) |
continue; |
gfx::Rect icon_bounds = |
- shell->launcher()->GetScreenBoundsOfItemIconForWindow(panel_win); |
+ shell->launcher()->GetScreenBoundsOfItemIconForWindow(panel); |
// An empty rect indicates that there is no icon for the panel in the |
// launcher. Just use the current bounds, as there's no icon to draw the |
// panel above. |
+ // TODO(dcheng): Need to anchor to overflow icon. |
if (icon_bounds.IsEmpty()) |
continue; |
+ if (panel->HasFocus()) { |
+ DCHECK(!active_panel); |
+ active_panel = panel; |
+ } |
+ |
gfx::Point icon_origin = icon_bounds.origin(); |
aura::Window::ConvertPointToWindow(panel_container_->GetRootWindow(), |
panel_container_, &icon_origin); |
- gfx::Rect bounds = panel_win->bounds(); |
+ // TODO(dcheng): Need to clamp to screen edges. |
+ gfx::Rect bounds = panel->bounds(); |
bounds.set_x( |
icon_origin.x() + icon_bounds.width() / 2 - bounds.width() / 2); |
bounds.set_y(icon_origin.y() - bounds.height()); |
- SetChildBoundsDirect(panel_win, bounds); |
+ SetChildBoundsDirect(panel, bounds); |
} |
+ |
+ UpdateStacking(active_panel); |
+} |
+ |
+void PanelLayoutManager::UpdateStacking(aura::Window* active_panel) { |
+ if (!active_panel) { |
+ if (!last_active_panel_) |
+ return; |
+ active_panel = last_active_panel_; |
+ } |
+ |
+ // We want to to stack the panels like a deck of cards: |
+ // ,--,--,--,-------.--.--. |
+ // | | | | | | | |
+ // | | | | | | | |
+ // |
+ // We use the middle of each panel to figure out how to stack the panels. This |
+ // allows us to update the stacking when a panel is being dragged around by |
+ // the titlebar--even though it doesn't update the launcher icon positions, we |
+ // still want the visual effect. |
+ 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(); |
+ window_ordering.insert(std::make_pair(bounds.x() + bounds.width() / 2, |
+ *it)); |
+ } |
+ |
+ aura::Window* previous_panel = NULL; |
+ for (std::map<int, aura::Window*>::const_iterator it = |
+ window_ordering.begin(); |
+ it != window_ordering.end() && it->second != active_panel; ++it) { |
+ if (previous_panel) |
+ panel_container_->StackChildAbove(it->second, previous_panel); |
+ previous_panel = it->second; |
+ } |
+ |
+ previous_panel = NULL; |
+ for (std::map<int, aura::Window*>::const_reverse_iterator it = |
+ window_ordering.rbegin(); |
+ it != window_ordering.rend() && it->second != active_panel; ++it) { |
+ if (previous_panel) |
+ panel_container_->StackChildAbove(it->second, previous_panel); |
+ previous_panel = it->second; |
+ } |
+ |
+ panel_container_->StackChildAtTop(active_panel); |
+ last_active_panel_ = active_panel; |
} |
} // namespace internal |