15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/wm/workspace/phantom_window_controller.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <math.h>
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell_window_ids.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/wm/coordinate_conversion.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "grit/ash_resources.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/layer.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/scoped_layer_animation_settings.h"
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/background.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/painter.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/view.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ash {
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The duration of the show animation.
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kAnimationDurationMs = 200;
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The size of the phantom window at the beginning of the show animation in
28010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// relation to the size of the phantom window at the end of the animation.
29010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)const float kStartBoundsRatio = 0.85f;
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The amount of pixels that the phantom window's shadow should extend past
32010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// the bounds passed into Show().
33010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)const int kShadowThickness = 15;
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
35010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// The minimum size of a phantom window including the shadow. The minimum size
36010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// is derived from the size of the IDR_AURA_PHANTOM_WINDOW image assets.
37010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)const int kMinSizeWithShadow = 100;
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Adjusts the phantom window's bounds so that the bounds:
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// - Include the size of the shadow.
41010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// - Have a size equal to or larger than the minimum phantom window size.
42010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)gfx::Rect GetAdjustedBounds(const gfx::Rect& bounds) {
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int x_inset = std::max(
44010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      static_cast<int>(ceil((kMinSizeWithShadow - bounds.width()) / 2.0f)),
45010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      kShadowThickness);
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int y_inset = std::max(
47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      static_cast<int>(ceil((kMinSizeWithShadow - bounds.height()) / 2.0f)),
48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      kShadowThickness);
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gfx::Rect adjusted_bounds(bounds);
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  adjusted_bounds.Inset(-x_inset, -y_inset);
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return adjusted_bounds;
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Starts an animation of |widget| to |new_bounds_in_screen|. No-op if |widget|
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// is NULL.
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AnimateToBounds(views::Widget* widget,
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     const gfx::Rect& new_bounds_in_screen) {
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!widget)
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ui::ScopedLayerAnimationSettings scoped_setter(
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      widget->GetNativeWindow()->layer()->GetAnimator());
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_setter.SetTweenType(gfx::Tween::EASE_IN);
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_setter.SetPreemptionStrategy(
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_setter.SetTransitionDuration(
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(kAnimationDurationMs));
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  widget->SetBounds(new_bounds_in_screen);
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// PhantomWindowController ----------------------------------------------------
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PhantomWindowController::PhantomWindowController(aura::Window* window)
77010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    : window_(window) {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PhantomWindowController::~PhantomWindowController() {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void PhantomWindowController::Show(const gfx::Rect& bounds_in_screen) {
84010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  gfx::Rect adjusted_bounds_in_screen = GetAdjustedBounds(bounds_in_screen);
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (adjusted_bounds_in_screen == target_bounds_in_screen_)
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  target_bounds_in_screen_ = adjusted_bounds_in_screen;
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gfx::Rect start_bounds_in_screen = target_bounds_in_screen_;
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int start_width = std::max(
91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      kMinSizeWithShadow,
92010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      static_cast<int>(start_bounds_in_screen.width() * kStartBoundsRatio));
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int start_height = std::max(
94010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      kMinSizeWithShadow,
95010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      static_cast<int>(start_bounds_in_screen.height() * kStartBoundsRatio));
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  start_bounds_in_screen.Inset(
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      floor((start_bounds_in_screen.width() - start_width) / 2.0f),
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      floor((start_bounds_in_screen.height() - start_height) / 2.0f));
99010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  phantom_widget_ = CreatePhantomWidget(
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      wm::GetRootWindowMatching(target_bounds_in_screen_),
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      start_bounds_in_screen);
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  AnimateToBounds(phantom_widget_.get(), target_bounds_in_screen_);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<views::Widget> PhantomWindowController::CreatePhantomWidget(
1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    aura::Window* root_window,
1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const gfx::Rect& bounds_in_screen) {
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<views::Widget> phantom_widget(new views::Widget);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // PhantomWindowController is used by FrameMaximizeButton to highlight the
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // launcher button. Put the phantom in the same window as the launcher so that
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the phantom is visible.
1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  params.parent = Shell::GetContainer(root_window,
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      kShellWindowId_ShelfContainer);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.keep_on_top = true;
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  phantom_widget->set_focus_on_creation(false);
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  phantom_widget->Init(params);
1213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  phantom_widget->SetVisibilityChangedAnimationsEnabled(false);
1223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  phantom_widget->GetNativeWindow()->SetName("PhantomWindow");
1233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  phantom_widget->GetNativeWindow()->set_id(kShellWindowId_PhantomWindow);
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  phantom_widget->SetBounds(bounds_in_screen);
125010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  phantom_widget->StackAbove(window_);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
127010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const int kImages[] = IMAGE_GRID(IDR_AURA_PHANTOM_WINDOW);
128010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  views::Painter* background_painter =
129010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      views::Painter::CreateImageGridPainter(kImages);
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  views::View* content_view = new views::View;
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  content_view->set_background(
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      views::Background::CreateBackgroundPainter(true, background_painter));
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  phantom_widget->SetContentsView(content_view);
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Show the widget after all the setups.
1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  phantom_widget->Show();
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fade the window in.
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ui::Layer* widget_layer = phantom_widget->GetNativeWindow()->layer();
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  widget_layer->SetOpacity(0);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::ScopedLayerAnimationSettings scoped_setter(widget_layer->GetAnimator());
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_setter.SetTransitionDuration(
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(kAnimationDurationMs));
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  widget_layer->SetOpacity(1);
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return phantom_widget.Pass();
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace ash
150