feat: support dip <-> screen conversion on Linux X11 (#46895)
feat: support dip <-> screen conversion on Linux Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
This commit is contained in:
parent
bf94f88569
commit
d783f134d9
9 changed files with 106 additions and 31 deletions
2
BUILD.gn
2
BUILD.gn
|
@ -670,6 +670,8 @@ source_set("electron_lib") {
|
|||
sources += [
|
||||
"shell/browser/certificate_manager_model.cc",
|
||||
"shell/browser/certificate_manager_model.h",
|
||||
"shell/browser/linux/x11_util.cc",
|
||||
"shell/browser/linux/x11_util.h",
|
||||
"shell/browser/ui/gtk_util.cc",
|
||||
"shell/browser/ui/gtk_util.h",
|
||||
]
|
||||
|
|
|
@ -356,7 +356,7 @@ as `-webkit-app-region: drag` in a frameless window.
|
|||
|
||||
Calling `event.preventDefault()` will prevent the menu from being displayed.
|
||||
|
||||
To convert `point` to DIP, use [`screen.screenToDipPoint(point)`](./screen.md#screenscreentodippointpoint-windows).
|
||||
To convert `point` to DIP, use [`screen.screenToDipPoint(point)`](./screen.md#screenscreentodippointpoint-windows-linux).
|
||||
|
||||
### Static Methods
|
||||
|
||||
|
|
|
@ -435,7 +435,7 @@ as `-webkit-app-region: drag` in a frameless window.
|
|||
|
||||
Calling `event.preventDefault()` will prevent the menu from being displayed.
|
||||
|
||||
To convert `point` to DIP, use [`screen.screenToDipPoint(point)`](./screen.md#screenscreentodippointpoint-windows).
|
||||
To convert `point` to DIP, use [`screen.screenToDipPoint(point)`](./screen.md#screenscreentodippointpoint-windows-linux).
|
||||
|
||||
### Static Methods
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ Returns [`Display`](structures/display.md) - The display nearest the specified p
|
|||
Returns [`Display`](structures/display.md) - The display that most closely
|
||||
intersects the provided bounds.
|
||||
|
||||
### `screen.screenToDipPoint(point)` _Windows_
|
||||
### `screen.screenToDipPoint(point)` _Windows_ _Linux_
|
||||
|
||||
* `point` [Point](structures/point.md)
|
||||
|
||||
|
@ -133,7 +133,10 @@ Returns [`Point`](structures/point.md)
|
|||
Converts a screen physical point to a screen DIP point.
|
||||
The DPI scale is performed relative to the display containing the physical point.
|
||||
|
||||
### `screen.dipToScreenPoint(point)` _Windows_
|
||||
Not currently supported on Wayland - if used there it will return the point passed
|
||||
in with no changes.
|
||||
|
||||
### `screen.dipToScreenPoint(point)` _Windows_ _Linux_
|
||||
|
||||
* `point` [Point](structures/point.md)
|
||||
|
||||
|
@ -142,6 +145,8 @@ Returns [`Point`](structures/point.md)
|
|||
Converts a screen DIP point to a screen physical point.
|
||||
The DPI scale is performed relative to the display containing the DIP point.
|
||||
|
||||
Not currently supported on Wayland.
|
||||
|
||||
### `screen.screenToDipRect(window, rect)` _Windows_
|
||||
|
||||
* `window` [BrowserWindow](browser-window.md) | null
|
||||
|
|
|
@ -20,11 +20,18 @@
|
|||
#include "ui/display/display.h"
|
||||
#include "ui/display/screen.h"
|
||||
#include "ui/gfx/geometry/point.h"
|
||||
#include "ui/gfx/geometry/point_conversions.h"
|
||||
#include "ui/gfx/geometry/point_f.h"
|
||||
#include "ui/gfx/geometry/vector2d_conversions.h"
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
#include "ui/display/win/screen_win.h"
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
#include "shell/browser/linux/x11_util.h"
|
||||
#endif
|
||||
|
||||
#if defined(USE_OZONE)
|
||||
#include "ui/ozone/public/ozone_platform.h"
|
||||
#endif
|
||||
|
@ -102,14 +109,6 @@ static gfx::Rect DIPToScreenRect(electron::NativeWindow* window,
|
|||
return display::win::GetScreenWin()->DIPToScreenRect(hwnd, rect);
|
||||
}
|
||||
|
||||
static gfx::PointF ScreenToDIPPoint(const gfx::PointF& pixel_point) {
|
||||
return display::win::GetScreenWin()->ScreenToDIPPoint(pixel_point);
|
||||
}
|
||||
|
||||
static gfx::Point DIPToScreenPoint(const gfx::Point& dip_point) {
|
||||
return display::win::GetScreenWin()->DIPToScreenPoint(dip_point);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void Screen::OnDisplayAdded(const display::Display& new_display) {
|
||||
|
@ -134,6 +133,44 @@ void Screen::OnDisplayMetricsChanged(const display::Display& display,
|
|||
MetricsToArray(changed_metrics)));
|
||||
}
|
||||
|
||||
gfx::PointF Screen::ScreenToDIPPoint(const gfx::PointF& point_px) {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
return display::win::GetScreenWin()->ScreenToDIPPoint(point_px);
|
||||
#elif BUILDFLAG(IS_LINUX)
|
||||
if (x11_util::IsX11()) {
|
||||
gfx::Point pt_px = gfx::ToFlooredPoint(point_px);
|
||||
display::Display display = GetDisplayNearestPoint(pt_px);
|
||||
gfx::Vector2d delta_px = pt_px - display.native_origin();
|
||||
gfx::Vector2dF delta_dip =
|
||||
gfx::ScaleVector2d(delta_px, 1.0 / display.device_scale_factor());
|
||||
return gfx::PointF(display.bounds().origin()) + delta_dip;
|
||||
} else {
|
||||
return point_px;
|
||||
}
|
||||
#else
|
||||
return point_px;
|
||||
#endif
|
||||
}
|
||||
|
||||
gfx::Point Screen::DIPToScreenPoint(const gfx::Point& point_dip) {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
return display::win::GetScreenWin()->DIPToScreenPoint(point_dip);
|
||||
#elif BUILDFLAG(IS_LINUX)
|
||||
if (x11_util::IsX11()) {
|
||||
display::Display display = GetDisplayNearestPoint(point_dip);
|
||||
gfx::Rect bounds_dip = display.bounds();
|
||||
gfx::Vector2d delta_dip = point_dip - bounds_dip.origin();
|
||||
gfx::Vector2d delta_px = gfx::ToFlooredVector2d(
|
||||
gfx::ScaleVector2d(delta_dip, display.device_scale_factor()));
|
||||
return display.native_origin() + delta_px;
|
||||
} else {
|
||||
return point_dip;
|
||||
}
|
||||
#else
|
||||
return point_dip;
|
||||
#endif
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Local<v8::Value> Screen::Create(gin_helper::ErrorThrower error_thrower) {
|
||||
if (!Browser::Get()->is_ready()) {
|
||||
|
@ -161,9 +198,11 @@ gin::ObjectTemplateBuilder Screen::GetObjectTemplateBuilder(
|
|||
.SetMethod("getPrimaryDisplay", &Screen::GetPrimaryDisplay)
|
||||
.SetMethod("getAllDisplays", &Screen::GetAllDisplays)
|
||||
.SetMethod("getDisplayNearestPoint", &Screen::GetDisplayNearestPoint)
|
||||
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
|
||||
.SetMethod("screenToDipPoint", &Screen::ScreenToDIPPoint)
|
||||
.SetMethod("dipToScreenPoint", &Screen::DIPToScreenPoint)
|
||||
#endif
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
.SetMethod("screenToDipPoint", &ScreenToDIPPoint)
|
||||
.SetMethod("dipToScreenPoint", &DIPToScreenPoint)
|
||||
.SetMethod("screenToDipRect", &ScreenToDIPRect)
|
||||
.SetMethod("dipToScreenRect", &DIPToScreenRect)
|
||||
#endif
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
namespace gfx {
|
||||
class Point;
|
||||
class PointF;
|
||||
class Rect;
|
||||
class Screen;
|
||||
} // namespace gfx
|
||||
|
@ -58,6 +59,9 @@ class Screen final : public gin::Wrappable<Screen>,
|
|||
return screen_->GetDisplayMatching(match_rect);
|
||||
}
|
||||
|
||||
gfx::PointF ScreenToDIPPoint(const gfx::PointF& point_px);
|
||||
gfx::Point DIPToScreenPoint(const gfx::Point& point_dip);
|
||||
|
||||
// display::DisplayObserver:
|
||||
void OnDisplayAdded(const display::Display& new_display) override;
|
||||
void OnDisplaysRemoved(const display::Displays& removed_displays) override;
|
||||
|
|
17
shell/browser/linux/x11_util.cc
Normal file
17
shell/browser/linux/x11_util.cc
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Copyright (c) 2025 Microsoft GmbH.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/linux/x11_util.h"
|
||||
|
||||
#include "ui/ozone/public/ozone_platform.h"
|
||||
|
||||
namespace x11_util {
|
||||
|
||||
bool IsX11() {
|
||||
return ui::OzonePlatform::GetInstance()
|
||||
->GetPlatformProperties()
|
||||
.electron_can_call_x11;
|
||||
}
|
||||
|
||||
} // namespace x11_util
|
14
shell/browser/linux/x11_util.h
Normal file
14
shell/browser/linux/x11_util.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) 2025 Microsoft GmbH.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ELECTRON_SHELL_BROWSER_LINUX_X11_UTIL_H_
|
||||
#define ELECTRON_SHELL_BROWSER_LINUX_X11_UTIL_H_
|
||||
|
||||
namespace x11_util {
|
||||
|
||||
bool IsX11();
|
||||
|
||||
} // namespace x11_util
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_LINUX_X11_UTIL_H_
|
|
@ -53,6 +53,7 @@
|
|||
#include "base/strings/string_util.h"
|
||||
#include "shell/browser/browser.h"
|
||||
#include "shell/browser/linux/unity_service.h"
|
||||
#include "shell/browser/linux/x11_util.h"
|
||||
#include "shell/browser/ui/electron_desktop_window_tree_host_linux.h"
|
||||
#include "shell/browser/ui/views/client_frame_view_linux.h"
|
||||
#include "shell/browser/ui/views/native_frame_view.h"
|
||||
|
@ -163,13 +164,6 @@ gfx::Size WindowSizeToContentSizeBuggy(HWND hwnd, const gfx::Size& size) {
|
|||
|
||||
#endif
|
||||
|
||||
[[maybe_unused, nodiscard]] bool IsX11() {
|
||||
static const bool is_x11 = ui::OzonePlatform::GetInstance()
|
||||
->GetPlatformProperties()
|
||||
.electron_can_call_x11;
|
||||
return is_x11;
|
||||
}
|
||||
|
||||
class NativeWindowClientView : public views::ClientView {
|
||||
public:
|
||||
NativeWindowClientView(views::Widget* widget,
|
||||
|
@ -331,7 +325,7 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options,
|
|||
if (parent)
|
||||
SetParentWindow(parent);
|
||||
|
||||
if (IsX11()) {
|
||||
if (x11_util::IsX11()) {
|
||||
// Before the window is mapped the SetWMSpecState can not work, so we have
|
||||
// to manually set the _NET_WM_STATE.
|
||||
std::vector<x11::Atom> state_atom_list;
|
||||
|
@ -452,7 +446,7 @@ NativeWindowViews::~NativeWindowViews() {
|
|||
|
||||
void NativeWindowViews::SetGTKDarkThemeEnabled(bool use_dark_theme) {
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
if (IsX11()) {
|
||||
if (x11_util::IsX11()) {
|
||||
const std::string color = use_dark_theme ? "dark" : "light";
|
||||
auto* connection = x11::Connection::Get();
|
||||
connection->SetStringProperty(
|
||||
|
@ -514,7 +508,7 @@ void NativeWindowViews::Show() {
|
|||
|
||||
// On X11, setting Z order before showing the window doesn't take effect,
|
||||
// so we have to call it again.
|
||||
if (IsX11())
|
||||
if (x11_util::IsX11())
|
||||
widget()->SetZOrderLevel(widget()->GetZOrderLevel());
|
||||
#endif
|
||||
}
|
||||
|
@ -530,7 +524,7 @@ void NativeWindowViews::ShowInactive() {
|
|||
|
||||
// On X11, setting Z order before showing the window doesn't take effect,
|
||||
// so we have to call it again.
|
||||
if (IsX11())
|
||||
if (x11_util::IsX11())
|
||||
widget()->SetZOrderLevel(widget()->GetZOrderLevel());
|
||||
#endif
|
||||
}
|
||||
|
@ -575,7 +569,7 @@ bool NativeWindowViews::IsEnabled() const {
|
|||
#if BUILDFLAG(IS_WIN)
|
||||
return ::IsWindowEnabled(GetAcceleratedWidget());
|
||||
#elif BUILDFLAG(IS_LINUX)
|
||||
if (IsX11())
|
||||
if (x11_util::IsX11())
|
||||
return !event_disabler_.get();
|
||||
NOTIMPLEMENTED();
|
||||
return true;
|
||||
|
@ -612,7 +606,7 @@ void NativeWindowViews::SetEnabledInternal(bool enable) {
|
|||
#if BUILDFLAG(IS_WIN)
|
||||
::EnableWindow(GetAcceleratedWidget(), enable);
|
||||
#else
|
||||
if (IsX11()) {
|
||||
if (x11_util::IsX11()) {
|
||||
views::DesktopWindowTreeHostPlatform* tree_host =
|
||||
views::DesktopWindowTreeHostLinux::GetHostForWidget(
|
||||
GetAcceleratedWidget());
|
||||
|
@ -944,7 +938,7 @@ bool NativeWindowViews::MoveAbove(const std::string& sourceId) {
|
|||
0, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
|
||||
#else
|
||||
if (IsX11()) {
|
||||
if (x11_util::IsX11()) {
|
||||
if (!IsWindowValid(static_cast<x11::Window>(id.id)))
|
||||
return false;
|
||||
|
||||
|
@ -966,7 +960,7 @@ void NativeWindowViews::MoveTop() {
|
|||
size.width(), size.height(),
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
|
||||
#else
|
||||
if (IsX11())
|
||||
if (x11_util::IsX11())
|
||||
electron::MoveWindowToForeground(
|
||||
static_cast<x11::Window>(GetAcceleratedWidget()));
|
||||
#endif
|
||||
|
@ -1280,7 +1274,7 @@ void NativeWindowViews::SetIgnoreMouseEvents(bool ignore, bool forward) {
|
|||
SetForwardMouseMessages(forward);
|
||||
}
|
||||
#else
|
||||
if (IsX11()) {
|
||||
if (x11_util::IsX11()) {
|
||||
auto* connection = x11::Connection::Get();
|
||||
if (ignore) {
|
||||
x11::Rectangle r{0, 0, 1, 1};
|
||||
|
@ -1401,7 +1395,7 @@ void NativeWindowViews::SetParentWindow(NativeWindow* parent) {
|
|||
NativeWindow::SetParentWindow(parent);
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
if (IsX11()) {
|
||||
if (x11_util::IsX11()) {
|
||||
auto* connection = x11::Connection::Get();
|
||||
connection->SetProperty(
|
||||
static_cast<x11::Window>(GetAcceleratedWidget()),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue