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 for (WindowList::iterator iter = transform_windows_.begin(); 96 iter != transform_windows_.end(); iter++) { 97 (*iter)->window()->RemoveObserver(this); 98 } 99 } 100 101 void WindowSelectorPanels::AddWindow(aura::Window* window) { 102 DCHECK(window->GetRootWindow() == panels_root_window_); 103 window->AddObserver(this); 104 transform_windows_.push_back(new ScopedTransformPanelWindow(window)); 105 } 106 107 aura::Window* WindowSelectorPanels::GetRootWindow() { 108 return transform_windows_.front()->window()->GetRootWindow(); 109 } 110 111 bool WindowSelectorPanels::HasSelectableWindow(const aura::Window* window) { 112 for (WindowList::const_iterator iter = transform_windows_.begin(); 113 iter != transform_windows_.end(); ++iter) { 114 if ((*iter)->window() == window) 115 return true; 116 } 117 return false; 118 } 119 120 bool WindowSelectorPanels::Contains(const aura::Window* target) { 121 for (WindowList::const_iterator iter = transform_windows_.begin(); 122 iter != transform_windows_.end(); ++iter) { 123 if ((*iter)->Contains(target)) 124 return true; 125 } 126 return false; 127 } 128 129 void WindowSelectorPanels::RestoreWindowOnExit(aura::Window* window) { 130 for (WindowList::iterator iter = transform_windows_.begin(); 131 iter != transform_windows_.end(); ++iter) { 132 if ((*iter)->Contains(window)) { 133 (*iter)->RestoreWindowOnExit(); 134 break; 135 } 136 } 137 } 138 139 aura::Window* WindowSelectorPanels::SelectionWindow() { 140 return transform_windows_.front()->window(); 141 } 142 143 void WindowSelectorPanels::RemoveWindow(const aura::Window* window) { 144 for (WindowList::iterator iter = transform_windows_.begin(); 145 iter != transform_windows_.end(); ++iter) { 146 if ((*iter)->window() == window) { 147 (*iter)->window()->RemoveObserver(this); 148 (*iter)->OnWindowDestroyed(); 149 transform_windows_.erase(iter); 150 break; 151 } 152 } 153 WindowSelectorItem::RemoveWindow(window); 154 } 155 156 bool WindowSelectorPanels::empty() const { 157 return transform_windows_.empty(); 158 } 159 160 void WindowSelectorPanels::PrepareForOverview() { 161 // |panel_windows| will hold all the windows in the panel container, sorted 162 // according to their stacking order. 163 const aura::Window::Windows panels = 164 transform_windows_.front()->window()->parent()->children(); 165 166 // Call PrepareForOverview() in the reverse stacking order so that the 167 // transparent windows that handle the events are in the correct stacking 168 // order. 169 size_t transformed_windows = 0; 170 for (aura::Window::Windows::const_reverse_iterator iter = panels.rbegin(); 171 iter != panels.rend(); iter++) { 172 for (size_t j = 0; j < transform_windows_.size(); ++j) { 173 if (transform_windows_[j]->window() == (*iter)) { 174 transform_windows_[j]->PrepareForOverview(); 175 transformed_windows++; 176 } 177 } 178 } 179 DCHECK(transformed_windows == transform_windows_.size()); 180 } 181 182 void WindowSelectorPanels::SetItemBounds(aura::Window* root_window, 183 const gfx::Rect& target_bounds, 184 bool animate) { 185 gfx::Rect bounding_rect; 186 for (WindowList::iterator iter = transform_windows_.begin(); 187 iter != transform_windows_.end(); ++iter) { 188 bounding_rect.Union((*iter)->GetBoundsInScreen()); 189 } 190 set_bounds(ScopedTransformOverviewWindow:: 191 ShrinkRectToFitPreservingAspectRatio(bounding_rect, target_bounds)); 192 gfx::Transform bounding_transform = 193 ScopedTransformOverviewWindow::GetTransformForRect(bounding_rect, 194 bounds()); 195 for (WindowList::iterator iter = transform_windows_.begin(); 196 iter != transform_windows_.end(); ++iter) { 197 gfx::Transform transform; 198 gfx::Rect bounds = (*iter)->GetBoundsInScreen(); 199 transform.Translate(bounding_rect.x() - bounds.x(), 200 bounding_rect.y() - bounds.y()); 201 transform.PreconcatTransform(bounding_transform); 202 transform.Translate(bounds.x() - bounding_rect.x(), 203 bounds.y() - bounding_rect.y()); 204 (*iter)->SetTransform(root_window, transform, animate); 205 } 206 } 207 208 void WindowSelectorPanels::SetOpacity(float opacity) { 209 // TODO(flackr): find a way to make panels that are hidden behind other panels 210 // look nice. 211 for (WindowList::iterator iter = transform_windows_.begin(); 212 iter != transform_windows_.end(); iter++) { 213 (*iter)->window()->layer()->SetOpacity(opacity); 214 } 215 WindowSelectorItem::SetOpacity(opacity); 216 } 217 218 } // namespace ash 219