Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(404)

Side by Side Diff: ui/views/widget/desktop_aura/desktop_screen_x11.cc

Issue 23536057: linux_aura: Implement most of DesktopScreenX11. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixes for derat + more tests. Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/views/widget/desktop_aura/desktop_screen.h" 5 #include "ui/views/widget/desktop_aura/desktop_screen_x11.h"
6 6
7 #include <X11/extensions/Xrandr.h>
7 #include <X11/Xlib.h> 8 #include <X11/Xlib.h>
8 9
9 // It clashes with out RootWindow. 10 // It clashes with out RootWindow.
10 #undef RootWindow 11 #undef RootWindow
11 12
13 #include "base/edid_parser_x11.h"
12 #include "base/logging.h" 14 #include "base/logging.h"
13 #include "ui/aura/root_window.h" 15 #include "ui/aura/root_window.h"
14 #include "ui/aura/root_window_host.h" 16 #include "ui/aura/root_window_host.h"
15 #include "ui/base/x/x11_util.h" 17 #include "ui/base/x/x11_util.h"
16 #include "ui/gfx/display.h" 18 #include "ui/gfx/display.h"
19 #include "ui/gfx/display_observer.h"
17 #include "ui/gfx/native_widget_types.h" 20 #include "ui/gfx/native_widget_types.h"
18 #include "ui/gfx/screen.h" 21 #include "ui/views/widget/desktop_aura/desktop_screen.h"
19 22
20 namespace { 23 namespace {
21 24
22 // TODO(erg): This method is a temporary hack, until we can reliably extract 25 // The delay to perform configuration after RRNotify. See the comment
23 // location data out of XRandR. 26 // in |Dispatch()|.
24 gfx::Size GetPrimaryDisplaySize() { 27 const int64 kConfigureDelayMs = 500;
28
29 std::vector<gfx::Display> GetFallbackDisplayList() {
25 ::Display* display = ui::GetXDisplay(); 30 ::Display* display = ui::GetXDisplay();
26 ::Screen* screen = DefaultScreenOfDisplay(display); 31 ::Screen* screen = DefaultScreenOfDisplay(display);
27 int width = WidthOfScreen(screen); 32 int width = WidthOfScreen(screen);
28 int height = HeightOfScreen(screen); 33 int height = HeightOfScreen(screen);
29 34
30 return gfx::Size(width, height); 35 return std::vector<gfx::Display>(
36 1, gfx::Display(0, gfx::Rect(0, 0, width, height)));
31 } 37 }
32 38
33 class DesktopScreenX11 : public gfx::Screen { 39 } // namespace
34 public:
35 DesktopScreenX11();
36 virtual ~DesktopScreenX11();
37 40
38 // Overridden from gfx::Screen: 41 namespace views {
39 virtual bool IsDIPEnabled() OVERRIDE;
40 virtual gfx::Point GetCursorScreenPoint() OVERRIDE;
41 virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE;
42 virtual gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point)
43 OVERRIDE;
44 virtual int GetNumDisplays() const OVERRIDE;
45 virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE;
46 virtual gfx::Display GetDisplayNearestWindow(
47 gfx::NativeView window) const OVERRIDE;
48 virtual gfx::Display GetDisplayNearestPoint(
49 const gfx::Point& point) const OVERRIDE;
50 virtual gfx::Display GetDisplayMatching(
51 const gfx::Rect& match_rect) const OVERRIDE;
52 virtual gfx::Display GetPrimaryDisplay() const OVERRIDE;
53 virtual void AddObserver(gfx::DisplayObserver* observer) OVERRIDE;
54 virtual void RemoveObserver(gfx::DisplayObserver* observer) OVERRIDE;
55
56 private:
57 DISALLOW_COPY_AND_ASSIGN(DesktopScreenX11);
58 };
59 42
60 //////////////////////////////////////////////////////////////////////////////// 43 ////////////////////////////////////////////////////////////////////////////////
61 // DesktopScreenX11, public: 44 // DesktopScreenX11, public:
62 45
63 DesktopScreenX11::DesktopScreenX11() { 46 DesktopScreenX11::DesktopScreenX11()
47 : xdisplay_(base::MessagePumpX11::GetDefaultXDisplay()),
48 x_root_window_(DefaultRootWindow(xdisplay_)),
49 has_xrandr_(false),
50 xrandr_event_base_(0) {
51 // We only support 1.3+. There were library changes before this and we should
52 // use the new interface instead of the 1.2 one.
53 int randr_version_major = 0;
54 int randr_version_minor = 0;
55 has_xrandr_ = XRRQueryVersion(
56 xdisplay_, &randr_version_major, &randr_version_minor) &&
57 randr_version_major == 1 &&
58 randr_version_minor >= 3;
59
60 if (has_xrandr_) {
61 int error_base_ignored = 0;
62 XRRQueryExtension(xdisplay_, &xrandr_event_base_, &error_base_ignored);
63
64 base::MessagePumpX11::Current()->AddDispatcherForRootWindow(this);
65 XRRSelectInput(xdisplay_,
66 x_root_window_,
67 RRScreenChangeNotifyMask | RROutputChangeNotifyMask);
68
69 displays_ = BuildDisplaysFromXRandRInfo();
70 } else {
71 displays_ = GetFallbackDisplayList();
72 }
64 } 73 }
65 74
66 DesktopScreenX11::~DesktopScreenX11() { 75 DesktopScreenX11::~DesktopScreenX11() {
76 if (has_xrandr_)
77 base::MessagePumpX11::Current()->RemoveDispatcherForRootWindow(this);
78 }
79
80 void DesktopScreenX11::ProcessDisplayChange(
81 const std::vector<gfx::Display>& incoming) {
82 std::vector<gfx::Display>::const_iterator cur_it = displays_.begin();
83 for (; cur_it != displays_.end(); ++cur_it) {
84 bool found = false;
85 for (std::vector<gfx::Display>::const_iterator incoming_it =
86 incoming.begin(); incoming_it != incoming.end(); ++incoming_it) {
87 if (cur_it->id() == incoming_it->id()) {
88 found = true;
89 break;
90 }
91 }
92
93 if (!found) {
94 FOR_EACH_OBSERVER(gfx::DisplayObserver, observer_list_,
95 OnDisplayRemoved(*cur_it));
96 }
97 }
98
99 std::vector<gfx::Display>::const_iterator incoming_it = incoming.begin();
100 for (; incoming_it != incoming.end(); ++incoming_it) {
101 bool found = false;
102 for (std::vector<gfx::Display>::const_iterator cur_it = displays_.begin();
103 cur_it != displays_.end(); ++cur_it) {
104 if (incoming_it->id() == cur_it->id()) {
105 if (incoming_it->bounds() != cur_it->bounds()) {
106 FOR_EACH_OBSERVER(gfx::DisplayObserver, observer_list_,
107 OnDisplayBoundsChanged(*incoming_it));
108 }
109
110 found = true;
111 break;
112 }
113 }
114
115 if (!found) {
116 FOR_EACH_OBSERVER(gfx::DisplayObserver, observer_list_,
117 OnDisplayAdded(*incoming_it));
118 }
119 }
120
121 displays_ = incoming;
67 } 122 }
68 123
69 //////////////////////////////////////////////////////////////////////////////// 124 ////////////////////////////////////////////////////////////////////////////////
70 // DesktopScreenX11, gfx::Screen implementation: 125 // DesktopScreenX11, gfx::Screen implementation:
71 126
72 bool DesktopScreenX11::IsDIPEnabled() { 127 bool DesktopScreenX11::IsDIPEnabled() {
73 return false; 128 return false;
74 } 129 }
75 130
76 gfx::Point DesktopScreenX11::GetCursorScreenPoint() { 131 gfx::Point DesktopScreenX11::GetCursorScreenPoint() {
77 Display* display = ui::GetXDisplay(); 132 Display* display = ui::GetXDisplay();
78 133
79 ::Window root, child; 134 ::Window root, child;
80 int root_x, root_y, win_x, win_y; 135 int root_x, root_y, win_x, win_y;
81 unsigned int mask; 136 unsigned int mask;
82 XQueryPointer(display, 137 XQueryPointer(display,
83 DefaultRootWindow(display), 138 DefaultRootWindow(display),
84 &root, 139 &root,
85 &child, 140 &child,
86 &root_x, 141 &root_x,
87 &root_y, 142 &root_y,
88 &win_x, 143 &win_x,
89 &win_y, 144 &win_y,
90 &mask); 145 &mask);
91 146
92 return gfx::Point(root_x, root_y); 147 return gfx::Point(root_x, root_y);
93 } 148 }
94 149
95 gfx::NativeWindow DesktopScreenX11::GetWindowUnderCursor() { 150 gfx::NativeWindow DesktopScreenX11::GetWindowUnderCursor() {
96 // TODO(erg): Implement using the discussion at 151 return GetWindowAtScreenPoint(GetCursorScreenPoint());
97 // http://codereview.chromium.org/10279005/
98 return NULL;
99 } 152 }
100 153
101 gfx::NativeWindow DesktopScreenX11::GetWindowAtScreenPoint( 154 gfx::NativeWindow DesktopScreenX11::GetWindowAtScreenPoint(
102 const gfx::Point& point) { 155 const gfx::Point& point) {
156 // TODO(erg): Implement using the discussion at
157 // http://codereview.chromium.org/10279005/
103 NOTIMPLEMENTED(); 158 NOTIMPLEMENTED();
104 return NULL; 159 return NULL;
105 } 160 }
106 161
107 int DesktopScreenX11::GetNumDisplays() const { 162 int DesktopScreenX11::GetNumDisplays() const {
108 // TODO(erg): Figure this out with oshima or piman because I have no clue 163 return displays_.size();
109 // about the XRandR implications here.
110 return 1;
111 } 164 }
112 165
113 std::vector<gfx::Display> DesktopScreenX11::GetAllDisplays() const { 166 std::vector<gfx::Display> DesktopScreenX11::GetAllDisplays() const {
114 // TODO(erg): Do the right thing once we know what that is. 167 return displays_;
115 return std::vector<gfx::Display>(1, GetPrimaryDisplay());
116 } 168 }
117 169
118 gfx::Display DesktopScreenX11::GetDisplayNearestWindow( 170 gfx::Display DesktopScreenX11::GetDisplayNearestWindow(
119 gfx::NativeView window) const { 171 gfx::NativeView window) const {
120 // TODO(erg): Do the right thing once we know what that is. 172 // TODO(erg): This should theoretically be easy, but it isn't. At the time we
121 return gfx::Display(0, gfx::Rect(GetPrimaryDisplaySize())); 173 // get called here, our aura::Window has not been Init()ed, because this
174 // method is called to get the device scale factor as part of
175 // RootWindow::Init(), before Window::Init(). This seems very confused; we're
176 // trying to get a display nearest window even before we've allocated the
177 // root window. Once fixed, the correct implementation should probably be:
178 //
179 // return GetDisplayMatching(window->GetBoundsInScreen());
180 //
181 // But at least for now, we'll just fallback:
182 return GetPrimaryDisplay();
122 } 183 }
123 184
124 gfx::Display DesktopScreenX11::GetDisplayNearestPoint( 185 gfx::Display DesktopScreenX11::GetDisplayNearestPoint(
125 const gfx::Point& point) const { 186 const gfx::Point& point) const {
126 // TODO(erg): Do the right thing once we know what that is. 187 for (std::vector<gfx::Display>::const_iterator it = displays_.begin();
127 return gfx::Display(0, gfx::Rect(GetPrimaryDisplaySize())); 188 it != displays_.end(); ++it) {
189 if (it->bounds().Contains(point))
190 return *it;
191 }
192
193 return GetPrimaryDisplay();
128 } 194 }
129 195
130 gfx::Display DesktopScreenX11::GetDisplayMatching( 196 gfx::Display DesktopScreenX11::GetDisplayMatching(
131 const gfx::Rect& match_rect) const { 197 const gfx::Rect& match_rect) const {
132 // TODO(erg): Do the right thing once we know what that is. 198 int max_area = 0;
133 return gfx::Display(0, gfx::Rect(GetPrimaryDisplaySize())); 199 const gfx::Display* matching = NULL;
200 for (std::vector<gfx::Display>::const_iterator it = displays_.begin();
201 it != displays_.end(); ++it) {
202 gfx::Rect intersect = gfx::IntersectRects(it->bounds(), match_rect);
203 int area = intersect.width() * intersect.height();
204 if (area > max_area) {
205 max_area = area;
206 matching = &*it;
207 }
208 }
209 // Fallback to the primary display if there is no matching display.
210 return matching ? *matching : GetPrimaryDisplay();
134 } 211 }
135 212
136 gfx::Display DesktopScreenX11::GetPrimaryDisplay() const { 213 gfx::Display DesktopScreenX11::GetPrimaryDisplay() const {
137 // TODO(erg): Do the right thing once we know what that is. 214 return displays_.front();
138 return gfx::Display(0, gfx::Rect(GetPrimaryDisplaySize()));
139 } 215 }
140 216
141 void DesktopScreenX11::AddObserver(gfx::DisplayObserver* observer) { 217 void DesktopScreenX11::AddObserver(gfx::DisplayObserver* observer) {
142 // TODO(erg|oshima): Do the right thing once we know what that is. 218 observer_list_.AddObserver(observer);
143 // crbug.com/122863
144 }
145 void DesktopScreenX11::RemoveObserver(gfx::DisplayObserver* observer) {
146 // TODO(erg|oshima): Do the right thing once we know what that is.
147 // crbug.com/122863
148 } 219 }
149 220
150 } // namespace 221 void DesktopScreenX11::RemoveObserver(gfx::DisplayObserver* observer) {
222 observer_list_.RemoveObserver(observer);
223 }
224
225 bool DesktopScreenX11::Dispatch(const base::NativeEvent& event) {
226 if (event->type - xrandr_event_base_ == RRScreenChangeNotify) {
227 // Pass the event through to xlib.
228 XRRUpdateConfiguration(event);
229 } else if (event->type - xrandr_event_base_ == RRNotify) {
230 // There's some sort of observer dispatch going on here, but I don't think
231 // it's the screen's?
232 DLOG(ERROR) << "DesktopScreenX11::Dispatch() -> RRNotify";
233
234 if (configure_timer_.get()) {
235 configure_timer_->Reset();
236 } else {
237 configure_timer_.reset(new base::OneShotTimer<DesktopScreenX11>());
238 configure_timer_->Start(
239 FROM_HERE,
240 base::TimeDelta::FromMilliseconds(kConfigureDelayMs),
241 this,
242 &DesktopScreenX11::ConfigureTimerFired);
243 }
244 }
245
246 return true;
247 }
248
249 ////////////////////////////////////////////////////////////////////////////////
250 // DesktopScreenX11, private:
251
252 DesktopScreenX11::DesktopScreenX11(
253 const std::vector<gfx::Display>& test_displays)
254 : xdisplay_(base::MessagePumpX11::GetDefaultXDisplay()),
255 x_root_window_(DefaultRootWindow(xdisplay_)),
256 has_xrandr_(false),
257 xrandr_event_base_(0),
258 displays_(test_displays) {
259 }
260
261 std::vector<gfx::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
262 std::vector<gfx::Display> displays;
263 XRRScreenResources* resources =
264 XRRGetScreenResourcesCurrent(xdisplay_, x_root_window_);
265 if (!resources) {
266 LOG(ERROR) << "XRandR returned no displays. Falling back to Root Window.";
267 return GetFallbackDisplayList();
268 }
269
270 bool has_work_area = false;
271 gfx::Rect work_area;
272 std::vector<int> value;
273 if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
274 value.size() >= 4) {
275 work_area = gfx::Rect(value[0], value[1], value[2], value[3]);
276 has_work_area = true;
277 }
278
279 for (int i = 0; i < resources->noutput; ++i) {
280 RROutput output_id = resources->outputs[i];
281 XRROutputInfo* output_info =
282 XRRGetOutputInfo(xdisplay_, resources, output_id);
283
284 bool is_connected = (output_info->connection == RR_Connected);
285 if (!is_connected) {
286 XRRFreeOutputInfo(output_info);
287 continue;
288 }
289
290 if (output_info->crtc) {
291 XRRCrtcInfo *crtc = XRRGetCrtcInfo(xdisplay_,
292 resources,
293 output_info->crtc);
294
295 int64 display_id = -1;
296 if (!base::GetDisplayId(output_id, i, &display_id)) {
297 // It isn't ideal, but if we can't parse the EDID data, fallback on the
298 // display number.
299 display_id = i;
300 }
301
302 gfx::Rect crtc_bounds(crtc->x, crtc->y, crtc->width, crtc->height);
303 gfx::Display display(display_id, crtc_bounds);
304 if (has_work_area) {
305 gfx::Rect intersection = crtc_bounds;
306 intersection.Intersect(work_area);
307 display.set_work_area(intersection);
308 }
309
310 displays.push_back(display);
311
312 XRRFreeCrtcInfo(crtc);
313 }
314
315 XRRFreeOutputInfo(output_info);
316 }
317
318 XRRFreeScreenResources(resources);
319
320 if (displays.empty()) {
321 LOG(ERROR) << "XRandR claims there are no valid displays. Falling back.";
Daniel Erat 2013/09/19 23:32:37 i wonder if this legitimately happens if the user
322 return GetFallbackDisplayList();
323 }
324
325 return displays;
326 }
327
328 void DesktopScreenX11::ConfigureTimerFired() {
329 std::vector<gfx::Display> new_displays = BuildDisplaysFromXRandRInfo();
330 ProcessDisplayChange(new_displays);
331 }
151 332
152 //////////////////////////////////////////////////////////////////////////////// 333 ////////////////////////////////////////////////////////////////////////////////
153 334
154 namespace views {
155
156 gfx::Screen* CreateDesktopScreen() { 335 gfx::Screen* CreateDesktopScreen() {
157 return new DesktopScreenX11; 336 return new DesktopScreenX11;
158 } 337 }
159 338
160 } // namespace views 339 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698