1 // Copyright (c) 2012 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/views/widget/desktop_aura/desktop_screen_x11.h"
6 
7 #include <set>
8 #include <string>
9 #include <vector>
10 
11 #include "base/command_line.h"
12 #include "base/trace_event/trace_event.h"
13 #include "ui/aura/window.h"
14 #include "ui/aura/window_event_dispatcher.h"
15 #include "ui/aura/window_tree_host.h"
16 #include "ui/base/layout.h"
17 #include "ui/base/x/x11_display_util.h"
18 #include "ui/base/x/x11_util.h"
19 #include "ui/display/display.h"
20 #include "ui/display/display_finder.h"
21 #include "ui/display/util/display_util.h"
22 #include "ui/gfx/font_render_params.h"
23 #include "ui/gfx/geometry/dip_util.h"
24 #include "ui/gfx/geometry/point_conversions.h"
25 #include "ui/gfx/geometry/rect_conversions.h"
26 #include "ui/gfx/native_widget_types.h"
27 #include "ui/gfx/switches.h"
28 #include "ui/platform_window/x11/x11_topmost_window_finder.h"
29 #include "ui/views/widget/desktop_aura/desktop_screen.h"
30 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h"
31 
32 namespace views {
33 
DesktopScreenX11()34 DesktopScreenX11::DesktopScreenX11() {
35   if (LinuxUI::instance())
36     display_scale_factor_observer_.Add(LinuxUI::instance());
37 }
38 
~DesktopScreenX11()39 DesktopScreenX11::~DesktopScreenX11() {
40   display::Screen::SetScreenInstance(old_screen_);
41 }
42 
Init()43 void DesktopScreenX11::Init() {
44   if (x11_display_manager_->IsXrandrAvailable() &&
45       ui::X11EventSource::HasInstance())
46     event_source_observer_.Add(ui::X11EventSource::GetInstance());
47   x11_display_manager_->Init();
48 }
49 
GetCursorScreenPoint()50 gfx::Point DesktopScreenX11::GetCursorScreenPoint() {
51   TRACE_EVENT0("views", "DesktopScreenX11::GetCursorScreenPoint()");
52 
53   base::Optional<gfx::Point> point_in_pixels;
54   if (const auto* const event_source = ui::X11EventSource::GetInstance())
55     point_in_pixels = event_source->GetRootCursorLocationFromCurrentEvent();
56   if (!point_in_pixels) {
57     // This call is expensive so we explicitly only call it when
58     // |point_in_pixels| is not set. We note that base::Optional::value_or()
59     // would cause it to be called regardless.
60     point_in_pixels = x11_display_manager_->GetCursorLocation();
61   }
62   // TODO(danakj): Should this be rounded? Or kept as a floating point?
63   return gfx::ToFlooredPoint(
64       gfx::ConvertPointToDips(*point_in_pixels, GetXDisplayScaleFactor()));
65 }
66 
IsWindowUnderCursor(gfx::NativeWindow window)67 bool DesktopScreenX11::IsWindowUnderCursor(gfx::NativeWindow window) {
68   return GetWindowAtScreenPoint(GetCursorScreenPoint()) == window;
69 }
70 
GetWindowAtScreenPoint(const gfx::Point & point)71 gfx::NativeWindow DesktopScreenX11::GetWindowAtScreenPoint(
72     const gfx::Point& point) {
73   // TODO(danakj): Should this be rounded?
74   gfx::Point point_in_pixels = gfx::ToFlooredPoint(
75       gfx::ConvertPointToPixels(point, GetXDisplayScaleFactor()));
76   auto window = ui::X11TopmostWindowFinder().FindLocalProcessWindowAt(
77       point_in_pixels, {});
78   return window != x11::Window::None
79              ? views::DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
80                    static_cast<gfx::AcceleratedWidget>(window))
81              : nullptr;
82 }
83 
GetLocalProcessWindowAtPoint(const gfx::Point & point,const std::set<gfx::NativeWindow> & ignore)84 gfx::NativeWindow DesktopScreenX11::GetLocalProcessWindowAtPoint(
85     const gfx::Point& point,
86     const std::set<gfx::NativeWindow>& ignore) {
87   std::set<gfx::AcceleratedWidget> ignore_widgets;
88   for (auto* const window : ignore)
89     ignore_widgets.emplace(window->GetHost()->GetAcceleratedWidget());
90   // TODO(danakj): Should this be rounded?
91   gfx::Point point_in_pixels = gfx::ToFlooredPoint(
92       gfx::ConvertPointToPixels(point, GetXDisplayScaleFactor()));
93   auto window = ui::X11TopmostWindowFinder().FindLocalProcessWindowAt(
94       point_in_pixels, ignore_widgets);
95   return window != x11::Window::None
96              ? views::DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
97                    static_cast<gfx::AcceleratedWidget>(window))
98              : nullptr;
99 }
100 
GetNumDisplays() const101 int DesktopScreenX11::GetNumDisplays() const {
102   return int{x11_display_manager_->displays().size()};
103 }
104 
GetAllDisplays() const105 const std::vector<display::Display>& DesktopScreenX11::GetAllDisplays() const {
106   return x11_display_manager_->displays();
107 }
108 
GetDisplayNearestWindow(gfx::NativeView window) const109 display::Display DesktopScreenX11::GetDisplayNearestWindow(
110     gfx::NativeView window) const {
111   // Getting screen bounds here safely is hard.
112   //
113   // You'd think we'd be able to just call window->GetBoundsInScreen(), but we
114   // can't because |window| (and the associated WindowEventDispatcher*) can be
115   // partially initialized at this point; WindowEventDispatcher initializations
116   // call through into GetDisplayNearestWindow(). But the X11 resources are
117   // created before we create the aura::WindowEventDispatcher. So we ask what
118   // the DRWHX11 believes the window bounds are instead of going through the
119   // aura::Window's screen bounds.
120   if (aura::WindowTreeHost* host = window ? window->GetHost() : nullptr) {
121     const auto* const desktop_host =
122         DesktopWindowTreeHostLinux::GetHostForWidget(
123             host->GetAcceleratedWidget());
124     if (desktop_host) {
125       gfx::Rect match_rect_in_pixels = desktop_host->GetBoundsInPixels();
126       gfx::Rect match_rect = gfx::ToEnclosingRect(gfx::ConvertRectToDips(
127           match_rect_in_pixels, GetXDisplayScaleFactor()));
128       return GetDisplayMatching(match_rect);
129     }
130   }
131 
132   return GetPrimaryDisplay();
133 }
134 
GetDisplayNearestPoint(const gfx::Point & point) const135 display::Display DesktopScreenX11::GetDisplayNearestPoint(
136     const gfx::Point& point) const {
137   return (GetNumDisplays() <= 1)
138              ? GetPrimaryDisplay()
139              : *FindDisplayNearestPoint(GetAllDisplays(), point);
140 }
141 
GetDisplayMatching(const gfx::Rect & match_rect) const142 display::Display DesktopScreenX11::GetDisplayMatching(
143     const gfx::Rect& match_rect) const {
144   const display::Display* const matching =
145       display::FindDisplayWithBiggestIntersection(GetAllDisplays(), match_rect);
146   return matching ? *matching : GetPrimaryDisplay();
147 }
148 
GetPrimaryDisplay() const149 display::Display DesktopScreenX11::GetPrimaryDisplay() const {
150   return x11_display_manager_->GetPrimaryDisplay();
151 }
152 
AddObserver(display::DisplayObserver * observer)153 void DesktopScreenX11::AddObserver(display::DisplayObserver* observer) {
154   x11_display_manager_->AddObserver(observer);
155 }
156 
RemoveObserver(display::DisplayObserver * observer)157 void DesktopScreenX11::RemoveObserver(display::DisplayObserver* observer) {
158   x11_display_manager_->RemoveObserver(observer);
159 }
160 
GetCurrentWorkspace()161 std::string DesktopScreenX11::GetCurrentWorkspace() {
162   return x11_display_manager_->GetCurrentWorkspace();
163 }
164 
DispatchXEvent(x11::Event * event)165 bool DesktopScreenX11::DispatchXEvent(x11::Event* event) {
166   return x11_display_manager_->ProcessEvent(event);
167 }
168 
OnDeviceScaleFactorChanged()169 void DesktopScreenX11::OnDeviceScaleFactorChanged() {
170   x11_display_manager_->DispatchDelayedDisplayListUpdate();
171 }
172 
173 // static
UpdateDeviceScaleFactorForTest()174 void DesktopScreenX11::UpdateDeviceScaleFactorForTest() {
175   auto* screen = static_cast<DesktopScreenX11*>(display::Screen::GetScreen());
176   screen->x11_display_manager_->UpdateDisplayList();
177 }
178 
OnXDisplayListUpdated()179 void DesktopScreenX11::OnXDisplayListUpdated() {
180   gfx::SetFontRenderParamsDeviceScaleFactor(
181       GetPrimaryDisplay().device_scale_factor());
182 }
183 
GetXDisplayScaleFactor() const184 float DesktopScreenX11::GetXDisplayScaleFactor() const {
185   if (LinuxUI::instance())
186     return LinuxUI::instance()->GetDeviceScaleFactor();
187   return display::Display::HasForceDeviceScaleFactor()
188              ? display::Display::GetForcedDeviceScaleFactor()
189              : 1.0f;
190 }
191 
192 }  // namespace views
193