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 |