screen.cc 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // Copyright 2012 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. #include "ui/display/screen.h"
  5. #include <utility>
  6. #include "base/check.h"
  7. #include "base/containers/contains.h"
  8. #include "base/memory/ptr_util.h"
  9. #include "base/notreached.h"
  10. #include "base/time/time.h"
  11. #include "build/build_config.h"
  12. #include "ui/display/display.h"
  13. #include "ui/display/display_util.h"
  14. #include "ui/display/types/display_constants.h"
  15. #include "ui/gfx/geometry/rect.h"
  16. namespace display {
  17. namespace {
  18. Screen* g_screen;
  19. } // namespace
  20. Screen::Screen() : display_id_for_new_windows_(kInvalidDisplayId) {}
  21. Screen::~Screen() = default;
  22. // static
  23. Screen* Screen::GetScreen() {
  24. #if BUILDFLAG(IS_IOS)
  25. if (!g_screen)
  26. g_screen = CreateNativeScreen();
  27. #endif
  28. return g_screen;
  29. }
  30. // static
  31. Screen* Screen::SetScreenInstance(Screen* instance,
  32. const base::Location& location) {
  33. // Do not allow screen instance override. The screen object has a lot of
  34. // states, such as current display settings as well as observers, and safely
  35. // transferring these to new screen implementation is very difficult and not
  36. // safe. If you hit the DCHECK in a test, please look for other examples that
  37. // that set a test screen instance in the setup process.
  38. DCHECK(!g_screen || !instance || (instance && instance->shutdown_))
  39. << "fail=" << location.ToString();
  40. return std::exchange(g_screen, instance);
  41. }
  42. // static
  43. bool Screen::HasScreen() {
  44. return !!g_screen;
  45. }
  46. void Screen::SetCursorScreenPointForTesting(const gfx::Point& point) {
  47. NOTIMPLEMENTED_LOG_ONCE();
  48. }
  49. Display Screen::GetDisplayNearestView(gfx::NativeView view) const {
  50. return GetDisplayNearestWindow(GetWindowForView(view));
  51. }
  52. Display Screen::GetDisplayForNewWindows() const {
  53. Display display;
  54. // Scoped value can override if it is set.
  55. if (scoped_display_id_for_new_windows_ != kInvalidDisplayId &&
  56. GetDisplayWithDisplayId(scoped_display_id_for_new_windows_, &display)) {
  57. return display;
  58. }
  59. if (GetDisplayWithDisplayId(display_id_for_new_windows_, &display))
  60. return display;
  61. // Fallback to primary display.
  62. return GetPrimaryDisplay();
  63. }
  64. void Screen::SetDisplayForNewWindows(int64_t display_id) {
  65. // GetDisplayForNewWindows() handles invalid display ids.
  66. display_id_for_new_windows_ = display_id;
  67. }
  68. #if BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_LINUX)
  69. Screen::ScreenSaverSuspender::~ScreenSaverSuspender() = default;
  70. std::unique_ptr<Screen::ScreenSaverSuspender> Screen::SuspendScreenSaver() {
  71. NOTIMPLEMENTED_LOG_ONCE();
  72. return nullptr;
  73. }
  74. #endif // BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_LINUX)
  75. bool Screen::IsScreenSaverActive() const {
  76. NOTIMPLEMENTED_LOG_ONCE();
  77. return false;
  78. }
  79. base::TimeDelta Screen::CalculateIdleTime() const {
  80. NOTIMPLEMENTED_LOG_ONCE();
  81. return base::Seconds(0);
  82. }
  83. gfx::Rect Screen::ScreenToDIPRectInWindow(gfx::NativeWindow window,
  84. const gfx::Rect& screen_rect) const {
  85. float scale = GetDisplayNearestWindow(window).device_scale_factor();
  86. return ScaleToEnclosingRect(screen_rect, 1.0f / scale);
  87. }
  88. gfx::Rect Screen::DIPToScreenRectInWindow(gfx::NativeWindow window,
  89. const gfx::Rect& dip_rect) const {
  90. float scale = GetDisplayNearestWindow(window).device_scale_factor();
  91. return ScaleToEnclosingRect(dip_rect, scale);
  92. }
  93. bool Screen::GetDisplayWithDisplayId(int64_t display_id,
  94. Display* display) const {
  95. for (const Display& display_in_list : GetAllDisplays()) {
  96. if (display_in_list.id() == display_id) {
  97. *display = display_in_list;
  98. return true;
  99. }
  100. }
  101. return false;
  102. }
  103. void Screen::SetPanelRotationForTesting(int64_t display_id,
  104. Display::Rotation rotation) {
  105. // Not implemented.
  106. DCHECK(false);
  107. }
  108. std::string Screen::GetCurrentWorkspace() {
  109. NOTIMPLEMENTED_LOG_ONCE();
  110. return {};
  111. }
  112. base::Value::List Screen::GetGpuExtraInfo(
  113. const gfx::GpuExtraInfo& gpu_extra_info) {
  114. return base::Value::List();
  115. }
  116. void Screen::SetScopedDisplayForNewWindows(int64_t display_id) {
  117. if (display_id == scoped_display_id_for_new_windows_)
  118. return;
  119. // Only allow set and clear, not switch.
  120. DCHECK(display_id == kInvalidDisplayId ^
  121. scoped_display_id_for_new_windows_ == kInvalidDisplayId)
  122. << "display_id=" << display_id << ", scoped_display_id_for_new_windows_="
  123. << scoped_display_id_for_new_windows_;
  124. scoped_display_id_for_new_windows_ = display_id;
  125. }
  126. ScreenInfos Screen::GetScreenInfosNearestDisplay(int64_t nearest_id) const {
  127. ScreenInfos result;
  128. // Determine the current and primary display ids.
  129. std::vector<Display> displays = GetAllDisplays();
  130. Display primary = GetPrimaryDisplay();
  131. // Note: displays being empty can happen in Fuchsia unit tests.
  132. if (displays.empty()) {
  133. if (primary.id() == kInvalidDisplayId) {
  134. // If we are in a situation where we have no displays and so the primary
  135. // display is invalid, then it's a logic error (elsewhere) to pass in a
  136. // valid id, because where would it come from?
  137. DCHECK_EQ(nearest_id, kInvalidDisplayId);
  138. primary.set_id(kDefaultDisplayId);
  139. }
  140. displays = {primary};
  141. }
  142. // Use the primary and nearest displays as fallbacks for each other, if the
  143. // counterpart exists in `displays`. Otherwise, use `display[0]` for both.
  144. int64_t primary_id = primary.id();
  145. int64_t current_id = nearest_id;
  146. const bool has_primary = base::Contains(displays, primary_id, &Display::id);
  147. const bool has_nearest = base::Contains(displays, nearest_id, &Display::id);
  148. if (!has_primary)
  149. primary_id = has_nearest ? nearest_id : displays[0].id();
  150. if (!has_nearest)
  151. current_id = primary_id;
  152. // Build ScreenInfos from discovered ids and set of all displays.
  153. bool current_display_exists = false;
  154. bool primary_display_exists = false;
  155. for (const auto& display : displays) {
  156. ScreenInfo screen_info;
  157. DisplayUtil::DisplayToScreenInfo(&screen_info, display);
  158. if (display.id() == current_id) {
  159. result.current_display_id = display.id();
  160. current_display_exists = true;
  161. }
  162. // TODO(enne): move DisplayToScreenInfo to be a private function here,
  163. // so that we don't need to overwrite this.
  164. screen_info.is_primary = display.id() == primary_id;
  165. if (display.id() == primary_id)
  166. primary_display_exists = true;
  167. result.screen_infos.push_back(screen_info);
  168. }
  169. // This is a bit overkill, but verify that the logic above is correct
  170. // because it will cause crashes elsewhere to not have a current display.
  171. CHECK(current_display_exists);
  172. CHECK(primary_display_exists);
  173. return result;
  174. }
  175. #if !BUILDFLAG(IS_ANDROID)
  176. ScopedNativeScreen::ScopedNativeScreen(const base::Location& location) {
  177. MaybeInit(location);
  178. }
  179. ScopedNativeScreen::ScopedNativeScreen(bool call_maybe_init,
  180. const base::Location& location) {
  181. if (call_maybe_init)
  182. MaybeInit(location);
  183. }
  184. ScopedNativeScreen::~ScopedNativeScreen() {
  185. Shutdown();
  186. }
  187. void ScopedNativeScreen::MaybeInit(const base::Location& location) {
  188. maybe_init_called_ = true;
  189. if (!Screen::HasScreen()) {
  190. #if BUILDFLAG(IS_IOS)
  191. Screen::GetScreen();
  192. #else
  193. screen_ = base::WrapUnique(CreateScreen());
  194. // ScreenOzone and DesktopScreenWin sets the instance by itself.
  195. if (Screen::GetScreen() != screen_.get())
  196. Screen::SetScreenInstance(screen_.get(), location);
  197. #endif
  198. }
  199. }
  200. void ScopedNativeScreen::Shutdown() {
  201. DCHECK(maybe_init_called_);
  202. if (screen_) {
  203. DCHECK_EQ(screen_.get(), Screen::GetScreen());
  204. Screen::SetScreenInstance(nullptr);
  205. screen_.reset();
  206. }
  207. }
  208. Screen* ScopedNativeScreen::CreateScreen() {
  209. return CreateNativeScreen();
  210. }
  211. #endif
  212. } // namespace display