1 // Copyright 2018 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
5 #include "ui/ozone/platform/x11/x11_screen_ozone.h"
6
7 #include "ui/base/x/x11_util.h"
8 #include "ui/display/display_finder.h"
9 #include "ui/display/util/display_util.h"
10 #include "ui/events/platform/x11/x11_event_source.h"
11 #include "ui/gfx/font_render_params.h"
12 #include "ui/gfx/geometry/dip_util.h"
13 #include "ui/ozone/platform/x11/x11_window_ozone.h"
14 #include "ui/platform_window/x11/x11_window_manager.h"
15
16 namespace ui {
17
18 namespace {
19
GetDeviceScaleFactor()20 float GetDeviceScaleFactor() {
21 float device_scale_factor = 1.0f;
22 // TODO(crbug.com/891175): Implement PlatformScreen for X11
23 // Get device scale factor using scale factor and resolution like
24 // 'GtkUi::GetRawDeviceScaleFactor'.
25 if (display::Display::HasForceDeviceScaleFactor())
26 device_scale_factor = display::Display::GetForcedDeviceScaleFactor();
27 return device_scale_factor;
28 }
29
PixelToDIPPoint(const gfx::Point & pixel_point)30 gfx::Point PixelToDIPPoint(const gfx::Point& pixel_point) {
31 return gfx::ConvertPointToDIP(GetDeviceScaleFactor(), pixel_point);
32 }
33
34 // ui::EnumerateTopLevelWindows API is used here to retrieve the x11 window
35 // stack, so that windows are checked in descending z-order, covering window
36 // overlapping cases gracefully.
37 // TODO(nickdiego): Consider refactoring ui::EnumerateTopLevelWindows to use
38 // lambda/callback instead of Delegate interface.
39 class LocalProcessWindowFinder : public EnumerateWindowsDelegate {
40 public:
41 LocalProcessWindowFinder() = default;
42 ~LocalProcessWindowFinder() override = default;
43
44 X11Window* FindWindowAt(const gfx::Point& screen_point_in_pixels);
45
46 private:
47 // ui::EnumerateWindowsDelegate
48 bool ShouldStopIterating(XID xid) override;
49
50 // Returns true if |window| is visible and contains the
51 // |screen_point_in_pixels_| within its bounds, even if custom shape is used.
52 bool MatchWindow(X11Window* window) const;
53
54 X11Window* window_found_ = nullptr;
55 gfx::Point screen_point_in_pixels_;
56 };
57
FindWindowAt(const gfx::Point & screen_point_in_pixels)58 X11Window* LocalProcessWindowFinder::FindWindowAt(
59 const gfx::Point& screen_point_in_pixels) {
60 screen_point_in_pixels_ = screen_point_in_pixels;
61 ui::EnumerateTopLevelWindows(this);
62 return window_found_;
63 }
64
ShouldStopIterating(XID xid)65 bool LocalProcessWindowFinder::ShouldStopIterating(XID xid) {
66 X11Window* window = X11WindowManager::GetInstance()->GetWindow(xid);
67 if (!window || !MatchWindow(window))
68 return false;
69
70 window_found_ = window;
71 return true;
72 }
73
MatchWindow(X11Window * window) const74 bool LocalProcessWindowFinder::MatchWindow(X11Window* window) const {
75 DCHECK(window);
76
77 if (!window->IsVisible())
78 return false;
79
80 gfx::Rect window_bounds = window->GetOutterBounds();
81 if (!window_bounds.Contains(screen_point_in_pixels_))
82 return false;
83
84 ::Region shape = window->shape();
85 if (!shape)
86 return true;
87
88 gfx::Point window_point(screen_point_in_pixels_);
89 window_point.Offset(-window_bounds.origin().x(), -window_bounds.origin().y());
90 return XPointInRegion(shape, window_point.x(), window_point.y()) == x11::True;
91 }
92
93 } // namespace
94
X11ScreenOzone()95 X11ScreenOzone::X11ScreenOzone()
96 : window_manager_(X11WindowManager::GetInstance()),
97 x11_display_manager_(std::make_unique<XDisplayManager>(this)) {
98 DCHECK(window_manager_);
99 }
100
~X11ScreenOzone()101 X11ScreenOzone::~X11ScreenOzone() {
102 if (x11_display_manager_->IsXrandrAvailable() &&
103 X11EventSource::HasInstance()) {
104 X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
105 }
106 }
107
Init()108 void X11ScreenOzone::Init() {
109 if (x11_display_manager_->IsXrandrAvailable() &&
110 X11EventSource::HasInstance()) {
111 X11EventSource::GetInstance()->AddXEventDispatcher(this);
112 }
113 x11_display_manager_->Init();
114 }
115
GetAllDisplays() const116 const std::vector<display::Display>& X11ScreenOzone::GetAllDisplays() const {
117 return x11_display_manager_->displays();
118 }
119
GetPrimaryDisplay() const120 display::Display X11ScreenOzone::GetPrimaryDisplay() const {
121 return x11_display_manager_->GetPrimaryDisplay();
122 }
123
GetDisplayForAcceleratedWidget(gfx::AcceleratedWidget widget) const124 display::Display X11ScreenOzone::GetDisplayForAcceleratedWidget(
125 gfx::AcceleratedWidget widget) const {
126 if (widget == gfx::kNullAcceleratedWidget)
127 return GetPrimaryDisplay();
128
129 X11Window* window = window_manager_->GetWindow(widget);
130 return window ? GetDisplayMatching(window->GetBounds()) : GetPrimaryDisplay();
131 }
132
GetCursorScreenPoint() const133 gfx::Point X11ScreenOzone::GetCursorScreenPoint() const {
134 if (ui::X11EventSource::HasInstance()) {
135 base::Optional<gfx::Point> point =
136 ui::X11EventSource::GetInstance()
137 ->GetRootCursorLocationFromCurrentEvent();
138 if (point)
139 return PixelToDIPPoint(point.value());
140 }
141 return PixelToDIPPoint(GetCursorLocation());
142 }
143
GetAcceleratedWidgetAtScreenPoint(const gfx::Point & point) const144 gfx::AcceleratedWidget X11ScreenOzone::GetAcceleratedWidgetAtScreenPoint(
145 const gfx::Point& point) const {
146 LocalProcessWindowFinder finder;
147 X11Window* window = finder.FindWindowAt(point);
148 return window ? window->GetWidget() : gfx::kNullAcceleratedWidget;
149 }
150
GetDisplayNearestPoint(const gfx::Point & point) const151 display::Display X11ScreenOzone::GetDisplayNearestPoint(
152 const gfx::Point& point) const {
153 auto displays = GetAllDisplays();
154 if (displays.size() <= 1)
155 return GetPrimaryDisplay();
156 return *display::FindDisplayNearestPoint(displays, point);
157 }
158
GetDisplayMatching(const gfx::Rect & match_rect) const159 display::Display X11ScreenOzone::GetDisplayMatching(
160 const gfx::Rect& match_rect) const {
161 const display::Display* matching_display =
162 display::FindDisplayWithBiggestIntersection(
163 x11_display_manager_->displays(),
164 gfx::ConvertRectToDIP(GetDeviceScaleFactor(), match_rect));
165 return matching_display ? *matching_display : GetPrimaryDisplay();
166 }
167
AddObserver(display::DisplayObserver * observer)168 void X11ScreenOzone::AddObserver(display::DisplayObserver* observer) {
169 x11_display_manager_->AddObserver(observer);
170 }
171
RemoveObserver(display::DisplayObserver * observer)172 void X11ScreenOzone::RemoveObserver(display::DisplayObserver* observer) {
173 x11_display_manager_->RemoveObserver(observer);
174 }
175
GetCurrentWorkspace()176 std::string X11ScreenOzone::GetCurrentWorkspace() {
177 return x11_display_manager_->GetCurrentWorkspace();
178 }
179
DispatchXEvent(XEvent * xev)180 bool X11ScreenOzone::DispatchXEvent(XEvent* xev) {
181 return x11_display_manager_->ProcessEvent(xev);
182 }
183
GetCursorLocation() const184 gfx::Point X11ScreenOzone::GetCursorLocation() const {
185 return x11_display_manager_->GetCursorLocation();
186 }
187
OnXDisplayListUpdated()188 void X11ScreenOzone::OnXDisplayListUpdated() {
189 float scale_factor =
190 x11_display_manager_->GetPrimaryDisplay().device_scale_factor();
191 gfx::SetFontRenderParamsDeviceScaleFactor(scale_factor);
192 }
193
GetXDisplayScaleFactor() const194 float X11ScreenOzone::GetXDisplayScaleFactor() const {
195 return GetDeviceScaleFactor();
196 }
197
198 } // namespace ui
199