// 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 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(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