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::NotifyMetricsChanged(const gfx::Display& display, 192 uint32_t metrics) { 193 FOR_EACH_OBSERVER(gfx::DisplayObserver, 194 observers_, 195 OnDisplayMetricsChanged(display, metrics)); 196} 197 198void ScreenAsh::NotifyDisplayAdded(const gfx::Display& display) { 199 FOR_EACH_OBSERVER(gfx::DisplayObserver, observers_, OnDisplayAdded(display)); 200} 201 202void ScreenAsh::NotifyDisplayRemoved(const gfx::Display& display) { 203 FOR_EACH_OBSERVER( 204 gfx::DisplayObserver, observers_, OnDisplayRemoved(display)); 205} 206 207bool ScreenAsh::IsDIPEnabled() { 208 return true; 209} 210 211gfx::Point ScreenAsh::GetCursorScreenPoint() { 212 return aura::Env::GetInstance()->last_mouse_location(); 213} 214 215gfx::NativeWindow ScreenAsh::GetWindowUnderCursor() { 216 return GetWindowAtScreenPoint(Shell::GetScreen()->GetCursorScreenPoint()); 217} 218 219gfx::NativeWindow ScreenAsh::GetWindowAtScreenPoint(const gfx::Point& point) { 220 return wm::GetRootWindowAt(point)->GetTopWindowContainingPoint(point); 221} 222 223int ScreenAsh::GetNumDisplays() const { 224 return GetDisplayManager()->GetNumDisplays(); 225} 226 227std::vector<gfx::Display> ScreenAsh::GetAllDisplays() const { 228 return GetDisplayManager()->displays(); 229} 230 231gfx::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 252gfx::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 263gfx::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 272gfx::Display ScreenAsh::GetPrimaryDisplay() const { 273 return GetDisplayManager()->GetDisplayForId( 274 DisplayController::GetPrimaryDisplayId()); 275} 276 277void ScreenAsh::AddObserver(gfx::DisplayObserver* observer) { 278 observers_.AddObserver(observer); 279} 280 281void ScreenAsh::RemoveObserver(gfx::DisplayObserver* observer) { 282 observers_.RemoveObserver(observer); 283} 284 285gfx::Screen* ScreenAsh::CloneForShutdown() { 286 return new ScreenForShutdown(this); 287} 288 289} // namespace ash 290