electron_api_screen.cc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. // Copyright (c) 2013 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "shell/browser/api/electron_api_screen.h"
  5. #include <string>
  6. #include "base/functional/bind.h"
  7. #include "gin/dictionary.h"
  8. #include "gin/handle.h"
  9. #include "shell/browser/browser.h"
  10. #include "shell/common/gin_converters/callback_converter.h"
  11. #include "shell/common/gin_converters/gfx_converter.h"
  12. #include "shell/common/gin_converters/native_window_converter.h"
  13. #include "shell/common/gin_helper/dictionary.h"
  14. #include "shell/common/gin_helper/object_template_builder.h"
  15. #include "shell/common/node_includes.h"
  16. #include "ui/display/display.h"
  17. #include "ui/display/screen.h"
  18. #include "ui/gfx/geometry/point.h"
  19. #if BUILDFLAG(IS_WIN)
  20. #include "ui/display/win/screen_win.h"
  21. #endif
  22. #if defined(USE_OZONE)
  23. #include "ui/ozone/public/ozone_platform.h"
  24. #endif
  25. namespace electron::api {
  26. gin::WrapperInfo Screen::kWrapperInfo = {gin::kEmbedderNativeGin};
  27. namespace {
  28. // Convert the changed_metrics bitmask to string array.
  29. std::vector<std::string> MetricsToArray(uint32_t metrics) {
  30. std::vector<std::string> array;
  31. if (metrics & display::DisplayObserver::DISPLAY_METRIC_BOUNDS)
  32. array.emplace_back("bounds");
  33. if (metrics & display::DisplayObserver::DISPLAY_METRIC_WORK_AREA)
  34. array.emplace_back("workArea");
  35. if (metrics & display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR)
  36. array.emplace_back("scaleFactor");
  37. if (metrics & display::DisplayObserver::DISPLAY_METRIC_ROTATION)
  38. array.emplace_back("rotation");
  39. return array;
  40. }
  41. void DelayEmit(Screen* screen,
  42. base::StringPiece name,
  43. const display::Display& display) {
  44. screen->Emit(name, display);
  45. }
  46. void DelayEmitWithMetrics(Screen* screen,
  47. base::StringPiece name,
  48. const display::Display& display,
  49. const std::vector<std::string>& metrics) {
  50. screen->Emit(name, display, metrics);
  51. }
  52. } // namespace
  53. Screen::Screen(v8::Isolate* isolate, display::Screen* screen)
  54. : screen_(screen) {
  55. screen_->AddObserver(this);
  56. }
  57. Screen::~Screen() {
  58. screen_->RemoveObserver(this);
  59. }
  60. gfx::Point Screen::GetCursorScreenPoint(v8::Isolate* isolate) {
  61. #if defined(USE_OZONE)
  62. // Wayland will crash unless a window is created prior to calling
  63. // GetCursorScreenPoint.
  64. if (!ui::OzonePlatform::IsInitialized()) {
  65. gin_helper::ErrorThrower thrower(isolate);
  66. thrower.ThrowError(
  67. "screen.getCursorScreenPoint() cannot be called before a window has "
  68. "been created.");
  69. return gfx::Point();
  70. }
  71. #endif
  72. return screen_->GetCursorScreenPoint();
  73. }
  74. #if BUILDFLAG(IS_WIN)
  75. static gfx::Rect ScreenToDIPRect(electron::NativeWindow* window,
  76. const gfx::Rect& rect) {
  77. HWND hwnd = window ? window->GetAcceleratedWidget() : nullptr;
  78. return display::win::ScreenWin::ScreenToDIPRect(hwnd, rect);
  79. }
  80. static gfx::Rect DIPToScreenRect(electron::NativeWindow* window,
  81. const gfx::Rect& rect) {
  82. HWND hwnd = window ? window->GetAcceleratedWidget() : nullptr;
  83. return display::win::ScreenWin::DIPToScreenRect(hwnd, rect);
  84. }
  85. #endif
  86. void Screen::OnDisplayAdded(const display::Display& new_display) {
  87. base::SingleThreadTaskRunner::GetCurrentDefault()->PostNonNestableTask(
  88. FROM_HERE, base::BindOnce(&DelayEmit, base::Unretained(this),
  89. "display-added", new_display));
  90. }
  91. void Screen::OnDisplayRemoved(const display::Display& old_display) {
  92. base::SingleThreadTaskRunner::GetCurrentDefault()->PostNonNestableTask(
  93. FROM_HERE, base::BindOnce(&DelayEmit, base::Unretained(this),
  94. "display-removed", old_display));
  95. }
  96. void Screen::OnDisplayMetricsChanged(const display::Display& display,
  97. uint32_t changed_metrics) {
  98. base::SingleThreadTaskRunner::GetCurrentDefault()->PostNonNestableTask(
  99. FROM_HERE, base::BindOnce(&DelayEmitWithMetrics, base::Unretained(this),
  100. "display-metrics-changed", display,
  101. MetricsToArray(changed_metrics)));
  102. }
  103. // static
  104. v8::Local<v8::Value> Screen::Create(gin_helper::ErrorThrower error_thrower) {
  105. if (!Browser::Get()->is_ready()) {
  106. error_thrower.ThrowError(
  107. "The 'screen' module can't be used before the app 'ready' event");
  108. return v8::Null(error_thrower.isolate());
  109. }
  110. display::Screen* screen = display::Screen::GetScreen();
  111. if (!screen) {
  112. error_thrower.ThrowError("Failed to get screen information");
  113. return v8::Null(error_thrower.isolate());
  114. }
  115. return gin::CreateHandle(error_thrower.isolate(),
  116. new Screen(error_thrower.isolate(), screen))
  117. .ToV8();
  118. }
  119. gin::ObjectTemplateBuilder Screen::GetObjectTemplateBuilder(
  120. v8::Isolate* isolate) {
  121. return gin_helper::EventEmitterMixin<Screen>::GetObjectTemplateBuilder(
  122. isolate)
  123. .SetMethod("getCursorScreenPoint", &Screen::GetCursorScreenPoint)
  124. .SetMethod("getPrimaryDisplay", &Screen::GetPrimaryDisplay)
  125. .SetMethod("getAllDisplays", &Screen::GetAllDisplays)
  126. .SetMethod("getDisplayNearestPoint", &Screen::GetDisplayNearestPoint)
  127. #if BUILDFLAG(IS_WIN)
  128. .SetMethod("screenToDipPoint", &display::win::ScreenWin::ScreenToDIPPoint)
  129. .SetMethod("dipToScreenPoint", &display::win::ScreenWin::DIPToScreenPoint)
  130. .SetMethod("screenToDipRect", &ScreenToDIPRect)
  131. .SetMethod("dipToScreenRect", &DIPToScreenRect)
  132. #endif
  133. .SetMethod("getDisplayMatching", &Screen::GetDisplayMatching);
  134. }
  135. const char* Screen::GetTypeName() {
  136. return "Screen";
  137. }
  138. } // namespace electron::api
  139. namespace {
  140. using electron::api::Screen;
  141. void Initialize(v8::Local<v8::Object> exports,
  142. v8::Local<v8::Value> unused,
  143. v8::Local<v8::Context> context,
  144. void* priv) {
  145. v8::Isolate* isolate = context->GetIsolate();
  146. gin_helper::Dictionary dict(isolate, exports);
  147. dict.SetMethod("createScreen", base::BindRepeating(&Screen::Create));
  148. }
  149. } // namespace
  150. NODE_LINKED_BINDING_CONTEXT_AWARE(electron_browser_screen, Initialize)