Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / ui / views / widget / desktop_aura / desktop_screen_x11.cc
blobfc477e61d5d2d745dc4a8416cfe361196d4c04fc
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.
5 #include "ui/views/widget/desktop_aura/desktop_screen_x11.h"
7 #include <X11/extensions/Xrandr.h>
8 #include <X11/Xlib.h>
10 // It clashes with out RootWindow.
11 #undef RootWindow
13 #include "base/logging.h"
14 #include "base/trace_event/trace_event.h"
15 #include "ui/aura/window.h"
16 #include "ui/aura/window_event_dispatcher.h"
17 #include "ui/aura/window_tree_host.h"
18 #include "ui/base/layout.h"
19 #include "ui/display/util/display_util.h"
20 #include "ui/display/util/x11/edid_parser_x11.h"
21 #include "ui/events/platform/platform_event_source.h"
22 #include "ui/gfx/display.h"
23 #include "ui/gfx/geometry/point_conversions.h"
24 #include "ui/gfx/geometry/size_conversions.h"
25 #include "ui/gfx/native_widget_types.h"
26 #include "ui/gfx/screen.h"
27 #include "ui/gfx/x/x11_types.h"
28 #include "ui/views/linux_ui/linux_ui.h"
29 #include "ui/views/widget/desktop_aura/desktop_screen.h"
30 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
31 #include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h"
33 namespace {
35 // The delay to perform configuration after RRNotify. See the comment
36 // in |Dispatch()|.
37 const int64 kConfigureDelayMs = 500;
39 double GetDeviceScaleFactor() {
40 float device_scale_factor = 1.0f;
41 if (views::LinuxUI::instance())
42 device_scale_factor =
43 views::LinuxUI::instance()->GetDeviceScaleFactor();
44 return device_scale_factor;
47 gfx::Point PixelToDIPPoint(const gfx::Point& pixel_point) {
48 return ToFlooredPoint(ScalePoint(pixel_point, 1.0f / GetDeviceScaleFactor()));
51 gfx::Point DIPToPixelPoint(const gfx::Point& dip_point) {
52 return ToFlooredPoint(gfx::ScalePoint(dip_point, GetDeviceScaleFactor()));
55 std::vector<gfx::Display> GetFallbackDisplayList() {
56 ::XDisplay* display = gfx::GetXDisplay();
57 ::Screen* screen = DefaultScreenOfDisplay(display);
58 int width = WidthOfScreen(screen);
59 int height = HeightOfScreen(screen);
60 gfx::Size physical_size(WidthMMOfScreen(screen), HeightMMOfScreen(screen));
62 gfx::Rect bounds_in_pixels(0, 0, width, height);
63 gfx::Display gfx_display(0, bounds_in_pixels);
64 if (!gfx::Display::HasForceDeviceScaleFactor() &&
65 !ui::IsDisplaySizeBlackListed(physical_size)) {
66 const float device_scale_factor = GetDeviceScaleFactor();
67 DCHECK_LE(1.0f, device_scale_factor);
68 gfx_display.SetScaleAndBounds(device_scale_factor, bounds_in_pixels);
71 return std::vector<gfx::Display>(1, gfx_display);
74 } // namespace
76 namespace views {
78 ////////////////////////////////////////////////////////////////////////////////
79 // DesktopScreenX11, public:
81 DesktopScreenX11::DesktopScreenX11()
82 : xdisplay_(gfx::GetXDisplay()),
83 x_root_window_(DefaultRootWindow(xdisplay_)),
84 has_xrandr_(false),
85 xrandr_event_base_(0) {
86 // We only support 1.3+. There were library changes before this and we should
87 // use the new interface instead of the 1.2 one.
88 int randr_version_major = 0;
89 int randr_version_minor = 0;
90 has_xrandr_ = XRRQueryVersion(
91 xdisplay_, &randr_version_major, &randr_version_minor) &&
92 randr_version_major == 1 &&
93 randr_version_minor >= 3;
95 if (has_xrandr_) {
96 int error_base_ignored = 0;
97 XRRQueryExtension(xdisplay_, &xrandr_event_base_, &error_base_ignored);
99 if (ui::PlatformEventSource::GetInstance())
100 ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
101 XRRSelectInput(xdisplay_,
102 x_root_window_,
103 RRScreenChangeNotifyMask |
104 RROutputChangeNotifyMask |
105 RRCrtcChangeNotifyMask);
107 displays_ = BuildDisplaysFromXRandRInfo();
108 } else {
109 displays_ = GetFallbackDisplayList();
113 DesktopScreenX11::~DesktopScreenX11() {
114 if (has_xrandr_ && ui::PlatformEventSource::GetInstance())
115 ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
118 ////////////////////////////////////////////////////////////////////////////////
119 // DesktopScreenX11, gfx::Screen implementation:
121 gfx::Point DesktopScreenX11::GetCursorScreenPoint() {
122 TRACE_EVENT0("views", "DesktopScreenX11::GetCursorScreenPoint()");
124 XDisplay* display = gfx::GetXDisplay();
126 ::Window root, child;
127 int root_x, root_y, win_x, win_y;
128 unsigned int mask;
129 XQueryPointer(display,
130 DefaultRootWindow(display),
131 &root,
132 &child,
133 &root_x,
134 &root_y,
135 &win_x,
136 &win_y,
137 &mask);
139 return PixelToDIPPoint(gfx::Point(root_x, root_y));
142 gfx::NativeWindow DesktopScreenX11::GetWindowUnderCursor() {
143 return GetWindowAtScreenPoint(GetCursorScreenPoint());
146 gfx::NativeWindow DesktopScreenX11::GetWindowAtScreenPoint(
147 const gfx::Point& point) {
148 X11TopmostWindowFinder finder;
149 return finder.FindLocalProcessWindowAt(
150 DIPToPixelPoint(point), std::set<aura::Window*>());
153 int DesktopScreenX11::GetNumDisplays() const {
154 return displays_.size();
157 std::vector<gfx::Display> DesktopScreenX11::GetAllDisplays() const {
158 return displays_;
161 gfx::Display DesktopScreenX11::GetDisplayNearestWindow(
162 gfx::NativeView window) const {
163 if (!window)
164 return GetPrimaryDisplay();
166 // Getting screen bounds here safely is hard.
168 // You'd think we'd be able to just call window->GetBoundsInScreen(), but we
169 // can't because |window| (and the associated WindowEventDispatcher*) can be
170 // partially initialized at this point; WindowEventDispatcher initializations
171 // call through into GetDisplayNearestWindow(). But the X11 resources are
172 // created before we create the aura::WindowEventDispatcher. So we ask what
173 // the DRWHX11 believes the window bounds are instead of going through the
174 // aura::Window's screen bounds.
175 aura::WindowTreeHost* host = window->GetHost();
176 if (host) {
177 DesktopWindowTreeHostX11* rwh = DesktopWindowTreeHostX11::GetHostForXID(
178 host->GetAcceleratedWidget());
179 if (rwh)
180 return GetDisplayMatching(rwh->GetX11RootWindowBounds());
183 return GetPrimaryDisplay();
186 gfx::Display DesktopScreenX11::GetDisplayNearestPoint(
187 const gfx::Point& requested_point) const {
188 const gfx::Point point_in_pixel = DIPToPixelPoint(requested_point);
189 for (std::vector<gfx::Display>::const_iterator it = displays_.begin();
190 it != displays_.end(); ++it) {
191 if (it->bounds().Contains(point_in_pixel))
192 return *it;
195 return GetPrimaryDisplay();
198 gfx::Display DesktopScreenX11::GetDisplayMatching(
199 const gfx::Rect& match_rect) const {
200 int max_area = 0;
201 const gfx::Display* matching = NULL;
202 for (std::vector<gfx::Display>::const_iterator it = displays_.begin();
203 it != displays_.end(); ++it) {
204 gfx::Rect intersect = gfx::IntersectRects(it->bounds(), match_rect);
205 int area = intersect.width() * intersect.height();
206 if (area > max_area) {
207 max_area = area;
208 matching = &*it;
211 // Fallback to the primary display if there is no matching display.
212 return matching ? *matching : GetPrimaryDisplay();
215 gfx::Display DesktopScreenX11::GetPrimaryDisplay() const {
216 return displays_.front();
219 void DesktopScreenX11::AddObserver(gfx::DisplayObserver* observer) {
220 change_notifier_.AddObserver(observer);
223 void DesktopScreenX11::RemoveObserver(gfx::DisplayObserver* observer) {
224 change_notifier_.RemoveObserver(observer);
227 bool DesktopScreenX11::CanDispatchEvent(const ui::PlatformEvent& event) {
228 return event->type - xrandr_event_base_ == RRScreenChangeNotify ||
229 event->type - xrandr_event_base_ == RRNotify;
232 uint32_t DesktopScreenX11::DispatchEvent(const ui::PlatformEvent& event) {
233 if (event->type - xrandr_event_base_ == RRScreenChangeNotify) {
234 // Pass the event through to xlib.
235 XRRUpdateConfiguration(event);
236 } else if (event->type - xrandr_event_base_ == RRNotify) {
237 // There's some sort of observer dispatch going on here, but I don't think
238 // it's the screen's?
239 if (configure_timer_.get() && configure_timer_->IsRunning()) {
240 configure_timer_->Reset();
241 } else {
242 configure_timer_.reset(new base::OneShotTimer<DesktopScreenX11>());
243 configure_timer_->Start(
244 FROM_HERE,
245 base::TimeDelta::FromMilliseconds(kConfigureDelayMs),
246 this,
247 &DesktopScreenX11::ConfigureTimerFired);
249 } else {
250 NOTREACHED();
253 return ui::POST_DISPATCH_NONE;
256 ////////////////////////////////////////////////////////////////////////////////
257 // DesktopScreenX11, private:
259 DesktopScreenX11::DesktopScreenX11(
260 const std::vector<gfx::Display>& test_displays)
261 : xdisplay_(gfx::GetXDisplay()),
262 x_root_window_(DefaultRootWindow(xdisplay_)),
263 has_xrandr_(false),
264 xrandr_event_base_(0),
265 displays_(test_displays) {
268 std::vector<gfx::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
269 std::vector<gfx::Display> displays;
270 gfx::XScopedPtr<
271 XRRScreenResources,
272 gfx::XObjectDeleter<XRRScreenResources, void, XRRFreeScreenResources>>
273 resources(XRRGetScreenResourcesCurrent(xdisplay_, x_root_window_));
274 if (!resources) {
275 LOG(ERROR) << "XRandR returned no displays. Falling back to Root Window.";
276 return GetFallbackDisplayList();
279 bool has_work_area = false;
280 gfx::Rect work_area_in_pixels;
281 std::vector<int> value;
282 if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
283 value.size() >= 4) {
284 work_area_in_pixels = gfx::Rect(value[0], value[1], value[2], value[3]);
285 has_work_area = true;
288 // As per-display scale factor is not supported right now,
289 // the X11 root window's scale factor is always used.
290 const float device_scale_factor = GetDeviceScaleFactor();
291 for (int i = 0; i < resources->noutput; ++i) {
292 RROutput output_id = resources->outputs[i];
293 gfx::XScopedPtr<XRROutputInfo,
294 gfx::XObjectDeleter<XRROutputInfo, void, XRRFreeOutputInfo>>
295 output_info(XRRGetOutputInfo(xdisplay_, resources.get(), output_id));
297 bool is_connected = (output_info->connection == RR_Connected);
298 if (!is_connected)
299 continue;
301 if (output_info->crtc) {
302 gfx::XScopedPtr<XRRCrtcInfo,
303 gfx::XObjectDeleter<XRRCrtcInfo, void, XRRFreeCrtcInfo>>
304 crtc(XRRGetCrtcInfo(xdisplay_, resources.get(), output_info->crtc));
306 int64 display_id = -1;
307 if (!ui::GetDisplayId(output_id, static_cast<uint8>(i), &display_id)) {
308 // It isn't ideal, but if we can't parse the EDID data, fallback on the
309 // display number.
310 display_id = i;
313 gfx::Rect crtc_bounds(crtc->x, crtc->y, crtc->width, crtc->height);
314 gfx::Display display(display_id, crtc_bounds);
316 if (!gfx::Display::HasForceDeviceScaleFactor()) {
317 display.SetScaleAndBounds(device_scale_factor, crtc_bounds);
320 if (has_work_area) {
321 gfx::Rect intersection_in_pixels = crtc_bounds;
322 intersection_in_pixels.Intersect(work_area_in_pixels);
323 // SetScaleAndBounds() above does the conversion from pixels to DIP for
324 // us, but set_work_area does not, so we need to do it here.
325 display.set_work_area(gfx::Rect(
326 gfx::ToFlooredPoint(
327 gfx::ScalePoint(intersection_in_pixels.origin(),
328 1.0f / display.device_scale_factor())),
329 gfx::ToFlooredSize(
330 gfx::ScaleSize(intersection_in_pixels.size(),
331 1.0f / display.device_scale_factor()))));
334 switch (crtc->rotation) {
335 case RR_Rotate_0:
336 display.set_rotation(gfx::Display::ROTATE_0);
337 break;
338 case RR_Rotate_90:
339 display.set_rotation(gfx::Display::ROTATE_90);
340 break;
341 case RR_Rotate_180:
342 display.set_rotation(gfx::Display::ROTATE_180);
343 break;
344 case RR_Rotate_270:
345 display.set_rotation(gfx::Display::ROTATE_270);
346 break;
349 displays.push_back(display);
353 if (displays.empty())
354 return GetFallbackDisplayList();
356 return displays;
359 void DesktopScreenX11::ConfigureTimerFired() {
360 std::vector<gfx::Display> old_displays = displays_;
361 displays_ = BuildDisplaysFromXRandRInfo();
363 change_notifier_.NotifyDisplaysChanged(old_displays, displays_);
366 ////////////////////////////////////////////////////////////////////////////////
368 gfx::Screen* CreateDesktopScreen() {
369 return new DesktopScreenX11;
372 } // namespace views