feat: support dip <-> screen conversion on Linux (#47125)
* feat: support dip <-> screen conversion on Linux * chore: fix build
This commit is contained in:
parent
6dea52b6c0
commit
a4dfd9b6f3
9 changed files with 107 additions and 24 deletions
2
BUILD.gn
2
BUILD.gn
|
@ -670,6 +670,8 @@ source_set("electron_lib") {
|
||||||
sources += [
|
sources += [
|
||||||
"shell/browser/certificate_manager_model.cc",
|
"shell/browser/certificate_manager_model.cc",
|
||||||
"shell/browser/certificate_manager_model.h",
|
"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.cc",
|
||||||
"shell/browser/ui/gtk_util.h",
|
"shell/browser/ui/gtk_util.h",
|
||||||
]
|
]
|
||||||
|
|
|
@ -362,7 +362,7 @@ as `-webkit-app-region: drag` in a frameless window.
|
||||||
|
|
||||||
Calling `event.preventDefault()` will prevent the menu from being displayed.
|
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
|
### Static Methods
|
||||||
|
|
||||||
|
|
|
@ -441,7 +441,7 @@ as `-webkit-app-region: drag` in a frameless window.
|
||||||
|
|
||||||
Calling `event.preventDefault()` will prevent the menu from being displayed.
|
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
|
### Static Methods
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,7 @@ Returns [`Display`](structures/display.md) - The display nearest the specified p
|
||||||
Returns [`Display`](structures/display.md) - The display that most closely
|
Returns [`Display`](structures/display.md) - The display that most closely
|
||||||
intersects the provided bounds.
|
intersects the provided bounds.
|
||||||
|
|
||||||
### `screen.screenToDipPoint(point)` _Windows_
|
### `screen.screenToDipPoint(point)` _Windows_ _Linux_
|
||||||
|
|
||||||
* `point` [Point](structures/point.md)
|
* `point` [Point](structures/point.md)
|
||||||
|
|
||||||
|
@ -143,7 +143,10 @@ Returns [`Point`](structures/point.md)
|
||||||
Converts a screen physical point to a screen DIP point.
|
Converts a screen physical point to a screen DIP point.
|
||||||
The DPI scale is performed relative to the display containing the physical 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)
|
* `point` [Point](structures/point.md)
|
||||||
|
|
||||||
|
@ -152,6 +155,8 @@ Returns [`Point`](structures/point.md)
|
||||||
Converts a screen DIP point to a screen physical point.
|
Converts a screen DIP point to a screen physical point.
|
||||||
The DPI scale is performed relative to the display containing the DIP point.
|
The DPI scale is performed relative to the display containing the DIP point.
|
||||||
|
|
||||||
|
Not currently supported on Wayland.
|
||||||
|
|
||||||
### `screen.screenToDipRect(window, rect)` _Windows_
|
### `screen.screenToDipRect(window, rect)` _Windows_
|
||||||
|
|
||||||
* `window` [BrowserWindow](browser-window.md) | null
|
* `window` [BrowserWindow](browser-window.md) | null
|
||||||
|
|
|
@ -20,11 +20,18 @@
|
||||||
#include "ui/display/display.h"
|
#include "ui/display/display.h"
|
||||||
#include "ui/display/screen.h"
|
#include "ui/display/screen.h"
|
||||||
#include "ui/gfx/geometry/point.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)
|
#if BUILDFLAG(IS_WIN)
|
||||||
#include "ui/display/win/screen_win.h"
|
#include "ui/display/win/screen_win.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if BUILDFLAG(IS_LINUX)
|
||||||
|
#include "shell/browser/linux/x11_util.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(USE_OZONE)
|
#if defined(USE_OZONE)
|
||||||
#include "ui/ozone/public/ozone_platform.h"
|
#include "ui/ozone/public/ozone_platform.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -126,6 +133,44 @@ void Screen::OnDisplayMetricsChanged(const display::Display& display,
|
||||||
MetricsToArray(changed_metrics)));
|
MetricsToArray(changed_metrics)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gfx::PointF Screen::ScreenToDIPPoint(const gfx::PointF& point_px) {
|
||||||
|
#if BUILDFLAG(IS_WIN)
|
||||||
|
return display::win::ScreenWin::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::ScreenWin::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
|
// static
|
||||||
v8::Local<v8::Value> Screen::Create(gin_helper::ErrorThrower error_thrower) {
|
v8::Local<v8::Value> Screen::Create(gin_helper::ErrorThrower error_thrower) {
|
||||||
if (!Browser::Get()->is_ready()) {
|
if (!Browser::Get()->is_ready()) {
|
||||||
|
@ -153,9 +198,11 @@ gin::ObjectTemplateBuilder Screen::GetObjectTemplateBuilder(
|
||||||
.SetMethod("getPrimaryDisplay", &Screen::GetPrimaryDisplay)
|
.SetMethod("getPrimaryDisplay", &Screen::GetPrimaryDisplay)
|
||||||
.SetMethod("getAllDisplays", &Screen::GetAllDisplays)
|
.SetMethod("getAllDisplays", &Screen::GetAllDisplays)
|
||||||
.SetMethod("getDisplayNearestPoint", &Screen::GetDisplayNearestPoint)
|
.SetMethod("getDisplayNearestPoint", &Screen::GetDisplayNearestPoint)
|
||||||
|
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
|
||||||
|
.SetMethod("screenToDipPoint", &Screen::ScreenToDIPPoint)
|
||||||
|
.SetMethod("dipToScreenPoint", &Screen::DIPToScreenPoint)
|
||||||
|
#endif
|
||||||
#if BUILDFLAG(IS_WIN)
|
#if BUILDFLAG(IS_WIN)
|
||||||
.SetMethod("screenToDipPoint", &display::win::ScreenWin::ScreenToDIPPoint)
|
|
||||||
.SetMethod("dipToScreenPoint", &display::win::ScreenWin::DIPToScreenPoint)
|
|
||||||
.SetMethod("screenToDipRect", &ScreenToDIPRect)
|
.SetMethod("screenToDipRect", &ScreenToDIPRect)
|
||||||
.SetMethod("dipToScreenRect", &DIPToScreenRect)
|
.SetMethod("dipToScreenRect", &DIPToScreenRect)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
namespace gfx {
|
namespace gfx {
|
||||||
class Point;
|
class Point;
|
||||||
|
class PointF;
|
||||||
class Rect;
|
class Rect;
|
||||||
class Screen;
|
class Screen;
|
||||||
} // namespace gfx
|
} // namespace gfx
|
||||||
|
@ -58,6 +59,9 @@ class Screen final : public gin::Wrappable<Screen>,
|
||||||
return screen_->GetDisplayMatching(match_rect);
|
return screen_->GetDisplayMatching(match_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gfx::PointF ScreenToDIPPoint(const gfx::PointF& point_px);
|
||||||
|
gfx::Point DIPToScreenPoint(const gfx::Point& point_dip);
|
||||||
|
|
||||||
// display::DisplayObserver:
|
// display::DisplayObserver:
|
||||||
void OnDisplayAdded(const display::Display& new_display) override;
|
void OnDisplayAdded(const display::Display& new_display) override;
|
||||||
void OnDisplaysRemoved(const display::Displays& removed_displays) 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_
|
|
@ -55,6 +55,7 @@
|
||||||
#include "base/strings/string_util.h"
|
#include "base/strings/string_util.h"
|
||||||
#include "shell/browser/browser.h"
|
#include "shell/browser/browser.h"
|
||||||
#include "shell/browser/linux/unity_service.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/electron_desktop_window_tree_host_linux.h"
|
||||||
#include "shell/browser/ui/views/client_frame_view_linux.h"
|
#include "shell/browser/ui/views/client_frame_view_linux.h"
|
||||||
#include "shell/browser/ui/views/native_frame_view.h"
|
#include "shell/browser/ui/views/native_frame_view.h"
|
||||||
|
@ -164,13 +165,6 @@ gfx::Size WindowSizeToContentSizeBuggy(HWND hwnd, const gfx::Size& size) {
|
||||||
|
|
||||||
#endif
|
#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 {
|
class NativeWindowClientView : public views::ClientView {
|
||||||
public:
|
public:
|
||||||
NativeWindowClientView(views::Widget* widget,
|
NativeWindowClientView(views::Widget* widget,
|
||||||
|
@ -328,7 +322,7 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options,
|
||||||
if (parent)
|
if (parent)
|
||||||
SetParentWindow(parent);
|
SetParentWindow(parent);
|
||||||
|
|
||||||
if (IsX11()) {
|
if (x11_util::IsX11()) {
|
||||||
// Before the window is mapped the SetWMSpecState can not work, so we have
|
// Before the window is mapped the SetWMSpecState can not work, so we have
|
||||||
// to manually set the _NET_WM_STATE.
|
// to manually set the _NET_WM_STATE.
|
||||||
std::vector<x11::Atom> state_atom_list;
|
std::vector<x11::Atom> state_atom_list;
|
||||||
|
@ -479,7 +473,7 @@ NativeWindowViews::~NativeWindowViews() {
|
||||||
|
|
||||||
void NativeWindowViews::SetGTKDarkThemeEnabled(bool use_dark_theme) {
|
void NativeWindowViews::SetGTKDarkThemeEnabled(bool use_dark_theme) {
|
||||||
#if BUILDFLAG(IS_LINUX)
|
#if BUILDFLAG(IS_LINUX)
|
||||||
if (IsX11()) {
|
if (x11_util::IsX11()) {
|
||||||
const std::string color = use_dark_theme ? "dark" : "light";
|
const std::string color = use_dark_theme ? "dark" : "light";
|
||||||
auto* connection = x11::Connection::Get();
|
auto* connection = x11::Connection::Get();
|
||||||
connection->SetStringProperty(
|
connection->SetStringProperty(
|
||||||
|
@ -545,7 +539,7 @@ void NativeWindowViews::Show() {
|
||||||
|
|
||||||
// On X11, setting Z order before showing the window doesn't take effect,
|
// On X11, setting Z order before showing the window doesn't take effect,
|
||||||
// so we have to call it again.
|
// so we have to call it again.
|
||||||
if (IsX11())
|
if (x11_util::IsX11())
|
||||||
widget()->SetZOrderLevel(widget()->GetZOrderLevel());
|
widget()->SetZOrderLevel(widget()->GetZOrderLevel());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -561,7 +555,7 @@ void NativeWindowViews::ShowInactive() {
|
||||||
|
|
||||||
// On X11, setting Z order before showing the window doesn't take effect,
|
// On X11, setting Z order before showing the window doesn't take effect,
|
||||||
// so we have to call it again.
|
// so we have to call it again.
|
||||||
if (IsX11())
|
if (x11_util::IsX11())
|
||||||
widget()->SetZOrderLevel(widget()->GetZOrderLevel());
|
widget()->SetZOrderLevel(widget()->GetZOrderLevel());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -606,7 +600,7 @@ bool NativeWindowViews::IsEnabled() const {
|
||||||
#if BUILDFLAG(IS_WIN)
|
#if BUILDFLAG(IS_WIN)
|
||||||
return ::IsWindowEnabled(GetAcceleratedWidget());
|
return ::IsWindowEnabled(GetAcceleratedWidget());
|
||||||
#elif BUILDFLAG(IS_LINUX)
|
#elif BUILDFLAG(IS_LINUX)
|
||||||
if (IsX11())
|
if (x11_util::IsX11())
|
||||||
return !event_disabler_.get();
|
return !event_disabler_.get();
|
||||||
NOTIMPLEMENTED();
|
NOTIMPLEMENTED();
|
||||||
return true;
|
return true;
|
||||||
|
@ -643,7 +637,7 @@ void NativeWindowViews::SetEnabledInternal(bool enable) {
|
||||||
#if BUILDFLAG(IS_WIN)
|
#if BUILDFLAG(IS_WIN)
|
||||||
::EnableWindow(GetAcceleratedWidget(), enable);
|
::EnableWindow(GetAcceleratedWidget(), enable);
|
||||||
#else
|
#else
|
||||||
if (IsX11()) {
|
if (x11_util::IsX11()) {
|
||||||
views::DesktopWindowTreeHostPlatform* tree_host =
|
views::DesktopWindowTreeHostPlatform* tree_host =
|
||||||
views::DesktopWindowTreeHostLinux::GetHostForWidget(
|
views::DesktopWindowTreeHostLinux::GetHostForWidget(
|
||||||
GetAcceleratedWidget());
|
GetAcceleratedWidget());
|
||||||
|
@ -975,7 +969,7 @@ bool NativeWindowViews::MoveAbove(const std::string& sourceId) {
|
||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
|
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
|
||||||
#else
|
#else
|
||||||
if (IsX11()) {
|
if (x11_util::IsX11()) {
|
||||||
if (!IsWindowValid(static_cast<x11::Window>(id.id)))
|
if (!IsWindowValid(static_cast<x11::Window>(id.id)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -997,7 +991,7 @@ void NativeWindowViews::MoveTop() {
|
||||||
size.width(), size.height(),
|
size.width(), size.height(),
|
||||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
|
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
|
||||||
#else
|
#else
|
||||||
if (IsX11())
|
if (x11_util::IsX11())
|
||||||
electron::MoveWindowToForeground(
|
electron::MoveWindowToForeground(
|
||||||
static_cast<x11::Window>(GetAcceleratedWidget()));
|
static_cast<x11::Window>(GetAcceleratedWidget()));
|
||||||
#endif
|
#endif
|
||||||
|
@ -1312,7 +1306,7 @@ void NativeWindowViews::SetIgnoreMouseEvents(bool ignore, bool forward) {
|
||||||
SetForwardMouseMessages(forward);
|
SetForwardMouseMessages(forward);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (IsX11()) {
|
if (x11_util::IsX11()) {
|
||||||
auto* connection = x11::Connection::Get();
|
auto* connection = x11::Connection::Get();
|
||||||
if (ignore) {
|
if (ignore) {
|
||||||
x11::Rectangle r{0, 0, 1, 1};
|
x11::Rectangle r{0, 0, 1, 1};
|
||||||
|
@ -1434,7 +1428,7 @@ void NativeWindowViews::SetParentWindow(NativeWindow* parent) {
|
||||||
NativeWindow::SetParentWindow(parent);
|
NativeWindow::SetParentWindow(parent);
|
||||||
|
|
||||||
#if BUILDFLAG(IS_LINUX)
|
#if BUILDFLAG(IS_LINUX)
|
||||||
if (IsX11()) {
|
if (x11_util::IsX11()) {
|
||||||
auto* connection = x11::Connection::Get();
|
auto* connection = x11::Connection::Get();
|
||||||
connection->SetProperty(
|
connection->SetProperty(
|
||||||
static_cast<x11::Window>(GetAcceleratedWidget()),
|
static_cast<x11::Window>(GetAcceleratedWidget()),
|
||||||
|
@ -1574,7 +1568,7 @@ bool NativeWindowViews::IsVisibleOnAllWorkspaces() const {
|
||||||
return view_native_widget->IsVisibleOnAllWorkspaces();
|
return view_native_widget->IsVisibleOnAllWorkspaces();
|
||||||
|
|
||||||
#if BUILDFLAG(IS_LINUX)
|
#if BUILDFLAG(IS_LINUX)
|
||||||
if (IsX11()) {
|
if (x11_util::IsX11()) {
|
||||||
// Use the presence/absence of _NET_WM_STATE_STICKY in _NET_WM_STATE to
|
// Use the presence/absence of _NET_WM_STATE_STICKY in _NET_WM_STATE to
|
||||||
// determine whether the current window is visible on all workspaces.
|
// determine whether the current window is visible on all workspaces.
|
||||||
x11::Atom sticky_atom = x11::GetAtom("_NET_WM_STATE_STICKY");
|
x11::Atom sticky_atom = x11::GetAtom("_NET_WM_STATE_STICKY");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue