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 |