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/window_tree_host_manager.h"
8 #include "ash/public/cpp/ash_switches.h"
9 #include "ash/public/cpp/window_finder.h"
10 #include "ash/root_window_controller.h"
11 #include "ash/root_window_settings.h"
12 #include "ash/shelf/shelf_widget.h"
13 #include "ash/shell.h"
14 #include "ash/wm/window_util.h"
15 #include "base/check.h"
16 #include "base/command_line.h"
17 #include "base/notreached.h"
18 #include "ui/aura/client/screen_position_client.h"
19 #include "ui/aura/env.h"
20 #include "ui/aura/window.h"
21 #include "ui/aura/window_event_dispatcher.h"
22 #include "ui/display/display.h"
23 #include "ui/display/display_finder.h"
24 #include "ui/display/manager/display_manager.h"
25 #include "ui/display/screen.h"
26 #include "ui/display/types/display_constants.h"
27 
28 namespace ash {
29 
30 namespace {
31 
32 // Intentionally leaked in production.
33 display::Screen* screen_for_shutdown = nullptr;
34 
GetDisplayManager()35 display::DisplayManager* GetDisplayManager() {
36   return Shell::Get()->display_manager();
37 }
38 
39 class ScreenForShutdown : public display::Screen {
40  public:
ScreenForShutdown(display::Screen * screen_ash)41   explicit ScreenForShutdown(display::Screen* screen_ash)
42       : display_list_(screen_ash->GetAllDisplays()),
43         primary_display_(screen_ash->GetPrimaryDisplay()) {
44     SetDisplayForNewWindows(primary_display_.id());
45   }
46 
47   // display::Screen overrides:
GetCursorScreenPoint()48   gfx::Point GetCursorScreenPoint() override { return gfx::Point(); }
IsWindowUnderCursor(gfx::NativeWindow window)49   bool IsWindowUnderCursor(gfx::NativeWindow window) override { return false; }
GetWindowAtScreenPoint(const gfx::Point & point)50   gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) override {
51     return nullptr;
52   }
GetLocalProcessWindowAtPoint(const gfx::Point & point,const std::set<gfx::NativeWindow> & ignore)53   gfx::NativeWindow GetLocalProcessWindowAtPoint(
54       const gfx::Point& point,
55       const std::set<gfx::NativeWindow>& ignore) override {
56     return nullptr;
57   }
GetNumDisplays() const58   int GetNumDisplays() const override { return display_list_.size(); }
GetAllDisplays() const59   const std::vector<display::Display>& GetAllDisplays() const override {
60     return display_list_;
61   }
GetDisplayNearestWindow(gfx::NativeView view) const62   display::Display GetDisplayNearestWindow(
63       gfx::NativeView view) const override {
64     return primary_display_;
65   }
GetDisplayNearestPoint(const gfx::Point & point) const66   display::Display GetDisplayNearestPoint(
67       const gfx::Point& point) const override {
68     return *display::FindDisplayNearestPoint(display_list_, point);
69   }
GetDisplayMatching(const gfx::Rect & match_rect) const70   display::Display GetDisplayMatching(
71       const gfx::Rect& match_rect) const override {
72     const display::Display* matching =
73         display::FindDisplayWithBiggestIntersection(display_list_, match_rect);
74     // Fallback to the primary display if there is no matching display.
75     return matching ? *matching : GetPrimaryDisplay();
76   }
GetPrimaryDisplay() const77   display::Display GetPrimaryDisplay() const override {
78     return primary_display_;
79   }
AddObserver(display::DisplayObserver * observer)80   void AddObserver(display::DisplayObserver* observer) override {
81     NOTREACHED() << "Observer should not be added during shutdown";
82   }
RemoveObserver(display::DisplayObserver * observer)83   void RemoveObserver(display::DisplayObserver* observer) override {}
84 
85  private:
86   const std::vector<display::Display> display_list_;
87   const display::Display primary_display_;
88 
89   DISALLOW_COPY_AND_ASSIGN(ScreenForShutdown);
90 };
91 
92 }  // namespace
93 
94 ScreenAsh::ScreenAsh() = default;
95 
96 ScreenAsh::~ScreenAsh() = default;
97 
GetCursorScreenPoint()98 gfx::Point ScreenAsh::GetCursorScreenPoint() {
99   return aura::Env::GetInstance()->last_mouse_location();
100 }
101 
IsWindowUnderCursor(gfx::NativeWindow window)102 bool ScreenAsh::IsWindowUnderCursor(gfx::NativeWindow window) {
103   return window->Contains(GetWindowAtScreenPoint(
104       display::Screen::GetScreen()->GetCursorScreenPoint()));
105 }
106 
GetWindowAtScreenPoint(const gfx::Point & point)107 gfx::NativeWindow ScreenAsh::GetWindowAtScreenPoint(const gfx::Point& point) {
108   aura::Window* root_window = window_util::GetRootWindowAt(point);
109   aura::client::ScreenPositionClient* position_client =
110       aura::client::GetScreenPositionClient(root_window);
111 
112   gfx::Point local_point = point;
113   if (position_client)
114     position_client->ConvertPointFromScreen(root_window, &local_point);
115 
116   return root_window->GetEventHandlerForPoint(local_point);
117 }
118 
GetLocalProcessWindowAtPoint(const gfx::Point & point,const std::set<gfx::NativeWindow> & ignore)119 gfx::NativeWindow ScreenAsh::GetLocalProcessWindowAtPoint(
120     const gfx::Point& point,
121     const std::set<gfx::NativeWindow>& ignore) {
122   return ash::GetTopmostWindowAtPoint(point, ignore);
123 }
124 
GetNumDisplays() const125 int ScreenAsh::GetNumDisplays() const {
126   return GetDisplayManager()->GetNumDisplays();
127 }
128 
GetAllDisplays() const129 const std::vector<display::Display>& ScreenAsh::GetAllDisplays() const {
130   return GetDisplayManager()->active_display_list();
131 }
132 
GetDisplayNearestWindow(gfx::NativeView window) const133 display::Display ScreenAsh::GetDisplayNearestWindow(
134     gfx::NativeView window) const {
135   if (!window)
136     return GetPrimaryDisplay();
137 
138   const aura::Window* root_window = window->GetRootWindow();
139   if (!root_window)
140     return GetPrimaryDisplay();
141   const RootWindowSettings* rws = GetRootWindowSettings(root_window);
142   int64_t id = rws->display_id;
143   // if id is |kInvaildDisplayID|, it's being deleted.
144   DCHECK(id != display::kInvalidDisplayId);
145   if (id == display::kInvalidDisplayId)
146     return GetPrimaryDisplay();
147 
148   display::DisplayManager* display_manager = GetDisplayManager();
149   // RootWindow needs Display to determine its device scale factor
150   // for non desktop display.
151   display::Display mirroring_display =
152       display_manager->GetMirroringDisplayById(id);
153   if (mirroring_display.is_valid())
154     return mirroring_display;
155   return display_manager->GetDisplayForId(id);
156 }
157 
GetDisplayNearestPoint(const gfx::Point & point) const158 display::Display ScreenAsh::GetDisplayNearestPoint(
159     const gfx::Point& point) const {
160   const display::Display& display =
161       GetDisplayManager()->FindDisplayContainingPoint(point);
162   if (display.is_valid())
163     return display;
164   // Fallback to the display that has the shortest Manhattan distance from
165   // the |point|. This is correct in the only areas that matter, namely in the
166   // corners between the physical screens.
167   return *display::FindDisplayNearestPoint(
168       GetDisplayManager()->active_only_display_list(), point);
169 }
170 
GetDisplayMatching(const gfx::Rect & match_rect) const171 display::Display ScreenAsh::GetDisplayMatching(
172     const gfx::Rect& match_rect) const {
173   if (match_rect.IsEmpty())
174     return GetDisplayNearestPoint(match_rect.origin());
175   const display::Display* matching =
176       display::FindDisplayWithBiggestIntersection(
177           GetDisplayManager()->active_only_display_list(), match_rect);
178   // Fallback to the primary display if there is no matching display.
179   return matching ? *matching : GetPrimaryDisplay();
180 }
181 
GetPrimaryDisplay() const182 display::Display ScreenAsh::GetPrimaryDisplay() const {
183   if (!WindowTreeHostManager::HasValidPrimaryDisplayId()) {
184     // This should only be allowed temporarily when there are no displays
185     // available and hence no primary display. In this case we return a default
186     // display to avoid crashes for display observers trying to get the primary
187     // display when notified with the removal of the last display.
188     // https://crbug.com/866714.
189     DCHECK(
190         Shell::Get()->window_tree_host_manager()->GetAllRootWindows().empty());
191     return display::DisplayManager::GetFakePrimaryDisplay();
192   }
193 
194   return GetDisplayManager()->GetDisplayForId(
195       WindowTreeHostManager::GetPrimaryDisplayId());
196 }
197 
AddObserver(display::DisplayObserver * observer)198 void ScreenAsh::AddObserver(display::DisplayObserver* observer) {
199   GetDisplayManager()->AddObserver(observer);
200 }
201 
RemoveObserver(display::DisplayObserver * observer)202 void ScreenAsh::RemoveObserver(display::DisplayObserver* observer) {
203   GetDisplayManager()->RemoveObserver(observer);
204 }
205 
206 // static
CreateDisplayManager()207 display::DisplayManager* ScreenAsh::CreateDisplayManager() {
208   std::unique_ptr<ScreenAsh> screen(new ScreenAsh);
209 
210   display::Screen* current = display::Screen::GetScreen();
211   // If there is no native, or the native was for shutdown,
212   // use ash's screen.
213   if (!current || current == screen_for_shutdown)
214     display::Screen::SetScreenInstance(screen.get());
215   display::DisplayManager* manager =
216       new display::DisplayManager(std::move(screen));
217   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
218           switches::kAshEnableTabletMode)) {
219     manager->set_internal_display_has_accelerometer(true);
220   }
221   return manager;
222 }
223 
224 // static
CreateScreenForShutdown()225 void ScreenAsh::CreateScreenForShutdown() {
226   delete screen_for_shutdown;
227   screen_for_shutdown = new ScreenForShutdown(display::Screen::GetScreen());
228   display::Screen::SetScreenInstance(screen_for_shutdown);
229 }
230 
231 // static
DeleteScreenForShutdown()232 void ScreenAsh::DeleteScreenForShutdown() {
233   if (display::Screen::GetScreen() == screen_for_shutdown)
234     display::Screen::SetScreenInstance(nullptr);
235   delete screen_for_shutdown;
236   screen_for_shutdown = nullptr;
237 }
238 
239 }  // namespace ash
240