Chromium Code Reviews| 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 |
| 33 // static | 32 // static |
| 34 NativePanelStackWindow* NativePanelStackWindow::Create( | 33 NativePanelStackWindow* NativePanelStackWindow::Create( |
| 35 NativePanelStackWindowDelegate* delegate) { | 34 NativePanelStackWindowDelegate* delegate) { |
| 36 #if defined(OS_WIN) | 35 #if defined(OS_WIN) |
| 37 return new PanelStackView(delegate); | 36 return new PanelStackView(delegate); |
| 38 #else | 37 #else |
| 39 NOTIMPLEMENTED(); | 38 NOTIMPLEMENTED(); |
| 40 return NULL; | 39 return NULL; |
| 41 #endif | 40 #endif |
| 42 } | 41 } |
| 43 | 42 |
| 44 PanelStackView::PanelStackView(NativePanelStackWindowDelegate* delegate) | 43 PanelStackView::PanelStackView(NativePanelStackWindowDelegate* delegate) |
| 45 : delegate_(delegate), | 44 : delegate_(delegate), |
| 46 window_(NULL), | 45 window_(NULL), |
| 47 is_closing_(false), | 46 is_closing_(false), |
| 48 is_drawing_attention_(false), | 47 is_drawing_attention_(false), |
| 48 is_minimizing_(false), | |
| 49 animate_bounds_updates_(false), | 49 animate_bounds_updates_(false), |
| 50 bounds_updates_started_(false) { | 50 bounds_updates_started_(false) { |
| 51 DCHECK(delegate); | 51 DCHECK(delegate); |
| 52 views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this); | 52 views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this); |
| 53 } | 53 } |
| 54 | 54 |
| 55 PanelStackView::~PanelStackView() { | 55 PanelStackView::~PanelStackView() { |
| 56 } | 56 } |
| 57 | 57 |
| 58 void PanelStackView::Close() { | 58 void PanelStackView::Close() { |
| 59 is_closing_ = true; | 59 is_closing_ = true; |
| 60 delegate_ = NULL; | 60 delegate_ = NULL; |
| 61 if (bounds_animator_) | 61 if (bounds_animator_) |
| 62 bounds_animator_.reset(); | 62 bounds_animator_.reset(); |
| 63 if (window_) | 63 if (window_) |
| 64 window_->Close(); | 64 window_->Close(); |
| 65 views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this); | 65 views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this); |
| 66 } | 66 } |
| 67 | 67 |
| 68 void PanelStackView::AddPanel(Panel* panel) { | 68 void PanelStackView::AddPanel(Panel* panel) { |
| 69 panels_.push_back(panel); | 69 panels_.push_back(panel); |
| 70 | 70 |
| 71 EnsureWindowCreated(); | 71 EnsureWindowCreated(); |
| 72 MakeStackWindowOwnPanelWindow(panel, this); | 72 MakeStackWindowOwnPanelWindow(panel, this); |
| 73 UpdateStackWindowBounds(); | 73 UpdateStackWindowBounds(); |
| 74 | 74 |
| 75 window_->UpdateWindowTitle(); | 75 window_->UpdateWindowTitle(); |
| 76 window_->UpdateWindowIcon(); | 76 window_->UpdateWindowIcon(); |
| 77 | |
| 78 #if defined(OS_WIN) | |
| 79 StartOrStopCustomThumbnailForMinimizePanel(); | |
| 80 #endif | |
| 77 } | 81 } |
| 78 | 82 |
| 79 void PanelStackView::RemovePanel(Panel* panel) { | 83 void PanelStackView::RemovePanel(Panel* panel) { |
| 80 panels_.remove(panel); | 84 panels_.remove(panel); |
| 81 | 85 |
| 82 MakeStackWindowOwnPanelWindow(panel, NULL); | 86 MakeStackWindowOwnPanelWindow(panel, NULL); |
| 83 UpdateStackWindowBounds(); | 87 UpdateStackWindowBounds(); |
| 88 | |
| 89 #if defined(OS_WIN) | |
| 90 StartOrStopCustomThumbnailForMinimizePanel(); | |
| 91 #endif | |
| 84 } | 92 } |
| 85 | 93 |
| 86 void PanelStackView::MergeWith(NativePanelStackWindow* another) { | 94 void PanelStackView::MergeWith(NativePanelStackWindow* another) { |
| 87 PanelStackView* another_stack = static_cast<PanelStackView*>(another); | 95 PanelStackView* another_stack = static_cast<PanelStackView*>(another); |
| 88 | 96 |
| 89 for (Panels::const_iterator iter = another_stack->panels_.begin(); | 97 for (Panels::const_iterator iter = another_stack->panels_.begin(); |
| 90 iter != another_stack->panels_.end(); ++iter) { | 98 iter != another_stack->panels_.end(); ++iter) { |
| 91 Panel* panel = *iter; | 99 Panel* panel = *iter; |
| 92 panels_.push_back(panel); | 100 panels_.push_back(panel); |
| 93 MakeStackWindowOwnPanelWindow(panel, this); | 101 MakeStackWindowOwnPanelWindow(panel, this); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 165 | 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 owner stack window is minimized by the system, its live preview |
| 173 // is lost. We need to set it explicitly. This has to be done before the | 181 // is lost. We need to set it explicitly. This has to be done before the |
| 174 // minimization. | 182 // minimization. |
| 175 CaptureThumbnailForLivePreview(); | 183 CaptureThumbnailForLivePreview(true); |
| 176 #endif | 184 #endif |
| 177 | 185 |
| 186 // On Windows, the system will activate the window before it is minimized. | |
| 187 // Set this flag such that the thumbnailer will not be stopped in | |
| 188 // OnWidgetActivationChanged. | |
| 189 is_minimizing_ = true; | |
| 178 window_->Minimize(); | 190 window_->Minimize(); |
| 191 is_minimizing_ = false; | |
| 179 } | 192 } |
| 180 | 193 |
| 181 bool PanelStackView::IsMinimized() const { | 194 bool PanelStackView::IsMinimized() const { |
| 182 return window_ ? window_->IsMinimized() : false; | 195 return window_ ? window_->IsMinimized() : false; |
| 183 } | 196 } |
| 184 | 197 |
| 185 void PanelStackView::DrawSystemAttention(bool draw_attention) { | 198 void PanelStackView::DrawSystemAttention(bool draw_attention) { |
| 186 // The underlying call of FlashFrame, FlashWindowEx, seems not to work | 199 // The underlying call of FlashFrame, FlashWindowEx, seems not to work |
| 187 // correctly if it is called more than once consecutively. | 200 // correctly if it is called more than once consecutively. |
| 188 if (draw_attention == is_drawing_attention_) | 201 if (draw_attention == is_drawing_attention_) |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 266 } | 279 } |
| 267 | 280 |
| 268 void PanelStackView::OnWidgetDestroying(views::Widget* widget) { | 281 void PanelStackView::OnWidgetDestroying(views::Widget* widget) { |
| 269 if (widget == window_) | 282 if (widget == window_) |
| 270 window_ = NULL; | 283 window_ = NULL; |
| 271 } | 284 } |
| 272 | 285 |
| 273 void PanelStackView::OnWidgetActivationChanged(views::Widget* widget, | 286 void PanelStackView::OnWidgetActivationChanged(views::Widget* widget, |
| 274 bool active) { | 287 bool active) { |
| 275 #if defined(OS_WIN) | 288 #if defined(OS_WIN) |
| 276 if (active && thumbnailer_) | 289 if (active && !is_minimizing_ && thumbnailer_) |
| 277 thumbnailer_->Stop(); | 290 thumbnailer_->Stop(); |
| 278 #endif | 291 #endif |
| 279 } | 292 } |
| 280 | 293 |
| 281 void PanelStackView::OnNativeFocusChange(gfx::NativeView focused_before, | 294 void PanelStackView::OnNativeFocusChange(gfx::NativeView focused_before, |
| 282 gfx::NativeView focused_now) { | 295 gfx::NativeView focused_now) { |
| 283 // When the user selects the stacked panels via ALT-TAB or WIN-TAB, the | 296 // 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 | 297 // 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 | 298 // WM_SETFOCUS message. To deal with this, we listen to the focus change event |
| 286 // and activate the most recently active panel. | 299 // and activate the most recently active panel. |
| 287 // Note that OnNativeFocusChange might be called when window_ has not be | 300 // Note that OnNativeFocusChange might be called when window_ has not be |
| 288 // created yet. | 301 // created yet. |
| 289 #if defined(OS_WIN) | 302 #if defined(OS_WIN) |
| 290 if (!panels_.empty() && window_ && focused_now == window_->GetNativeView()) { | 303 if (!panels_.empty() && window_ && focused_now == window_->GetNativeView()) { |
| 291 Panel* panel_to_focus = | 304 Panel* panel_to_focus = |
| 292 panels_.front()->stack()->most_recently_active_panel(); | 305 panels_.front()->stack()->most_recently_active_panel(); |
| 293 if (panel_to_focus) | 306 if (panel_to_focus) |
| 294 panel_to_focus->Activate(); | 307 panel_to_focus->Activate(); |
| 295 } | 308 } |
| 296 #endif | 309 #endif |
| 297 } | 310 } |
| 298 | 311 |
| 312 #if defined(OS_WIN) | |
| 313 std::vector<HWND> PanelStackView::GetSnapshotWindowHandles() const { | |
| 314 std::vector<HWND> native_panel_windows; | |
| 315 for (Panels::const_iterator iter = panels_.begin(); | |
| 316 iter != panels_.end(); ++iter) { | |
| 317 Panel* panel = *iter; | |
| 318 native_panel_windows.push_back( | |
| 319 views::HWNDForWidget( | |
| 320 static_cast<PanelView*>(panel->native_panel())->window())); | |
| 321 } | |
| 322 return native_panel_windows; | |
| 323 } | |
| 324 #endif | |
| 325 | |
| 299 void PanelStackView::AnimationEnded(const ui::Animation* animation) { | 326 void PanelStackView::AnimationEnded(const ui::Animation* animation) { |
| 300 bounds_updates_started_ = false; | 327 bounds_updates_started_ = false; |
| 301 | 328 |
| 302 PanelManager* panel_manager = PanelManager::GetInstance(); | 329 PanelManager* panel_manager = PanelManager::GetInstance(); |
| 303 for (BoundsUpdates::const_iterator iter = bounds_updates_.begin(); | 330 for (BoundsUpdates::const_iterator iter = bounds_updates_.begin(); |
| 304 iter != bounds_updates_.end(); ++iter) { | 331 iter != bounds_updates_.end(); ++iter) { |
| 305 panel_manager->OnPanelAnimationEnded(iter->first); | 332 panel_manager->OnPanelAnimationEnded(iter->first); |
| 306 } | 333 } |
| 307 bounds_updates_.clear(); | 334 bounds_updates_.clear(); |
| 308 | 335 |
| 309 delegate_->PanelBoundsBatchUpdateCompleted(); | 336 delegate_->PanelBoundsBatchUpdateCompleted(); |
| 337 | |
| 338 #if defined(OS_WIN) | |
| 339 StartOrStopCustomThumbnailForMinimizePanel(); | |
| 340 #endif | |
| 310 } | 341 } |
| 311 | 342 |
| 312 void PanelStackView::AnimationProgressed(const ui::Animation* animation) { | 343 void PanelStackView::AnimationProgressed(const ui::Animation* animation) { |
| 313 UpdatePanelsBounds(); | 344 UpdatePanelsBounds(); |
| 314 } | 345 } |
| 315 | 346 |
| 316 void PanelStackView::UpdatePanelsBounds() { | 347 void PanelStackView::UpdatePanelsBounds() { |
| 317 #if defined(OS_WIN) | 348 #if defined(OS_WIN) |
| 318 // Add an extra count for the background stack window. | 349 // Add an extra count for the background stack window. |
| 319 HDWP defer_update = ::BeginDeferWindowPos(bounds_updates_.size() + 1); | 350 HDWP defer_update = ::BeginDeferWindowPos(bounds_updates_.size() + 1); |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 448 void PanelStackView::EnsureWindowCreated() { | 479 void PanelStackView::EnsureWindowCreated() { |
| 449 if (window_) | 480 if (window_) |
| 450 return; | 481 return; |
| 451 | 482 |
| 452 // Empty size is not allowed so a temporary small size is passed. SetBounds | 483 // Empty size is not allowed so a temporary small size is passed. SetBounds |
| 453 // will be called later to update the bounds. | 484 // will be called later to update the bounds. |
| 454 window_ = CreateWindowWithBounds(gfx::Rect(0, 0, 1, 1)); | 485 window_ = CreateWindowWithBounds(gfx::Rect(0, 0, 1, 1)); |
| 455 } | 486 } |
| 456 | 487 |
| 457 #if defined(OS_WIN) | 488 #if defined(OS_WIN) |
| 458 void PanelStackView::CaptureThumbnailForLivePreview() { | 489 void PanelStackView::StartOrStopCustomThumbnailForMinimizePanel() { |
|
Dmitry Titov
2013/05/29 01:14:48
Is it possible to have a StartThumbnailer() and St
jianli
2013/05/29 18:31:52
All 3 places need the same code because otherwise
| |
| 490 bool has_minimized_panel = false; | |
| 491 for (Panels::const_iterator iter = panels_.begin(); | |
| 492 iter != panels_.end(); ++iter) { | |
| 493 if ((*iter)->IsMinimized()) { | |
| 494 has_minimized_panel = true; | |
| 495 break; | |
| 496 } | |
| 497 } | |
| 498 | |
| 499 // If custom thumbnail is still needed, stopping the thumbnailer and starting | |
| 500 // it again will make the system use the fresh snapshot. | |
| 501 if (thumbnailer_) | |
| 502 thumbnailer_->Stop(); | |
| 503 | |
| 504 // Start the thumbnailer to capture the snapshot only when the system requests | |
| 505 // it. When a panel has just been changed, its rendering might not be | |
| 506 // completed at this point. So we want to delay the snapshot until the system | |
| 507 // asks for it. | |
| 508 if (has_minimized_panel) | |
| 509 CaptureThumbnailForLivePreview(false); | |
| 510 } | |
| 511 | |
| 512 void PanelStackView::CaptureThumbnailForLivePreview(bool should_capture_now) { | |
| 459 // Live preview is only available since Windows 7. | 513 // Live preview is only available since Windows 7. |
| 460 if (base::win::GetVersion() < base::win::VERSION_WIN7) | 514 if (base::win::GetVersion() < base::win::VERSION_WIN7) |
| 461 return; | 515 return; |
| 462 | 516 |
| 463 HWND native_window = views::HWNDForWidget(window_); | 517 HWND native_window = views::HWNDForWidget(window_); |
| 464 | 518 |
| 465 if (!thumbnailer_.get()) { | 519 if (!thumbnailer_.get()) { |
| 466 DCHECK(native_window); | 520 DCHECK(native_window); |
| 467 thumbnailer_.reset(new TaskbarWindowThumbnailerWin(native_window)); | 521 thumbnailer_.reset(new TaskbarWindowThumbnailerWin(native_window, this)); |
| 468 ui::HWNDSubclass::AddFilterToTarget(native_window, thumbnailer_.get()); | 522 ui::HWNDSubclass::AddFilterToTarget(native_window, thumbnailer_.get()); |
| 469 } | 523 } |
| 470 | 524 |
| 471 std::vector<HWND> native_panel_windows; | 525 thumbnailer_->Start(should_capture_now); |
| 472 for (Panels::const_iterator iter = panels_.begin(); | |
| 473 iter != panels_.end(); ++iter) { | |
| 474 Panel* panel = *iter; | |
| 475 native_panel_windows.push_back( | |
| 476 views::HWNDForWidget( | |
| 477 static_cast<PanelView*>(panel->native_panel())->window())); | |
| 478 } | |
| 479 thumbnailer_->Start(native_panel_windows); | |
| 480 } | 526 } |
| 481 | 527 |
| 482 void PanelStackView::DeferUpdateNativeWindowBounds(HDWP defer_window_pos_info, | 528 void PanelStackView::DeferUpdateNativeWindowBounds(HDWP defer_window_pos_info, |
| 483 views::Widget* window, | 529 views::Widget* window, |
| 484 const gfx::Rect& bounds) { | 530 const gfx::Rect& bounds) { |
| 485 ::DeferWindowPos(defer_window_pos_info, | 531 ::DeferWindowPos(defer_window_pos_info, |
| 486 views::HWNDForWidget(window), | 532 views::HWNDForWidget(window), |
| 487 NULL, | 533 NULL, |
| 488 bounds.x(), | 534 bounds.x(), |
| 489 bounds.y(), | 535 bounds.y(), |
| 490 bounds.width(), | 536 bounds.width(), |
| 491 bounds.height(), | 537 bounds.height(), |
| 492 SWP_NOACTIVATE | SWP_NOZORDER); | 538 SWP_NOACTIVATE | SWP_NOZORDER); |
| 493 } | 539 } |
| 494 #endif | 540 #endif |
| OLD | NEW |