| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/views/panels/panel_stack_view.h" | 5 #include "chrome/browser/ui/views/panels/panel_stack_view.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/utf_string_conversions.h" | 8 #include "base/utf_string_conversions.h" |
| 9 #include "chrome/browser/profiles/profile.h" | 9 #include "chrome/browser/profiles/profile.h" |
| 10 #include "chrome/browser/ui/panels/panel.h" | 10 #include "chrome/browser/ui/panels/panel.h" |
| 11 #include "chrome/browser/ui/panels/panel_manager.h" | 11 #include "chrome/browser/ui/panels/panel_manager.h" |
| 12 #include "chrome/browser/ui/panels/stacked_panel_collection.h" | 12 #include "chrome/browser/ui/panels/stacked_panel_collection.h" |
| 13 #include "chrome/browser/ui/views/panels/panel_view.h" | 13 #include "chrome/browser/ui/views/panels/panel_view.h" |
| 14 #include "ui/base/animation/linear_animation.h" | 14 #include "ui/base/animation/linear_animation.h" |
| 15 #include "ui/gfx/image/image_skia.h" | 15 #include "ui/gfx/image/image_skia.h" |
| 16 #include "ui/gfx/rect.h" | 16 #include "ui/gfx/rect.h" |
| 17 #include "ui/views/widget/widget.h" | 17 #include "ui/views/widget/widget.h" |
| 18 | 18 |
| 19 #if defined(OS_WIN) | 19 #if defined(OS_WIN) |
| 20 #include "base/win/windows_version.h" | 20 #include "base/win/windows_version.h" |
| 21 #include "chrome/browser/shell_integration.h" | 21 #include "chrome/browser/shell_integration.h" |
| 22 #include "chrome/browser/ui/views/panels/taskbar_window_thumbnailer_win.h" | |
| 23 #include "ui/base/win/shell.h" | 22 #include "ui/base/win/shell.h" |
| 24 #include "ui/views/win/hwnd_util.h" | 23 #include "ui/views/win/hwnd_util.h" |
| 25 #endif | 24 #endif |
| 26 | 25 |
| 27 namespace { | 26 namespace { |
| 28 // These values are experimental and subjective. | 27 // These values are experimental and subjective. |
| 29 const int kDefaultFramerateHz = 50; | 28 const int kDefaultFramerateHz = 50; |
| 30 const int kSetBoundsAnimationMs = 180; | 29 const int kSetBoundsAnimationMs = 180; |
| 31 } | 30 } |
| 32 | 31 |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 void PanelStackView::EndBatchUpdatePanelBounds() { | 144 void PanelStackView::EndBatchUpdatePanelBounds() { |
| 146 DCHECK(bounds_updates_started_); | 145 DCHECK(bounds_updates_started_); |
| 147 | 146 |
| 148 if (bounds_updates_.empty() || !animate_bounds_updates_) { | 147 if (bounds_updates_.empty() || !animate_bounds_updates_) { |
| 149 if (!bounds_updates_.empty()) { | 148 if (!bounds_updates_.empty()) { |
| 150 UpdatePanelsBounds(); | 149 UpdatePanelsBounds(); |
| 151 bounds_updates_.clear(); | 150 bounds_updates_.clear(); |
| 152 } | 151 } |
| 153 | 152 |
| 154 bounds_updates_started_ = false; | 153 bounds_updates_started_ = false; |
| 155 delegate_->PanelBoundsBatchUpdateCompleted(); | 154 NotifyBoundsUpdateCompleted(); |
| 156 return; | 155 return; |
| 157 } | 156 } |
| 158 | 157 |
| 159 bounds_animator_.reset(new ui::LinearAnimation( | 158 bounds_animator_.reset(new ui::LinearAnimation( |
| 160 PanelManager::AdjustTimeInterval(kSetBoundsAnimationMs), | 159 PanelManager::AdjustTimeInterval(kSetBoundsAnimationMs), |
| 161 kDefaultFramerateHz, | 160 kDefaultFramerateHz, |
| 162 this)); | 161 this)); |
| 163 bounds_animator_->Start(); | 162 bounds_animator_->Start(); |
| 164 } | 163 } |
| 165 | 164 |
| 165 void PanelStackView::NotifyBoundsUpdateCompleted() { |
| 166 delegate_->PanelBoundsBatchUpdateCompleted(); |
| 167 |
| 168 #if defined(OS_WIN) |
| 169 // Refresh the thumbnail each time when any bounds updates are done. |
| 170 RefreshLivePreviewThumbnail(); |
| 171 #endif |
| 172 } |
| 173 |
| 166 bool PanelStackView::IsAnimatingPanelBounds() const { | 174 bool PanelStackView::IsAnimatingPanelBounds() const { |
| 167 return bounds_updates_started_ && animate_bounds_updates_; | 175 return bounds_updates_started_ && animate_bounds_updates_; |
| 168 } | 176 } |
| 169 | 177 |
| 170 void PanelStackView::Minimize() { | 178 void PanelStackView::Minimize() { |
| 171 #if defined(OS_WIN) | 179 #if defined(OS_WIN) |
| 172 // When the owner stack window is minimized by the system, its live preview | 180 // When the stack window is minimized by the system, its snapshot could not |
| 173 // is lost. We need to set it explicitly. This has to be done before the | 181 // be obtained. We need to capture the snapshot before the minimization. |
| 174 // minimization. | 182 if (thumbnailer_) |
| 175 CaptureThumbnailForLivePreview(); | 183 thumbnailer_->CaptureSnapshot(); |
| 176 #endif | 184 #endif |
| 177 | 185 |
| 178 window_->Minimize(); | 186 window_->Minimize(); |
| 179 } | 187 } |
| 180 | 188 |
| 181 bool PanelStackView::IsMinimized() const { | 189 bool PanelStackView::IsMinimized() const { |
| 182 return window_ ? window_->IsMinimized() : false; | 190 return window_ ? window_->IsMinimized() : false; |
| 183 } | 191 } |
| 184 | 192 |
| 185 void PanelStackView::DrawSystemAttention(bool draw_attention) { | 193 void PanelStackView::DrawSystemAttention(bool draw_attention) { |
| 186 // The underlying call of FlashFrame, FlashWindowEx, seems not to work | 194 // The underlying call of FlashFrame, FlashWindowEx, seems not to work |
| 187 // correctly if it is called more than once consecutively. | 195 // correctly if it is called more than once consecutively. |
| 188 if (draw_attention == is_drawing_attention_) | 196 if (draw_attention == is_drawing_attention_) |
| 189 return; | 197 return; |
| 190 is_drawing_attention_ = draw_attention; | 198 is_drawing_attention_ = draw_attention; |
| 191 | 199 |
| 192 #if defined(OS_WIN) | 200 #if defined(OS_WIN) |
| 201 // Refresh the thumbnail when a panel could change something for the |
| 202 // attention. |
| 203 RefreshLivePreviewThumbnail(); |
| 204 |
| 193 if (draw_attention) { | 205 if (draw_attention) { |
| 194 // The default implementation of Widget::FlashFrame only flashes 5 times. | 206 // The default implementation of Widget::FlashFrame only flashes 5 times. |
| 195 // We need more than that. | 207 // We need more than that. |
| 196 FLASHWINFO fwi; | 208 FLASHWINFO fwi; |
| 197 fwi.cbSize = sizeof(fwi); | 209 fwi.cbSize = sizeof(fwi); |
| 198 fwi.hwnd = views::HWNDForWidget(window_); | 210 fwi.hwnd = views::HWNDForWidget(window_); |
| 199 fwi.dwFlags = FLASHW_ALL; | 211 fwi.dwFlags = FLASHW_ALL; |
| 200 fwi.uCount = panel::kNumberOfTimesToFlashPanelForAttention; | 212 fwi.uCount = panel::kNumberOfTimesToFlashPanelForAttention; |
| 201 fwi.dwTimeout = 0; | 213 fwi.dwTimeout = 0; |
| 202 ::FlashWindowEx(&fwi); | 214 ::FlashWindowEx(&fwi); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 // window is really being closed. | 275 // window is really being closed. |
| 264 if (is_closing_) | 276 if (is_closing_) |
| 265 delete this; | 277 delete this; |
| 266 } | 278 } |
| 267 | 279 |
| 268 void PanelStackView::OnWidgetDestroying(views::Widget* widget) { | 280 void PanelStackView::OnWidgetDestroying(views::Widget* widget) { |
| 269 if (widget == window_) | 281 if (widget == window_) |
| 270 window_ = NULL; | 282 window_ = NULL; |
| 271 } | 283 } |
| 272 | 284 |
| 273 void PanelStackView::OnWidgetActivationChanged(views::Widget* widget, | |
| 274 bool active) { | |
| 275 #if defined(OS_WIN) | |
| 276 if (active && thumbnailer_) | |
| 277 thumbnailer_->Stop(); | |
| 278 #endif | |
| 279 } | |
| 280 | |
| 281 void PanelStackView::OnNativeFocusChange(gfx::NativeView focused_before, | 285 void PanelStackView::OnNativeFocusChange(gfx::NativeView focused_before, |
| 282 gfx::NativeView focused_now) { | 286 gfx::NativeView focused_now) { |
| 283 // When the user selects the stacked panels via ALT-TAB or WIN-TAB, the | 287 // When the user selects the stacked panels via ALT-TAB or WIN-TAB, the |
| 284 // background stack window, instead of the foreground panel window, receives | 288 // background stack window, instead of the foreground panel window, receives |
| 285 // WM_SETFOCUS message. To deal with this, we listen to the focus change event | 289 // WM_SETFOCUS message. To deal with this, we listen to the focus change event |
| 286 // and activate the most recently active panel. | 290 // and activate the most recently active panel. |
| 287 // Note that OnNativeFocusChange might be called when window_ has not be | 291 // Note that OnNativeFocusChange might be called when window_ has not be |
| 288 // created yet. | 292 // created yet. |
| 289 #if defined(OS_WIN) | 293 #if defined(OS_WIN) |
| 290 if (!panels_.empty() && window_ && focused_now == window_->GetNativeView()) { | 294 if (!panels_.empty() && window_ && focused_now == window_->GetNativeView()) { |
| 291 Panel* panel_to_focus = | 295 Panel* panel_to_focus = |
| 292 panels_.front()->stack()->most_recently_active_panel(); | 296 panels_.front()->stack()->most_recently_active_panel(); |
| 293 if (panel_to_focus) | 297 if (panel_to_focus) |
| 294 panel_to_focus->Activate(); | 298 panel_to_focus->Activate(); |
| 295 } | 299 } |
| 296 #endif | 300 #endif |
| 297 } | 301 } |
| 298 | 302 |
| 299 void PanelStackView::AnimationEnded(const ui::Animation* animation) { | 303 void PanelStackView::AnimationEnded(const ui::Animation* animation) { |
| 300 bounds_updates_started_ = false; | 304 bounds_updates_started_ = false; |
| 301 | 305 |
| 302 PanelManager* panel_manager = PanelManager::GetInstance(); | 306 PanelManager* panel_manager = PanelManager::GetInstance(); |
| 303 for (BoundsUpdates::const_iterator iter = bounds_updates_.begin(); | 307 for (BoundsUpdates::const_iterator iter = bounds_updates_.begin(); |
| 304 iter != bounds_updates_.end(); ++iter) { | 308 iter != bounds_updates_.end(); ++iter) { |
| 305 panel_manager->OnPanelAnimationEnded(iter->first); | 309 panel_manager->OnPanelAnimationEnded(iter->first); |
| 306 } | 310 } |
| 307 bounds_updates_.clear(); | 311 bounds_updates_.clear(); |
| 308 | 312 |
| 309 delegate_->PanelBoundsBatchUpdateCompleted(); | 313 NotifyBoundsUpdateCompleted(); |
| 310 } | 314 } |
| 311 | 315 |
| 312 void PanelStackView::AnimationProgressed(const ui::Animation* animation) { | 316 void PanelStackView::AnimationProgressed(const ui::Animation* animation) { |
| 313 UpdatePanelsBounds(); | 317 UpdatePanelsBounds(); |
| 314 } | 318 } |
| 315 | 319 |
| 316 void PanelStackView::UpdatePanelsBounds() { | 320 void PanelStackView::UpdatePanelsBounds() { |
| 317 #if defined(OS_WIN) | 321 #if defined(OS_WIN) |
| 318 // Add an extra count for the background stack window. | 322 // Add an extra count for the background stack window. |
| 319 HDWP defer_update = ::BeginDeferWindowPos(bounds_updates_.size() + 1); | 323 HDWP defer_update = ::BeginDeferWindowPos(bounds_updates_.size() + 1); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 371 for (Panels::const_iterator iter = panels_.begin(); | 375 for (Panels::const_iterator iter = panels_.begin(); |
| 372 iter != panels_.end(); ++iter) { | 376 iter != panels_.end(); ++iter) { |
| 373 Panel* panel = *iter; | 377 Panel* panel = *iter; |
| 374 enclosing_bounds = UnionRects(enclosing_bounds, panel->GetBounds()); | 378 enclosing_bounds = UnionRects(enclosing_bounds, panel->GetBounds()); |
| 375 } | 379 } |
| 376 return enclosing_bounds; | 380 return enclosing_bounds; |
| 377 } | 381 } |
| 378 | 382 |
| 379 void PanelStackView::UpdateStackWindowBounds() { | 383 void PanelStackView::UpdateStackWindowBounds() { |
| 380 window_->SetBounds(GetStackWindowBounds()); | 384 window_->SetBounds(GetStackWindowBounds()); |
| 385 |
| 386 #if defined(OS_WIN) |
| 387 // Refresh the thumbnail each time whne the stack window is changed, due to |
| 388 // adding or removing a panel. |
| 389 RefreshLivePreviewThumbnail(); |
| 390 #endif |
| 381 } | 391 } |
| 382 | 392 |
| 383 // static | 393 // static |
| 384 void PanelStackView::MakeStackWindowOwnPanelWindow( | 394 void PanelStackView::MakeStackWindowOwnPanelWindow( |
| 385 Panel* panel, PanelStackView* stack_window) { | 395 Panel* panel, PanelStackView* stack_window) { |
| 386 #if defined(OS_WIN) | 396 #if defined(OS_WIN) |
| 387 // The panel widget window might already be gone when a panel is closed. | 397 // The panel widget window might already be gone when a panel is closed. |
| 388 views::Widget* panel_window = | 398 views::Widget* panel_window = |
| 389 static_cast<PanelView*>(panel->native_panel())->window(); | 399 static_cast<PanelView*>(panel->native_panel())->window(); |
| 390 if (!panel_window) | 400 if (!panel_window) |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 433 window->AddObserver(this); | 443 window->AddObserver(this); |
| 434 window->ShowInactive(); | 444 window->ShowInactive(); |
| 435 | 445 |
| 436 #if defined(OS_WIN) | 446 #if defined(OS_WIN) |
| 437 DCHECK(!panels_.empty()); | 447 DCHECK(!panels_.empty()); |
| 438 Panel* panel = panels_.front(); | 448 Panel* panel = panels_.front(); |
| 439 ui::win::SetAppIdForWindow( | 449 ui::win::SetAppIdForWindow( |
| 440 ShellIntegration::GetAppModelIdForProfile(UTF8ToWide(panel->app_name()), | 450 ShellIntegration::GetAppModelIdForProfile(UTF8ToWide(panel->app_name()), |
| 441 panel->profile()->GetPath()), | 451 panel->profile()->GetPath()), |
| 442 views::HWNDForWidget(window)); | 452 views::HWNDForWidget(window)); |
| 453 |
| 454 if (base::win::GetVersion() >= base::win::VERSION_WIN7) { |
| 455 HWND native_window = views::HWNDForWidget(window); |
| 456 thumbnailer_.reset(new TaskbarWindowThumbnailerWin(native_window, this)); |
| 457 thumbnailer_->Start(); |
| 458 } |
| 443 #endif | 459 #endif |
| 444 | 460 |
| 445 return window; | 461 return window; |
| 446 } | 462 } |
| 447 | 463 |
| 448 void PanelStackView::EnsureWindowCreated() { | 464 void PanelStackView::EnsureWindowCreated() { |
| 449 if (window_) | 465 if (window_) |
| 450 return; | 466 return; |
| 451 | 467 |
| 452 // Empty size is not allowed so a temporary small size is passed. SetBounds | 468 // Empty size is not allowed so a temporary small size is passed. SetBounds |
| 453 // will be called later to update the bounds. | 469 // will be called later to update the bounds. |
| 454 window_ = CreateWindowWithBounds(gfx::Rect(0, 0, 1, 1)); | 470 window_ = CreateWindowWithBounds(gfx::Rect(0, 0, 1, 1)); |
| 455 } | 471 } |
| 456 | 472 |
| 457 #if defined(OS_WIN) | 473 #if defined(OS_WIN) |
| 458 void PanelStackView::CaptureThumbnailForLivePreview() { | 474 std::vector<HWND> PanelStackView::GetSnapshotWindowHandles() const { |
| 459 // Live preview is only available since Windows 7. | |
| 460 if (base::win::GetVersion() < base::win::VERSION_WIN7) | |
| 461 return; | |
| 462 | |
| 463 HWND native_window = views::HWNDForWidget(window_); | |
| 464 | |
| 465 if (!thumbnailer_.get()) { | |
| 466 DCHECK(native_window); | |
| 467 thumbnailer_.reset(new TaskbarWindowThumbnailerWin(native_window)); | |
| 468 ui::HWNDSubclass::AddFilterToTarget(native_window, thumbnailer_.get()); | |
| 469 } | |
| 470 | |
| 471 std::vector<HWND> native_panel_windows; | 475 std::vector<HWND> native_panel_windows; |
| 472 for (Panels::const_iterator iter = panels_.begin(); | 476 for (Panels::const_iterator iter = panels_.begin(); |
| 473 iter != panels_.end(); ++iter) { | 477 iter != panels_.end(); ++iter) { |
| 474 Panel* panel = *iter; | 478 Panel* panel = *iter; |
| 475 native_panel_windows.push_back( | 479 native_panel_windows.push_back( |
| 476 views::HWNDForWidget( | 480 views::HWNDForWidget( |
| 477 static_cast<PanelView*>(panel->native_panel())->window())); | 481 static_cast<PanelView*>(panel->native_panel())->window())); |
| 478 } | 482 } |
| 479 thumbnailer_->Start(native_panel_windows); | 483 return native_panel_windows; |
| 484 } |
| 485 |
| 486 void PanelStackView::RefreshLivePreviewThumbnail() { |
| 487 if (!thumbnailer_.get()) |
| 488 return; |
| 489 thumbnailer_->InvalidateSnapshot(); |
| 480 } | 490 } |
| 481 | 491 |
| 482 void PanelStackView::DeferUpdateNativeWindowBounds(HDWP defer_window_pos_info, | 492 void PanelStackView::DeferUpdateNativeWindowBounds(HDWP defer_window_pos_info, |
| 483 views::Widget* window, | 493 views::Widget* window, |
| 484 const gfx::Rect& bounds) { | 494 const gfx::Rect& bounds) { |
| 485 ::DeferWindowPos(defer_window_pos_info, | 495 ::DeferWindowPos(defer_window_pos_info, |
| 486 views::HWNDForWidget(window), | 496 views::HWNDForWidget(window), |
| 487 NULL, | 497 NULL, |
| 488 bounds.x(), | 498 bounds.x(), |
| 489 bounds.y(), | 499 bounds.y(), |
| 490 bounds.width(), | 500 bounds.width(), |
| 491 bounds.height(), | 501 bounds.height(), |
| 492 SWP_NOACTIVATE | SWP_NOZORDER); | 502 SWP_NOACTIVATE | SWP_NOZORDER); |
| 493 } | 503 } |
| 494 #endif | 504 #endif |
| OLD | NEW |