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