blob: b4e65e25a7b2f50761de5c0c524936e86163917c [file] [log] [blame]
// 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