summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
authoroshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-04 03:20:01 +0000
committeroshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-04 03:20:01 +0000
commite9a71317209f27bb07ccd72d34e6c40e8469556f (patch)
treeaccfb9eda5029197dbd71d3a44f22e46b9015f21 /ash
parent919b2f83216c7a9f07d2e3569ad74ab8c1a06675 (diff)
downloadchromium_src-e9a71317209f27bb07ccd72d34e6c40e8469556f.zip
chromium_src-e9a71317209f27bb07ccd72d34e6c40e8469556f.tar.gz
chromium_src-e9a71317209f27bb07ccd72d34e6c40e8469556f.tar.bz2
Move WindowPositioner to ash/wm
WindowPositioner doesn't depend on chrome at all. window_positioner_unittest remains c/b/ui/ash as it depends on browser. I'll add separate tests in ash for this. BUG=272460 TBR=sky@chromium.org Review URL: https://codereview.chromium.org/25852004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@226941 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r--ash/ash.gyp2
-rw-r--r--ash/shell.cc2
-rw-r--r--ash/shell.h7
-rw-r--r--ash/wm/window_positioner.cc188
-rw-r--r--ash/wm/window_positioner.h75
5 files changed, 273 insertions, 1 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp
index 7793fc0..aee601b 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -515,6 +515,8 @@
'wm/window_cycle_controller.h',
'wm/window_cycle_list.cc',
'wm/window_cycle_list.h',
+ 'wm/window_positioner.cc',
+ 'wm/window_positioner.h',
'wm/window_state.cc',
'wm/window_state.h',
'wm/window_state_observer.h',
diff --git a/ash/shell.cc b/ash/shell.cc
index ccdbae2..8bbad04 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -70,6 +70,7 @@
#include "ash/wm/video_detector.h"
#include "ash/wm/window_animations.h"
#include "ash/wm/window_cycle_controller.h"
+#include "ash/wm/window_positioner.h"
#include "ash/wm/window_properties.h"
#include "ash/wm/window_util.h"
#include "ash/wm/workspace_controller.h"
@@ -162,6 +163,7 @@ Shell::Shell(ShellDelegate* delegate)
target_root_window_(NULL),
scoped_target_root_window_(NULL),
delegate_(delegate),
+ window_positioner_(new WindowPositioner),
activation_client_(NULL),
#if defined(OS_CHROMEOS) && defined(USE_X11)
output_configurator_(new chromeos::OutputConfigurator()),
diff --git a/ash/shell.h b/ash/shell.h
index ed007b9..74c6311 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -97,6 +97,7 @@ class UserWallpaperDelegate;
class VideoDetector;
class WebNotificationTray;
class WindowCycleController;
+class WindowPositioner;
class WindowSelectorController;
namespace internal {
@@ -120,7 +121,6 @@ class OverlayEventFilter;
class ResizeShadowController;
class ResolutionNotificationController;
class RootWindowController;
-class RootWindowLayoutManager;
class ScopedTargetRootWindow;
class ScreenPositionController;
class SlowAnimationEventFilter;
@@ -473,6 +473,10 @@ class ASH_EXPORT Shell
return launcher_model_.get();
}
+ WindowPositioner* window_positioner() {
+ return window_positioner_.get();
+ }
+
// Returns the launcher delegate, creating if necesary.
LauncherDelegate* GetLauncherDelegate();
@@ -551,6 +555,7 @@ class ASH_EXPORT Shell
app_list_shelf_item_delegate_;
scoped_ptr<LauncherModel> launcher_model_;
+ scoped_ptr<ash::WindowPositioner> window_positioner_;
scoped_ptr<internal::AppListController> app_list_controller_;
diff --git a/ash/wm/window_positioner.cc b/ash/wm/window_positioner.cc
new file mode 100644
index 0000000..1a7af44
--- /dev/null
+++ b/ash/wm/window_positioner.cc
@@ -0,0 +1,188 @@
+// Copyright 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/window_positioner.h"
+
+#include "ash/shell.h"
+#include "ash/wm/mru_window_tracker.h"
+#include "ash/wm/window_resizer.h"
+#include "ash/wm/window_state.h"
+#include "ash/wm/window_util.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_delegate.h"
+#include "ui/compositor/layer.h"
+#include "ui/gfx/screen.h"
+
+namespace ash {
+
+// statics
+
+const int WindowPositioner::kMinimumWindowOffset = 32;
+
+WindowPositioner::WindowPositioner()
+ : pop_position_offset_increment_x(0),
+ pop_position_offset_increment_y(0),
+ popup_position_offset_from_screen_corner_x(0),
+ popup_position_offset_from_screen_corner_y(0),
+ last_popup_position_x_(0),
+ last_popup_position_y_(0) {
+}
+
+WindowPositioner::~WindowPositioner() {
+}
+
+gfx::Rect WindowPositioner::GetPopupPosition(const gfx::Rect& old_pos) {
+ int grid = kMinimumWindowOffset;
+ popup_position_offset_from_screen_corner_x = grid;
+ popup_position_offset_from_screen_corner_y = grid;
+ if (!pop_position_offset_increment_x) {
+ // When the popup position increment is , the last popup position
+ // was not yet initialized.
+ last_popup_position_x_ = popup_position_offset_from_screen_corner_x;
+ last_popup_position_y_ = popup_position_offset_from_screen_corner_y;
+ }
+ pop_position_offset_increment_x = grid;
+ pop_position_offset_increment_y = grid;
+ // We handle the Multi monitor support by retrieving the active window's
+ // work area.
+ aura::Window* window = ash::wm::GetActiveWindow();
+ const gfx::Rect work_area = window && window->IsVisible() ?
+ Shell::GetScreen()->GetDisplayNearestWindow(window).work_area() :
+ Shell::GetScreen()->GetPrimaryDisplay().work_area();
+ // Only try to reposition the popup when it is not spanning the entire
+ // screen.
+ if ((old_pos.width() + popup_position_offset_from_screen_corner_x >=
+ work_area.width()) ||
+ (old_pos.height() + popup_position_offset_from_screen_corner_y >=
+ work_area.height()))
+ return AlignPopupPosition(old_pos, work_area, grid);
+ const gfx::Rect result = SmartPopupPosition(old_pos, work_area, grid);
+ if (!result.IsEmpty())
+ return AlignPopupPosition(result, work_area, grid);
+ return NormalPopupPosition(old_pos, work_area);
+}
+
+gfx::Rect WindowPositioner::NormalPopupPosition(
+ const gfx::Rect& old_pos,
+ const gfx::Rect& work_area) {
+ int w = old_pos.width();
+ int h = old_pos.height();
+ // Note: The 'last_popup_position' is checked and kept relative to the
+ // screen size. The offsetting will be done in the last step when the
+ // target rectangle gets returned.
+ bool reset = false;
+ if (last_popup_position_y_ + h > work_area.height() ||
+ last_popup_position_x_ + w > work_area.width()) {
+ // Popup does not fit on screen. Reset to next diagonal row.
+ last_popup_position_x_ -= last_popup_position_y_ -
+ popup_position_offset_from_screen_corner_x -
+ pop_position_offset_increment_x;
+ last_popup_position_y_ = popup_position_offset_from_screen_corner_y;
+ reset = true;
+ }
+ if (last_popup_position_x_ + w > work_area.width()) {
+ // Start again over.
+ last_popup_position_x_ = popup_position_offset_from_screen_corner_x;
+ last_popup_position_y_ = popup_position_offset_from_screen_corner_y;
+ reset = true;
+ }
+ int x = last_popup_position_x_;
+ int y = last_popup_position_y_;
+ if (!reset) {
+ last_popup_position_x_ += pop_position_offset_increment_x;
+ last_popup_position_y_ += pop_position_offset_increment_y;
+ }
+ return gfx::Rect(x + work_area.x(), y + work_area.y(), w, h);
+}
+
+gfx::Rect WindowPositioner::SmartPopupPosition(
+ const gfx::Rect& old_pos,
+ const gfx::Rect& work_area,
+ int grid) {
+ const std::vector<aura::Window*> windows =
+ ash::MruWindowTracker::BuildWindowList(false);
+
+ std::vector<const gfx::Rect*> regions;
+ // Process the window list and check if we can bail immediately.
+ for (size_t i = 0; i < windows.size(); i++) {
+ // We only include opaque and visible windows.
+ if (windows[i] && windows[i]->IsVisible() && windows[i]->layer() &&
+ (!windows[i]->transparent() ||
+ windows[i]->layer()->GetTargetOpacity() == 1.0)) {
+ ash::wm::WindowState* window_state = ash::wm::GetWindowState(windows[i]);
+ // When any window is maximized we cannot find any free space.
+ if (window_state->IsMaximizedOrFullscreen())
+ return gfx::Rect(0, 0, 0, 0);
+ if (window_state->IsNormalShowState())
+ regions.push_back(&windows[i]->bounds());
+ }
+ }
+
+ if (regions.empty())
+ return gfx::Rect(0, 0, 0, 0);
+
+ int w = old_pos.width();
+ int h = old_pos.height();
+ int x_end = work_area.width() / 2;
+ int x, x_increment;
+ // We parse for a proper location on the screen. We do this in two runs:
+ // The first run will start from the left, parsing down, skipping any
+ // overlapping windows it will encounter until the popup's height can not
+ // be served anymore. Then the next grid position to the right will be
+ // taken, and the same cycle starts again. This will be repeated until we
+ // hit the middle of the screen (or we find a suitable location).
+ // In the second run we parse beginning from the right corner downwards and
+ // then to the left.
+ // When no location was found, an empty rectangle will be returned.
+ for (int run = 0; run < 2; run++) {
+ if (run == 0) { // First run: Start left, parse right till mid screen.
+ x = 0;
+ x_increment = pop_position_offset_increment_x;
+ } else { // Second run: Start right, parse left till mid screen.
+ x = work_area.width() - w;
+ x_increment = -pop_position_offset_increment_x;
+ }
+ // Note: The passing (x,y,w,h) window is always relative to the work area's
+ // origin.
+ for (; x_increment > 0 ? (x < x_end) : (x > x_end); x += x_increment) {
+ int y = 0;
+ while (y + h <= work_area.height()) {
+ size_t i;
+ for (i = 0; i < regions.size(); i++) {
+ if (regions[i]->Intersects(gfx::Rect(x + work_area.x(),
+ y + work_area.y(), w, h))) {
+ y = regions[i]->bottom() - work_area.y();
+ break;
+ }
+ }
+ if (i >= regions.size())
+ return gfx::Rect(x + work_area.x(), y + work_area.y(), w, h);
+ }
+ }
+ }
+ return gfx::Rect(0, 0, 0, 0);
+}
+
+gfx::Rect WindowPositioner::AlignPopupPosition(
+ const gfx::Rect& pos,
+ const gfx::Rect& work_area,
+ int grid) {
+ if (grid <= 1)
+ return pos;
+
+ int x = pos.x() - (pos.x() - work_area.x()) % grid;
+ int y = pos.y() - (pos.y() - work_area.y()) % grid;
+ int w = pos.width();
+ int h = pos.height();
+
+ // If the alignment was pushing the window out of the screen, we ignore the
+ // alignment for that call.
+ if (abs(pos.right() - work_area.right()) < grid)
+ x = work_area.right() - w;
+ if (abs(pos.bottom() - work_area.bottom()) < grid)
+ y = work_area.bottom() - h;
+ return gfx::Rect(x, y, w, h);
+}
+
+} // namespace ash
diff --git a/ash/wm/window_positioner.h b/ash/wm/window_positioner.h
new file mode 100644
index 0000000..8a95b2e
--- /dev/null
+++ b/ash/wm/window_positioner.h
@@ -0,0 +1,75 @@
+// Copyright 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.
+
+#ifndef ASH_WM_WINDOW_POSITIONER_H_
+#define ASH_WM_WINDOW_POSITIONER_H_
+
+#include "ash/ash_export.h"
+#include "base/basictypes.h"
+#include "ui/gfx/rect.h"
+
+namespace aura {
+class Window;
+}
+
+namespace ash {
+
+namespace test {
+class WindowPositionerTest;
+}
+
+// WindowPositioner is used by the browser to move new popups automatically to
+// a usable position on the closest work area (of the active window).
+class ASH_EXPORT WindowPositioner {
+ public:
+ WindowPositioner();
+ ~WindowPositioner();
+
+ // Find a suitable screen position for a popup window and return it. The
+ // passed input position is only used to retrieve the width and height.
+ // The position is determined on the left / right / top / bottom first. If
+ // no smart space is found, the position will follow the standard what other
+ // operating systems do (default cascading style).
+ gfx::Rect GetPopupPosition(const gfx::Rect& old_pos);
+
+ protected:
+ friend class test::WindowPositionerTest;
+
+ // Find a smart way to position the popup window. If there is no space this
+ // function will return an empty rectangle.
+ gfx::Rect SmartPopupPosition(const gfx::Rect& old_pos,
+ const gfx::Rect& work_area,
+ int grid);
+
+ // Find the next available cascading popup position (on the given screen).
+ gfx::Rect NormalPopupPosition(const gfx::Rect& old_pos,
+ const gfx::Rect& work_area);
+
+ // Align the location to the grid / snap to the right / bottom corner.
+ gfx::Rect AlignPopupPosition(const gfx::Rect &pos,
+ const gfx::Rect &work_area,
+ int grid);
+
+ // Constant exposed for unittest.
+ static const int kMinimumWindowOffset;
+
+ // The offset in X and Y for the next popup which opens.
+ int pop_position_offset_increment_x;
+ int pop_position_offset_increment_y;
+
+ // The position on the screen for the first popup which gets shown if no
+ // empty space can be found.
+ int popup_position_offset_from_screen_corner_x;
+ int popup_position_offset_from_screen_corner_y;
+
+ // The last used position.
+ int last_popup_position_x_;
+ int last_popup_position_y_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowPositioner);
+};
+
+} // namespace ash
+
+#endif // ASH_WM_WINDOW_POSITIONER_H_