| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/shelf/shelf_window_watcher.h" |
| |
| #include "ash/display/display_controller.h" |
| #include "ash/shelf/shelf_item_delegate_manager.h" |
| #include "ash/shelf/shelf_model.h" |
| #include "ash/shelf/shelf_util.h" |
| #include "ash/shelf/shelf_window_watcher_item_delegate.h" |
| #include "ash/shell.h" |
| #include "ash/shell_window_ids.h" |
| #include "ash/wm/window_util.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "ui/aura/client/activation_client.h" |
| #include "ui/aura/window.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "ui/gfx/image/image_skia.h" |
| #include "ui/gfx/screen.h" |
| |
| namespace { |
| |
| // Sets LauncherItem property by using the value of |details|. |
| void SetLauncherItemDetailsForLauncherItem( |
| ash::LauncherItem* item, |
| const ash::LauncherItemDetails& details) { |
| item->type = details.type; |
| if (details.image_resource_id != ash::kInvalidImageResourceID) { |
| ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| item->image = *rb.GetImageSkiaNamed(details.image_resource_id); |
| } |
| } |
| |
| // Returns true if |window| has a LauncherItem added by ShelfWindowWatcher. |
| bool HasLauncherItemForWindow(aura::Window* window) { |
| if (ash::GetLauncherItemDetailsForWindow(window) != NULL && |
| ash::GetLauncherIDForWindow(window) != ash::kInvalidLauncherID) |
| return true; |
| return false; |
| } |
| |
| } // namespace |
| |
| namespace ash { |
| namespace internal { |
| |
| ShelfWindowWatcher::RootWindowObserver::RootWindowObserver( |
| ShelfWindowWatcher* window_watcher) |
| : window_watcher_(window_watcher) { |
| } |
| |
| ShelfWindowWatcher::RootWindowObserver::~RootWindowObserver() { |
| } |
| |
| void ShelfWindowWatcher::RootWindowObserver::OnWindowDestroying( |
| aura::Window* window) { |
| window_watcher_->OnRootWindowRemoved(window); |
| } |
| |
| ShelfWindowWatcher::ShelfWindowWatcher( |
| ShelfModel* model, |
| ShelfItemDelegateManager* item_delegate_manager) |
| : model_(model), |
| item_delegate_manager_(item_delegate_manager), |
| root_window_observer_(this), |
| observed_windows_(this), |
| observed_root_windows_(&root_window_observer_), |
| observed_activation_clients_(this) { |
| // We can't assume all RootWindows have the same ActivationClient. |
| // Add a RootWindow and its ActivationClient to the observed list. |
| aura::Window::Windows root_windows = Shell::GetAllRootWindows(); |
| for (aura::Window::Windows::const_iterator it = root_windows.begin(); |
| it != root_windows.end(); ++it) |
| OnRootWindowAdded(*it); |
| |
| Shell::GetScreen()->AddObserver(this); |
| } |
| |
| ShelfWindowWatcher::~ShelfWindowWatcher() { |
| Shell::GetScreen()->RemoveObserver(this); |
| } |
| |
| void ShelfWindowWatcher::AddLauncherItem(aura::Window* window) { |
| const LauncherItemDetails* item_details = |
| GetLauncherItemDetailsForWindow(window); |
| LauncherItem item; |
| LauncherID id = model_->next_id(); |
| item.status = ash::wm::IsActiveWindow(window) ? STATUS_ACTIVE: STATUS_RUNNING; |
| SetLauncherItemDetailsForLauncherItem(&item, *item_details); |
| SetLauncherIDForWindow(id, window); |
| scoped_ptr<ShelfItemDelegate> item_delegate( |
| new ShelfWindowWatcherItemDelegate(window)); |
| // |item_delegate| is owned by |item_delegate_manager_|. |
| item_delegate_manager_->SetShelfItemDelegate(id, item_delegate.Pass()); |
| model_->Add(item); |
| } |
| |
| void ShelfWindowWatcher::RemoveLauncherItem(aura::Window* window) { |
| model_->RemoveItemAt(model_->ItemIndexByID(GetLauncherIDForWindow(window))); |
| SetLauncherIDForWindow(kInvalidLauncherID, window); |
| } |
| |
| void ShelfWindowWatcher::OnRootWindowAdded(aura::Window* root_window) { |
| // |observed_activation_clients_| can have the same ActivationClient multiple |
| // times - which would be handled by the |observed_activation_clients_|. |
| observed_activation_clients_.Add( |
| aura::client::GetActivationClient(root_window)); |
| observed_root_windows_.Add(root_window); |
| |
| aura::Window* default_container = Shell::GetContainer( |
| root_window, |
| kShellWindowId_DefaultContainer); |
| observed_windows_.Add(default_container); |
| for (size_t i = 0; i < default_container->children().size(); ++i) |
| observed_windows_.Add(default_container->children()[i]); |
| } |
| |
| void ShelfWindowWatcher::OnRootWindowRemoved(aura::Window* root_window) { |
| observed_root_windows_.Remove(root_window); |
| observed_activation_clients_.Remove( |
| aura::client::GetActivationClient(root_window)); |
| } |
| |
| void ShelfWindowWatcher::UpdateLauncherItemStatus(aura::Window* window, |
| bool is_active) { |
| int index = GetLauncherItemIndexForWindow(window); |
| DCHECK_GE(index, 0); |
| |
| LauncherItem item = model_->items()[index]; |
| item.status = is_active ? STATUS_ACTIVE : STATUS_RUNNING; |
| model_->Set(index, item); |
| } |
| |
| int ShelfWindowWatcher::GetLauncherItemIndexForWindow( |
| aura::Window* window) const { |
| return model_->ItemIndexByID(GetLauncherIDForWindow(window)); |
| } |
| |
| void ShelfWindowWatcher::OnWindowActivated(aura::Window* gained_active, |
| aura::Window* lost_active) { |
| if (gained_active && HasLauncherItemForWindow(gained_active)) |
| UpdateLauncherItemStatus(gained_active, true); |
| if (lost_active && HasLauncherItemForWindow(lost_active)) |
| UpdateLauncherItemStatus(lost_active, false); |
| } |
| |
| void ShelfWindowWatcher::OnWindowAdded(aura::Window* window) { |
| observed_windows_.Add(window); |
| // Add LauncherItem if |window| already has a LauncherItemDetails when it is |
| // created. Don't make a new LauncherItem for the re-parented |window| that |
| // already has a LauncherItem. |
| if (GetLauncherIDForWindow(window) == ash::kInvalidLauncherID && |
| GetLauncherItemDetailsForWindow(window)) |
| AddLauncherItem(window); |
| } |
| |
| void ShelfWindowWatcher::OnWillRemoveWindow(aura::Window* window) { |
| // Remove a child window of default container and its item if it has. |
| if (observed_windows_.IsObserving(window)) |
| observed_windows_.Remove(window); |
| |
| if (HasLauncherItemForWindow(window)) |
| RemoveLauncherItem(window); |
| } |
| |
| void ShelfWindowWatcher::OnWindowDestroying(aura::Window* window) { |
| // Remove the default container. |
| if (observed_windows_.IsObserving(window)) |
| observed_windows_.Remove(window); |
| } |
| |
| void ShelfWindowWatcher::OnWindowPropertyChanged(aura::Window* window, |
| const void* key, |
| intptr_t old) { |
| if (key != kLauncherItemDetailsKey) |
| return; |
| |
| if (GetLauncherItemDetailsForWindow(window) == NULL) { |
| // Removes LauncherItem for |window| when it has a LauncherItem. |
| if (reinterpret_cast<LauncherItemDetails*>(old) != NULL) |
| RemoveLauncherItem(window); |
| return; |
| } |
| |
| // When LauncherItemDetails is changed, update LauncherItem. |
| if (HasLauncherItemForWindow(window)) { |
| int index = GetLauncherItemIndexForWindow(window); |
| DCHECK_GE(index, 0); |
| LauncherItem item = model_->items()[index]; |
| const LauncherItemDetails* details = |
| GetLauncherItemDetailsForWindow(window); |
| SetLauncherItemDetailsForLauncherItem(&item, *details); |
| model_->Set(index, item); |
| return; |
| } |
| |
| // Creates a new LauncherItem for |window|. |
| AddLauncherItem(window); |
| } |
| |
| void ShelfWindowWatcher::OnDisplayBoundsChanged(const gfx::Display& display) { |
| } |
| |
| void ShelfWindowWatcher::OnDisplayAdded(const gfx::Display& new_display) { |
| // Add a new RootWindow and its ActivationClient to observed list. |
| aura::Window* root_window = Shell::GetInstance()->display_controller()-> |
| GetRootWindowForDisplayId(new_display.id()); |
| |
| // When the primary root window's display get removed, the existing root |
| // window is taken over by the new display and the observer is already set. |
| if (!observed_root_windows_.IsObserving(root_window)) |
| OnRootWindowAdded(root_window); |
| } |
| |
| void ShelfWindowWatcher::OnDisplayRemoved(const gfx::Display& old_display) { |
| // When this is called, RootWindow of |old_display| is already removed. |
| // Instead, we remove an observer from RootWindow and ActivationClient in the |
| // OnRootWindowDestroyed(). |
| // Do nothing here. |
| } |
| |
| } // namespace internal |
| } // namespace ash |