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