1 // Copyright 2013 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. 4 5 #include "ash/wm/overview/window_selector_panels.h" 6 7 #include "ash/screen_util.h" 8 #include "ash/shell.h" 9 #include "ash/shell_window_ids.h" 10 #include "ash/wm/overview/scoped_transform_overview_window.h" 11 #include "ash/wm/overview/transparent_activate_window_button.h" 12 #include "ash/wm/panels/panel_layout_manager.h" 13 #include "ash/wm/window_util.h" 14 #include "ui/aura/window.h" 15 #include "ui/compositor/layer.h" 16 #include "ui/compositor/layer_animation_observer.h" 17 #include "ui/compositor/layer_animation_sequence.h" 18 #include "ui/views/controls/button/button.h" 19 20 namespace ash { 21 22 namespace { 23 24 // This class extends ScopedTransformOverviewMode to hide and show the callout 25 // widget for a panel window when entering / leaving overview mode, as well as 26 // to add a transparent button for each panel window. 27 class ScopedTransformPanelWindow : public ScopedTransformOverviewWindow { 28 public: 29 explicit ScopedTransformPanelWindow(aura::Window* window); 30 virtual ~ScopedTransformPanelWindow(); 31 32 // ScopedTransformOverviewWindow overrides: 33 virtual void PrepareForOverview() OVERRIDE; 34 35 virtual void SetTransform( 36 aura::Window* root_window, 37 const gfx::Transform& transform, 38 bool animate) OVERRIDE; 39 40 private: 41 // Returns the panel window bounds after the transformation. 42 gfx::Rect GetTransformedBounds(); 43 44 scoped_ptr<TransparentActivateWindowButton> window_button_; 45 46 DISALLOW_COPY_AND_ASSIGN(ScopedTransformPanelWindow); 47 }; 48 49 ScopedTransformPanelWindow::ScopedTransformPanelWindow(aura::Window* window) 50 : ScopedTransformOverviewWindow(window) { 51 } 52 53 ScopedTransformPanelWindow::~ScopedTransformPanelWindow() { 54 } 55 56 void ScopedTransformPanelWindow::PrepareForOverview() { 57 ScopedTransformOverviewWindow::PrepareForOverview(); 58 window_button_.reset(new TransparentActivateWindowButton(window())); 59 } 60 61 void ScopedTransformPanelWindow::SetTransform( 62 aura::Window* root_window, 63 const gfx::Transform& transform, 64 bool animate) { 65 ScopedTransformOverviewWindow::SetTransform(root_window, transform, animate); 66 window_button_->SetBounds(GetTransformedBounds()); 67 } 68 69 gfx::Rect ScopedTransformPanelWindow::GetTransformedBounds() { 70 gfx::RectF bounds(ScreenUtil::ConvertRectToScreen( 71 window()->GetRootWindow(), window()->layer()->bounds())); 72 gfx::Transform new_transform; 73 new_transform.Translate(bounds.x(), 74 bounds.y()); 75 new_transform.PreconcatTransform(window()->layer()->GetTargetTransform()); 76 new_transform.Translate(-bounds.x(), 77 -bounds.y()); 78 new_transform.TransformRect(&bounds); 79 return ToEnclosingRect(bounds); 80 } 81 82 } // namespace 83 84 WindowSelectorPanels::WindowSelectorPanels(aura::Window* panels_root_window) 85 : panels_root_window_(panels_root_window) { 86 static_cast<PanelLayoutManager*>( 87 Shell::GetContainer(panels_root_window_, kShellWindowId_PanelContainer)-> 88 layout_manager())->SetShowCalloutWidgets(false); 89 } 90 91 WindowSelectorPanels::~WindowSelectorPanels() { 92 static_cast<PanelLayoutManager*>( 93 Shell::GetContainer(panels_root_window_, kShellWindowId_PanelContainer)-> 94 layout_manager())->SetShowCalloutWidgets(true); 95 } 96 97 void WindowSelectorPanels::AddWindow(aura::Window* window) { 98 DCHECK(window->GetRootWindow() == panels_root_window_); 99 transform_windows_.push_back(new ScopedTransformPanelWindow(window)); 100 } 101 102 aura::Window* WindowSelectorPanels::GetRootWindow() { 103 return transform_windows_.front()->window()->GetRootWindow(); 104 } 105 106 bool WindowSelectorPanels::HasSelectableWindow(const aura::Window* window) { 107 for (WindowList::const_iterator iter = transform_windows_.begin(); 108 iter != transform_windows_.end(); ++iter) { 109 if ((*iter)->window() == window) 110 return true; 111 } 112 return false; 113 } 114 115 bool WindowSelectorPanels::Contains(const aura::Window* target) { 116 for (WindowList::const_iterator iter = transform_windows_.begin(); 117 iter != transform_windows_.end(); ++iter) { 118 if ((*iter)->Contains(target)) 119 return true; 120 } 121 return false; 122 } 123 124 void WindowSelectorPanels::RestoreWindowOnExit(aura::Window* window) { 125 for (WindowList::iterator iter = transform_windows_.begin(); 126 iter != transform_windows_.end(); ++iter) { 127 if ((*iter)->Contains(window)) { 128 (*iter)->RestoreWindowOnExit(); 129 break; 130 } 131 } 132 } 133 134 aura::Window* WindowSelectorPanels::SelectionWindow() { 135 return transform_windows_.front()->window(); 136 } 137 138 void WindowSelectorPanels::RemoveWindow(const aura::Window* window) { 139 for (WindowList::iterator iter = transform_windows_.begin(); 140 iter != transform_windows_.end(); ++iter) { 141 if ((*iter)->window() == window) { 142 (*iter)->OnWindowDestroyed(); 143 transform_windows_.erase(iter); 144 break; 145 } 146 } 147 WindowSelectorItem::RemoveWindow(window); 148 } 149 150 bool WindowSelectorPanels::empty() const { 151 return transform_windows_.empty(); 152 } 153 154 void WindowSelectorPanels::PrepareForOverview() { 155 // |panel_windows| will hold all the windows in the panel container, sorted 156 // according to their stacking order. 157 const aura::Window::Windows panels = 158 transform_windows_[0]->window()->parent()->children(); 159 160 // Call PrepareForOverview() in the reverse stacking order so that the 161 // transparent windows that handle the events are in the correct stacking 162 // order. 163 size_t transformed_windows = 0; 164 for (aura::Window::Windows::const_reverse_iterator iter = panels.rbegin(); 165 iter != panels.rend(); iter++) { 166 for (size_t j = 0; j < transform_windows_.size(); ++j) { 167 if (transform_windows_[j]->window() == (*iter)) { 168 transform_windows_[j]->PrepareForOverview(); 169 transformed_windows++; 170 } 171 } 172 } 173 DCHECK(transformed_windows == transform_windows_.size()); 174 } 175 176 void WindowSelectorPanels::SetItemBounds(aura::Window* root_window, 177 const gfx::Rect& target_bounds, 178 bool animate) { 179 gfx::Rect bounding_rect; 180 for (WindowList::iterator iter = transform_windows_.begin(); 181 iter != transform_windows_.end(); ++iter) { 182 bounding_rect.Union((*iter)->GetBoundsInScreen()); 183 } 184 set_bounds(ScopedTransformOverviewWindow:: 185 ShrinkRectToFitPreservingAspectRatio(bounding_rect, target_bounds)); 186 gfx::Transform bounding_transform = 187 ScopedTransformOverviewWindow::GetTransformForRect(bounding_rect, 188 bounds()); 189 for (WindowList::iterator iter = transform_windows_.begin(); 190 iter != transform_windows_.end(); ++iter) { 191 gfx::Transform transform; 192 gfx::Rect bounds = (*iter)->GetBoundsInScreen(); 193 transform.Translate(bounding_rect.x() - bounds.x(), 194 bounding_rect.y() - bounds.y()); 195 transform.PreconcatTransform(bounding_transform); 196 transform.Translate(bounds.x() - bounding_rect.x(), 197 bounds.y() - bounding_rect.y()); 198 (*iter)->SetTransform(root_window, transform, animate); 199 } 200 } 201 202 } // namespace ash 203