diff options
author | flackr@chromium.org <flackr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-20 15:19:04 +0000 |
---|---|---|
committer | flackr@chromium.org <flackr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-20 15:19:04 +0000 |
commit | 582022050957ad3a4ec42eaab9f20177ec13e9e2 (patch) | |
tree | 555f4f6e685f13633c9c477bbc8fad0f5441be50 /ash | |
parent | cd5664d9be154b4f051c47688803918a1a37d207 (diff) | |
download | chromium_src-582022050957ad3a4ec42eaab9f20177ec13e9e2.zip chromium_src-582022050957ad3a4ec42eaab9f20177ec13e9e2.tar.gz chromium_src-582022050957ad3a4ec42eaab9f20177ec13e9e2.tar.bz2 |
Allow detaching and reattaching panels when dragged from/to launcher.
BUG=160646
TEST=PanelWindowResizerTest.PanelDetachReattach
Review URL: https://chromiumcodereview.appspot.com/12281005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@183538 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r-- | ash/ash.gyp | 5 | ||||
-rw-r--r-- | ash/root_window_controller.cc | 6 | ||||
-rw-r--r-- | ash/root_window_controller.h | 1 | ||||
-rw-r--r-- | ash/wm/panel_layout_manager.cc | 12 | ||||
-rw-r--r-- | ash/wm/panel_layout_manager.h | 2 | ||||
-rw-r--r-- | ash/wm/panel_window_event_filter.cc | 115 | ||||
-rw-r--r-- | ash/wm/panel_window_event_filter.h | 60 | ||||
-rw-r--r-- | ash/wm/panel_window_resizer.cc | 126 | ||||
-rw-r--r-- | ash/wm/panel_window_resizer.h | 88 | ||||
-rw-r--r-- | ash/wm/panel_window_resizer_unittest.cc | 137 | ||||
-rw-r--r-- | ash/wm/stacking_controller.cc | 11 | ||||
-rw-r--r-- | ash/wm/window_properties.cc | 1 | ||||
-rw-r--r-- | ash/wm/window_properties.h | 3 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_window_resizer.cc | 7 |
14 files changed, 384 insertions, 190 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp index ef1872d..7330065 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -353,8 +353,8 @@ 'wm/panel_frame_view.h', 'wm/panel_layout_manager.cc', 'wm/panel_layout_manager.h', - 'wm/panel_window_event_filter.cc', - 'wm/panel_window_event_filter.h', + 'wm/panel_window_resizer.cc', + 'wm/panel_window_resizer.h', 'wm/partial_screenshot_view.cc', 'wm/partial_screenshot_view.h', 'wm/power_button_controller.cc', @@ -626,6 +626,7 @@ 'wm/drag_window_resizer_unittest.cc', 'wm/frame_painter_unittest.cc', 'wm/panel_layout_manager_unittest.cc', + 'wm/panel_window_resizer_unittest.cc', 'wm/power_button_controller_unittest.cc', 'wm/screen_dimmer_unittest.cc', 'wm/session_state_controller_impl2_unittest.cc', diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc index 19132d0..71c9101 100644 --- a/ash/root_window_controller.cc +++ b/ash/root_window_controller.cc @@ -22,7 +22,6 @@ #include "ash/wm/base_layout_manager.h" #include "ash/wm/boot_splash_screen.h" #include "ash/wm/panel_layout_manager.h" -#include "ash/wm/panel_window_event_filter.h" #include "ash/wm/property_util.h" #include "ash/wm/root_window_layout_manager.h" #include "ash/wm/screen_dimmer.h" @@ -305,9 +304,8 @@ void RootWindowController::InitForPrimaryDisplay() { internal::kShellWindowId_PanelContainer); panel_layout_manager_ = new internal::PanelLayoutManager(panel_container); - panel_container->AddPreTargetHandler( - new internal::PanelWindowEventFilter( - panel_container, panel_layout_manager_)); + panel_container_handler_.reset( + new ToplevelWindowEventHandler(panel_container)); panel_container->SetLayoutManager(panel_layout_manager_); } diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h index 4c6356b..83865c0 100644 --- a/ash/root_window_controller.h +++ b/ash/root_window_controller.h @@ -203,6 +203,7 @@ class ASH_EXPORT RootWindowController { scoped_ptr<ToplevelWindowEventHandler> always_on_top_container_handler_; scoped_ptr<ToplevelWindowEventHandler> modal_container_handler_; scoped_ptr<ToplevelWindowEventHandler> lock_modal_container_handler_; + scoped_ptr<ToplevelWindowEventHandler> panel_container_handler_; DISALLOW_COPY_AND_ASSIGN(RootWindowController); }; diff --git a/ash/wm/panel_layout_manager.cc b/ash/wm/panel_layout_manager.cc index aee2ca5..b7b6fc4 100644 --- a/ash/wm/panel_layout_manager.cc +++ b/ash/wm/panel_layout_manager.cc @@ -172,7 +172,8 @@ void PanelLayoutManager::StartDragging(aura::Window* panel) { } void PanelLayoutManager::FinishDragging() { - DCHECK(dragged_panel_); + // Note, dragged panel may be null if the panel was just attached to the + // panel layout. dragged_panel_ = NULL; Relayout(); } @@ -207,6 +208,9 @@ void PanelLayoutManager::OnWindowAddedToLayout(aura::Window* child) { } void PanelLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) { +} + +void PanelLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) { PanelList::iterator found = std::find(panel_windows_.begin(), panel_windows_.end(), child); if (found != panel_windows_.end()) @@ -222,9 +226,6 @@ void PanelLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) { Relayout(); } -void PanelLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) { -} - void PanelLayoutManager::OnChildWindowVisibilityChanged(aura::Window* child, bool visible) { Relayout(); @@ -303,8 +304,7 @@ void PanelLayoutManager::OnWindowActivated(aura::Window* gained_active, // Ignore if the panel that is not managed by this was activated. if (gained_active && gained_active->type() == aura::client::WINDOW_TYPE_PANEL && - gained_active->GetRootWindow() == - launcher_->widget()->GetNativeView()->GetRootWindow()) { + gained_active->parent() == panel_container_) { UpdateStacking(gained_active); UpdateCallout(gained_active); } else { diff --git a/ash/wm/panel_layout_manager.h b/ash/wm/panel_layout_manager.h index 9b22e06..9c94fef 100644 --- a/ash/wm/panel_layout_manager.h +++ b/ash/wm/panel_layout_manager.h @@ -60,6 +60,7 @@ class ASH_EXPORT PanelLayoutManager void ToggleMinimize(aura::Window* panel); + ash::Launcher* launcher() { return launcher_; } void SetLauncher(ash::Launcher* launcher); // Overridden from aura::LayoutManager: @@ -88,6 +89,7 @@ class ASH_EXPORT PanelLayoutManager private: friend class PanelLayoutManagerTest; + friend class PanelWindowResizerTest; typedef std::list<aura::Window*> PanelList; diff --git a/ash/wm/panel_window_event_filter.cc b/ash/wm/panel_window_event_filter.cc deleted file mode 100644 index f101386..0000000 --- a/ash/wm/panel_window_event_filter.cc +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/panel_window_event_filter.h" - -#include "ash/wm/window_util.h" -#include "base/message_loop.h" -#include "ui/aura/client/aura_constants.h" -#include "ui/aura/root_window.h" -#include "ui/aura/window.h" -#include "ui/aura/window_delegate.h" -#include "ui/base/cursor/cursor.h" -#include "ui/base/events/event.h" -#include "ui/base/hit_test.h" -#include "ui/base/ui_base_types.h" -#include "ui/compositor/scoped_layer_animation_settings.h" -#include "ui/gfx/screen.h" - -namespace ash { -namespace internal { - -PanelWindowEventFilter::PanelWindowEventFilter( - aura::Window* panel_container, - PanelLayoutManager* layout_manager) - : panel_container_(panel_container), - layout_manager_(layout_manager), - dragged_panel_(NULL), - drag_state_(DRAG_NONE) { - panel_container_->AddObserver(this); -} - -PanelWindowEventFilter::~PanelWindowEventFilter() { - panel_container_->RemoveObserver(this); - panel_container_->RemovePreTargetHandler(this); -} - -void PanelWindowEventFilter::OnMouseEvent(ui::MouseEvent* event) { - aura::Window* target = static_cast<aura::Window*>(event->target()); - switch (event->type()) { - case ui::ET_MOUSE_PRESSED: { - int hitResult = target->delegate()-> - GetNonClientComponent(event->location()); - if (hitResult == HTCAPTION) { - if (drag_state_ == DRAG_NONE) { - dragged_panel_ = target; - drag_location_in_dragged_window_ = event->location(); - drag_state_ = DRAG_CLICKED; - event->StopPropagation(); - } - } - return; - } - - case ui::ET_MOUSE_DRAGGED: - if (drag_state_ == DRAG_CLICKED) { - drag_state_ = DRAG_STARTED; - layout_manager_->StartDragging(dragged_panel_); - } - if (drag_state_ == DRAG_STARTED && HandleDrag(target, event)) - event->StopPropagation(); - return; - - case ui::ET_MOUSE_CAPTURE_CHANGED: - if (drag_state_ == DRAG_STARTED) { - FinishDrag(); - event->StopPropagation(); - } else if (drag_state_ == DRAG_CLICKED) { - drag_state_ = DRAG_NONE; - dragged_panel_ = NULL; - event->StopPropagation(); - } - return; - - case ui::ET_MOUSE_RELEASED: - if (drag_state_ == DRAG_STARTED) { - FinishDrag(); - event->StopPropagation(); - } else if (dragged_panel_ != NULL) { - drag_state_ = DRAG_NONE; - dragged_panel_ = NULL; - event->StopPropagation(); - } - return; - default: - return; - } -} - -void PanelWindowEventFilter::OnWindowDestroying(aura::Window* window) { - CHECK_EQ(panel_container_, window); - delete this; -} - -bool PanelWindowEventFilter::HandleDrag(aura::Window* target, - ui::LocatedEvent* event) { - gfx::Rect target_bounds = dragged_panel_->bounds(); - gfx::Point event_location_in_parent(event->location()); - aura::Window::ConvertPointToTarget(target, - target->parent(), - &event_location_in_parent); - target_bounds.set_x( - event_location_in_parent.x() - drag_location_in_dragged_window_.x()); - dragged_panel_->SetBounds(target_bounds); - return true; -} - -void PanelWindowEventFilter::FinishDrag() { - layout_manager_->FinishDragging(); - drag_state_ = DRAG_NONE; - dragged_panel_ = NULL; -} - -} -} diff --git a/ash/wm/panel_window_event_filter.h b/ash/wm/panel_window_event_filter.h deleted file mode 100644 index 4a12338..0000000 --- a/ash/wm/panel_window_event_filter.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_PANEL_WINDOW_EVENT_FILTER_H -#define ASH_WM_PANEL_WINDOW_EVENT_FILTER_H - -#include "ash/wm/panel_layout_manager.h" -#include "ui/aura/window_observer.h" -#include "ui/base/events/event_handler.h" -#include "ui/gfx/point.h" -#include "ui/gfx/rect.h" - -namespace aura { -class Window; -} - -namespace ui { -class LocatedEvent; -} - -namespace ash { -namespace internal { - -class PanelWindowEventFilter : public ui::EventHandler, - public aura::WindowObserver { - public: - PanelWindowEventFilter(aura::Window* panel_container, - PanelLayoutManager* layout_manager); - virtual ~PanelWindowEventFilter(); - - // Overriden from ui::EventHandler: - virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE; - - // Overridden from aura::WindowObserver: - virtual void OnWindowDestroying(aura::Window* window) OVERRIDE; - - private: - enum DragState { - DRAG_NONE, - DRAG_CLICKED, - DRAG_STARTED - }; - - bool HandleDrag(aura::Window* target, ui::LocatedEvent* event); - void FinishDrag(); - - aura::Window* panel_container_; - PanelLayoutManager* layout_manager_; - gfx::Point drag_origin_; - gfx::Point drag_location_in_dragged_window_; - aura::Window* dragged_panel_; - DragState drag_state_; - - DISALLOW_COPY_AND_ASSIGN(PanelWindowEventFilter); -}; - -} -} -#endif // ASH_WM_PANEL_EVENT_FILTER_H diff --git a/ash/wm/panel_window_resizer.cc b/ash/wm/panel_window_resizer.cc new file mode 100644 index 0000000..fee35a5 --- /dev/null +++ b/ash/wm/panel_window_resizer.cc @@ -0,0 +1,126 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/wm/panel_window_resizer.h" + +#include "ash/launcher/launcher.h" +#include "ash/root_window_controller.h" +#include "ash/shell.h" +#include "ash/shell_window_ids.h" +#include "ash/wm/cursor_manager.h" +#include "ash/wm/panel_layout_manager.h" +#include "ash/wm/property_util.h" +#include "ash/wm/window_properties.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/env.h" +#include "ui/aura/root_window.h" +#include "ui/aura/window.h" +#include "ui/aura/window_delegate.h" +#include "ui/base/hit_test.h" +#include "ui/base/ui_base_types.h" +#include "ui/gfx/screen.h" +#include "ui/views/widget/widget.h" + +namespace ash { + +namespace { +const int kPanelSnapToLauncherDistance = 30; +} // namespace + +PanelWindowResizer::~PanelWindowResizer() { + ash::Shell::GetInstance()->cursor_manager()->UnlockCursor(); +} + +// static +PanelWindowResizer* +PanelWindowResizer::Create(aura::Window* window, + const gfx::Point& location, + int window_component) { + Details details(window, location, window_component); + return details.is_resizable ? new PanelWindowResizer(details) : NULL; +} + +void PanelWindowResizer::Drag(const gfx::Point& location, int event_flags) { + gfx::Rect bounds(CalculateBoundsForDrag(details_, location)); + if (bounds != details_.window->bounds()) { + if (!did_move_or_resize_) { + if (!details_.restore_bounds.IsEmpty()) + ClearRestoreBounds(details_.window); + StartedDragging(); + } + did_move_or_resize_ = true; + should_attach_ = AttachToLauncher(&bounds); + details_.window->SetBounds(bounds); + } +} + +void PanelWindowResizer::CompleteDrag(int event_flags) { + if (should_attach_ != was_attached_) { + details_.window->SetProperty(internal::kPanelAttachedKey, should_attach_); + details_.window->SetDefaultParentByRootWindow( + details_.window->GetRootWindow(), + details_.window->bounds()); + } + FinishDragging(); +} + +void PanelWindowResizer::RevertDrag() { + if (!did_move_or_resize_) + return; + + details_.window->SetBounds(details_.initial_bounds_in_parent); + + if (!details_.restore_bounds.IsEmpty()) + SetRestoreBoundsInScreen(details_.window, details_.restore_bounds); + FinishDragging(); +} + +aura::Window* PanelWindowResizer::GetTarget() { + return details_.window; +} + +PanelWindowResizer::PanelWindowResizer(const Details& details) + : details_(details), + panel_container_(NULL), + panel_layout_manager_(NULL), + did_move_or_resize_(false), + was_attached_(details_.window->GetProperty(internal::kPanelAttachedKey)), + should_attach_(was_attached_) { + DCHECK(details_.is_resizable); + ash::internal::RootWindowController* root_window_controller = + GetRootWindowController(details.window->GetRootWindow()); + panel_container_ = root_window_controller->GetContainer( + internal::kShellWindowId_PanelContainer); + if (panel_container_) { + panel_layout_manager_ = static_cast<internal::PanelLayoutManager*>( + panel_container_->layout_manager()); + } + ash::Shell::GetInstance()->cursor_manager()->LockCursor(); +} + +bool PanelWindowResizer::AttachToLauncher(gfx::Rect* bounds) { + bool should_attach = false; + if (panel_layout_manager_) { + int launcher_top = panel_layout_manager_->launcher()->widget()-> + GetWindowBoundsInScreen().y(); + if (bounds->y() >= (launcher_top - bounds->height() - + kPanelSnapToLauncherDistance)) { + should_attach = true; + bounds->set_y(launcher_top - bounds->height()); + } + } + return should_attach; +} + +void PanelWindowResizer::StartedDragging() { + if (was_attached_) + panel_layout_manager_->StartDragging(details_.window); +} + +void PanelWindowResizer::FinishDragging() { + if (was_attached_) + panel_layout_manager_->FinishDragging(); +} + +} // namespace aura diff --git a/ash/wm/panel_window_resizer.h b/ash/wm/panel_window_resizer.h new file mode 100644 index 0000000..93cbb30 --- /dev/null +++ b/ash/wm/panel_window_resizer.h @@ -0,0 +1,88 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_WM_PANEL_WINDOW_RESIZER_H_ +#define ASH_WM_PANEL_WINDOW_RESIZER_H_ + +#include "ash/wm/window_resizer.h" +#include "base/compiler_specific.h" + +namespace gfx { +class Rect; +} + +namespace ash { + +namespace internal { +class PanelLayoutManager; +} + +// PanelWindowResizer is used by ToplevelWindowEventFilter to handle dragging, +// moving or resizing panel window. These can be attached and detached from the +// launcher. +class ASH_EXPORT PanelWindowResizer : public WindowResizer { + public: + virtual ~PanelWindowResizer(); + + // Creates a new PanelWindowResizer. The caller takes ownership of the + // returned object. Returns NULL if not resizable. + static PanelWindowResizer* Create(aura::Window* window, + const gfx::Point& location, + int window_component); + + // Returns true if the drag will result in changing the window in anyway. + bool is_resizable() const { return details_.is_resizable; } + + bool changed_size() const { + return !(details_.bounds_change & kBoundsChange_Repositions); + } + + // WindowResizer overides: + virtual void Drag(const gfx::Point& location, int event_flags) OVERRIDE; + virtual void CompleteDrag(int event_flags) OVERRIDE; + virtual void RevertDrag() OVERRIDE; + virtual aura::Window* GetTarget() OVERRIDE; + + const gfx::Point& GetInitialLocationInParentForTest() const { + return details_.initial_location_in_parent; + } + + private: + explicit PanelWindowResizer(const Details& details); + + // Checks if the provided window bounds should attach to the launcher. If true + // the bounds are modified to snap the window to the launcher. + bool AttachToLauncher(gfx::Rect* bounds); + + // Tracks the panel's initial position and attachment at the start of a drag + // and informs the PanelLayoutManager that a drag has started if necessary. + void StartedDragging(); + + // Informs the PanelLayoutManager that the drag is complete if it was informed + // of the drag start. + void FinishDragging(); + + const Details details_; + + // Panel container window. + aura::Window* panel_container_; + + // Weak pointer, owned by panel container. + internal::PanelLayoutManager* panel_layout_manager_; + + // Set to true once Drag() is invoked and the bounds of the window change. + bool did_move_or_resize_; + + // True if the window started attached to the launcher. + const bool was_attached_; + + // True if the window should attach to the launcher after releasing. + bool should_attach_; + + DISALLOW_COPY_AND_ASSIGN(PanelWindowResizer); +}; + +} // namespace aura + +#endif // ASH_WM_PANEL_WINDOW_RESIZER_H_ diff --git a/ash/wm/panel_window_resizer_unittest.cc b/ash/wm/panel_window_resizer_unittest.cc new file mode 100644 index 0000000..aff789d --- /dev/null +++ b/ash/wm/panel_window_resizer_unittest.cc @@ -0,0 +1,137 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/wm/panel_window_resizer.h" + +#include "ash/launcher/launcher.h" +#include "ash/root_window_controller.h" +#include "ash/shell.h" +#include "ash/shell_window_ids.h" +#include "ash/test/ash_test_base.h" +#include "ash/test/cursor_manager_test_api.h" +#include "ash/test/test_launcher_delegate.h" +#include "ash/wm/panel_layout_manager.h" +#include "ash/wm/window_properties.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/root_window.h" +#include "ui/aura/test/test_window_delegate.h" +#include "ui/base/hit_test.h" +#include "ui/base/ui_base_types.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace internal { + +class PanelWindowResizerTest : public test::AshTestBase { + public: + PanelWindowResizerTest() : window_(NULL) {} + virtual ~PanelWindowResizerTest() {} + + virtual void SetUp() OVERRIDE { + AshTestBase::SetUp(); + window_.reset(CreatePanelWindow(gfx::Rect(0, 0, 201, 201))); + + panel_layout_manager_ = static_cast<internal::PanelLayoutManager*>( + GetPanelContainer()->layout_manager()); + launcher_top_ = panel_layout_manager_->launcher()->widget()-> + GetWindowBoundsInScreen().y(); + EXPECT_EQ(launcher_top_, window_->bounds().bottom()); + } + + virtual void TearDown() OVERRIDE { + window_.reset(); + AshTestBase::TearDown(); + } + + protected: + gfx::Point CalculateDragPoint(const PanelWindowResizer& resizer, + int delta_x, + int delta_y) const { + gfx::Point location = resizer.GetInitialLocationInParentForTest(); + location.set_x(location.x() + delta_x); + location.set_y(location.y() + delta_y); + return location; + } + + aura::Window* CreatePanelWindow(const gfx::Rect& bounds) { + aura::Window* window = CreateTestWindowInShellWithDelegateAndType( + NULL, + aura::client::WINDOW_TYPE_PANEL, + 0, + bounds); + test::TestLauncherDelegate* launcher_delegate = + test::TestLauncherDelegate::instance(); + launcher_delegate->AddLauncherItem(window); + PanelLayoutManager* manager = + static_cast<PanelLayoutManager*>(GetPanelContainer()->layout_manager()); + manager->Relayout(); + return window; + } + + aura::Window* GetPanelContainer() { + return Shell::GetContainer( + Shell::GetPrimaryRootWindow(), + internal::kShellWindowId_PanelContainer); + } + + static PanelWindowResizer* CreatePanelWindowResizer( + aura::Window* window, + const gfx::Point& point_in_parent, + int window_component) { + return static_cast<PanelWindowResizer*>(CreateWindowResizer( + window, point_in_parent, window_component).release()); + } + + aura::test::TestWindowDelegate delegate_; + scoped_ptr<aura::Window> window_; + aura::Window* panel_container_; + internal::PanelLayoutManager* panel_layout_manager_; + int launcher_top_; + + private: + DISALLOW_COPY_AND_ASSIGN(PanelWindowResizerTest); +}; + +// Verifies a window can be dragged from the panel and detached and then +// reattached. +TEST_F(PanelWindowResizerTest, PanelDetachReattach) { + EXPECT_TRUE(window_->GetProperty(kPanelAttachedKey)); + { + scoped_ptr<PanelWindowResizer> resizer(CreatePanelWindowResizer( + window_.get(), gfx::Point(), HTCAPTION)); + ASSERT_TRUE(resizer.get()); + gfx::Rect initial_bounds = window_->bounds(); + + // Drag the panel up slightly. The window should still be snapped to the + // launcher. + resizer->Drag(CalculateDragPoint(*resizer, 0, -5), 0); + EXPECT_EQ(initial_bounds.y(), window_->bounds().y()); + + // Drag further up and the window should now move to the cursor. + resizer->Drag(CalculateDragPoint(*resizer, 0, -100), 0); + EXPECT_EQ(initial_bounds.y() - 100, window_->bounds().y()); + + resizer->CompleteDrag(0); + } + // The panel should be detached. + EXPECT_FALSE(window_->GetProperty(kPanelAttachedKey)); + + { + scoped_ptr<PanelWindowResizer> resizer(CreatePanelWindowResizer( + window_.get(), gfx::Point(), HTCAPTION)); + ASSERT_TRUE(resizer.get()); + gfx::Rect initial_bounds = window_->bounds(); + + // Drag the panel down. + resizer->Drag(CalculateDragPoint(*resizer, 0, 95), 0); + // Release the mouse and the panel should be reattached. + resizer->CompleteDrag(0); + } + // The panel should be reattached and have snapped to the launcher. + EXPECT_TRUE(window_->GetProperty(kPanelAttachedKey)); + EXPECT_EQ(launcher_top_, window_->bounds().bottom()); +} + +} // namespace internal +} // namespace ash diff --git a/ash/wm/stacking_controller.cc b/ash/wm/stacking_controller.cc index a9df31d..18b87fb 100644 --- a/ash/wm/stacking_controller.cc +++ b/ash/wm/stacking_controller.cc @@ -49,6 +49,10 @@ bool IsWindowModal(aura::Window* window) { window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_WINDOW; } +bool IsPanelAttached(aura::Window* window) { + return window->GetProperty(internal::kPanelAttachedKey); +} + } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -86,8 +90,11 @@ aura::Window* StackingController::GetDefaultParent(aura::Window* context, return GetContainerById( target_root, internal::kShellWindowId_UnparentedControlContainer); case aura::client::WINDOW_TYPE_PANEL: - return GetContainerById(target_root, - internal::kShellWindowId_PanelContainer); + if (IsPanelAttached(window)) + return GetContainerById(target_root, + internal::kShellWindowId_PanelContainer); + else + return GetAlwaysOnTopController(target_root)->GetContainer(window); case aura::client::WINDOW_TYPE_MENU: return GetContainerById( target_root, internal::kShellWindowId_MenuContainer); diff --git a/ash/wm/window_properties.cc b/ash/wm/window_properties.cc index a52ab21..493cea7 100644 --- a/ash/wm/window_properties.cc +++ b/ash/wm/window_properties.cc @@ -23,6 +23,7 @@ DEFINE_OWNED_WINDOW_PROPERTY_KEY(ash::internal::AlwaysOnTopController, DEFINE_WINDOW_PROPERTY_KEY(bool, kIgnoreSoloWindowFramePainterPolicy, false); DEFINE_WINDOW_PROPERTY_KEY(bool, kIgnoredByShelfKey, false); DEFINE_WINDOW_PROPERTY_KEY(bool, kImmersiveModeKey, false); +DEFINE_WINDOW_PROPERTY_KEY(bool, kPanelAttachedKey, true); DEFINE_WINDOW_PROPERTY_KEY( ui::WindowShowState, kRestoreShowStateKey, ui::SHOW_STATE_DEFAULT); DEFINE_WINDOW_PROPERTY_KEY(RootWindowController*, diff --git a/ash/wm/window_properties.h b/ash/wm/window_properties.h index 38d9cf9..41144c9 100644 --- a/ash/wm/window_properties.h +++ b/ash/wm/window_properties.h @@ -42,6 +42,9 @@ extern const aura::WindowProperty<bool>* const // True if this is a browser window in immersive mode. ASH_EXPORT extern const aura::WindowProperty<bool>* const kImmersiveModeKey; +// True if this window is an attached panel. +ASH_EXPORT extern const aura::WindowProperty<bool>* const kPanelAttachedKey; + // Used to remember the show state before the window was minimized. extern const aura::WindowProperty<ui::WindowShowState>* const kRestoreShowStateKey; diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc index 62ef772..748edf5 100644 --- a/ash/wm/workspace/workspace_window_resizer.cc +++ b/ash/wm/workspace/workspace_window_resizer.cc @@ -17,11 +17,13 @@ #include "ash/wm/cursor_manager.h" #include "ash/wm/default_window_resizer.h" #include "ash/wm/drag_window_resizer.h" +#include "ash/wm/panel_window_resizer.h" #include "ash/wm/property_util.h" #include "ash/wm/window_util.h" #include "ash/wm/workspace/phantom_window_controller.h" #include "ash/wm/workspace/snap_sizer.h" #include "ui/aura/client/aura_constants.h" +#include "ui/aura/client/window_types.h" #include "ui/aura/root_window.h" #include "ui/aura/window.h" #include "ui/aura/window_delegate.h" @@ -41,7 +43,10 @@ scoped_ptr<WindowResizer> CreateWindowResizer(aura::Window* window, return scoped_ptr<WindowResizer>(); WindowResizer* window_resizer = NULL; - if (window->parent() && + if (window->type() == aura::client::WINDOW_TYPE_PANEL) { + window_resizer = PanelWindowResizer::Create( + window, point_in_parent, window_component); + } else if (window->parent() && window->parent()->id() == internal::kShellWindowId_WorkspaceContainer) { // Allow dragging maximized windows if it's not tracked by workspace. This // is set by tab dragging code. |