diff options
-rw-r--r-- | ash/wm/frame_painter.cc | 17 | ||||
-rw-r--r-- | ash/wm/workspace/workspace2.cc | 8 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_layout_manager2.cc | 15 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_manager2.cc | 53 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_manager2.h | 2 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_manager2_unittest.cc | 41 | ||||
-rw-r--r-- | chrome/browser/ui/views/tabs/tab_drag_controller.cc | 3 | ||||
-rw-r--r-- | chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc | 54 |
8 files changed, 178 insertions, 15 deletions
diff --git a/ash/wm/frame_painter.cc b/ash/wm/frame_painter.cc index 568438f..fc950ae 100644 --- a/ash/wm/frame_painter.cc +++ b/ash/wm/frame_painter.cc @@ -8,6 +8,7 @@ #include "ash/shell.h" #include "ash/shell_window_ids.h" #include "ash/wm/property_util.h" +#include "ash/wm/window_properties.h" #include "ash/wm/window_util.h" #include "ash/wm/workspace_controller.h" #include "base/logging.h" // DCHECK @@ -475,7 +476,8 @@ void FramePainter::LayoutHeader(views::NonClientFrameView* view, bool shorter_layout) { // The new assets only make sense if the window is actually maximized. if (internal::WorkspaceController::IsWorkspace2Enabled() && - shorter_layout && frame_->IsMaximized()) { + shorter_layout && frame_->IsMaximized() && + GetTrackedByWorkspace(frame_->GetNativeWindow())) { SetButtonImages(close_button_, IDR_AURA_WINDOW_MAXIMIZED_CLOSE2, IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_H, @@ -537,6 +539,13 @@ void FramePainter::LayoutHeader(views::NonClientFrameView* view, void FramePainter::OnWindowPropertyChanged(aura::Window* window, const void* key, intptr_t old) { + if (key == internal::kWindowTrackedByWorkspaceKey && + GetTrackedByWorkspace(window)) { + // When 'kWindowTrackedByWorkspaceKey' changes we're going to paint the + // header differently. Schedule a paint to ensure everything is updated + // correctly. + frame_->non_client_view()->SchedulePaint(); + } if (key != aura::client::kShowStateKey) return; @@ -627,9 +636,11 @@ int FramePainter::GetHeaderOpacity(HeaderMode header_mode, if (theme_frame_overlay) return kFullyOpaque; - // Maximized windows with workspace2 are totally transparent. + // Maximized windows with workspace2 are totally transparent, except those not + // tracked by workspace code (which are used for tab dragging). if (frame_->IsMaximized() && - internal::WorkspaceController::IsWorkspace2Enabled()) + internal::WorkspaceController::IsWorkspace2Enabled() && + GetTrackedByWorkspace(frame_->GetNativeWindow())) return 0; // Single browser window is very transparent. diff --git a/ash/wm/workspace/workspace2.cc b/ash/wm/workspace/workspace2.cc index 03567b6..089e83c 100644 --- a/ash/wm/workspace/workspace2.cc +++ b/ash/wm/workspace/workspace2.cc @@ -63,7 +63,8 @@ bool Workspace2::ShouldMoveToPending() const { bool has_visible_non_maximized_window = false; for (size_t i = 0; i < window_->children().size(); ++i) { aura::Window* child(window_->children()[i]); - if (!child->TargetVisibility() || wm::IsWindowMinimized(child)) + if (!GetTrackedByWorkspace(child) || !child->TargetVisibility() || + wm::IsWindowMinimized(child)) continue; if (WorkspaceManager2::IsMaximized(child)) return false; @@ -78,8 +79,9 @@ int Workspace2::GetNumMaximizedWindows() const { int count = 0; for (size_t i = 0; i < window_->children().size(); ++i) { aura::Window* child = window_->children()[i]; - if (WorkspaceManager2::IsMaximized(child) || - WorkspaceManager2::WillRestoreMaximized(child)) { + if (GetTrackedByWorkspace(child) && + (WorkspaceManager2::IsMaximized(child) || + WorkspaceManager2::WillRestoreMaximized(child))) { if (++count == 2) return count; } diff --git a/ash/wm/workspace/workspace_layout_manager2.cc b/ash/wm/workspace/workspace_layout_manager2.cc index 8f966f7..7f3be99 100644 --- a/ash/wm/workspace/workspace_layout_manager2.cc +++ b/ash/wm/workspace/workspace_layout_manager2.cc @@ -129,6 +129,10 @@ void WorkspaceLayoutManager2::OnChildWindowVisibilityChanged(Window* child, void WorkspaceLayoutManager2::SetChildBounds( Window* child, const gfx::Rect& requested_bounds) { + if (!GetTrackedByWorkspace(child)) { + SetChildBoundsDirect(child, requested_bounds); + return; + } gfx::Rect child_bounds(requested_bounds); // Some windows rely on this to set their initial bounds. if (!SetMaximizedOrFullscreenBounds(child)) @@ -211,6 +215,11 @@ void WorkspaceLayoutManager2::OnWindowPropertyChanged(Window* window, SetRestoreBoundsInScreen(window, restore); } + if (key == internal::kWindowTrackedByWorkspaceKey && + GetTrackedByWorkspace(window)) { + workspace_manager()->OnTrackedByWorkspaceChanged(workspace_, window); + } + if (key == aura::client::kAlwaysOnTopKey && window->GetProperty(aura::client::kAlwaysOnTopKey)) { internal::AlwaysOnTopController* controller = @@ -274,7 +283,8 @@ void WorkspaceLayoutManager2::AdjustWindowSizesForScreenChange( void WorkspaceLayoutManager2::AdjustWindowSizeForScreenChange( Window* window, AdjustWindowReason reason) { - if (!SetMaximizedOrFullscreenBounds(window)) { + if (GetTrackedByWorkspace(window) && + !SetMaximizedOrFullscreenBounds(window)) { if (reason == ADJUST_WINDOW_SCREEN_SIZE_CHANGED) { // The work area may be smaller than the full screen. Put as much of the // window as possible within the display area. @@ -339,6 +349,9 @@ void WorkspaceLayoutManager2::UpdateBoundsFromShowState(Window* window) { bool WorkspaceLayoutManager2::SetMaximizedOrFullscreenBounds( aura::Window* window) { + if (!GetTrackedByWorkspace(window)) + return false; + // During animations there is a transform installed on the workspace // windows. For this reason this code uses the parent so that the transform is // ignored. diff --git a/ash/wm/workspace/workspace_manager2.cc b/ash/wm/workspace/workspace_manager2.cc index 247a961..ad7546b 100644 --- a/ash/wm/workspace/workspace_manager2.cc +++ b/ash/wm/workspace/workspace_manager2.cc @@ -199,16 +199,28 @@ void WorkspaceManager2::SetActiveWorkspaceByWindow(Window* window) { return; if (workspace != active_workspace_) { - // If the window persists across all workspaces, move it to the current - // workspace. - // A popup which was first maximized, is minimized and getts restored has - // to go through the SetActiveWorkspace since it persists across workspaces - // and is not (yet) maximized (see crbug.com/151698). - if (GetPersistsAcrossAllWorkspaces(window) && !IsMaximized(window) && - !(wm::IsWindowMinimized(window) && WillRestoreMaximized(window))) + // A window is being made active. In the following cases we reparent to + // the active desktop: + // . The window is not tracked by workspace code. This is used for tab + // dragging. Since tab dragging needs to happen in the active workspace we + // have to reparent the window (otherwise the window you dragged the tab + // out of would disappear since the workspace changed). Since this case is + // only transiently used (property reset on input release) we don't worry + // about window state. In fact we can't consider window state here as we + // have to allow dragging of a maximized window to work in this case. + // . The window persists across all workspaces. For example, the task + // manager is in the desktop worskpace and the current workspace is + // maximized. If we swapped to the desktop you would lose context. Instead + // we reparent. The exception to this is if the window is maximized (it + // needs its own workspace then) or we're in the process of maximizing. If + // we're in the process of maximizing the window needs its own workspace. + if (!GetTrackedByWorkspace(window) || + (GetPersistsAcrossAllWorkspaces(window) && !IsMaximized(window) && + !(wm::IsWindowMinimized(window) && WillRestoreMaximized(window)))) { ReparentWindow(window, active_workspace_->window(), NULL); - else + } else { SetActiveWorkspace(workspace, ANIMATE_OLD_AND_NEW); + } } } @@ -222,6 +234,9 @@ Window* WorkspaceManager2::GetParentForNewWindow(Window* window) { // Fall through to normal logic. } + if (!GetTrackedByWorkspace(window)) + return active_workspace_->window(); + if (IsMaximized(window)) { // Wait for the window to be made active before showing the workspace. Workspace2* workspace = CreateWorkspace(true); @@ -577,5 +592,27 @@ void WorkspaceManager2::OnWorkspaceWindowShowStateChanged( UpdateShelfVisibility(); } +void WorkspaceManager2::OnTrackedByWorkspaceChanged(Workspace2* workspace, + aura::Window* window) { + Workspace2* new_workspace = NULL; + if (IsMaximized(window)) { + new_workspace = CreateWorkspace(true); + pending_workspaces_.insert(new_workspace); + } else if (workspace->is_maximized()) { + new_workspace = desktop_workspace(); + } else { + return; + } + // If the window is active we need to make sure the destination Workspace + // window is showing. Otherwise the window will be parented to a hidden window + // and lose activation. + const bool is_active = wm::IsActiveWindow(window); + if (is_active) + new_workspace->window()->Show(); + ReparentWindow(window, new_workspace->window(), NULL); + if (is_active) + SetActiveWorkspace(new_workspace, ANIMATE_OLD_AND_NEW); +} + } // namespace internal } // namespace ash diff --git a/ash/wm/workspace/workspace_manager2.h b/ash/wm/workspace/workspace_manager2.h index 653d684..6c85243 100644 --- a/ash/wm/workspace/workspace_manager2.h +++ b/ash/wm/workspace/workspace_manager2.h @@ -155,6 +155,8 @@ class ASH_EXPORT WorkspaceManager2 aura::Window* child, ui::WindowShowState last_show_state, ui::Layer* old_layer); + void OnTrackedByWorkspaceChanged(Workspace2* workspace, + aura::Window* window); aura::Window* contents_view_; diff --git a/ash/wm/workspace/workspace_manager2_unittest.cc b/ash/wm/workspace/workspace_manager2_unittest.cc index 10ac744..786f54b 100644 --- a/ash/wm/workspace/workspace_manager2_unittest.cc +++ b/ash/wm/workspace/workspace_manager2_unittest.cc @@ -1037,5 +1037,46 @@ TEST_F(WorkspaceManager2Test, TransientParent) { EXPECT_EQ(w2->parent(), w1->parent()); } +// Verifies changing TrackedByWorkspace works. +TEST_F(WorkspaceManager2Test, TrackedByWorkspace) { + // Create a window maximized. + scoped_ptr<Window> w1(CreateTestWindow()); + w1->Show(); + wm::ActivateWindow(w1.get()); + w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); + EXPECT_TRUE(wm::IsActiveWindow(w1.get())); + EXPECT_TRUE(w1->IsVisible()); + + // Create a second window maximized and mark it not tracked by workspace + // manager. + scoped_ptr<Window> w2(CreateTestWindowUnparented()); + w2->SetBounds(gfx::Rect(1, 6, 25, 30)); + w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); + w2->SetParent(NULL); + w2->Show(); + SetTrackedByWorkspace(w2.get(), false); + wm::ActivateWindow(w2.get()); + + // Activating |w2| should force it to have the same parent as |w1|. + EXPECT_EQ(w1->parent(), w2->parent()); + EXPECT_TRUE(wm::IsActiveWindow(w2.get())); + EXPECT_TRUE(w1->IsVisible()); + EXPECT_TRUE(w2->IsVisible()); + + // Because |w2| isn't tracked we should be able to set the bounds of it. + gfx::Rect bounds(w2->bounds()); + bounds.Offset(4, 5); + w2->SetBounds(bounds); + EXPECT_EQ(bounds.ToString(), w2->bounds().ToString()); + + // Transition it to tracked by worskpace. It should end up in its own + // workspace. + SetTrackedByWorkspace(w2.get(), true); + EXPECT_TRUE(wm::IsActiveWindow(w2.get())); + EXPECT_FALSE(w1->IsVisible()); + EXPECT_TRUE(w2->IsVisible()); + EXPECT_NE(w1->parent(), w2->parent()); +} + } // namespace internal } // namespace ash diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc index 3f50828..7458b11 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc @@ -1953,6 +1953,9 @@ Browser* TabDragController::CreateBrowserForDrag( create_params.initial_bounds = new_bounds; Browser* browser = new Browser(create_params); SetTrackedByWorkspace(browser->window()->GetNativeWindow(), false); + // If the window is created maximized then the bounds we supplied are ignored. + // We need to reset them again so they are honored. + browser->window()->SetBounds(new_bounds); return browser; } diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc index 0677143..11d183b 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc @@ -843,6 +843,60 @@ IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, #if defined(USE_ASH) +namespace { + +void DragInMaximizedWindowStep2(DetachToBrowserTabDragControllerTest* test, + Browser* browser, + TabStrip* tab_strip) { + // There should be another browser. + ASSERT_EQ(2u, BrowserList::size()); + Browser* new_browser = *(++BrowserList::begin()); + EXPECT_NE(browser, new_browser); + ASSERT_TRUE(new_browser->window()->IsActive()); + TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser); + + ASSERT_TRUE(tab_strip2->IsDragSessionActive()); + ASSERT_FALSE(tab_strip->IsDragSessionActive()); + + // Both windows should be visible. + EXPECT_TRUE(tab_strip->GetWidget()->IsVisible()); + EXPECT_TRUE(tab_strip2->GetWidget()->IsVisible()); + + // Stops dragging. + ASSERT_TRUE(test->ReleaseInput()); +} + +} // namespace + +// Creates a browser with two tabs, maximizes it, drags the tab out. +IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, + DragInMaximizedWindow) { + AddTabAndResetBrowser(browser()); + browser()->window()->Maximize(); + + TabStrip* tab_strip = GetTabStripForBrowser(browser()); + + // Move to the first tab and drag it enough so that it detaches. + gfx::Point tab_0_center( + GetCenterInScreenCoordinates(tab_strip->tab_at(0))); + ASSERT_TRUE(PressInput(tab_0_center)); + ASSERT_TRUE(DragInputToNotifyWhenDone( + tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), + base::Bind(&DragInMaximizedWindowStep2, this, browser(), tab_strip))); + QuitWhenNotDragging(); + + ASSERT_FALSE(TabDragController::IsActive()); + + // Should be two browsers. + ASSERT_EQ(2u, BrowserList::size()); + Browser* new_browser = *(++BrowserList::begin()); + ASSERT_TRUE(new_browser->window()->IsActive()); + + // Only the new browser should be visible. + EXPECT_FALSE(browser()->window()->GetNativeWindow()->IsVisible()); + EXPECT_TRUE(new_browser->window()->GetNativeWindow()->IsVisible()); +} + // Subclass of DetachToBrowserInSeparateDisplayTabDragControllerTest that // creates multiple displays. class DetachToBrowserInSeparateDisplayTabDragControllerTest |