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/shelf/shelf_window_watcher.h" 6 7 #include "ash/display/display_controller.h" 8 #include "ash/shelf/shelf_item_delegate_manager.h" 9 #include "ash/shelf/shelf_model.h" 10 #include "ash/shelf/shelf_util.h" 11 #include "ash/shelf/shelf_window_watcher_item_delegate.h" 12 #include "ash/shell.h" 13 #include "ash/shell_window_ids.h" 14 #include "ash/wm/window_util.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "ui/aura/client/activation_client.h" 17 #include "ui/aura/window.h" 18 #include "ui/base/resource/resource_bundle.h" 19 #include "ui/gfx/image/image_skia.h" 20 #include "ui/gfx/screen.h" 21 22 namespace { 23 24 // Sets LauncherItem property by using the value of |details|. 25 void SetLauncherItemDetailsForLauncherItem( 26 ash::LauncherItem* item, 27 const ash::LauncherItemDetails& details) { 28 item->type = details.type; 29 if (details.image_resource_id != ash::kInvalidImageResourceID) { 30 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 31 item->image = *rb.GetImageSkiaNamed(details.image_resource_id); 32 } 33 } 34 35 // Returns true if |window| has a LauncherItem added by ShelfWindowWatcher. 36 bool HasLauncherItemForWindow(aura::Window* window) { 37 if (ash::GetLauncherItemDetailsForWindow(window) != NULL && 38 ash::GetLauncherIDForWindow(window) != ash::kInvalidLauncherID) 39 return true; 40 return false; 41 } 42 43 } // namespace 44 45 namespace ash { 46 namespace internal { 47 48 ShelfWindowWatcher::RootWindowObserver::RootWindowObserver( 49 ShelfWindowWatcher* window_watcher) 50 : window_watcher_(window_watcher) { 51 } 52 53 ShelfWindowWatcher::RootWindowObserver::~RootWindowObserver() { 54 } 55 56 void ShelfWindowWatcher::RootWindowObserver::OnWindowDestroying( 57 aura::Window* window) { 58 window_watcher_->OnRootWindowRemoved(window); 59 } 60 61 ShelfWindowWatcher::ShelfWindowWatcher( 62 ShelfModel* model, 63 ShelfItemDelegateManager* item_delegate_manager) 64 : model_(model), 65 item_delegate_manager_(item_delegate_manager), 66 root_window_observer_(this), 67 observed_windows_(this), 68 observed_root_windows_(&root_window_observer_), 69 observed_activation_clients_(this) { 70 // We can't assume all RootWindows have the same ActivationClient. 71 // Add a RootWindow and its ActivationClient to the observed list. 72 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); 73 for (aura::Window::Windows::const_iterator it = root_windows.begin(); 74 it != root_windows.end(); ++it) 75 OnRootWindowAdded(*it); 76 77 Shell::GetScreen()->AddObserver(this); 78 } 79 80 ShelfWindowWatcher::~ShelfWindowWatcher() { 81 Shell::GetScreen()->RemoveObserver(this); 82 } 83 84 void ShelfWindowWatcher::AddLauncherItem(aura::Window* window) { 85 const LauncherItemDetails* item_details = 86 GetLauncherItemDetailsForWindow(window); 87 LauncherItem item; 88 LauncherID id = model_->next_id(); 89 item.status = ash::wm::IsActiveWindow(window) ? STATUS_ACTIVE: STATUS_RUNNING; 90 SetLauncherItemDetailsForLauncherItem(&item, *item_details); 91 SetLauncherIDForWindow(id, window); 92 scoped_ptr<ShelfItemDelegate> item_delegate( 93 new ShelfWindowWatcherItemDelegate(window)); 94 // |item_delegate| is owned by |item_delegate_manager_|. 95 item_delegate_manager_->SetShelfItemDelegate(id, item_delegate.Pass()); 96 model_->Add(item); 97 } 98 99 void ShelfWindowWatcher::RemoveLauncherItem(aura::Window* window) { 100 model_->RemoveItemAt(model_->ItemIndexByID(GetLauncherIDForWindow(window))); 101 SetLauncherIDForWindow(kInvalidLauncherID, window); 102 } 103 104 void ShelfWindowWatcher::OnRootWindowAdded(aura::Window* root_window) { 105 // |observed_activation_clients_| can have the same ActivationClient multiple 106 // times - which would be handled by the |observed_activation_clients_|. 107 observed_activation_clients_.Add( 108 aura::client::GetActivationClient(root_window)); 109 observed_root_windows_.Add(root_window); 110 111 aura::Window* default_container = Shell::GetContainer( 112 root_window, 113 kShellWindowId_DefaultContainer); 114 observed_windows_.Add(default_container); 115 for (size_t i = 0; i < default_container->children().size(); ++i) 116 observed_windows_.Add(default_container->children()[i]); 117 } 118 119 void ShelfWindowWatcher::OnRootWindowRemoved(aura::Window* root_window) { 120 observed_root_windows_.Remove(root_window); 121 observed_activation_clients_.Remove( 122 aura::client::GetActivationClient(root_window)); 123 } 124 125 void ShelfWindowWatcher::UpdateLauncherItemStatus(aura::Window* window, 126 bool is_active) { 127 int index = GetLauncherItemIndexForWindow(window); 128 DCHECK_GE(index, 0); 129 130 LauncherItem item = model_->items()[index]; 131 item.status = is_active ? STATUS_ACTIVE : STATUS_RUNNING; 132 model_->Set(index, item); 133 } 134 135 int ShelfWindowWatcher::GetLauncherItemIndexForWindow( 136 aura::Window* window) const { 137 return model_->ItemIndexByID(GetLauncherIDForWindow(window)); 138 } 139 140 void ShelfWindowWatcher::OnWindowActivated(aura::Window* gained_active, 141 aura::Window* lost_active) { 142 if (gained_active && HasLauncherItemForWindow(gained_active)) 143 UpdateLauncherItemStatus(gained_active, true); 144 if (lost_active && HasLauncherItemForWindow(lost_active)) 145 UpdateLauncherItemStatus(lost_active, false); 146 } 147 148 void ShelfWindowWatcher::OnWindowAdded(aura::Window* window) { 149 observed_windows_.Add(window); 150 // Add LauncherItem if |window| already has a LauncherItemDetails when it is 151 // created. Don't make a new LauncherItem for the re-parented |window| that 152 // already has a LauncherItem. 153 if (GetLauncherIDForWindow(window) == ash::kInvalidLauncherID && 154 GetLauncherItemDetailsForWindow(window)) 155 AddLauncherItem(window); 156 } 157 158 void ShelfWindowWatcher::OnWillRemoveWindow(aura::Window* window) { 159 // Remove a child window of default container and its item if it has. 160 if (observed_windows_.IsObserving(window)) 161 observed_windows_.Remove(window); 162 163 if (HasLauncherItemForWindow(window)) 164 RemoveLauncherItem(window); 165 } 166 167 void ShelfWindowWatcher::OnWindowDestroying(aura::Window* window) { 168 // Remove the default container. 169 if (observed_windows_.IsObserving(window)) 170 observed_windows_.Remove(window); 171 } 172 173 void ShelfWindowWatcher::OnWindowPropertyChanged(aura::Window* window, 174 const void* key, 175 intptr_t old) { 176 if (key != kLauncherItemDetailsKey) 177 return; 178 179 if (GetLauncherItemDetailsForWindow(window) == NULL) { 180 // Removes LauncherItem for |window| when it has a LauncherItem. 181 if (reinterpret_cast<LauncherItemDetails*>(old) != NULL) 182 RemoveLauncherItem(window); 183 return; 184 } 185 186 // When LauncherItemDetails is changed, update LauncherItem. 187 if (HasLauncherItemForWindow(window)) { 188 int index = GetLauncherItemIndexForWindow(window); 189 DCHECK_GE(index, 0); 190 LauncherItem item = model_->items()[index]; 191 const LauncherItemDetails* details = 192 GetLauncherItemDetailsForWindow(window); 193 SetLauncherItemDetailsForLauncherItem(&item, *details); 194 model_->Set(index, item); 195 return; 196 } 197 198 // Creates a new LauncherItem for |window|. 199 AddLauncherItem(window); 200 } 201 202 void ShelfWindowWatcher::OnDisplayBoundsChanged(const gfx::Display& display) { 203 } 204 205 void ShelfWindowWatcher::OnDisplayAdded(const gfx::Display& new_display) { 206 // Add a new RootWindow and its ActivationClient to observed list. 207 aura::Window* root_window = Shell::GetInstance()->display_controller()-> 208 GetRootWindowForDisplayId(new_display.id()); 209 210 // When the primary root window's display get removed, the existing root 211 // window is taken over by the new display and the observer is already set. 212 if (!observed_root_windows_.IsObserving(root_window)) 213 OnRootWindowAdded(root_window); 214 } 215 216 void ShelfWindowWatcher::OnDisplayRemoved(const gfx::Display& old_display) { 217 // When this is called, RootWindow of |old_display| is already removed. 218 // Instead, we remove an observer from RootWindow and ActivationClient in the 219 // OnRootWindowDestroyed(). 220 // Do nothing here. 221 } 222 223 } // namespace internal 224 } // namespace ash 225