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