1ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved.
27d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
37d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// found in the LICENSE file.
47d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
57d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ash/wm/dock/docked_window_layout_manager.h"
67d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/screen_util.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/shelf/shelf.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/shelf/shelf_constants.h"
107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ash/shelf/shelf_layout_manager.h"
117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ash/shelf/shelf_types.h"
127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ash/shelf/shelf_widget.h"
137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ash/shell.h"
147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ash/shell_window_ids.h"
157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ash/wm/coordinate_conversion.h"
16d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ash/wm/window_animations.h"
17ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "ash/wm/window_properties.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/wm/window_resizer.h"
1968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "ash/wm/window_state.h"
207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ash/wm/window_util.h"
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ash/wm/workspace_controller.h"
227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/auto_reset.h"
23d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/command_line.h"
24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/metrics/histogram.h"
25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "grit/ash_resources.h"
26bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "third_party/skia/include/core/SkColor.h"
27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "third_party/skia/include/core/SkPaint.h"
288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "ui/aura/client/focus_client.h"
291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ui/aura/client/window_tree_client.h"
307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ui/aura/window.h"
3168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "ui/aura/window_delegate.h"
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/window_event_dispatcher.h"
33a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
3468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "ui/compositor/scoped_layer_animation_settings.h"
35a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/gfx/canvas.h"
36a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/gfx/image/image_skia_operations.h"
377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ui/gfx/rect.h"
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/background.h"
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/wm/core/window_util.h"
40effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "ui/wm/public/activation_client.h"
417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)namespace ash {
437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
44ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Minimum, maximum width of the dock area and a width of the gap
45d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// static
46d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const int DockedWindowLayoutManager::kMaxDockWidth = 360;
47d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// static
48ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochconst int DockedWindowLayoutManager::kMinDockWidth = 200;
49d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// static
50ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochconst int DockedWindowLayoutManager::kMinDockGap = 2;
518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// static
5268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int DockedWindowLayoutManager::kIdealWidth = 250;
538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)const int kMinimumHeight = 250;
5468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kSlideDurationMs = 120;
55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int kFadeDurationMs = 60;
56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int kMinimizeDurationMs = 720;
57ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class DockedBackgroundWidget : public views::Widget,
59c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                               public BackgroundAnimatorDelegate {
60bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch public:
61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  explicit DockedBackgroundWidget(aura::Window* container)
62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      : alignment_(DOCKED_ALIGNMENT_NONE),
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        background_animator_(this, 0, kShelfBackgroundAlpha),
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        alpha_(0),
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        opaque_background_(ui::LAYER_SOLID_COLOR),
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        visible_background_type_(SHELF_BACKGROUND_DEFAULT),
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        visible_background_change_type_(BACKGROUND_CHANGE_IMMEDIATE) {
68bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    InitWidget(container);
69bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  }
70bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Sets widget bounds and sizes opaque background layer to fill the widget.
72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void SetBackgroundBounds(const gfx::Rect bounds, DockedAlignment alignment) {
73a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    SetBounds(bounds);
74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    opaque_background_.SetBounds(gfx::Rect(bounds.size()));
75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    alignment_ = alignment;
76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Sets the background type. Starts an animation to transition to
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // |background_type| if the widget is visible. If the widget is not visible,
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the animation is postponed till the widget becomes visible.
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void SetBackgroundType(ShelfBackgroundType background_type,
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         BackgroundAnimatorChangeType change_type) {
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    visible_background_type_ = background_type;
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    visible_background_change_type_ = change_type;
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (IsVisible())
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      UpdateBackground();
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // views::Widget:
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void OnNativeWidgetVisibilityChanged(bool visible) OVERRIDE {
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    views::Widget::OnNativeWidgetVisibilityChanged(visible);
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UpdateBackground();
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual void OnNativeWidgetPaint(gfx::Canvas* canvas) OVERRIDE {
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const gfx::ImageSkia& shelf_background(
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        alignment_ == DOCKED_ALIGNMENT_LEFT ?
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            shelf_background_left_ : shelf_background_right_);
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    gfx::Rect rect = gfx::Rect(GetWindowBoundsInScreen().size());
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    SkPaint paint;
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    paint.setAlpha(alpha_);
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    canvas->DrawImageInt(shelf_background,
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         0,
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         0,
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         shelf_background.width(),
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         shelf_background.height(),
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         alignment_ == DOCKED_ALIGNMENT_LEFT
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             ? rect.width() - shelf_background.width()
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             : 0,
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         0,
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         shelf_background.width(),
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         rect.height(),
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         false,
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         paint);
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    canvas->DrawImageInt(
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        shelf_background,
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        alignment_ == DOCKED_ALIGNMENT_LEFT ? 0 : shelf_background.width() - 1,
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        0,
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        1,
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        shelf_background.height(),
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        alignment_ == DOCKED_ALIGNMENT_LEFT ? 0 : shelf_background.width(),
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        0,
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        rect.width() - shelf_background.width(),
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        rect.height(),
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        false,
126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        paint);
127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // BackgroundAnimatorDelegate:
130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual void UpdateBackground(int alpha) OVERRIDE {
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    alpha_ = alpha;
132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    SchedulePaintInRect(gfx::Rect(GetWindowBoundsInScreen().size()));
133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
135bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch private:
136bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  void InitWidget(aura::Window* parent) {
137bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    views::Widget::InitParams params;
138bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    params.type = views::Widget::InitParams::TYPE_POPUP;
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
140bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    params.keep_on_top = false;
141bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
142bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    params.parent = parent;
143bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    params.accept_events = false;
144bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    set_focus_on_creation(false);
145bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    Init(params);
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetVisibilityChangedAnimationsEnabled(false);
147c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    GetNativeWindow()->SetProperty(kStayInSameRootWindowKey, true);
148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    opaque_background_.SetColor(SK_ColorBLACK);
149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    opaque_background_.SetBounds(gfx::Rect(GetWindowBoundsInScreen().size()));
150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    opaque_background_.SetOpacity(0.0f);
151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    GetNativeWindow()->layer()->Add(&opaque_background_);
152bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    Hide();
153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
154c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gfx::ImageSkia shelf_background =
156c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        *rb.GetImageSkiaNamed(IDR_ASH_SHELF_BACKGROUND);
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    shelf_background_left_ = gfx::ImageSkiaOperations::CreateRotatedImage(
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        shelf_background, SkBitmapOperations::ROTATION_90_CW);
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    shelf_background_right_ = gfx::ImageSkiaOperations::CreateRotatedImage(
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        shelf_background, SkBitmapOperations::ROTATION_270_CW);
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Transitions to |visible_background_type_| if the widget is visible and to
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // SHELF_BACKGROUND_DEFAULT if it is not.
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void UpdateBackground() {
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ShelfBackgroundType background_type = IsVisible() ?
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        visible_background_type_ : SHELF_BACKGROUND_DEFAULT;
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    BackgroundAnimatorChangeType change_type = IsVisible() ?
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        visible_background_change_type_ : BACKGROUND_CHANGE_IMMEDIATE;
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    float target_opacity =
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        (background_type == SHELF_BACKGROUND_MAXIMIZED) ? 1.0f : 0.0f;
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<ui::ScopedLayerAnimationSettings> opaque_background_animation;
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (change_type != BACKGROUND_CHANGE_IMMEDIATE) {
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      opaque_background_animation.reset(new ui::ScopedLayerAnimationSettings(
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          opaque_background_.GetAnimator()));
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      opaque_background_animation->SetTransitionDuration(
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::TimeDelta::FromMilliseconds(kTimeToSwitchBackgroundMs));
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    opaque_background_.SetOpacity(target_opacity);
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // TODO(varkha): use ui::Layer on both opaque_background and normal
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // background retire background_animator_ at all. It would be simpler.
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // See also ShelfWidget::SetPaintsBackground.
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    background_animator_.SetPaintsBackground(
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        background_type != SHELF_BACKGROUND_DEFAULT,
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        change_type);
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SchedulePaintInRect(gfx::Rect(GetWindowBoundsInScreen().size()));
189bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  }
190bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
191a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DockedAlignment alignment_;
192a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // The animator for the background transitions.
194c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  BackgroundAnimator background_animator_;
195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
196a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // The alpha to use for drawing image assets covering the docked background.
197a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  int alpha_;
198a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
199a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Solid black background that can be made fully opaque.
200a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ui::Layer opaque_background_;
201a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
202a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Backgrounds created from shelf background by 90 or 270 degree rotation.
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gfx::ImageSkia shelf_background_left_;
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gfx::ImageSkia shelf_background_right_;
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The background type to use when the widget is visible. When not visible,
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the widget uses SHELF_BACKGROUND_DEFAULT.
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ShelfBackgroundType visible_background_type_;
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Whether the widget should animate to |visible_background_type_|.
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BackgroundAnimatorChangeType visible_background_change_type_;
212a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
213bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  DISALLOW_COPY_AND_ASSIGN(DockedBackgroundWidget);
214bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch};
215bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
216a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace {
217a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
2184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Returns true if a window is a popup or a transient child.
219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool IsPopupOrTransient(const aura::Window* window) {
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return (window->type() == ui::wm::WINDOW_TYPE_POPUP ||
221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          ::wm::GetTransientParent(window));
2224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
224ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Certain windows (minimized, hidden or popups) do not matter to docking.
225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool IsUsedByLayout(const aura::Window* window) {
226ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return (window->IsVisible() &&
22768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          !wm::GetWindowState(window)->IsMinimized() &&
2284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          !IsPopupOrTransient(window));
229ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
230ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void UndockWindow(aura::Window* window) {
2328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  gfx::Rect previous_bounds = window->bounds();
233a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  aura::Window* old_parent = window->parent();
2341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  aura::client::ParentWindowWithContext(window, window, gfx::Rect());
235a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (window->parent() != old_parent)
236a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    wm::ReparentTransientChildrenOfChild(window, old_parent, window->parent());
2371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Start maximize or fullscreen (affecting packaged apps) animation from
2381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // previous window bounds.
2391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  window->layer()->SetBounds(previous_bounds);
2408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
2418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Returns width that is as close as possible to |target_width| while being
2438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// consistent with docked min and max restrictions and respects the |window|'s
2448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// minimum and maximum size.
2458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int GetWindowWidthCloseTo(const aura::Window* window, int target_width) {
2468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!wm::GetWindowState(window)->CanResize()) {
2478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    DCHECK_LE(window->bounds().width(),
2488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)              DockedWindowLayoutManager::kMaxDockWidth);
2498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return window->bounds().width();
2508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
2518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  int width = std::max(DockedWindowLayoutManager::kMinDockWidth,
2528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                       std::min(target_width,
2538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                DockedWindowLayoutManager::kMaxDockWidth));
2548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (window->delegate()) {
2558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (window->delegate()->GetMinimumSize().width() != 0)
2568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      width = std::max(width, window->delegate()->GetMinimumSize().width());
2578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (window->delegate()->GetMaximumSize().width() != 0)
2588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      width = std::min(width, window->delegate()->GetMaximumSize().width());
2598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
2608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK_LE(width, DockedWindowLayoutManager::kMaxDockWidth);
2618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return width;
2628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
2638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Returns height that is as close as possible to |target_height| while
2658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// respecting the |window|'s minimum and maximum size.
2668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int GetWindowHeightCloseTo(const aura::Window* window, int target_height) {
2678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!wm::GetWindowState(window)->CanResize())
2688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return window->bounds().height();
2698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  int minimum_height = kMinimumHeight;
2708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  int maximum_height = 0;
2718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  const aura::WindowDelegate* delegate(window->delegate());
2728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (delegate) {
2738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (delegate->GetMinimumSize().height() != 0) {
2748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      minimum_height = std::max(kMinimumHeight,
2758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                delegate->GetMinimumSize().height());
2768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
2778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (delegate->GetMaximumSize().height() != 0)
2788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      maximum_height = delegate->GetMaximumSize().height();
2798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
2808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (minimum_height)
2818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    target_height = std::max(target_height, minimum_height);
2828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (maximum_height)
2838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    target_height = std::min(target_height, maximum_height);
2848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return target_height;
2858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
2868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// A functor used to sort the windows in order of their minimum height.
2888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)struct CompareMinimumHeight {
2898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  bool operator()(WindowWithHeight win1, WindowWithHeight win2) {
2908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return GetWindowHeightCloseTo(win1.window(), 0) <
2918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        GetWindowHeightCloseTo(win2.window(), 0);
2928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
2938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)};
2948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// A functor used to sort the windows in order of their center Y position.
2963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// |delta| is a pre-calculated distance from the bottom of one window to the top
2973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// of the next. Its value can be positive (gap) or negative (overlap).
2983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Half of |delta| is used as a transition point at which windows could ideally
2993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// swap positions.
3003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)struct CompareWindowPos {
301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  CompareWindowPos(aura::Window* dragged_window,
302a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   aura::Window* docked_container,
303a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   float delta)
3043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      : dragged_window_(dragged_window),
305a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        docked_container_(docked_container),
3063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        delta_(delta / 2) {}
3073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  bool operator()(WindowWithHeight window_with_height1,
3098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                  WindowWithHeight window_with_height2) {
31068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // Use target coordinates since animations may be active when windows are
31168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // reordered.
3128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    aura::Window* win1(window_with_height1.window());
3138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    aura::Window* win2(window_with_height2.window());
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gfx::Rect win1_bounds = ScreenUtil::ConvertRectToScreen(
315a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        docked_container_, win1->GetTargetBounds());
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gfx::Rect win2_bounds = ScreenUtil::ConvertRectToScreen(
317a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        docked_container_, win2->GetTargetBounds());
3188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    win1_bounds.set_height(window_with_height1.height_);
3198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    win2_bounds.set_height(window_with_height2.height_);
3203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // If one of the windows is the |dragged_window_| attempt to make an
3213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // earlier swap between the windows than just based on their centers.
3223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // This is possible if the dragged window is at least as tall as the other
3233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // window.
3243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (win1 == dragged_window_)
3253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return compare_two_windows(win1_bounds, win2_bounds);
3263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (win2 == dragged_window_)
3273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return !compare_two_windows(win2_bounds, win1_bounds);
3283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Otherwise just compare the centers.
3293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return win1_bounds.CenterPoint().y() < win2_bounds.CenterPoint().y();
3303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Based on center point tries to deduce where the drag is coming from.
3333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // When dragging from below up the transition point is lower.
3343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // When dragging from above down the transition point is higher.
3353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool compare_bounds(const gfx::Rect dragged, const gfx::Rect other) {
3363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (dragged.CenterPoint().y() < other.CenterPoint().y())
3373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return dragged.CenterPoint().y() < other.y() - delta_;
3383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return dragged.CenterPoint().y() < other.bottom() + delta_;
3393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Performs comparison both ways and selects stable result.
3423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool compare_two_windows(const gfx::Rect bounds1, const gfx::Rect bounds2) {
3433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Try comparing windows in both possible orders and see if the comparison
3443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // is stable.
3453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    bool result1 = compare_bounds(bounds1, bounds2);
3463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    bool result2 = compare_bounds(bounds2, bounds1);
3473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (result1 != result2)
3483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return result1;
3493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Otherwise it is not possible to be sure that the windows will not bounce.
3513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // In this case just compare the centers.
3523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return bounds1.CenterPoint().y() < bounds2.CenterPoint().y();
3533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private:
3563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  aura::Window* dragged_window_;
357a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  aura::Window* docked_container_;
3583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  float delta_;
3593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
360bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
3617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}  // namespace
3627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// A class that observes shelf for bounds changes.
365a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class DockedWindowLayoutManager::ShelfWindowObserver : public WindowObserver {
366a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public:
367a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  explicit ShelfWindowObserver(
368a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      DockedWindowLayoutManager* docked_layout_manager)
369a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      : docked_layout_manager_(docked_layout_manager) {
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(docked_layout_manager_->shelf()->shelf_widget());
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    docked_layout_manager_->shelf()->shelf_widget()->GetNativeView()
372a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        ->AddObserver(this);
373a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
374a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
375a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual ~ShelfWindowObserver() {
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (docked_layout_manager_->shelf() &&
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        docked_layout_manager_->shelf()->shelf_widget())
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      docked_layout_manager_->shelf()->shelf_widget()->GetNativeView()
379a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          ->RemoveObserver(this);
380a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
381a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
382a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // aura::WindowObserver:
383a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual void OnWindowBoundsChanged(aura::Window* window,
384a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                     const gfx::Rect& old_bounds,
385a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                     const gfx::Rect& new_bounds) OVERRIDE {
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    shelf_bounds_in_screen_ = ScreenUtil::ConvertRectToScreen(
387a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        window->parent(), new_bounds);
388a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    docked_layout_manager_->OnShelfBoundsChanged();
389a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
390a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
391a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const gfx::Rect& shelf_bounds_in_screen() const {
392a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return shelf_bounds_in_screen_;
393a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
394a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
395a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private:
396a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DockedWindowLayoutManager* docked_layout_manager_;
397a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  gfx::Rect shelf_bounds_in_screen_;
398a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
399a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ShelfWindowObserver);
400a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
401a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
402a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
403a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// DockedWindowLayoutManager public implementation:
4047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)DockedWindowLayoutManager::DockedWindowLayoutManager(
4055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    aura::Window* dock_container,
4065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    WorkspaceController* workspace_controller)
4075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : SnapToPixelLayoutManager(dock_container),
4085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      dock_container_(dock_container),
4097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      in_layout_(false),
4107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      dragged_window_(NULL),
4113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      is_dragged_window_docked_(false),
4123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      is_dragged_from_dock_(false),
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      shelf_(NULL),
4144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      workspace_controller_(workspace_controller),
4154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      in_fullscreen_(workspace_controller_->GetWindowState() ==
4165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                     WORKSPACE_WINDOW_STATE_FULL_SCREEN),
417ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      docked_width_(0),
418bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      alignment_(DOCKED_ALIGNMENT_NONE),
419bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      last_active_window_(NULL),
420f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      last_action_time_(base::Time::Now()),
421bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      background_widget_(new DockedBackgroundWidget(dock_container_)) {
4227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DCHECK(dock_container);
4237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
4247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      AddObserver(this);
4257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  Shell::GetInstance()->AddShellObserver(this);
4267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
4277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
4287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)DockedWindowLayoutManager::~DockedWindowLayoutManager() {
429ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  Shutdown();
430ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
431ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
432ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid DockedWindowLayoutManager::Shutdown() {
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (shelf_ && shelf_->shelf_widget()) {
4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ShelfLayoutManager* shelf_layout_manager = ShelfLayoutManager::ForShelf(
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        shelf_->shelf_widget()->GetNativeWindow());
436a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    shelf_layout_manager->RemoveObserver(this);
437a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    shelf_observer_.reset();
438a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  shelf_ = NULL;
4404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (size_t i = 0; i < dock_container_->children().size(); ++i) {
4414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    aura::Window* child = dock_container_->children()[i];
4424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    child->RemoveObserver(this);
4434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    wm::GetWindowState(child)->RemoveObserver(this);
4444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
4467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      RemoveObserver(this);
4477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  Shell::GetInstance()->RemoveShellObserver(this);
4487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
4497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
450ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid DockedWindowLayoutManager::AddObserver(
451ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DockedWindowLayoutManagerObserver* observer) {
452ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  observer_list_.AddObserver(observer);
453ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
454ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
455ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid DockedWindowLayoutManager::RemoveObserver(
456ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DockedWindowLayoutManagerObserver* observer) {
457ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  observer_list_.RemoveObserver(observer);
458ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
459ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
4607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void DockedWindowLayoutManager::StartDragging(aura::Window* window) {
4617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DCHECK(!dragged_window_);
4627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  dragged_window_ = window;
4634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(!IsPopupOrTransient(window));
4643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Start observing a window unless it is docked container's child in which
4653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // case it is already observed.
4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  wm::WindowState* dragged_state = wm::GetWindowState(dragged_window_);
4674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (dragged_window_->parent() != dock_container_) {
4683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    dragged_window_->AddObserver(this);
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    dragged_state->AddObserver(this);
4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else if (!IsAnyWindowDocked() &&
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             dragged_state->drag_details() &&
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             !(dragged_state->drag_details()->bounds_change &
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 WindowResizer::kBoundsChange_Resizes)) {
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // If there are no other docked windows clear alignment when a docked window
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // is moved (but not when it is resized or the window could get undocked
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // when resized away from the edge while docked).
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    alignment_ = DOCKED_ALIGNMENT_NONE;
4784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  is_dragged_from_dock_ = window->parent() == dock_container_;
4803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(!is_dragged_window_docked_);
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Resize all windows that are flush with the dock edge together if one of
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // them gets resized.
4845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (dragged_window_->bounds().width() == docked_width_ &&
4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      (dragged_state->drag_details()->bounds_change &
4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          WindowResizer::kBoundsChange_Resizes) &&
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      (dragged_state->drag_details()->size_change_direction &
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          WindowResizer::kBoundsChangeDirection_Horizontal)) {
4895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (size_t i = 0; i < dock_container_->children().size(); ++i) {
4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      aura::Window* window1(dock_container_->children()[i]);
4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (IsUsedByLayout(window1) &&
4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          window1 != dragged_window_ &&
4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          window1->bounds().width() == docked_width_) {
4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        wm::GetWindowState(window1)->set_bounds_changed_by_user(false);
4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
4997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
5003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void DockedWindowLayoutManager::DockDraggedWindow(aura::Window* window) {
5014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(!IsPopupOrTransient(window));
5028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  OnDraggedWindowDocked(window);
5037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  Relayout();
5047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
5057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
5063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void DockedWindowLayoutManager::UndockDraggedWindow() {
5074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(!IsPopupOrTransient(dragged_window_));
5088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  OnDraggedWindowUndocked();
5093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Relayout();
5104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED);
5113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  is_dragged_from_dock_ = false;
5123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
513ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
514f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DockedWindowLayoutManager::FinishDragging(DockedAction action,
515f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                               DockedActionSource source) {
5163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(dragged_window_);
5174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(!IsPopupOrTransient(dragged_window_));
5183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (is_dragged_window_docked_)
5198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    OnDraggedWindowUndocked();
5203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK (!is_dragged_window_docked_);
5213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Stop observing a window unless it is docked container's child in which
5223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // case it needs to keep being observed after the drag completes.
523d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (dragged_window_->parent() != dock_container_) {
5243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    dragged_window_->RemoveObserver(this);
5254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    wm::GetWindowState(dragged_window_)->RemoveObserver(this);
526d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (last_active_window_ == dragged_window_)
527d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      last_active_window_ = NULL;
52868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  } else {
5295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // If this is the first window that got docked by a move update alignment.
5305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (alignment_ == DOCKED_ALIGNMENT_NONE)
5315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      alignment_ = GetEdgeNearestWindow(dragged_window_);
53268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // A window is no longer dragged and is a child.
53368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // When a window becomes a child at drag start this is
53468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // the only opportunity we will have to enforce a window
53568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // count limit so do it here.
53668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    MaybeMinimizeChildrenExcept(dragged_window_);
537d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
5383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  dragged_window_ = NULL;
539d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  dragged_bounds_ = gfx::Rect();
5403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Relayout();
5414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED);
542f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RecordUmaAction(action, source);
5437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
5447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DockedWindowLayoutManager::SetShelf(Shelf* shelf) {
5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!shelf_);
5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  shelf_ = shelf;
5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (shelf_->shelf_widget()) {
5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ShelfLayoutManager* shelf_layout_manager = ShelfLayoutManager::ForShelf(
5505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        shelf_->shelf_widget()->GetNativeWindow());
551a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    shelf_layout_manager->AddObserver(this);
552a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    shelf_observer_.reset(new ShelfWindowObserver(this));
553a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
5547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
5557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
5563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)DockedAlignment DockedWindowLayoutManager::GetAlignmentOfWindow(
5573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const aura::Window* window) const {
5583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const gfx::Rect& bounds(window->GetBoundsInScreen());
5593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
560d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Test overlap with an existing docked area first.
561d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (docked_bounds_.Intersects(bounds) &&
562d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      alignment_ != DOCKED_ALIGNMENT_NONE) {
563d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // A window is being added to other docked windows (on the same side).
564d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return alignment_;
565d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
5663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
567d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const gfx::Rect container_bounds = dock_container_->GetBoundsInScreen();
568d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (bounds.x() <= container_bounds.x() &&
569d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      bounds.right() > container_bounds.x()) {
5703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return DOCKED_ALIGNMENT_LEFT;
571d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  } else if (bounds.x() < container_bounds.right() &&
572d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)             bounds.right() >= container_bounds.right()) {
5733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return DOCKED_ALIGNMENT_RIGHT;
5743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
5753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return DOCKED_ALIGNMENT_NONE;
5763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
5773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
578ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochDockedAlignment DockedWindowLayoutManager::CalculateAlignment() const {
579ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Find a child that is not being dragged and is not a popup.
580ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // If such exists the current alignment is returned - even if some of the
581ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // children are hidden or minimized (so they can be restored without losing
582ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // the docked state).
583ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  for (size_t i = 0; i < dock_container_->children().size(); ++i) {
584ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    aura::Window* window(dock_container_->children()[i]);
5854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (window != dragged_window_ && !IsPopupOrTransient(window))
586ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      return alignment_;
587ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
588ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // No docked windows remain other than possibly the window being dragged.
589ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Return |NONE| to indicate that windows may get docked on either side.
590ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return DOCKED_ALIGNMENT_NONE;
591ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
592ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
593010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool DockedWindowLayoutManager::CanDockWindow(
594010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    aura::Window* window,
595010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DockedAlignment desired_alignment) {
5964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Don't allow interactive docking of windows with transient parents such as
5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // modal browser dialogs. Prevent docking of panels attached to shelf during
5985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the drag.
5995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  wm::WindowState* window_state = wm::GetWindowState(window);
6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool should_attach_to_shelf = window_state->drag_details() &&
6015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      window_state->drag_details()->should_attach_to_shelf;
6025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (IsPopupOrTransient(window) || should_attach_to_shelf)
6034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return false;
60468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // If a window is wide and cannot be resized down to maximum width allowed
60568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // then it cannot be docked.
6068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // TODO(varkha). Prevent windows from changing size programmatically while
6078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // they are docked. The size will take effect only once a window is undocked.
6088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // See http://crbug.com/307792.
60968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (window->bounds().width() > kMaxDockWidth &&
6105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      (!window_state->CanResize() ||
61168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)       (window->delegate() &&
61268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        window->delegate()->GetMinimumSize().width() != 0 &&
61368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        window->delegate()->GetMinimumSize().width() > kMaxDockWidth))) {
61468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return false;
61568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
6168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // If a window is tall and cannot be resized down to maximum height allowed
6178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // then it cannot be docked.
6188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  const gfx::Rect work_area =
6198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      Shell::GetScreen()->GetDisplayNearestWindow(dock_container_).work_area();
6205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (GetWindowHeightCloseTo(window, work_area.height()) > work_area.height())
6218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return false;
622d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Cannot dock on the other size from an existing dock.
623d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const DockedAlignment alignment = CalculateAlignment();
624010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (desired_alignment != DOCKED_ALIGNMENT_NONE &&
625010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      alignment != DOCKED_ALIGNMENT_NONE &&
626010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      alignment != desired_alignment) {
627d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return false;
628d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
6295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Do not allow docking on the same side as shelf.
630d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ShelfAlignment shelf_alignment = SHELF_ALIGNMENT_BOTTOM;
6315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (shelf_)
6325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    shelf_alignment = shelf_->alignment();
633010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if ((desired_alignment == DOCKED_ALIGNMENT_LEFT &&
634010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)       shelf_alignment == SHELF_ALIGNMENT_LEFT) ||
635010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      (desired_alignment == DOCKED_ALIGNMENT_RIGHT &&
636010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)       shelf_alignment == SHELF_ALIGNMENT_RIGHT)) {
637d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return false;
638d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
639d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return true;
640d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
641d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
642a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void DockedWindowLayoutManager::OnShelfBoundsChanged() {
643a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  Relayout();
644a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  UpdateDockBounds(DockedWindowLayoutManagerObserver::DISPLAY_INSETS_CHANGED);
645a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
646a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
6477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
648a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// DockedWindowLayoutManager, aura::LayoutManager implementation:
6497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void DockedWindowLayoutManager::OnWindowResized() {
6508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  MaybeMinimizeChildrenExcept(dragged_window_);
6517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  Relayout();
6523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // When screen resizes update the insets even when dock width or alignment
6533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // does not change.
6544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateDockBounds(DockedWindowLayoutManagerObserver::DISPLAY_RESIZED);
6557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
6567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
6577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void DockedWindowLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
6584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (IsPopupOrTransient(child))
659ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
6603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Dragged windows are already observed by StartDragging and do not change
6613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // docked alignment during the drag.
6623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (child == dragged_window_)
6633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
664ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // If this is the first window getting docked - update alignment.
6655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // A window can be added without proper bounds when window is moved to another
6665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // display via API or due to display configuration change, so the alignment
6675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // is set based on which edge is closer in the new display.
6685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (alignment_ == DOCKED_ALIGNMENT_NONE)
6695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    alignment_ = GetEdgeNearestWindow(child);
67068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  MaybeMinimizeChildrenExcept(child);
6713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  child->AddObserver(this);
6724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  wm::GetWindowState(child)->AddObserver(this);
6737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  Relayout();
6744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED);
6757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
6767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
6777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void DockedWindowLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
6784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (IsPopupOrTransient(child))
679ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
6803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Dragged windows are stopped being observed by FinishDragging and do not
6813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // change alignment during the drag. They also cannot be set to be the
6823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // |last_active_window_|.
6833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (child == dragged_window_)
6843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
6853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // If this is the last window, set alignment and maximize the workspace.
6863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!IsAnyWindowDocked()) {
687ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    alignment_ = DOCKED_ALIGNMENT_NONE;
688f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    UpdateDockedWidth(0);
6893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
690bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  if (last_active_window_ == child)
691bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    last_active_window_ = NULL;
6923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  child->RemoveObserver(this);
6934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  wm::GetWindowState(child)->RemoveObserver(this);
6947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  Relayout();
6951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED);
6967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
6977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
6987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void DockedWindowLayoutManager::OnChildWindowVisibilityChanged(
6997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    aura::Window* child,
7007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    bool visible) {
7014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (IsPopupOrTransient(child))
702ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
7037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (visible)
7044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    wm::GetWindowState(child)->Restore();
7057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  Relayout();
7064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED);
7077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
7087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
7097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void DockedWindowLayoutManager::SetChildBounds(
7107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    aura::Window* child,
7117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const gfx::Rect& requested_bounds) {
7125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // The minimum constraints have to be applied first by the layout manager.
7135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  gfx::Rect actual_new_bounds(requested_bounds);
7145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (child->delegate()) {
7155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const gfx::Size& min_size = child->delegate()->GetMinimumSize();
7165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    actual_new_bounds.set_width(
7175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        std::max(min_size.width(), actual_new_bounds.width()));
7185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    actual_new_bounds.set_height(
7195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        std::max(min_size.height(), actual_new_bounds.height()));
7205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
7215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  SnapToPixelLayoutManager::SetChildBounds(child, actual_new_bounds);
722a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (IsPopupOrTransient(child))
723a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;
7245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Whenever one of our windows is moved or resized enforce layout.
725c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ShelfLayoutManager* shelf_layout =
726c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      ShelfLayoutManager::ForShelf(dock_container_);
727a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (shelf_layout)
728a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    shelf_layout->UpdateVisibilityState();
7297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
7307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
7317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
732a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// DockedWindowLayoutManager, ash::ShellObserver implementation:
7337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
7344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void DockedWindowLayoutManager::OnDisplayWorkAreaInsetsChanged() {
7354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Relayout();
7364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateDockBounds(DockedWindowLayoutManagerObserver::DISPLAY_INSETS_CHANGED);
7378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  MaybeMinimizeChildrenExcept(dragged_window_);
7384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
7394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
7404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void DockedWindowLayoutManager::OnFullscreenStateChanged(
7411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    bool is_fullscreen, aura::Window* root_window) {
7424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (dock_container_->GetRootWindow() != root_window)
7434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
7444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Entering fullscreen mode (including immersive) hides docked windows.
7454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  in_fullscreen_ = workspace_controller_->GetWindowState() ==
7464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      WORKSPACE_WINDOW_STATE_FULL_SCREEN;
7474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  {
7484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // prevent Relayout from getting called multiple times during this
7494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
7508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // Use a copy of children array because a call to MinimizeDockedWindow or
7518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // RestoreDockedWindow can change order.
7528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    aura::Window::Windows children(dock_container_->children());
7538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    for (aura::Window::Windows::const_iterator iter = children.begin();
7548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)         iter != children.end(); ++iter) {
7554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      aura::Window* window(*iter);
7564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (IsPopupOrTransient(window))
7574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        continue;
7584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      wm::WindowState* window_state = wm::GetWindowState(window);
7594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (in_fullscreen_) {
7604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (window->IsVisible())
7614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          MinimizeDockedWindow(window_state);
7624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      } else {
7634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (!window_state->IsMinimized())
7644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          RestoreDockedWindow(window_state);
7654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }
7664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
7674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
7684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Relayout();
7694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED);
7704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
7714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
7727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void DockedWindowLayoutManager::OnShelfAlignmentChanged(
7731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    aura::Window* root_window) {
7747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (dock_container_->GetRootWindow() != root_window)
7757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return;
7767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
7775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!shelf_ || !shelf_->shelf_widget())
7787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return;
7797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
7807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (alignment_ == DOCKED_ALIGNMENT_NONE)
7817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return;
7827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
7835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Do not allow shelf and dock on the same side. Switch side that
7847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // the dock is attached to and move all dock windows to that new side.
7855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ShelfAlignment shelf_alignment = shelf_->shelf_widget()->GetAlignment();
7867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (alignment_ == DOCKED_ALIGNMENT_LEFT &&
7877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      shelf_alignment == SHELF_ALIGNMENT_LEFT) {
788ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    alignment_ = DOCKED_ALIGNMENT_RIGHT;
7897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  } else if (alignment_ == DOCKED_ALIGNMENT_RIGHT &&
7907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)             shelf_alignment == SHELF_ALIGNMENT_RIGHT) {
791ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    alignment_ = DOCKED_ALIGNMENT_LEFT;
7927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
7937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  Relayout();
7944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateDockBounds(DockedWindowLayoutManagerObserver::SHELF_ALIGNMENT_CHANGED);
7957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
7967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
7977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////
798a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// DockedWindowLayoutManager, ShelfLayoutManagerObserver implementation:
799a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void DockedWindowLayoutManager::OnBackgroundUpdated(
800a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    ShelfBackgroundType background_type,
801a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    BackgroundAnimatorChangeType change_type) {
8025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  background_widget_->SetBackgroundType(background_type, change_type);
803a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
804a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
805a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////
806a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// DockedWindowLayoutManager, WindowStateObserver implementation:
8077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
808a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DockedWindowLayoutManager::OnPreWindowStateTypeChange(
8094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    wm::WindowState* window_state,
810a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    wm::WindowStateType old_type) {
8114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  aura::Window* window = window_state->window();
8124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (IsPopupOrTransient(window))
8137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return;
8147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // The window property will still be set, but no actual change will occur
8154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // until OnFullscreenStateChange is called when exiting fullscreen.
8164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (in_fullscreen_)
8177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return;
8184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (window_state->IsMinimized()) {
8194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    MinimizeDockedWindow(window_state);
820a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  } else if (window_state->IsMaximizedOrFullscreen() ||
821a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)             window_state->IsSnapped()) {
822a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (window != dragged_window_) {
823a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      UndockWindow(window);
824a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      RecordUmaAction(DOCKED_ACTION_MAXIMIZE, DOCKED_ACTION_SOURCE_UNKNOWN);
825a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
826a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else if (old_type == wm::WINDOW_STATE_TYPE_MINIMIZED) {
8274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    RestoreDockedWindow(window_state);
8284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
8297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
8307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
8314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/////////////////////////////////////////////////////////////////////////////
832a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// DockedWindowLayoutManager, WindowObserver implementation:
8334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
834bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochvoid DockedWindowLayoutManager::OnWindowBoundsChanged(
835bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    aura::Window* window,
836bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    const gfx::Rect& old_bounds,
837bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    const gfx::Rect& new_bounds) {
8383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Only relayout if the dragged window would get docked.
8393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (window == dragged_window_ && is_dragged_window_docked_)
840bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    Relayout();
841bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
842bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
84368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void DockedWindowLayoutManager::OnWindowVisibilityChanging(
84468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    aura::Window* window, bool visible) {
8454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (IsPopupOrTransient(window))
8464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
847a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int animation_type = ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT;
84868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (visible) {
849a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    animation_type = ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_DROP;
850a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ::wm::SetWindowVisibilityAnimationDuration(
85168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        window, base::TimeDelta::FromMilliseconds(kFadeDurationMs));
852f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else if (wm::GetWindowState(window)->IsMinimized()) {
853f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    animation_type = WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE;
85468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
855a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ::wm::SetWindowVisibilityAnimationType(window, animation_type);
85668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
85768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
858bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochvoid DockedWindowLayoutManager::OnWindowDestroying(aura::Window* window) {
8593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (dragged_window_ == window) {
860f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    FinishDragging(DOCKED_ACTION_NONE, DOCKED_ACTION_SOURCE_UNKNOWN);
8613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK(!dragged_window_);
8625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(!is_dragged_window_docked_);
8633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
8643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (window == last_active_window_)
8653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    last_active_window_ = NULL;
866f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RecordUmaAction(DOCKED_ACTION_CLOSE, DOCKED_ACTION_SOURCE_UNKNOWN);
867bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
868bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
869bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
8707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
871a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// DockedWindowLayoutManager, aura::client::ActivationChangeObserver
872a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// implementation:
8737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
8747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void DockedWindowLayoutManager::OnWindowActivated(aura::Window* gained_active,
8757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                                  aura::Window* lost_active) {
8764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (gained_active && IsPopupOrTransient(gained_active))
8774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
8787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Ignore if the window that is not managed by this was activated.
8797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  aura::Window* ancestor = NULL;
8807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  for (aura::Window* parent = gained_active;
8817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)       parent; parent = parent->parent()) {
8827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (parent->parent() == dock_container_) {
8837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      ancestor = parent;
8847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      break;
8857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
8867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
8877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (ancestor)
8887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    UpdateStacking(ancestor);
8897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
8907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
8917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
892a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// DockedWindowLayoutManager private implementation:
8937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
89468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void DockedWindowLayoutManager::MaybeMinimizeChildrenExcept(
89568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    aura::Window* child) {
8968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Minimize any windows that don't fit without overlap.
8978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  const gfx::Rect work_area =
8988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      Shell::GetScreen()->GetDisplayNearestWindow(dock_container_).work_area();
8995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int available_room = work_area.height();
9005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool gap_needed = !!child;
9018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (child)
9025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    available_room -= GetWindowHeightCloseTo(child, 0);
9038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Use a copy of children array because a call to Minimize can change order.
90468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  aura::Window::Windows children(dock_container_->children());
90568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  aura::Window::Windows::const_reverse_iterator iter = children.rbegin();
90668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  while (iter != children.rend()) {
90768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    aura::Window* window(*iter++);
90868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (window == child || !IsUsedByLayout(window))
90968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      continue;
9105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int room_needed = GetWindowHeightCloseTo(window, 0) +
9115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        (gap_needed ? kMinDockGap : 0);
9125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gap_needed = true;
913a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (available_room > room_needed) {
9148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      available_room -= room_needed;
915a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else {
916a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // Slow down minimizing animations. Lock duration so that it is not
917a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // overridden by other ScopedLayerAnimationSettings down the stack.
918a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
919a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      settings.SetTransitionDuration(
920a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          base::TimeDelta::FromMilliseconds(kMinimizeDurationMs));
921a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      settings.LockTransitionDuration();
92268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      wm::GetWindowState(window)->Minimize();
923a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
92468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
92568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
92668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
9274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void DockedWindowLayoutManager::MinimizeDockedWindow(
9284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    wm::WindowState* window_state) {
9294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(!IsPopupOrTransient(window_state->window()));
9304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  window_state->window()->Hide();
93168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (window_state->IsActive())
93268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    window_state->Deactivate();
933f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RecordUmaAction(DOCKED_ACTION_MINIMIZE, DOCKED_ACTION_SOURCE_UNKNOWN);
9347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
9357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
9364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void DockedWindowLayoutManager::RestoreDockedWindow(
9374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    wm::WindowState* window_state) {
9384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  aura::Window* window = window_state->window();
9394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(!IsPopupOrTransient(window));
940a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Always place restored window at the bottom shuffling the other windows up.
94168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // TODO(varkha): add a separate container for docked windows to keep track
94268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // of ordering.
94368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  gfx::Display display = Shell::GetScreen()->GetDisplayNearestWindow(
94468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      dock_container_);
94568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const gfx::Rect work_area = display.work_area();
9468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
9478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Evict the window if it can no longer be docked because of its height.
948010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!CanDockWindow(window, DOCKED_ALIGNMENT_NONE)) {
9498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    UndockWindow(window);
950f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    RecordUmaAction(DOCKED_ACTION_EVICT, DOCKED_ACTION_SOURCE_UNKNOWN);
9518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
9528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
95368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  gfx::Rect bounds(window->bounds());
954a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  bounds.set_y(work_area.bottom());
95568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  window->SetBounds(bounds);
9567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  window->Show();
95768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  MaybeMinimizeChildrenExcept(window);
958f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RecordUmaAction(DOCKED_ACTION_RESTORE, DOCKED_ACTION_SOURCE_UNKNOWN);
959f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
960f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
961f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DockedWindowLayoutManager::RecordUmaAction(DockedAction action,
962f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                                DockedActionSource source) {
963f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (action == DOCKED_ACTION_NONE)
964f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
965f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Ash.Dock.Action", action, DOCKED_ACTION_COUNT);
966f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Ash.Dock.ActionSource", source,
967f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                            DOCKED_ACTION_SOURCE_COUNT);
968f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::Time time_now = base::Time::Now();
969f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::TimeDelta time_between_use = time_now - last_action_time_;
970f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.Dock.TimeBetweenUse",
971f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                              time_between_use.InSeconds(),
972f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                              1,
973f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                              base::TimeDelta::FromHours(10).InSeconds(),
974f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                              100);
975f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  last_action_time_ = time_now;
976f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int docked_all_count = 0;
977f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int docked_visible_count = 0;
978f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int docked_panels_count = 0;
979f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int large_windows_count = 0;
980f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (size_t i = 0; i < dock_container_->children().size(); ++i) {
981f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const aura::Window* window(dock_container_->children()[i]);
982f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (IsPopupOrTransient(window))
983f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      continue;
984f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    docked_all_count++;
985f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!IsUsedByLayout(window))
986f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      continue;
987f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    docked_visible_count++;
9885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (window->type() == ui::wm::WINDOW_TYPE_PANEL)
989f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      docked_panels_count++;
990f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const wm::WindowState* window_state = wm::GetWindowState(window);
991f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (window_state->HasRestoreBounds()) {
992f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      const gfx::Rect restore_bounds = window_state->GetRestoreBoundsInScreen();
993f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (restore_bounds.width() > kMaxDockWidth)
994f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        large_windows_count++;
995f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
996f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
997f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UMA_HISTOGRAM_COUNTS_100("Ash.Dock.ItemsAll", docked_all_count);
998f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UMA_HISTOGRAM_COUNTS_100("Ash.Dock.ItemsLarge", large_windows_count);
999f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UMA_HISTOGRAM_COUNTS_100("Ash.Dock.ItemsPanels", docked_panels_count);
1000f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UMA_HISTOGRAM_COUNTS_100("Ash.Dock.ItemsVisible", docked_visible_count);
1001f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
1002f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1003f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DockedWindowLayoutManager::UpdateDockedWidth(int width) {
1004f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (docked_width_ == width)
1005f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
1006f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  docked_width_ = width;
1007f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UMA_HISTOGRAM_COUNTS_10000("Ash.Dock.Width", docked_width_);
10087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
10097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
10108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void DockedWindowLayoutManager::OnDraggedWindowDocked(aura::Window* window) {
10113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(!is_dragged_window_docked_);
10123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  is_dragged_window_docked_ = true;
10133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
10143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
10158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void DockedWindowLayoutManager::OnDraggedWindowUndocked() {
10163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK (is_dragged_window_docked_);
10173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  is_dragged_window_docked_ = false;
10183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
10193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
10203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool DockedWindowLayoutManager::IsAnyWindowDocked() {
10213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return CalculateAlignment() != DOCKED_ALIGNMENT_NONE;
1022ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1023ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
10245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DockedAlignment DockedWindowLayoutManager::GetEdgeNearestWindow(
10255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const aura::Window* window) const {
10265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const gfx::Rect& bounds(window->GetBoundsInScreen());
10275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const gfx::Rect container_bounds = dock_container_->GetBoundsInScreen();
10285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return (abs(bounds.x() - container_bounds.x()) <
10295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          abs(bounds.right() - container_bounds.right())) ?
10305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              DOCKED_ALIGNMENT_LEFT : DOCKED_ALIGNMENT_RIGHT;
10315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
10325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
10337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void DockedWindowLayoutManager::Relayout() {
10343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (in_layout_)
10353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
10363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (alignment_ == DOCKED_ALIGNMENT_NONE && !is_dragged_window_docked_)
10377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return;
10387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
10397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
10403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  gfx::Rect dock_bounds = dock_container_->GetBoundsInScreen();
10417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  aura::Window* active_window = NULL;
10428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  std::vector<WindowWithHeight> visible_windows;
10437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  for (size_t i = 0; i < dock_container_->children().size(); ++i) {
10447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    aura::Window* window(dock_container_->children()[i]);
10457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
10463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!IsUsedByLayout(window) || window == dragged_window_)
10477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      continue;
10487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
10497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // If the shelf is currently hidden (full-screen mode), hide window until
10507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // full-screen mode is exited.
10514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (in_fullscreen_) {
10527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // The call to Hide does not set the minimize property, so the window will
10537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // be restored when the shelf becomes visible again.
10547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      window->Hide();
10557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      continue;
10567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
10577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (window->HasFocus() ||
10587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        window->Contains(
10597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            aura::client::GetFocusClient(window)->GetFocusedWindow())) {
10607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DCHECK(!active_window);
10617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      active_window = window;
10627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
10638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    visible_windows.push_back(WindowWithHeight(window));
1064bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
10653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Consider docked dragged_window_ when fanning out other child windows.
10663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (is_dragged_window_docked_) {
10678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    visible_windows.push_back(WindowWithHeight(dragged_window_));
10683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK(!active_window);
10693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    active_window = dragged_window_;
10703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1071bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
10728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Position docked windows as well as the window being dragged.
1073a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  gfx::Rect work_area =
10748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      Shell::GetScreen()->GetDisplayNearestWindow(dock_container_).work_area();
1075a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (shelf_observer_)
1076a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    work_area.Subtract(shelf_observer_->shelf_bounds_in_screen());
10778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  int available_room = CalculateWindowHeightsAndRemainingRoom(work_area,
10788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                                              &visible_windows);
10798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  FanOutChildren(work_area,
10808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                 CalculateIdealWidth(visible_windows),
10818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                 available_room,
10828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                 &visible_windows);
10838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
10848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // After the first Relayout allow the windows to change their order easier
10858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // since we know they are docked.
10868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  is_dragged_from_dock_ = true;
10878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  UpdateStacking(active_window);
10888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
10898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
10908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int DockedWindowLayoutManager::CalculateWindowHeightsAndRemainingRoom(
10918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const gfx::Rect work_area,
10928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    std::vector<WindowWithHeight>* visible_windows) {
10935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int available_room = work_area.height();
10948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  int remaining_windows = visible_windows->size();
10955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int gap_height = remaining_windows > 1 ? kMinDockGap : 0;
10968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
10978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Sort windows by their minimum heights and calculate target heights.
10988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  std::sort(visible_windows->begin(), visible_windows->end(),
10998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)            CompareMinimumHeight());
11008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Distribute the free space among the docked windows. Since the windows are
11018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // sorted (tall windows first) we can now assume that any window which
11028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // required more space than the current window will have already been
11038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // accounted for previously in this loop, so we can safely give that window
11048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // its proportional share of the remaining space.
11058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (std::vector<WindowWithHeight>::reverse_iterator iter =
11068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)           visible_windows->rbegin();
11078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      iter != visible_windows->rend(); ++iter) {
11088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    iter->height_ = GetWindowHeightCloseTo(
11095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        iter->window(),
11105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        (available_room + gap_height) / remaining_windows - gap_height);
11115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    available_room -= (iter->height_ + gap_height);
11128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    remaining_windows--;
11138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
11145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return available_room + gap_height;
11158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
11168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
11178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int DockedWindowLayoutManager::CalculateIdealWidth(
11188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const std::vector<WindowWithHeight>& visible_windows) {
1119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int smallest_max_width = kMaxDockWidth;
1120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int largest_min_width = kMinDockWidth;
1121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Ideal width of the docked area is as close to kIdealWidth as possible
1122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // while still respecting the minimum and maximum width restrictions on the
1123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // individual docked windows as well as the width that was possibly set by a
1124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // user (which needs to be preserved when dragging and rearranging windows).
11258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (std::vector<WindowWithHeight>::const_iterator iter =
11268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)           visible_windows.begin();
11278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)       iter != visible_windows.end(); ++iter) {
11288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const aura::Window* window = iter->window();
1129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int min_window_width = window->bounds().width();
1130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int max_window_width = min_window_width;
1131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!wm::GetWindowState(window)->bounds_changed_by_user()) {
1132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      min_window_width = GetWindowWidthCloseTo(window, kMinDockWidth);
1133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      max_window_width = GetWindowWidthCloseTo(window, kMaxDockWidth);
113468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
1135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    largest_min_width = std::max(largest_min_width, min_window_width);
1136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    smallest_max_width = std::min(smallest_max_width, max_window_width);
1137bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
1138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int ideal_width = std::max(largest_min_width,
1139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                             std::min(smallest_max_width, kIdealWidth));
1140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Restrict docked area width regardless of window restrictions.
1141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ideal_width = std::max(std::min(ideal_width, kMaxDockWidth), kMinDockWidth);
1142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return ideal_width;
11438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
11448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
11458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void DockedWindowLayoutManager::FanOutChildren(
11468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const gfx::Rect& work_area,
11478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    int ideal_docked_width,
11488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    int available_room,
11498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    std::vector<WindowWithHeight>* visible_windows) {
11508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  gfx::Rect dock_bounds = dock_container_->GetBoundsInScreen();
11518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
11528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Calculate initial vertical offset and the gap or overlap between windows.
11538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  const int num_windows = visible_windows->size();
11545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const float delta = static_cast<float>(available_room) /
1155bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      ((available_room > 0 || num_windows <= 1) ?
1156bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch          num_windows + 1 : num_windows - 1);
11575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  float y_pos = work_area.y() + ((delta > 0) ? delta : 0);
1158bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
115968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Docked area is shown only if there is at least one non-dragged visible
116068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // docked window.
1161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int new_width = ideal_docked_width;
11628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (visible_windows->empty() ||
11638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      (visible_windows->size() == 1 &&
11648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          (*visible_windows)[0].window() == dragged_window_)) {
1165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    new_width = 0;
116668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
1167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UpdateDockedWidth(new_width);
11683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Sort windows by their center positions and fan out overlapping
11693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // windows.
11708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  std::sort(visible_windows->begin(), visible_windows->end(),
11713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            CompareWindowPos(is_dragged_from_dock_ ? dragged_window_ : NULL,
1172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                             dock_container_,
1173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                             delta));
11748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (std::vector<WindowWithHeight>::iterator iter = visible_windows->begin();
1175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)       iter != visible_windows->end(); ++iter) {
11768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    aura::Window* window = iter->window();
11775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gfx::Rect bounds = ScreenUtil::ConvertRectToScreen(
1178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        dock_container_, window->GetTargetBounds());
1179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // A window is extended or shrunk to be as close as possible to the ideal
1180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // docked area width. Windows that were resized by a user are kept at their
1181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // existing size.
118268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // This also enforces the min / max restrictions on the docked area width.
118368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    bounds.set_width(GetWindowWidthCloseTo(
118468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        window,
1185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        wm::GetWindowState(window)->bounds_changed_by_user() ?
1186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            bounds.width() : ideal_docked_width));
118768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    DCHECK_LE(bounds.width(), ideal_docked_width);
1188bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
1189d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    DockedAlignment alignment = alignment_;
11905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (alignment == DOCKED_ALIGNMENT_NONE && window == dragged_window_)
11915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      alignment = GetEdgeNearestWindow(window);
1192d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1193bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    // Fan out windows evenly distributing the overlap or remaining free space.
11948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    bounds.set_height(iter->height_);
1195bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    bounds.set_y(std::max(work_area.y(),
1196bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                          std::min(work_area.bottom() - bounds.height(),
1197bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                                   static_cast<int>(y_pos + 0.5))));
11985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    y_pos += bounds.height() + delta + kMinDockGap;
1199bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
1200bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    // All docked windows other than the one currently dragged remain stuck
120168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // to the screen edge (flush with the edge or centered in the dock area).
1202d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    switch (alignment) {
1203bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      case DOCKED_ALIGNMENT_LEFT:
120468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        bounds.set_x(dock_bounds.x() +
120568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                     (ideal_docked_width - bounds.width()) / 2);
1206bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        break;
1207bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      case DOCKED_ALIGNMENT_RIGHT:
120868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        bounds.set_x(dock_bounds.right() -
120968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                     (ideal_docked_width + bounds.width()) / 2);
1210bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        break;
1211bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      case DOCKED_ALIGNMENT_NONE:
1212bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        break;
12137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
12143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (window == dragged_window_) {
12153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      dragged_bounds_ = bounds;
12163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      continue;
12173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1218d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // If the following asserts it is probably because not all the children
1219d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // have been removed when dock was closed.
12203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK_NE(alignment_, DOCKED_ALIGNMENT_NONE);
12215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bounds = ScreenUtil::ConvertRectFromScreen(dock_container_, bounds);
122268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (bounds != window->GetTargetBounds()) {
122368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ui::Layer* layer = window->layer();
122468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ui::ScopedLayerAnimationSettings slide_settings(layer->GetAnimator());
122568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      slide_settings.SetPreemptionStrategy(
122668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
122768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      slide_settings.SetTransitionDuration(
122868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          base::TimeDelta::FromMilliseconds(kSlideDurationMs));
122968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      SetChildBoundsDirect(window, bounds);
123068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
12317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
12327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
12337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
12344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void DockedWindowLayoutManager::UpdateDockBounds(
12354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DockedWindowLayoutManagerObserver::Reason reason) {
1236ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  int dock_inset = docked_width_ + (docked_width_ > 0 ? kMinDockGap : 0);
12374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const gfx::Rect work_area =
12384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      Shell::GetScreen()->GetDisplayNearestWindow(dock_container_).work_area();
1239ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  gfx::Rect bounds = gfx::Rect(
12403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      alignment_ == DOCKED_ALIGNMENT_RIGHT && dock_inset > 0 ?
1241ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          dock_container_->bounds().right() - dock_inset:
1242ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          dock_container_->bounds().x(),
1243ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      dock_container_->bounds().y(),
1244ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      dock_inset,
12454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      work_area.height());
1246ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  docked_bounds_ = bounds +
1247ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      dock_container_->GetBoundsInScreen().OffsetFromOrigin();
1248ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  FOR_EACH_OBSERVER(
1249ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      DockedWindowLayoutManagerObserver,
1250ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      observer_list_,
12514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      OnDockBoundsChanging(bounds, reason));
1252bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // Show or hide background for docked area.
1253a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  gfx::Rect background_bounds(docked_bounds_);
1254a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (shelf_observer_)
1255a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    background_bounds.Subtract(shelf_observer_->shelf_bounds_in_screen());
1256a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  background_widget_->SetBackgroundBounds(background_bounds, alignment_);
1257a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (docked_width_ > 0)
1258bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    background_widget_->Show();
1259a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  else
1260bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    background_widget_->Hide();
1261ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1262ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
12637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void DockedWindowLayoutManager::UpdateStacking(aura::Window* active_window) {
1264bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  if (!active_window) {
1265bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    if (!last_active_window_)
1266bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      return;
1267bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    active_window = last_active_window_;
1268bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
1269bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
12703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Windows are stacked like a deck of cards:
1271bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  //  ,------.
1272bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // |,------.|
1273bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // |,------.|
1274bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // | active |
1275bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // | window |
1276bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // |`------'|
1277bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // |`------'|
1278bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  //  `------'
12793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Use the middle of each window to figure out how to stack the window.
1280bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // This allows us to update the stacking when a window is being dragged around
1281bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // by the titlebar.
1282bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  std::map<int, aura::Window*> window_ordering;
1283bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  for (aura::Window::Windows::const_iterator it =
1284bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch           dock_container_->children().begin();
1285bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch       it != dock_container_->children().end(); ++it) {
12863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!IsUsedByLayout(*it) ||
12873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        ((*it) == dragged_window_ && !is_dragged_window_docked_)) {
1288bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      continue;
12893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1290bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    gfx::Rect bounds = (*it)->bounds();
1291bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    window_ordering.insert(std::make_pair(bounds.y() + bounds.height() / 2,
1292bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                                          *it));
1293bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
1294bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  int active_center_y = active_window->bounds().CenterPoint().y();
1295bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
12963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  aura::Window* previous_window = NULL;
1297bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  for (std::map<int, aura::Window*>::const_iterator it =
1298bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch       window_ordering.begin();
1299bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch       it != window_ordering.end() && it->first < active_center_y; ++it) {
1300bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    if (previous_window)
1301bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      dock_container_->StackChildAbove(it->second, previous_window);
1302bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    previous_window = it->second;
1303bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
1304bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  for (std::map<int, aura::Window*>::const_reverse_iterator it =
1305bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch       window_ordering.rbegin();
1306bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch       it != window_ordering.rend() && it->first > active_center_y; ++it) {
1307bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    if (previous_window)
1308bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      dock_container_->StackChildAbove(it->second, previous_window);
1309bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    previous_window = it->second;
1310bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
1311bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
13123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (previous_window && active_window->parent() == dock_container_)
13133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    dock_container_->StackChildAbove(active_window, previous_window);
13143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (active_window != dragged_window_)
13153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    last_active_window_ = active_window;
13167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
13177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
13187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
13197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// keyboard::KeyboardControllerObserver implementation:
13207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
13217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void DockedWindowLayoutManager::OnKeyboardBoundsChanging(
13227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const gfx::Rect& keyboard_bounds) {
13237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // This bounds change will have caused a change to the Shelf which does not
13247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // propagate automatically to this class, so manually recalculate bounds.
13254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Relayout();
13264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateDockBounds(DockedWindowLayoutManagerObserver::KEYBOARD_BOUNDS_CHANGING);
13277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
13287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
13297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}  // namespace ash
1330