Home | History | Annotate | Download | only in display
      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