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 22 namespace ash { 23 24 namespace { 25 26 DisplayManager* GetDisplayManager() { 27 return Shell::GetInstance()->display_manager(); 28 } 29 30 gfx::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 48 const 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 66 class 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 126 ScreenAsh::ScreenAsh() { 127 } 128 129 ScreenAsh::~ScreenAsh() { 130 } 131 132 // static 133 gfx::Display ScreenAsh::FindDisplayContainingPoint(const gfx::Point& point) { 134 return GetDisplayManager()->FindDisplayContainingPoint(point); 135 } 136 137 // static 138 gfx::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 146 gfx::Rect ScreenAsh::GetDisplayBoundsInParent(aura::Window* window) { 147 return ConvertRectFromScreen( 148 window->parent(), 149 Shell::GetScreen()->GetDisplayNearestWindow(window).bounds()); 150 } 151 152 // static 153 gfx::Rect ScreenAsh::GetDisplayWorkAreaBoundsInParent(aura::Window* window) { 154 return ConvertRectFromScreen( 155 window->parent(), 156 Shell::GetScreen()->GetDisplayNearestWindow(window).work_area()); 157 } 158 159 // static 160 gfx::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 169 gfx::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 178 const 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 187 const gfx::Display& ScreenAsh::GetDisplayForId(int64 display_id) { 188 return GetDisplayManager()->GetDisplayForId(display_id); 189 } 190 191 void ScreenAsh::NotifyMetricsChanged(const gfx::Display& display, 192 uint32_t metrics) { 193 FOR_EACH_OBSERVER(gfx::DisplayObserver, 194 observers_, 195 OnDisplayMetricsChanged(display, metrics)); 196 } 197 198 void ScreenAsh::NotifyDisplayAdded(const gfx::Display& display) { 199 FOR_EACH_OBSERVER(gfx::DisplayObserver, observers_, OnDisplayAdded(display)); 200 } 201 202 void ScreenAsh::NotifyDisplayRemoved(const gfx::Display& display) { 203 FOR_EACH_OBSERVER( 204 gfx::DisplayObserver, observers_, OnDisplayRemoved(display)); 205 } 206 207 bool ScreenAsh::IsDIPEnabled() { 208 return true; 209 } 210 211 gfx::Point ScreenAsh::GetCursorScreenPoint() { 212 return aura::Env::GetInstance()->last_mouse_location(); 213 } 214 215 gfx::NativeWindow ScreenAsh::GetWindowUnderCursor() { 216 return GetWindowAtScreenPoint(Shell::GetScreen()->GetCursorScreenPoint()); 217 } 218 219 gfx::NativeWindow ScreenAsh::GetWindowAtScreenPoint(const gfx::Point& point) { 220 return wm::GetRootWindowAt(point)->GetTopWindowContainingPoint(point); 221 } 222 223 int ScreenAsh::GetNumDisplays() const { 224 return GetDisplayManager()->GetNumDisplays(); 225 } 226 227 std::vector<gfx::Display> ScreenAsh::GetAllDisplays() const { 228 return GetDisplayManager()->displays(); 229 } 230 231 gfx::Display ScreenAsh::GetDisplayNearestWindow(gfx::NativeView window) const { 232 if (!window) 233 return GetPrimaryDisplay(); 234 const aura::Window* root_window = window->GetRootWindow(); 235 if (!root_window) 236 return GetPrimaryDisplay(); 237 const RootWindowSettings* rws = GetRootWindowSettings(root_window); 238 int64 id = rws->display_id; 239 // if id is |kInvaildDisplayID|, it's being deleted. 240 DCHECK(id != gfx::Display::kInvalidDisplayID); 241 if (id == gfx::Display::kInvalidDisplayID) 242 return GetPrimaryDisplay(); 243 244 DisplayManager* display_manager = GetDisplayManager(); 245 // RootWindow needs Display to determine its device scale factor 246 // for non desktop display. 247 if (display_manager->non_desktop_display().id() == id) 248 return display_manager->non_desktop_display(); 249 return display_manager->GetDisplayForId(id); 250 } 251 252 gfx::Display ScreenAsh::GetDisplayNearestPoint(const gfx::Point& point) const { 253 const gfx::Display& display = 254 GetDisplayManager()->FindDisplayContainingPoint(point); 255 if (display.is_valid()) 256 return display; 257 // Fallback to the display that has the shortest Manhattan distance from 258 // the |point|. This is correct in the only areas that matter, namely in the 259 // corners between the physical screens. 260 return FindDisplayNearestPoint(GetDisplayManager()->displays(), point); 261 } 262 263 gfx::Display ScreenAsh::GetDisplayMatching(const gfx::Rect& match_rect) const { 264 if (match_rect.IsEmpty()) 265 return GetDisplayNearestPoint(match_rect.origin()); 266 const gfx::Display* matching = 267 FindDisplayMatching(GetDisplayManager()->displays(), match_rect); 268 // Fallback to the primary display if there is no matching display. 269 return matching ? *matching : GetPrimaryDisplay(); 270 } 271 272 gfx::Display ScreenAsh::GetPrimaryDisplay() const { 273 return GetDisplayManager()->GetDisplayForId( 274 DisplayController::GetPrimaryDisplayId()); 275 } 276 277 void ScreenAsh::AddObserver(gfx::DisplayObserver* observer) { 278 observers_.AddObserver(observer); 279 } 280 281 void ScreenAsh::RemoveObserver(gfx::DisplayObserver* observer) { 282 observers_.RemoveObserver(observer); 283 } 284 285 gfx::Screen* ScreenAsh::CloneForShutdown() { 286 return new ScreenForShutdown(this); 287 } 288 289 } // namespace ash 290