Repository: electron/electron
File: shell/browser/api/electron_api_screen.cc (C++)

Code before:

void DelayEmit(Screen* screen,
               const std::string_view name,
               const display::Display& display) {
  screen->Emit(name, display);
}

void DelayEmitWithMetrics(Screen* screen,
                          const std::string_view name,
                          const display::Display& display,
                          const std::vector<std::string>& metrics) {
  screen->Emit(name, display, metrics);
}

}  // namespace

Screen::Screen(v8::Isolate* isolate, display::Screen* screen)
    : screen_(screen) {
  screen_->AddObserver(this);
}

Screen::~Screen() {
  screen_->RemoveObserver(this);
}

gfx::Point Screen::GetCursorScreenPoint(v8::Isolate* isolate) {
#if defined(USE_OZONE)
  // Wayland will crash unless a window is created prior to calling
  // GetCursorScreenPoint.
  if (!ui::OzonePlatform::IsInitialized()) {
    gin_helper::ErrorThrower thrower(isolate);
    thrower.ThrowError(
        "screen.getCursorScreenPoint() cannot be called before a window has "
        "been created.");
    return {};
  }
#endif
  return screen_->GetCursorScreenPoint();
}

#if BUILDFLAG(IS_WIN)

static gfx::Rect ScreenToDIPRect(electron::NativeWindow* window,
                                 const gfx::Rect& rect) {
  HWND hwnd = window ? window->GetAcceleratedWidget() : nullptr;
  return display::win::GetScreenWin()->ScreenToDIPRect(hwnd, rect);
}

static gfx::Rect DIPToScreenRect(electron::NativeWindow* window,
                                 const gfx::Rect& rect) {
  HWND hwnd = window ? window->GetAcceleratedWidget() : nullptr;

Review comment (performance):
@ckerr I missed this new iteration change, if the api class is outliving the cached screen then we also need a similar check in https://github.com/electron/electron/blob/30f365d9d8b554107e5c5f7a624c3c8984f3b00d/shell/browser/api/electron_api_screen.cc#L98 to protect against use-after-free.

Code after:
}

void DelayEmit(Screen* screen,
               const std::string_view name,
               const display::Display& display) {
  screen->Emit(name, display);
}

void DelayEmitWithMetrics(Screen* screen,
                          const std::string_view name,
                          const display::Display& display,
                          const std::vector<std::string>& metrics) {
  screen->Emit(name, display, metrics);
}

}  // namespace

Screen::Screen(display::Screen* screen) : screen_{screen} {
  screen_->AddObserver(this);
}

Screen::~Screen() {
  // Use `display::Screen::Get()` here, not our cached `screen_`:
  // during shutdown, it can get torn down before us.
  if (auto* screen = display::Screen::Get())
    screen->RemoveObserver(this);
}

gfx::Point Screen::GetCursorScreenPoint(v8::Isolate* isolate) {
#if defined(USE_OZONE)
  // Wayland will crash unless a window is created prior to calling
  // GetCursorScreenPoint.
  if (!ui::OzonePlatform::IsInitialized()) {
    gin_helper::ErrorThrower thrower(isolate);
    thrower.ThrowError(
        "screen.getCursorScreenPoint() cannot be called before a window has "
        "been created.");
    return {};
  }
#endif
  return screen_->GetCursorScreenPoint();
}

#if BUILDFLAG(IS_WIN)

static gfx::Rect ScreenToDIPRect(electron::NativeWindow* window,
                                 const gfx::Rect& rect) {
  HWND hwnd = window ? window->GetAcceleratedWidget() : nullptr;
  return display::win::GetScreenWin()->ScreenToDIPRect(hwnd, rect);
}