Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ash / wm / panels / panel_layout_manager.cc
index 4d0f0d5..519d569 100644 (file)
@@ -7,10 +7,11 @@
 #include <algorithm>
 #include <map>
 
-#include "ash/launcher/launcher.h"
-#include "ash/screen_ash.h"
+#include "ash/screen_util.h"
+#include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shelf/shelf_types.h"
+#include "ash/shelf/shelf_util.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
 #include "ash/shell_window_ids.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkPaint.h"
 #include "third_party/skia/include/core/SkPath.h"
-#include "ui/aura/client/activation_client.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/client/window_tree_client.h"
-#include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
+#include "ui/aura/window_delegate.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tracker.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/rect.h"
 #include "ui/gfx/vector2d.h"
 #include "ui/views/background.h"
 #include "ui/views/widget/widget.h"
+#include "ui/wm/public/activation_client.h"
 
 namespace ash {
-namespace internal {
-
 namespace {
+
 const int kPanelIdealSpacing = 4;
 
 const float kMaxHeightFactor = .80f;
@@ -48,7 +50,7 @@ const float kMaxWidthFactor = .50f;
 const int kPanelSlideDurationMilliseconds = 50;
 const int kCalloutFadeDurationMilliseconds = 50;
 
-// Offset used when sliding panel in/out of the launcher. Used for minimizing,
+// Offset used when sliding panel in/out of the shelf. Used for minimizing,
 // restoring and the initial showing of a panel.
 const int kPanelSlideInOffset = 20;
 
@@ -61,7 +63,7 @@ class CalloutWidgetBackground : public views::Background {
   CalloutWidgetBackground() : alignment_(SHELF_ALIGNMENT_BOTTOM) {
   }
 
-  virtual void Paint(gfx::Canvas* canvas, views::View* view) const OVERRIDE {
+  void Paint(gfx::Canvas* canvas, views::View* view) const override {
     SkPath path;
     switch (alignment_) {
       case SHELF_ALIGNMENT_BOTTOM:
@@ -227,14 +229,13 @@ class PanelCalloutWidget : public views::Widget {
     views::Widget::InitParams params;
     params.type = views::Widget::InitParams::TYPE_POPUP;
     params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
-    params.can_activate = false;
     params.keep_on_top = true;
     params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
     params.parent = parent;
-    params.bounds = ScreenAsh::ConvertRectToScreen(parent, gfx::Rect());
+    params.bounds = ScreenUtil::ConvertRectToScreen(parent, gfx::Rect());
     params.bounds.set_width(kArrowWidth);
     params.bounds.set_height(kArrowHeight);
-    // Why do we need this and can_activate = false?
+    params.accept_events = false;
     set_focus_on_creation(false);
     Init(params);
     DCHECK_EQ(GetNativeView()->GetRootWindow(), parent->GetRootWindow());
@@ -257,10 +258,10 @@ PanelLayoutManager::PanelLayoutManager(aura::Window* panel_container)
     : panel_container_(panel_container),
       in_add_window_(false),
       in_layout_(false),
+      show_callout_widgets_(true),
       dragged_panel_(NULL),
-      launcher_(NULL),
+      shelf_(NULL),
       shelf_layout_manager_(NULL),
-      shelf_hidden_(false),
       last_active_panel_(NULL),
       weak_factory_(this) {
   DCHECK(panel_container);
@@ -283,9 +284,9 @@ void PanelLayoutManager::Shutdown() {
     delete iter->callout_widget;
   }
   panel_windows_.clear();
-  if (launcher_)
-    launcher_->RemoveIconObserver(this);
-  launcher_ = NULL;
+  if (shelf_)
+    shelf_->RemoveIconObserver(this);
+  shelf_ = NULL;
   aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
       RemoveObserver(this);
   Shell::GetInstance()->display_controller()->RemoveObserver(this);
@@ -303,14 +304,14 @@ void PanelLayoutManager::FinishDragging() {
   Relayout();
 }
 
-void PanelLayoutManager::SetLauncher(ash::Launcher* launcher) {
-  DCHECK(!launcher_);
+void PanelLayoutManager::SetShelf(Shelf* shelf) {
+  DCHECK(!shelf_);
   DCHECK(!shelf_layout_manager_);
-  launcher_ = launcher;
-  launcher_->AddIconObserver(this);
-  if (launcher_->shelf_widget()) {
-    shelf_layout_manager_ = ash::internal::ShelfLayoutManager::ForLauncher(
-        launcher_->shelf_widget()->GetNativeWindow());
+  shelf_ = shelf;
+  shelf_->AddIconObserver(this);
+  if (shelf_->shelf_widget()) {
+    shelf_layout_manager_ = ash::ShelfLayoutManager::ForShelf(
+        shelf_->shelf_widget()->GetNativeWindow());
     WillChangeVisibilityState(shelf_layout_manager_->visibility_state());
     shelf_layout_manager_->AddObserver(this);
   }
@@ -325,6 +326,13 @@ void PanelLayoutManager::ToggleMinimize(aura::Window* panel) {
     window_state->Minimize();
 }
 
+void PanelLayoutManager::SetShowCalloutWidgets(bool show) {
+  if (show_callout_widgets_ == show)
+    return;
+  show_callout_widgets_ = show;
+  UpdateCallouts();
+}
+
 views::Widget* PanelLayoutManager::GetCalloutWidgetForPanel(
     aura::Window* panel) {
   DCHECK(panel->parent() == panel_container_);
@@ -341,7 +349,7 @@ void PanelLayoutManager::OnWindowResized() {
 }
 
 void PanelLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
-  if (child->type() == aura::client::WINDOW_TYPE_POPUP)
+  if (child->type() == ui::wm::WINDOW_TYPE_POPUP)
     return;
   if (in_add_window_)
     return;
@@ -353,21 +361,17 @@ void PanelLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
     // back to appropriate container and ignore it.
     // TODO(varkha): Updating bounds during a drag can cause problems and a more
     // general solution is needed. See http://crbug.com/251813 .
+    aura::Window* old_parent = child->parent();
     aura::client::ParentWindowWithContext(
         child, child, child->GetRootWindow()->GetBoundsInScreen());
-    wm::ReparentTransientChildrenOfChild(child->parent(), child);
+    wm::ReparentTransientChildrenOfChild(child, old_parent, child->parent());
     DCHECK(child->parent()->id() != kShellWindowId_PanelContainer);
     return;
   }
   PanelInfo panel_info;
   panel_info.window = child;
   panel_info.callout_widget = new PanelCalloutWidget(panel_container_);
-  if (child != dragged_panel_) {
-    // Set the panel to 0 opacity until it has been positioned to prevent it
-    // from flashing briefly at position (0, 0).
-    child->layer()->SetOpacity(0);
-    panel_info.slide_in = true;
-  }
+  panel_info.slide_in = child != dragged_panel_;
   panel_windows_.push_back(panel_info);
   child->AddObserver(this);
   wm::GetWindowState(child)->AddObserver(this);
@@ -378,7 +382,7 @@ void PanelLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) {
 }
 
 void PanelLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
-  if (child->type() == aura::client::WINDOW_TYPE_POPUP)
+  if (child->type() == ui::wm::WINDOW_TYPE_POPUP)
     return;
   PanelList::iterator found =
       std::find(panel_windows_.begin(), panel_windows_.end(), child);
@@ -386,6 +390,8 @@ void PanelLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
     delete found->callout_widget;
     panel_windows_.erase(found);
   }
+  if (restore_windows_on_shelf_visible_)
+    restore_windows_on_shelf_visible_->Remove(child);
   child->RemoveObserver(this);
   wm::GetWindowState(child)->RemoveObserver(this);
 
@@ -400,6 +406,8 @@ void PanelLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
 
 void PanelLayoutManager::OnChildWindowVisibilityChanged(aura::Window* child,
                                                         bool visible) {
+  if (visible)
+    wm::GetWindowState(child)->Restore();
   Relayout();
 }
 
@@ -432,6 +440,12 @@ void PanelLayoutManager::SetChildBounds(aura::Window* child,
       panel_windows_.insert(new_position, dragged_panel_info);
     }
   }
+  // Respect the minimum size of the window.
+  if (child->delegate()) {
+    const gfx::Size& min_size = child->delegate()->GetMinimumSize();
+    bounds.set_width(std::max(min_size.width(), bounds.width()));
+    bounds.set_height(std::max(min_size.height(), bounds.height()));
+  }
 
   SetChildBoundsDirect(child, bounds);
   Relayout();
@@ -458,33 +472,46 @@ void PanelLayoutManager::OnShelfAlignmentChanged(aura::Window* root_window) {
 /////////////////////////////////////////////////////////////////////////////
 // PanelLayoutManager, WindowObserver implementation:
 
-void PanelLayoutManager::OnWindowShowTypeChanged(
+void PanelLayoutManager::OnWindowPropertyChanged(aura::Window* window,
+                                                 const void* key,
+                                                 intptr_t old) {
+  // Trigger a relayout to position the panels whenever the panel icon is set
+  // or changes.
+  if (key == kShelfID)
+    Relayout();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// PanelLayoutManager, WindowStateObserver implementation:
+
+void PanelLayoutManager::OnPostWindowStateTypeChange(
     wm::WindowState* window_state,
-    wm::WindowShowType old_type) {
-  // The window property will still be set, but no actual change will occur
-  // until WillChangeVisibilityState is called when the shelf is visible again.
-  if (shelf_hidden_)
+    wm::WindowStateType old_type) {
+  // If the shelf is currently hidden then windows will not actually be shown
+  // but the set to restore when the shelf becomes visible is updated.
+  if (restore_windows_on_shelf_visible_) {
+    if (window_state->IsMinimized()) {
+      MinimizePanel(window_state->window());
+      restore_windows_on_shelf_visible_->Remove(window_state->window());
+    } else {
+      restore_windows_on_shelf_visible_->Add(window_state->window());
+    }
     return;
+  }
+
   if (window_state->IsMinimized())
     MinimizePanel(window_state->window());
   else
     RestorePanel(window_state->window());
 }
 
-void PanelLayoutManager::OnWindowVisibilityChanged(
-    aura::Window* window, bool visible) {
-  if (visible)
-    wm::GetWindowState(window)->Restore();
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // PanelLayoutManager, aura::client::ActivationChangeObserver implementation:
 
 void PanelLayoutManager::OnWindowActivated(aura::Window* gained_active,
                                            aura::Window* lost_active) {
   // Ignore if the panel that is not managed by this was activated.
-  if (gained_active &&
-      gained_active->type() == aura::client::WINDOW_TYPE_PANEL &&
+  if (gained_active && gained_active->type() == ui::wm::WINDOW_TYPE_PANEL &&
       gained_active->parent() == panel_container_) {
     UpdateStacking(gained_active);
     UpdateCallouts();
@@ -506,24 +533,42 @@ void PanelLayoutManager::WillChangeVisibilityState(
   // On entering / leaving full screen mode the shelf visibility state is
   // changed to / from SHELF_HIDDEN. In this state, panel windows should hide
   // to allow the full-screen application to use the full screen.
-  shelf_hidden_ = new_state == ash::SHELF_HIDDEN;
+  bool shelf_hidden = new_state == ash::SHELF_HIDDEN;
+  if (!shelf_hidden) {
+    if (restore_windows_on_shelf_visible_) {
+      scoped_ptr<aura::WindowTracker> restore_windows(
+          restore_windows_on_shelf_visible_.Pass());
+      for (aura::WindowTracker::Windows::const_iterator iter =
+           restore_windows->windows().begin(); iter !=
+           restore_windows->windows().end(); ++iter) {
+        RestorePanel(*iter);
+      }
+    }
+    return;
+  }
+
+  if (restore_windows_on_shelf_visible_)
+    return;
+  scoped_ptr<aura::WindowTracker> minimized_windows(new aura::WindowTracker);
   for (PanelList::iterator iter = panel_windows_.begin();
-       iter != panel_windows_.end(); ++iter) {
-    if (shelf_hidden_) {
-      if (iter->window->IsVisible())
-        MinimizePanel(iter->window);
-    } else {
-      if (!wm::GetWindowState(iter->window)->IsMinimized())
-        RestorePanel(iter->window);
+       iter != panel_windows_.end();) {
+    aura::Window* window = iter->window;
+    // Minimizing a panel window may remove it from the panel_windows_ list.
+    // Advance the iterator before minimizing it: http://crbug.com/393047.
+    ++iter;
+    if (window != dragged_panel_ && window->IsVisible()) {
+      minimized_windows->Add(window);
+      wm::GetWindowState(window)->Minimize();
     }
   }
+  restore_windows_on_shelf_visible_ = minimized_windows.Pass();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // PanelLayoutManager private implementation:
 
 void PanelLayoutManager::MinimizePanel(aura::Window* panel) {
-  views::corewm::SetWindowVisibilityAnimationType(
+  ::wm::SetWindowVisibilityAnimationType(
       panel, WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE);
   ui::Layer* layer = panel->layer();
   ui::ScopedLayerAnimationSettings panel_slide_settings(layer->GetAnimator());
@@ -533,39 +578,36 @@ void PanelLayoutManager::MinimizePanel(aura::Window* panel) {
       base::TimeDelta::FromMilliseconds(kPanelSlideDurationMilliseconds));
   gfx::Rect bounds(panel->bounds());
   bounds.Offset(GetSlideInAnimationOffset(
-      launcher_->shelf_widget()->GetAlignment()));
+      shelf_->shelf_widget()->GetAlignment()));
   SetChildBoundsDirect(panel, bounds);
   panel->Hide();
-  PanelList::iterator found =
-      std::find(panel_windows_.begin(), panel_windows_.end(), panel);
-  if (found != panel_windows_.end()) {
-    layer->SetOpacity(0);
-    // The next time the window is visible it should slide into place.
-    found->slide_in = true;
-  }
+  layer->SetOpacity(0);
   if (wm::IsActiveWindow(panel))
     wm::DeactivateWindow(panel);
   Relayout();
 }
 
 void PanelLayoutManager::RestorePanel(aura::Window* panel) {
-  panel->Show();
+  PanelList::iterator found =
+      std::find(panel_windows_.begin(), panel_windows_.end(), panel);
+  DCHECK(found != panel_windows_.end());
+  found->slide_in = true;
   Relayout();
 }
 
 void PanelLayoutManager::Relayout() {
-  if (!launcher_ || !launcher_->shelf_widget())
+  if (!shelf_ || !shelf_->shelf_widget())
     return;
 
   if (in_layout_)
     return;
   base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
 
-  ShelfAlignment alignment = launcher_->shelf_widget()->GetAlignment();
+  ShelfAlignment alignment = shelf_->shelf_widget()->GetAlignment();
   bool horizontal = alignment == SHELF_ALIGNMENT_TOP ||
                     alignment == SHELF_ALIGNMENT_BOTTOM;
-  gfx::Rect launcher_bounds = ash::ScreenAsh::ConvertRectFromScreen(
-      panel_container_, launcher_->shelf_widget()->GetWindowBoundsInScreen());
+  gfx::Rect shelf_bounds = ash::ScreenUtil::ConvertRectFromScreen(
+      panel_container_, shelf_->shelf_widget()->GetWindowBoundsInScreen());
   int panel_start_bounds = kPanelIdealSpacing;
   int panel_end_bounds = horizontal ?
       panel_container_->bounds().width() - kPanelIdealSpacing :
@@ -578,28 +620,28 @@ void PanelLayoutManager::Relayout() {
     iter->callout_widget->SetAlignment(alignment);
 
     // Consider the dragged panel as part of the layout as long as it is
-    // touching the launcher.
-    if (!panel->IsVisible() ||
+    // touching the shelf.
+    if ((!panel->IsVisible() && !iter->slide_in) ||
         (panel == dragged_panel_ &&
-         !BoundsAdjacent(panel->bounds(), launcher_bounds))) {
+         !BoundsAdjacent(panel->bounds(), shelf_bounds))) {
       continue;
     }
 
-    // If the shelf is currently hidden (full-screen mode), hide panel until
-    // full-screen mode is exited.
-    if (shelf_hidden_) {
-      // The call to Hide does not set the minimize property, so the window will
-      // be restored when the shelf becomes visible again.
-      panel->Hide();
+    // If the shelf is currently hidden (full-screen mode), minimize panel until
+    // full-screen mode is exited. When a panel is dragged from another display
+    // the shelf state does not update before the panel is added so we exclude
+    // the dragged panel.
+    if (panel != dragged_panel_ && restore_windows_on_shelf_visible_) {
+      wm::GetWindowState(panel)->Minimize();
+      restore_windows_on_shelf_visible_->Add(panel);
       continue;
     }
 
-    gfx::Rect icon_bounds =
-        launcher_->GetScreenBoundsOfItemIconForWindow(panel);
+    gfx::Rect icon_bounds = shelf_->GetScreenBoundsOfItemIconForWindow(panel);
 
     // If both the icon width and height are 0 then there is no icon in the
-    // launcher. If the launcher is hidden, one of the height or width will be
-    // 0 but the position in the launcher and major dimension is still reported
+    // shelf. If the shelf is hidden, one of the height or width will be
+    // 0 but the position in the shelf and major dimension is still reported
     // correctly and the panel can be aligned above where the hidden icon is.
     if (icon_bounds.width() == 0 && icon_bounds.height() == 0)
       continue;
@@ -610,8 +652,8 @@ void PanelLayoutManager::Relayout() {
       DCHECK(!active_panel);
       active_panel = panel;
     }
-    icon_bounds = ScreenAsh::ConvertRectFromScreen(panel_container_,
-                                                   icon_bounds);
+    icon_bounds = ScreenUtil::ConvertRectFromScreen(panel_container_,
+                                                    icon_bounds);
     gfx::Point icon_origin = icon_bounds.origin();
     VisiblePanelPositionInfo position_info;
     int icon_start = horizontal ? icon_origin.x() : icon_origin.y();
@@ -658,19 +700,19 @@ void PanelLayoutManager::Relayout() {
     gfx::Rect bounds = visible_panels[i].window->GetTargetBounds();
     switch (alignment) {
       case SHELF_ALIGNMENT_BOTTOM:
-        bounds.set_y(launcher_bounds.y() - bounds.height());
+        bounds.set_y(shelf_bounds.y() - bounds.height());
         break;
       case SHELF_ALIGNMENT_LEFT:
-        bounds.set_x(launcher_bounds.right());
+        bounds.set_x(shelf_bounds.right());
         break;
       case SHELF_ALIGNMENT_RIGHT:
-        bounds.set_x(launcher_bounds.x() - bounds.width());
+        bounds.set_x(shelf_bounds.x() - bounds.width());
         break;
       case SHELF_ALIGNMENT_TOP:
-        bounds.set_y(launcher_bounds.bottom());
+        bounds.set_y(shelf_bounds.bottom());
         break;
     }
-    bool on_launcher = visible_panels[i].window->GetTargetBounds() == bounds;
+    bool on_shelf = visible_panels[i].window->GetTargetBounds() == bounds;
 
     if (horizontal) {
       bounds.set_x(visible_panels[i].major_pos -
@@ -682,15 +724,16 @@ void PanelLayoutManager::Relayout() {
 
     ui::Layer* layer = visible_panels[i].window->layer();
     if (slide_in) {
-      // New windows shift up from the launcher  into position.
+      // New windows shift up from the shelf into position and fade in.
+      layer->SetOpacity(0);
       gfx::Rect initial_bounds(bounds);
       initial_bounds.Offset(GetSlideInAnimationOffset(alignment));
       SetChildBoundsDirect(visible_panels[i].window, initial_bounds);
-      // Set on launcher so that the panel animates into its target position.
-      on_launcher = true;
+      // Set on shelf so that the panel animates into its target position.
+      on_shelf = true;
     }
 
-    if (on_launcher) {
+    if (on_shelf) {
       ui::ScopedLayerAnimationSettings panel_slide_settings(
           layer->GetAnimator());
       panel_slide_settings.SetPreemptionStrategy(
@@ -698,10 +741,12 @@ void PanelLayoutManager::Relayout() {
       panel_slide_settings.SetTransitionDuration(
           base::TimeDelta::FromMilliseconds(kPanelSlideDurationMilliseconds));
       SetChildBoundsDirect(visible_panels[i].window, bounds);
-      if (slide_in)
+      if (slide_in) {
         layer->SetOpacity(1);
+        visible_panels[i].window->Show();
+      }
     } else {
-      // If the launcher moved don't animate, move immediately to the new
+      // If the shelf moved don't animate, move immediately to the new
       // target location.
       SetChildBoundsDirect(visible_panels[i].window, bounds);
     }
@@ -718,7 +763,7 @@ void PanelLayoutManager::UpdateStacking(aura::Window* active_panel) {
     active_panel = last_active_panel_;
   }
 
-  ShelfAlignment alignment = launcher_->alignment();
+  ShelfAlignment alignment = shelf_->alignment();
   bool horizontal = alignment == SHELF_ALIGNMENT_TOP ||
                     alignment == SHELF_ALIGNMENT_BOTTOM;
 
@@ -729,7 +774,7 @@ void PanelLayoutManager::UpdateStacking(aura::Window* active_panel) {
   //
   // We use the middle of each panel to figure out how to stack the panels. This
   // allows us to update the stacking when a panel is being dragged around by
-  // the titlebar--even though it doesn't update the launcher icon positions, we
+  // the titlebar--even though it doesn't update the shelf icon positions, we
   // still want the visual effect.
   std::map<int, aura::Window*> window_ordering;
   for (PanelList::const_iterator it = panel_windows_.begin();
@@ -766,7 +811,7 @@ void PanelLayoutManager::UpdateStacking(aura::Window* active_panel) {
 }
 
 void PanelLayoutManager::UpdateCallouts() {
-  ShelfAlignment alignment = launcher_->alignment();
+  ShelfAlignment alignment = shelf_->alignment();
   bool horizontal = alignment == SHELF_ALIGNMENT_TOP ||
                     alignment == SHELF_ALIGNMENT_BOTTOM;
 
@@ -776,12 +821,12 @@ void PanelLayoutManager::UpdateCallouts() {
     views::Widget* callout_widget = iter->callout_widget;
 
     gfx::Rect current_bounds = panel->GetBoundsInScreen();
-    gfx::Rect bounds = ScreenAsh::ConvertRectToScreen(panel->parent(),
-                                                      panel->GetTargetBounds());
-    gfx::Rect icon_bounds =
-        launcher_->GetScreenBoundsOfItemIconForWindow(panel);
+    gfx::Rect bounds = ScreenUtil::ConvertRectToScreen(
+        panel->parent(),
+        panel->GetTargetBounds());
+    gfx::Rect icon_bounds = shelf_->GetScreenBoundsOfItemIconForWindow(panel);
     if (icon_bounds.IsEmpty() || !panel->layer()->GetTargetVisibility() ||
-        panel == dragged_panel_) {
+        panel == dragged_panel_ || !show_callout_widgets_) {
       callout_widget->Hide();
       callout_widget->GetNativeWindow()->layer()->SetOpacity(0);
       continue;
@@ -819,23 +864,20 @@ void PanelLayoutManager::UpdateCallouts() {
         callout_bounds.set_y(bounds.y() - callout_bounds.height());
         break;
     }
-    callout_bounds = ScreenAsh::ConvertRectFromScreen(
+    callout_bounds = ScreenUtil::ConvertRectFromScreen(
         callout_widget->GetNativeWindow()->parent(),
         callout_bounds);
 
     SetChildBoundsDirect(callout_widget->GetNativeWindow(), callout_bounds);
     panel_container_->StackChildAbove(callout_widget->GetNativeWindow(),
                                       panel);
-    callout_widget->Show();
 
     ui::Layer* layer = callout_widget->GetNativeWindow()->layer();
     // If the panel is not over the callout position or has just become visible
     // then fade in the callout.
-    if ((distance_until_over_panel > 0 || layer->GetTargetOpacity() < 1) &&
-        panel->layer()->GetTargetTransform().IsIdentity()) {
+    if ((distance_until_over_panel > 0 || layer->GetTargetOpacity() < 1)) {
       if (distance_until_over_panel > 0 &&
           slide_distance >= distance_until_over_panel) {
-        layer->SetOpacity(0);
         // If the panel is not yet over the callout, then delay fading in
         // the callout until after the panel should be over it.
         int delay = kPanelSlideDurationMilliseconds *
@@ -846,16 +888,18 @@ void PanelLayoutManager::UpdateCallouts() {
             base::TimeDelta::FromMilliseconds(delay),
             ui::LayerAnimationElement::OPACITY);
       }
-      {
-        ui::ScopedLayerAnimationSettings callout_settings(layer->GetAnimator());
-        callout_settings.SetPreemptionStrategy(
-            ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
-        callout_settings.SetTransitionDuration(
-            base::TimeDelta::FromMilliseconds(
-                kCalloutFadeDurationMilliseconds));
-        layer->SetOpacity(1);
-      }
+      ui::ScopedLayerAnimationSettings callout_settings(layer->GetAnimator());
+      callout_settings.SetPreemptionStrategy(
+          ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
+      callout_settings.SetTransitionDuration(
+          base::TimeDelta::FromMilliseconds(
+              kCalloutFadeDurationMilliseconds));
+      layer->SetOpacity(1);
     }
+
+    // Show after changing the opacity animation. This way we don't have a
+    // state where the widget is visible but the opacity is 0.
+    callout_widget->Show();
   }
 }
 
@@ -864,10 +908,38 @@ void PanelLayoutManager::UpdateCallouts() {
 
 void PanelLayoutManager::OnKeyboardBoundsChanging(
     const gfx::Rect& keyboard_bounds) {
+  gfx::Rect parent_bounds = panel_container_->bounds();
+  int available_space = parent_bounds.height() - keyboard_bounds.height();
+  for (PanelList::iterator iter = panel_windows_.begin();
+       iter != panel_windows_.end();
+       ++iter) {
+    aura::Window* panel = iter->window;
+    wm::WindowState* panel_state = wm::GetWindowState(panel);
+    if (keyboard_bounds.height() > 0) {
+      // Save existing bounds, so that we can restore them when the keyboard
+      // hides.
+      panel_state->SaveCurrentBoundsForRestore();
+
+      gfx::Rect panel_bounds = ScreenUtil::ConvertRectToScreen(
+          panel->parent(), panel->GetTargetBounds());
+      int delta = panel_bounds.height() - available_space;
+      // Ensure panels are not pushed above the parent boundaries, shrink any
+      // panels that violate this constraint.
+      if (delta > 0) {
+        SetChildBounds(panel,
+                       gfx::Rect(panel_bounds.x(),
+                                 panel_bounds.y() + delta,
+                                 panel_bounds.width(),
+                                 panel_bounds.height() - delta));
+      }
+    } else if (panel_state->HasRestoreBounds()) {
+      // Keyboard hidden, restore original bounds if they exist.
+      SetChildBounds(panel, panel_state->GetRestoreBoundsInScreen());
+    }
+  }
   // This bounds change will have caused a change to the Shelf which does not
   // propogate automatically to this class, so manually recalculate bounds.
   OnWindowResized();
 }
 
-}  // namespace internal
 }  // namespace ash