screen_ash.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "ash/display/screen_ash.h" 6 7#include "ash/display/display_controller.h" 8#include "ash/display/display_manager.h" 9#include "ash/root_window_controller.h" 10#include "ash/root_window_settings.h" 11#include "ash/shelf/shelf_layout_manager.h" 12#include "ash/shelf/shelf_widget.h" 13#include "ash/shell.h" 14#include "ash/wm/coordinate_conversion.h" 15#include "base/logging.h" 16#include "ui/aura/client/screen_position_client.h" 17#include "ui/aura/env.h" 18#include "ui/aura/window_event_dispatcher.h" 19#include "ui/gfx/display.h" 20#include "ui/gfx/screen.h" 21 22namespace ash { 23 24namespace { 25 26DisplayManager* GetDisplayManager() { 27 return Shell::GetInstance()->display_manager(); 28} 29 30gfx::Display FindDisplayNearestPoint(const std::vector<gfx::Display>& displays, 31 const gfx::Point& point) { 32 int min_distance = INT_MAX; 33 const gfx::Display* nearest_display = NULL; 34 for (std::vector<gfx::Display>::const_iterator iter = displays.begin(); 35 iter != displays.end(); ++iter) { 36 const gfx::Display& display = *iter; 37 int distance = display.bounds().ManhattanDistanceToPoint(point); 38 if (distance < min_distance) { 39 min_distance = distance; 40 nearest_display = &display; 41 } 42 } 43 // There should always be at least one display that is less than INT_MAX away. 44 DCHECK(nearest_display); 45 return *nearest_display; 46} 47 48const gfx::Display* FindDisplayMatching( 49 const std::vector<gfx::Display>& displays, 50 const gfx::Rect& match_rect) { 51 int max_area = 0; 52 const gfx::Display* matching = NULL; 53 for (std::vector<gfx::Display>::const_iterator iter = displays.begin(); 54 iter != displays.end(); ++iter) { 55 const gfx::Display& display = *iter; 56 gfx::Rect intersect = gfx::IntersectRects(display.bounds(), match_rect); 57 int area = intersect.width() * intersect.height(); 58 if (area > max_area) { 59 max_area = area; 60 matching = &display; 61 } 62 } 63 return matching; 64} 65 66class ScreenForShutdown : public gfx::Screen { 67 public: 68 explicit ScreenForShutdown(ScreenAsh* screen_ash) 69 : display_list_(screen_ash->GetAllDisplays()), 70 primary_display_(screen_ash->GetPrimaryDisplay()) { 71 } 72 73 // gfx::Screen overrides: 74 virtual bool IsDIPEnabled() OVERRIDE { 75 return true; 76 } 77 virtual gfx::Point GetCursorScreenPoint() OVERRIDE { 78 return gfx::Point(); 79 } 80 virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE { 81 return NULL; 82 } 83 virtual gfx::NativeWindow GetWindowAtScreenPoint( 84 const gfx::Point& point) OVERRIDE { 85 return NULL; 86 } 87 virtual int GetNumDisplays() const OVERRIDE { 88 return display_list_.size(); 89 } 90 virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE { 91 return display_list_; 92 } 93 virtual gfx::Display GetDisplayNearestWindow(gfx::NativeView view) 94 const OVERRIDE { 95 return primary_display_; 96 } 97 virtual gfx::Display GetDisplayNearestPoint( 98 const gfx::Point& point) const OVERRIDE { 99 return FindDisplayNearestPoint(display_list_, point); 100 } 101 virtual gfx::Display GetDisplayMatching(const gfx::Rect& match_rect) 102 const OVERRIDE { 103 const gfx::Display* matching = 104 FindDisplayMatching(display_list_, match_rect); 105 // Fallback to the primary display if there is no matching display. 106 return matching ? *matching : GetPrimaryDisplay(); 107 } 108 virtual gfx::Display GetPrimaryDisplay() const OVERRIDE { 109 return primary_display_; 110 } 111 virtual void AddObserver(gfx::DisplayObserver* observer) OVERRIDE { 112 NOTREACHED() << "Observer should not be added during shutdown"; 113 } 114 virtual void RemoveObserver(gfx::DisplayObserver* observer) OVERRIDE { 115 } 116 117 private: 118 const std::vector<gfx::Display> display_list_; 119 const gfx::Display primary_display_; 120 121 DISALLOW_COPY_AND_ASSIGN(ScreenForShutdown); 122}; 123 124} // namespace 125 126ScreenAsh::ScreenAsh() { 127} 128 129ScreenAsh::~ScreenAsh() { 130} 131 132// static 133gfx::Display ScreenAsh::FindDisplayContainingPoint(const gfx::Point& point) { 134 return GetDisplayManager()->FindDisplayContainingPoint(point); 135} 136 137// static 138gfx::Rect ScreenAsh::GetMaximizedWindowBoundsInParent(aura::Window* window) { 139 if (GetRootWindowController(window->GetRootWindow())->shelf()) 140 return GetDisplayWorkAreaBoundsInParent(window); 141 else 142 return GetDisplayBoundsInParent(window); 143} 144 145// static 146gfx::Rect ScreenAsh::GetDisplayBoundsInParent(aura::Window* window) { 147 return ConvertRectFromScreen( 148 window->parent(), 149 Shell::GetScreen()->GetDisplayNearestWindow(window).bounds()); 150} 151 152// static 153gfx::Rect ScreenAsh::GetDisplayWorkAreaBoundsInParent(aura::Window* window) { 154 return ConvertRectFromScreen( 155 window->parent(), 156 Shell::GetScreen()->GetDisplayNearestWindow(window).work_area()); 157} 158 159// static 160gfx::Rect ScreenAsh::ConvertRectToScreen(aura::Window* window, 161 const gfx::Rect& rect) { 162 gfx::Point point = rect.origin(); 163 aura::client::GetScreenPositionClient(window->GetRootWindow())-> 164 ConvertPointToScreen(window, &point); 165 return gfx::Rect(point, rect.size()); 166} 167 168// static 169gfx::Rect ScreenAsh::ConvertRectFromScreen(aura::Window* window, 170 const gfx::Rect& rect) { 171 gfx::Point point = rect.origin(); 172 aura::client::GetScreenPositionClient(window->GetRootWindow())-> 173 ConvertPointFromScreen(window, &point); 174 return gfx::Rect(point, rect.size()); 175} 176 177// static 178const gfx::Display& ScreenAsh::GetSecondaryDisplay() { 179 DisplayManager* display_manager = GetDisplayManager(); 180 CHECK_EQ(2U, display_manager->GetNumDisplays()); 181 return display_manager->GetDisplayAt(0).id() == 182 Shell::GetScreen()->GetPrimaryDisplay().id() ? 183 display_manager->GetDisplayAt(1) : display_manager->GetDisplayAt(0); 184} 185 186// static 187const gfx::Display& ScreenAsh::GetDisplayForId(int64 display_id) { 188 return GetDisplayManager()->GetDisplayForId(display_id); 189} 190 191void ScreenAsh::NotifyBoundsChanged(const gfx::Display& display) { 192 FOR_EACH_OBSERVER(gfx::DisplayObserver, observers_, 193 OnDisplayBoundsChanged(display)); 194} 195 196void ScreenAsh::NotifyDisplayAdded(const gfx::Display& display) { 197 FOR_EACH_OBSERVER(gfx::DisplayObserver, observers_, OnDisplayAdded(display)); 198} 199 200void ScreenAsh::NotifyDisplayRemoved(const gfx::Display& display) { 201 FOR_EACH_OBSERVER( 202 gfx::DisplayObserver, observers_, OnDisplayRemoved(display)); 203} 204 205bool ScreenAsh::IsDIPEnabled() { 206 return true; 207} 208 209gfx::Point ScreenAsh::GetCursorScreenPoint() { 210 return aura::Env::GetInstance()->last_mouse_location(); 211} 212 213gfx::NativeWindow ScreenAsh::GetWindowUnderCursor() { 214 return GetWindowAtScreenPoint(Shell::GetScreen()->GetCursorScreenPoint()); 215} 216 217gfx::NativeWindow ScreenAsh::GetWindowAtScreenPoint(const gfx::Point& point) { 218 return wm::GetRootWindowAt(point)->GetTopWindowContainingPoint(point); 219} 220 221int ScreenAsh::GetNumDisplays() const { 222 return GetDisplayManager()->GetNumDisplays(); 223} 224 225std::vector<gfx::Display> ScreenAsh::GetAllDisplays() const { 226 return GetDisplayManager()->displays(); 227} 228 229gfx::Display ScreenAsh::GetDisplayNearestWindow(gfx::NativeView window) const { 230 if (!window) 231 return GetPrimaryDisplay(); 232 const aura::Window* root_window = window->GetRootWindow(); 233 if (!root_window) 234 return GetPrimaryDisplay(); 235 const RootWindowSettings* rws = GetRootWindowSettings(root_window); 236 if (rws->shutdown) 237 return GetPrimaryDisplay(); 238 239 int64 id = rws->display_id; 240 // if id is |kInvaildDisplayID|, it's being deleted. 241 DCHECK(id != gfx::Display::kInvalidDisplayID); 242 243 DisplayManager* display_manager = GetDisplayManager(); 244 // RootWindow needs Display to determine its device scale factor 245 // for non desktop display. 246 if (display_manager->non_desktop_display().id() == id) 247 return display_manager->non_desktop_display(); 248 return display_manager->GetDisplayForId(id); 249} 250 251gfx::Display ScreenAsh::GetDisplayNearestPoint(const gfx::Point& point) const { 252 const gfx::Display& display = 253 GetDisplayManager()->FindDisplayContainingPoint(point); 254 if (display.is_valid()) 255 return display; 256 // Fallback to the display that has the shortest Manhattan distance from 257 // the |point|. This is correct in the only areas that matter, namely in the 258 // corners between the physical screens. 259 return FindDisplayNearestPoint(GetDisplayManager()->displays(), point); 260} 261 262gfx::Display ScreenAsh::GetDisplayMatching(const gfx::Rect& match_rect) const { 263 if (match_rect.IsEmpty()) 264 return GetDisplayNearestPoint(match_rect.origin()); 265 const gfx::Display* matching = 266 FindDisplayMatching(GetDisplayManager()->displays(), match_rect); 267 // Fallback to the primary display if there is no matching display. 268 return matching ? *matching : GetPrimaryDisplay(); 269} 270 271gfx::Display ScreenAsh::GetPrimaryDisplay() const { 272 return GetDisplayManager()->GetDisplayForId( 273 DisplayController::GetPrimaryDisplayId()); 274} 275 276void ScreenAsh::AddObserver(gfx::DisplayObserver* observer) { 277 observers_.AddObserver(observer); 278} 279 280void ScreenAsh::RemoveObserver(gfx::DisplayObserver* observer) { 281 observers_.RemoveObserver(observer); 282} 283 284gfx::Screen* ScreenAsh::CloneForShutdown() { 285 return new ScreenForShutdown(this); 286} 287 288} // namespace ash 289