| OLD | NEW |
| (Empty) |
| 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/common/shelf/shelf_window_watcher.h" | |
| 6 | |
| 7 #include <memory> | |
| 8 #include <utility> | |
| 9 | |
| 10 #include "ash/common/shelf/shelf_constants.h" | |
| 11 #include "ash/common/shelf/shelf_model.h" | |
| 12 #include "ash/common/shelf/shelf_window_watcher_item_delegate.h" | |
| 13 #include "ash/common/wm/window_state.h" | |
| 14 #include "ash/common/wm_shell.h" | |
| 15 #include "ash/common/wm_window.h" | |
| 16 #include "ash/public/cpp/shell_window_ids.h" | |
| 17 #include "ash/public/cpp/window_properties.h" | |
| 18 #include "ash/shell.h" | |
| 19 #include "ash/wm/window_properties.h" | |
| 20 #include "ash/wm/window_state_aura.h" | |
| 21 #include "ash/wm/window_util.h" | |
| 22 #include "ui/aura/client/aura_constants.h" | |
| 23 #include "ui/aura/env.h" | |
| 24 #include "ui/aura/window.h" | |
| 25 #include "ui/display/display.h" | |
| 26 #include "ui/display/screen.h" | |
| 27 #include "ui/wm/public/activation_client.h" | |
| 28 | |
| 29 namespace ash { | |
| 30 namespace { | |
| 31 | |
| 32 // Returns the shelf item type, with special temporary behavior for Mash: | |
| 33 // Mash provides a default shelf item type (TYPE_APP) for non-ignored windows. | |
| 34 ShelfItemType GetShelfItemType(aura::Window* window) { | |
| 35 if (aura::Env::GetInstance()->mode() == aura::Env::Mode::LOCAL || | |
| 36 window->GetProperty(kShelfItemTypeKey) != TYPE_UNDEFINED) { | |
| 37 return static_cast<ShelfItemType>(window->GetProperty(kShelfItemTypeKey)); | |
| 38 } | |
| 39 return wm::GetWindowState(window)->ignored_by_shelf() ? TYPE_UNDEFINED | |
| 40 : TYPE_APP; | |
| 41 } | |
| 42 | |
| 43 // Update the ShelfItem from relevant window properties. | |
| 44 void UpdateShelfItemForWindow(ShelfItem* item, aura::Window* window) { | |
| 45 item->type = GetShelfItemType(window); | |
| 46 | |
| 47 item->status = STATUS_RUNNING; | |
| 48 if (wm::IsActiveWindow(window)) | |
| 49 item->status = STATUS_ACTIVE; | |
| 50 else if (window->GetProperty(aura::client::kDrawAttentionKey)) | |
| 51 item->status = STATUS_ATTENTION; | |
| 52 | |
| 53 const std::string* app_id = window->GetProperty(aura::client::kAppIdKey); | |
| 54 item->app_id = app_id ? *app_id : std::string(); | |
| 55 | |
| 56 // Prefer app icons over window icons, they're typically larger. | |
| 57 gfx::ImageSkia* image = window->GetProperty(aura::client::kAppIconKey); | |
| 58 if (!image || image->isNull()) | |
| 59 image = window->GetProperty(aura::client::kWindowIconKey); | |
| 60 item->image = image ? *image : gfx::ImageSkia(); | |
| 61 | |
| 62 item->title = window->GetTitle(); | |
| 63 | |
| 64 // Do not show tooltips for visible attached app panel windows. | |
| 65 item->shows_tooltip = item->type != TYPE_APP_PANEL || !window->IsVisible() || | |
| 66 !window->GetProperty(kPanelAttachedKey); | |
| 67 } | |
| 68 | |
| 69 } // namespace | |
| 70 | |
| 71 ShelfWindowWatcher::ContainerWindowObserver::ContainerWindowObserver( | |
| 72 ShelfWindowWatcher* window_watcher) | |
| 73 : window_watcher_(window_watcher) {} | |
| 74 | |
| 75 ShelfWindowWatcher::ContainerWindowObserver::~ContainerWindowObserver() {} | |
| 76 | |
| 77 void ShelfWindowWatcher::ContainerWindowObserver::OnWindowHierarchyChanged( | |
| 78 const HierarchyChangeParams& params) { | |
| 79 if (!params.old_parent && params.new_parent && | |
| 80 (params.new_parent->id() == kShellWindowId_DefaultContainer || | |
| 81 params.new_parent->id() == kShellWindowId_PanelContainer)) { | |
| 82 // A new window was created in the default container or the panel container. | |
| 83 window_watcher_->OnUserWindowAdded(params.target); | |
| 84 } | |
| 85 } | |
| 86 | |
| 87 void ShelfWindowWatcher::ContainerWindowObserver::OnWindowDestroying( | |
| 88 aura::Window* window) { | |
| 89 window_watcher_->OnContainerWindowDestroying(window); | |
| 90 } | |
| 91 | |
| 92 //////////////////////////////////////////////////////////////////////////////// | |
| 93 | |
| 94 ShelfWindowWatcher::UserWindowObserver::UserWindowObserver( | |
| 95 ShelfWindowWatcher* window_watcher) | |
| 96 : window_watcher_(window_watcher) {} | |
| 97 | |
| 98 ShelfWindowWatcher::UserWindowObserver::~UserWindowObserver() {} | |
| 99 | |
| 100 void ShelfWindowWatcher::UserWindowObserver::OnWindowPropertyChanged( | |
| 101 aura::Window* window, | |
| 102 const void* key, | |
| 103 intptr_t old) { | |
| 104 if (key == aura::client::kAppIconKey || key == aura::client::kAppIdKey || | |
| 105 key == aura::client::kDrawAttentionKey || | |
| 106 key == aura::client::kWindowIconKey || key == kPanelAttachedKey || | |
| 107 key == kShelfItemTypeKey) { | |
| 108 window_watcher_->OnUserWindowPropertyChanged(window); | |
| 109 } | |
| 110 } | |
| 111 | |
| 112 void ShelfWindowWatcher::UserWindowObserver::OnWindowDestroying( | |
| 113 aura::Window* window) { | |
| 114 window_watcher_->OnUserWindowDestroying(window); | |
| 115 } | |
| 116 | |
| 117 void ShelfWindowWatcher::UserWindowObserver::OnWindowVisibilityChanged( | |
| 118 aura::Window* window, | |
| 119 bool visible) { | |
| 120 // OnWindowVisibilityChanged() is called for descendants too. We only care | |
| 121 // about changes to the visibility of windows we know about. | |
| 122 if (!window_watcher_->observed_user_windows_.IsObserving(window)) | |
| 123 return; | |
| 124 | |
| 125 // The tooltip behavior for panel windows depends on the panel visibility. | |
| 126 window_watcher_->OnUserWindowPropertyChanged(window); | |
| 127 } | |
| 128 | |
| 129 void ShelfWindowWatcher::UserWindowObserver::OnWindowTitleChanged( | |
| 130 aura::Window* window) { | |
| 131 window_watcher_->OnUserWindowPropertyChanged(window); | |
| 132 } | |
| 133 | |
| 134 //////////////////////////////////////////////////////////////////////////////// | |
| 135 | |
| 136 ShelfWindowWatcher::ShelfWindowWatcher(ShelfModel* model) | |
| 137 : model_(model), | |
| 138 container_window_observer_(this), | |
| 139 user_window_observer_(this), | |
| 140 observed_container_windows_(&container_window_observer_), | |
| 141 observed_user_windows_(&user_window_observer_) { | |
| 142 Shell::GetInstance()->activation_client()->AddObserver(this); | |
| 143 for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) | |
| 144 OnDisplayAdded(display); | |
| 145 display::Screen::GetScreen()->AddObserver(this); | |
| 146 } | |
| 147 | |
| 148 ShelfWindowWatcher::~ShelfWindowWatcher() { | |
| 149 display::Screen::GetScreen()->RemoveObserver(this); | |
| 150 Shell::GetInstance()->activation_client()->RemoveObserver(this); | |
| 151 } | |
| 152 | |
| 153 void ShelfWindowWatcher::AddShelfItem(aura::Window* window) { | |
| 154 user_windows_with_items_.insert(window); | |
| 155 ShelfItem item; | |
| 156 ShelfID id = model_->next_id(); | |
| 157 UpdateShelfItemForWindow(&item, window); | |
| 158 window->SetProperty(kShelfIDKey, id); | |
| 159 std::unique_ptr<ShelfItemDelegate> item_delegate( | |
| 160 new ShelfWindowWatcherItemDelegate(id, WmWindow::Get(window))); | |
| 161 model_->SetShelfItemDelegate(id, std::move(item_delegate)); | |
| 162 // Panels are inserted on the left so as not to push all existing panels over. | |
| 163 model_->AddAt(item.type == TYPE_APP_PANEL ? 0 : model_->item_count(), item); | |
| 164 } | |
| 165 | |
| 166 void ShelfWindowWatcher::RemoveShelfItem(aura::Window* window) { | |
| 167 user_windows_with_items_.erase(window); | |
| 168 int shelf_id = window->GetProperty(kShelfIDKey); | |
| 169 DCHECK_NE(shelf_id, kInvalidShelfID); | |
| 170 int index = model_->ItemIndexByID(shelf_id); | |
| 171 DCHECK_GE(index, 0); | |
| 172 model_->RemoveItemAt(index); | |
| 173 window->SetProperty(kShelfIDKey, kInvalidShelfID); | |
| 174 } | |
| 175 | |
| 176 void ShelfWindowWatcher::OnContainerWindowDestroying(aura::Window* container) { | |
| 177 observed_container_windows_.Remove(container); | |
| 178 } | |
| 179 | |
| 180 int ShelfWindowWatcher::GetShelfItemIndexForWindow(aura::Window* window) const { | |
| 181 return model_->ItemIndexByID(window->GetProperty(kShelfIDKey)); | |
| 182 } | |
| 183 | |
| 184 void ShelfWindowWatcher::OnUserWindowAdded(aura::Window* window) { | |
| 185 // The window may already be tracked from a prior display or parent container. | |
| 186 if (observed_user_windows_.IsObserving(window)) | |
| 187 return; | |
| 188 | |
| 189 observed_user_windows_.Add(window); | |
| 190 | |
| 191 // Add, update, or remove a ShelfItem for |window|, as needed. | |
| 192 OnUserWindowPropertyChanged(window); | |
| 193 } | |
| 194 | |
| 195 void ShelfWindowWatcher::OnUserWindowDestroying(aura::Window* window) { | |
| 196 if (observed_user_windows_.IsObserving(window)) | |
| 197 observed_user_windows_.Remove(window); | |
| 198 | |
| 199 if (user_windows_with_items_.count(window) > 0) | |
| 200 RemoveShelfItem(window); | |
| 201 DCHECK_EQ(0u, user_windows_with_items_.count(window)); | |
| 202 } | |
| 203 | |
| 204 void ShelfWindowWatcher::OnUserWindowPropertyChanged(aura::Window* window) { | |
| 205 if (GetShelfItemType(window) == TYPE_UNDEFINED) { | |
| 206 // Remove |window|'s ShelfItem if it was added by this ShelfWindowWatcher. | |
| 207 if (user_windows_with_items_.count(window) > 0) | |
| 208 RemoveShelfItem(window); | |
| 209 return; | |
| 210 } | |
| 211 | |
| 212 // Update an existing ShelfItem for |window| when a property has changed. | |
| 213 int index = GetShelfItemIndexForWindow(window); | |
| 214 if (index > 0) { | |
| 215 ShelfItem item = model_->items()[index]; | |
| 216 UpdateShelfItemForWindow(&item, window); | |
| 217 model_->Set(index, item); | |
| 218 return; | |
| 219 } | |
| 220 | |
| 221 // Creates a new ShelfItem for |window|. | |
| 222 AddShelfItem(window); | |
| 223 } | |
| 224 | |
| 225 void ShelfWindowWatcher::OnWindowActivated(ActivationReason reason, | |
| 226 aura::Window* gained_active, | |
| 227 aura::Window* lost_active) { | |
| 228 if (gained_active && user_windows_with_items_.count(gained_active) > 0) | |
| 229 OnUserWindowPropertyChanged(gained_active); | |
| 230 if (lost_active && user_windows_with_items_.count(lost_active) > 0) | |
| 231 OnUserWindowPropertyChanged(lost_active); | |
| 232 } | |
| 233 | |
| 234 void ShelfWindowWatcher::OnDisplayAdded(const display::Display& new_display) { | |
| 235 WmWindow* root = WmShell::Get()->GetRootWindowForDisplayId(new_display.id()); | |
| 236 aura::Window* aura_root = WmWindow::GetAuraWindow(root); | |
| 237 | |
| 238 // When the primary root window's display is removed, the existing root window | |
| 239 // is taken over by the new display, and the observer is already set. | |
| 240 aura::Window* default_container = | |
| 241 aura_root->GetChildById(kShellWindowId_DefaultContainer); | |
| 242 if (!observed_container_windows_.IsObserving(default_container)) { | |
| 243 for (aura::Window* window : default_container->children()) | |
| 244 OnUserWindowAdded(window); | |
| 245 observed_container_windows_.Add(default_container); | |
| 246 } | |
| 247 aura::Window* panel_container = | |
| 248 aura_root->GetChildById(kShellWindowId_PanelContainer); | |
| 249 if (!observed_container_windows_.IsObserving(panel_container)) { | |
| 250 for (aura::Window* window : panel_container->children()) | |
| 251 OnUserWindowAdded(window); | |
| 252 observed_container_windows_.Add(panel_container); | |
| 253 } | |
| 254 } | |
| 255 | |
| 256 void ShelfWindowWatcher::OnDisplayRemoved(const display::Display& old_display) { | |
| 257 } | |
| 258 | |
| 259 void ShelfWindowWatcher::OnDisplayMetricsChanged(const display::Display&, | |
| 260 uint32_t) {} | |
| 261 | |
| 262 } // namespace ash | |
| OLD | NEW |