Make castv2 performance test work.
[chromium-blink-merge.git] / ui / views / widget / desktop_aura / desktop_screen_x11.cc
blob019688fb9463fb518681202d611a0fc90160a6b2
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/widget/desktop_aura/desktop_screen.h"
29 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
30 #include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h"
32 namespace {
34 // The delay to perform configuration after RRNotify. See the comment
35 // in |Dispatch()|.
36 const int64 kConfigureDelayMs = 500;
38 // TODO(oshima): Consider using gtk-xft-dpi instead.
39 float GetDeviceScaleFactor(int screen_pixels, int screen_mm) {
40 const int kCSSDefaultDPI = 96;
41 const float kInchInMm = 25.4f;
43 float screen_inches = screen_mm / kInchInMm;
44 float screen_dpi = screen_pixels / screen_inches;
45 float scale = screen_dpi / kCSSDefaultDPI;
47 return ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactor(scale));
50 float GetDeviceScaleFactor() {
51 gfx::Display display = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
52 return display.device_scale_factor();
55 gfx::Point PixelToDIPPoint(const gfx::Point& pixel_point) {
56 return ToFlooredPoint(ScalePoint(pixel_point, 1.0f / GetDeviceScaleFactor()));
59 gfx::Point DIPToPixelPoint(const gfx::Point& dip_point) {
60 return ToFlooredPoint(gfx::ScalePoint(dip_point, GetDeviceScaleFactor()));
63 std::vector<gfx::Display> GetFallbackDisplayList() {
64 ::XDisplay* display = gfx::GetXDisplay();
65 ::Screen* screen = DefaultScreenOfDisplay(display);
66 int width = WidthOfScreen(screen);
67 int height = HeightOfScreen(screen);
68 gfx::Size physical_size(WidthMMOfScreen(screen), HeightMMOfScreen(screen));
70 gfx::Rect bounds_in_pixels(0, 0, width, height);
71 gfx::Display gfx_display(0, bounds_in_pixels);
72 if (!gfx::Display::HasForceDeviceScaleFactor() &&
73 !ui::IsDisplaySizeBlackListed(physical_size)) {
74 float device_scale_factor = GetDeviceScaleFactor(
75 width, physical_size.width());
76 DCHECK_LE(1.0f, device_scale_factor);
77 gfx_display.SetScaleAndBounds(device_scale_factor, bounds_in_pixels);
80 return std::vector<gfx::Display>(1, gfx_display);
83 } // namespace
85 namespace views {
87 ////////////////////////////////////////////////////////////////////////////////
88 // DesktopScreenX11, public:
90 DesktopScreenX11::DesktopScreenX11()
91 : xdisplay_(gfx::GetXDisplay()),
92 x_root_window_(DefaultRootWindow(xdisplay_)),
93 has_xrandr_(false),
94 xrandr_event_base_(0) {
95 // We only support 1.3+. There were library changes before this and we should
96 // use the new interface instead of the 1.2 one.
97 int randr_version_major = 0;
98 int randr_version_minor = 0;
99 has_xrandr_ = XRRQueryVersion(
100 xdisplay_, &randr_version_major, &randr_version_minor) &&
101 randr_version_major == 1 &&
102 randr_version_minor >= 3;
104 if (has_xrandr_) {
105 int error_base_ignored = 0;
106 XRRQueryExtension(xdisplay_, &xrandr_event_base_, &error_base_ignored);
108 if (ui::PlatformEventSource::GetInstance())
109 ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
110 XRRSelectInput(xdisplay_,
111 x_root_window_,
112 RRScreenChangeNotifyMask |
113 RROutputChangeNotifyMask |
114 RRCrtcChangeNotifyMask);
116 displays_ = BuildDisplaysFromXRandRInfo();
117 } else {
118 displays_ = GetFallbackDisplayList();
122 DesktopScreenX11::~DesktopScreenX11() {
123 if (has_xrandr_ && ui::PlatformEventSource::GetInstance())
124 ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
127 ////////////////////////////////////////////////////////////////////////////////
128 // DesktopScreenX11, gfx::Screen implementation:
130 gfx::Point DesktopScreenX11::GetCursorScreenPoint() {
131 TRACE_EVENT0("views", "DesktopScreenX11::GetCursorScreenPoint()");
133 XDisplay* display = gfx::GetXDisplay();
135 ::Window root, child;
136 int root_x, root_y, win_x, win_y;
137 unsigned int mask;
138 XQueryPointer(display,
139 DefaultRootWindow(display),
140 &root,
141 &child,
142 &root_x,
143 &root_y,
144 &win_x,
145 &win_y,
146 &mask);
148 return PixelToDIPPoint(gfx::Point(root_x, root_y));
151 gfx::NativeWindow DesktopScreenX11::GetWindowUnderCursor() {
152 return GetWindowAtScreenPoint(GetCursorScreenPoint());
155 gfx::NativeWindow DesktopScreenX11::GetWindowAtScreenPoint(
156 const gfx::Point& point) {
157 X11TopmostWindowFinder finder;
158 return finder.FindLocalProcessWindowAt(
159 DIPToPixelPoint(point), std::set<aura::Window*>());
162 int DesktopScreenX11::GetNumDisplays() const {
163 return displays_.size();
166 std::vector<gfx::Display> DesktopScreenX11::GetAllDisplays() const {
167 return displays_;
170 gfx::Display DesktopScreenX11::GetDisplayNearestWindow(
171 gfx::NativeView window) const {
172 if (!window)
173 return GetPrimaryDisplay();
175 // Getting screen bounds here safely is hard.
177 // You'd think we'd be able to just call window->GetBoundsInScreen(), but we
178 // can't because |window| (and the associated WindowEventDispatcher*) can be
179 // partially initialized at this point; WindowEventDispatcher initializations
180 // call through into GetDisplayNearestWindow(). But the X11 resources are
181 // created before we create the aura::WindowEventDispatcher. So we ask what
182 // the DRWHX11 believes the window bounds are instead of going through the
183 // aura::Window's screen bounds.
184 aura::WindowTreeHost* host = window->GetHost();
185 if (host) {
186 DesktopWindowTreeHostX11* rwh = DesktopWindowTreeHostX11::GetHostForXID(
187 host->GetAcceleratedWidget());
188 if (rwh)
189 return GetDisplayMatching(rwh->GetX11RootWindowBounds());
192 return GetPrimaryDisplay();
195 gfx::Display DesktopScreenX11::GetDisplayNearestPoint(
196 const gfx::Point& requested_point) const {
197 const gfx::Point point_in_pixel = DIPToPixelPoint(requested_point);
198 for (std::vector<gfx::Display>::const_iterator it = displays_.begin();
199 it != displays_.end(); ++it) {
200 if (it->bounds().Contains(point_in_pixel))
201 return *it;
204 return GetPrimaryDisplay();
207 gfx::Display DesktopScreenX11::GetDisplayMatching(
208 const gfx::Rect& match_rect) const {
209 int max_area = 0;
210 const gfx::Display* matching = NULL;
211 for (std::vector<gfx::Display>::const_iterator it = displays_.begin();
212 it != displays_.end(); ++it) {
213 gfx::Rect intersect = gfx::IntersectRects(it->bounds(), match_rect);
214 int area = intersect.width() * intersect.height();
215 if (area > max_area) {
216 max_area = area;
217 matching = &*it;
220 // Fallback to the primary display if there is no matching display.
221 return matching ? *matching : GetPrimaryDisplay();
224 gfx::Display DesktopScreenX11::GetPrimaryDisplay() const {
225 return displays_.front();
228 void DesktopScreenX11::AddObserver(gfx::DisplayObserver* observer) {
229 change_notifier_.AddObserver(observer);
232 void DesktopScreenX11::RemoveObserver(gfx::DisplayObserver* observer) {
233 change_notifier_.RemoveObserver(observer);
236 bool DesktopScreenX11::CanDispatchEvent(const ui::PlatformEvent& event) {
237 return event->type - xrandr_event_base_ == RRScreenChangeNotify ||
238 event->type - xrandr_event_base_ == RRNotify;
241 uint32_t DesktopScreenX11::DispatchEvent(const ui::PlatformEvent& event) {
242 if (event->type - xrandr_event_base_ == RRScreenChangeNotify) {
243 // Pass the event through to xlib.
244 XRRUpdateConfiguration(event);
245 } else if (event->type - xrandr_event_base_ == RRNotify) {
246 // There's some sort of observer dispatch going on here, but I don't think
247 // it's the screen's?
248 if (configure_timer_.get() && configure_timer_->IsRunning()) {
249 configure_timer_->Reset();
250 } else {
251 configure_timer_.reset(new base::OneShotTimer<DesktopScreenX11>());
252 configure_timer_->Start(
253 FROM_HERE,
254 base::TimeDelta::FromMilliseconds(kConfigureDelayMs),
255 this,
256 &DesktopScreenX11::ConfigureTimerFired);
258 } else {
259 NOTREACHED();
262 return ui::POST_DISPATCH_NONE;
265 ////////////////////////////////////////////////////////////////////////////////
266 // DesktopScreenX11, private:
268 DesktopScreenX11::DesktopScreenX11(
269 const std::vector<gfx::Display>& test_displays)
270 : xdisplay_(gfx::GetXDisplay()),
271 x_root_window_(DefaultRootWindow(xdisplay_)),
272 has_xrandr_(false),
273 xrandr_event_base_(0),
274 displays_(test_displays) {
277 std::vector<gfx::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
278 std::vector<gfx::Display> displays;
279 gfx::XScopedPtr<
280 XRRScreenResources,
281 gfx::XObjectDeleter<XRRScreenResources, void, XRRFreeScreenResources>>
282 resources(XRRGetScreenResourcesCurrent(xdisplay_, x_root_window_));
283 if (!resources) {
284 LOG(ERROR) << "XRandR returned no displays. Falling back to Root Window.";
285 return GetFallbackDisplayList();
288 bool has_work_area = false;
289 gfx::Rect work_area_in_pixels;
290 std::vector<int> value;
291 if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
292 value.size() >= 4) {
293 work_area_in_pixels = gfx::Rect(value[0], value[1], value[2], value[3]);
294 has_work_area = true;
297 float device_scale_factor = 1.0f;
298 for (int i = 0; i < resources->noutput; ++i) {
299 RROutput output_id = resources->outputs[i];
300 gfx::XScopedPtr<XRROutputInfo,
301 gfx::XObjectDeleter<XRROutputInfo, void, XRRFreeOutputInfo>>
302 output_info(XRRGetOutputInfo(xdisplay_, resources.get(), output_id));
304 bool is_connected = (output_info->connection == RR_Connected);
305 if (!is_connected)
306 continue;
308 if (output_info->crtc) {
309 gfx::XScopedPtr<XRRCrtcInfo,
310 gfx::XObjectDeleter<XRRCrtcInfo, void, XRRFreeCrtcInfo>>
311 crtc(XRRGetCrtcInfo(xdisplay_, resources.get(), output_info->crtc));
313 int64 display_id = -1;
314 if (!ui::GetDisplayId(output_id, static_cast<uint8>(i), &display_id)) {
315 // It isn't ideal, but if we can't parse the EDID data, fallback on the
316 // display number.
317 display_id = i;
320 gfx::Rect crtc_bounds(crtc->x, crtc->y, crtc->width, crtc->height);
321 gfx::Display display(display_id, crtc_bounds);
323 if (!gfx::Display::HasForceDeviceScaleFactor()) {
324 if (i == 0 && !ui::IsDisplaySizeBlackListed(
325 gfx::Size(output_info->mm_width, output_info->mm_height))) {
326 // As per display scale factor is not supported right now,
327 // the primary display's scale factor is always used.
328 device_scale_factor = GetDeviceScaleFactor(crtc->width,
329 output_info->mm_width);
330 DCHECK_LE(1.0f, device_scale_factor);
332 display.SetScaleAndBounds(device_scale_factor, crtc_bounds);
335 if (has_work_area) {
336 gfx::Rect intersection_in_pixels = crtc_bounds;
337 intersection_in_pixels.Intersect(work_area_in_pixels);
338 // SetScaleAndBounds() above does the conversion from pixels to DIP for
339 // us, but set_work_area does not, so we need to do it here.
340 display.set_work_area(gfx::Rect(
341 gfx::ToFlooredPoint(
342 gfx::ScalePoint(intersection_in_pixels.origin(),
343 1.0f / display.device_scale_factor())),
344 gfx::ToFlooredSize(
345 gfx::ScaleSize(intersection_in_pixels.size(),
346 1.0f / display.device_scale_factor()))));
349 switch (crtc->rotation) {
350 case RR_Rotate_0:
351 display.set_rotation(gfx::Display::ROTATE_0);
352 break;
353 case RR_Rotate_90:
354 display.set_rotation(gfx::Display::ROTATE_90);
355 break;
356 case RR_Rotate_180:
357 display.set_rotation(gfx::Display::ROTATE_180);
358 break;
359 case RR_Rotate_270:
360 display.set_rotation(gfx::Display::ROTATE_270);
361 break;
364 displays.push_back(display);
368 if (displays.empty())
369 return GetFallbackDisplayList();
371 return displays;
374 void DesktopScreenX11::ConfigureTimerFired() {
375 std::vector<gfx::Display> old_displays = displays_;
376 displays_ = BuildDisplaysFromXRandRInfo();
378 change_notifier_.NotifyDisplaysChanged(old_displays, displays_);
381 ////////////////////////////////////////////////////////////////////////////////
383 gfx::Screen* CreateDesktopScreen() {
384 return new DesktopScreenX11;
387 } // namespace views