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

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: Remove probably unneeded Xrandr flags. 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 gfx::Display GetFallbackDisplay() {
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 gfx::Display(0, gfx::Rect(0, 0, width, height));
31 } 36 }
32 37
33 class DesktopScreenX11 : public gfx::Screen { 38 } // namespace
34 public:
35 DesktopScreenX11();
36 virtual ~DesktopScreenX11();
37 39
38 // Overridden from gfx::Screen: 40 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 41
60 //////////////////////////////////////////////////////////////////////////////// 42 ////////////////////////////////////////////////////////////////////////////////
61 // DesktopScreenX11, public: 43 // DesktopScreenX11, public:
62 44
63 DesktopScreenX11::DesktopScreenX11() { 45 DesktopScreenX11::DesktopScreenX11()
46 : xdisplay_(base::MessagePumpX11::GetDefaultXDisplay()),
47 x_root_window_(DefaultRootWindow(xdisplay_)),
48 has_xrandr_(false),
49 randr_version_major_(0),
50 randr_version_minor_(0),
51 xrandr_event_base_(0) {
52 has_xrandr_ = XRRQueryVersion(
53 xdisplay_, &randr_version_major_, &randr_version_minor_);
Daniel Erat 2013/09/19 22:13:04 i don't see any reason why the major and minor ver
54
55 // We only support 1.3+. There were library changes before this and we should
56 // use the new interface instead of the 1.2 one.
57 has_xrandr_ = has_xrandr_ && 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 }
64 } 71 }
65 72
66 DesktopScreenX11::~DesktopScreenX11() { 73 DesktopScreenX11::~DesktopScreenX11() {
74 if (has_xrandr_)
75 base::MessagePumpX11::Current()->RemoveDispatcherForRootWindow(this);
76 }
77
78 void DesktopScreenX11::ProcessDisplayChange(
79 const std::vector<gfx::Display>& incoming) {
80 std::vector<gfx::Display>::const_iterator cur_it = displays_.begin();
81 for (; cur_it != displays_.end(); ++cur_it) {
82 bool found = false;
83 for (std::vector<gfx::Display>::const_iterator incoming_it =
84 incoming.begin(); incoming_it != incoming.end(); ++incoming_it) {
85 if (cur_it->id() == incoming_it->id()) {
86 found = true;
87 break;
88 }
89 }
90
91 if (!found) {
92 FOR_EACH_OBSERVER(gfx::DisplayObserver, observer_list_,
93 OnDisplayRemoved(*cur_it));
94 }
95 }
96
97 std::vector<gfx::Display>::const_iterator incoming_it = incoming.begin();
98 for (; incoming_it != incoming.end(); ++incoming_it) {
99 bool found = false;
100 for (std::vector<gfx::Display>::const_iterator cur_it = displays_.begin();
101 cur_it != displays_.end(); ++cur_it) {
102 if (incoming_it->id() == cur_it->id()) {
103 if (incoming_it->bounds() != cur_it->bounds()) {
104 FOR_EACH_OBSERVER(gfx::DisplayObserver, observer_list_,
105 OnDisplayBoundsChanged(*incoming_it));
106 }
107
108 found = true;
109 break;
110 }
111 }
112
113 if (!found) {
114 FOR_EACH_OBSERVER(gfx::DisplayObserver, observer_list_,
115 OnDisplayAdded(*incoming_it));
116 }
117 }
118
119 displays_ = incoming;
67 } 120 }
68 121
69 //////////////////////////////////////////////////////////////////////////////// 122 ////////////////////////////////////////////////////////////////////////////////
70 // DesktopScreenX11, gfx::Screen implementation: 123 // DesktopScreenX11, gfx::Screen implementation:
71 124
72 bool DesktopScreenX11::IsDIPEnabled() { 125 bool DesktopScreenX11::IsDIPEnabled() {
73 return false; 126 return false;
74 } 127 }
75 128
76 gfx::Point DesktopScreenX11::GetCursorScreenPoint() { 129 gfx::Point DesktopScreenX11::GetCursorScreenPoint() {
77 Display* display = ui::GetXDisplay(); 130 Display* display = ui::GetXDisplay();
78 131
79 ::Window root, child; 132 ::Window root, child;
80 int root_x, root_y, win_x, win_y; 133 int root_x, root_y, win_x, win_y;
81 unsigned int mask; 134 unsigned int mask;
82 XQueryPointer(display, 135 XQueryPointer(display,
83 DefaultRootWindow(display), 136 DefaultRootWindow(display),
84 &root, 137 &root,
85 &child, 138 &child,
86 &root_x, 139 &root_x,
87 &root_y, 140 &root_y,
88 &win_x, 141 &win_x,
89 &win_y, 142 &win_y,
90 &mask); 143 &mask);
91 144
92 return gfx::Point(root_x, root_y); 145 return gfx::Point(root_x, root_y);
93 } 146 }
94 147
95 gfx::NativeWindow DesktopScreenX11::GetWindowUnderCursor() { 148 gfx::NativeWindow DesktopScreenX11::GetWindowUnderCursor() {
149 return GetWindowAtScreenPoint(GetCursorScreenPoint());
150 }
151
152 gfx::NativeWindow DesktopScreenX11::GetWindowAtScreenPoint(
153 const gfx::Point& point) {
96 // TODO(erg): Implement using the discussion at 154 // TODO(erg): Implement using the discussion at
97 // http://codereview.chromium.org/10279005/ 155 // http://codereview.chromium.org/10279005/
98 return NULL;
99 }
100
101 gfx::NativeWindow DesktopScreenX11::GetWindowAtScreenPoint(
102 const gfx::Point& point) {
103 NOTIMPLEMENTED(); 156 NOTIMPLEMENTED();
104 return NULL; 157 return NULL;
105 } 158 }
106 159
107 int DesktopScreenX11::GetNumDisplays() const { 160 int DesktopScreenX11::GetNumDisplays() const {
108 // TODO(erg): Figure this out with oshima or piman because I have no clue 161 if (!has_xrandr_)
Daniel Erat 2013/09/19 22:13:04 can you just insert the fallback display in the c'
Elliot Glaysher 2013/09/19 23:08:34 That's a really good idea, and lets me unit test a
109 // about the XRandR implications here. 162 return 1;
110 return 1; 163
164 return displays_.size();
111 } 165 }
112 166
113 std::vector<gfx::Display> DesktopScreenX11::GetAllDisplays() const { 167 std::vector<gfx::Display> DesktopScreenX11::GetAllDisplays() const {
114 // TODO(erg): Do the right thing once we know what that is. 168 if (!has_xrandr_)
115 return std::vector<gfx::Display>(1, GetPrimaryDisplay()); 169 return std::vector<gfx::Display>(1, GetFallbackDisplay());
170
171 return displays_;
116 } 172 }
117 173
118 gfx::Display DesktopScreenX11::GetDisplayNearestWindow( 174 gfx::Display DesktopScreenX11::GetDisplayNearestWindow(
119 gfx::NativeView window) const { 175 gfx::NativeView window) const {
120 // TODO(erg): Do the right thing once we know what that is. 176 if (!has_xrandr_)
121 return gfx::Display(0, gfx::Rect(GetPrimaryDisplaySize())); 177 return GetFallbackDisplay();
178
179 // TODO(erg): This should theoretically be easy, but it isn't. At the time we
180 // get called here, our aura::Window has not been Init()ed, because this
181 // method is called to get the device scale factor as part of
182 // RootWindow::Init(), before Window::Init(). This seems very confused; we're
183 // trying to get a display nearest window even before we've allocated the
184 // root window. Once fixed, the correct implementation should probably be:
185 //
186 // return GetDisplayMatching(window->GetBoundsInScreen());
187 //
188 // But at least for now, we'll just fallback:
189 return GetPrimaryDisplay();
122 } 190 }
123 191
124 gfx::Display DesktopScreenX11::GetDisplayNearestPoint( 192 gfx::Display DesktopScreenX11::GetDisplayNearestPoint(
125 const gfx::Point& point) const { 193 const gfx::Point& point) const {
126 // TODO(erg): Do the right thing once we know what that is. 194 if (!has_xrandr_)
127 return gfx::Display(0, gfx::Rect(GetPrimaryDisplaySize())); 195 return GetFallbackDisplay();
196
197 for (std::vector<gfx::Display>::const_iterator it = displays_.begin();
198 it != displays_.end(); ++it) {
199 if (it->bounds().Contains(point))
200 return *it;
201 }
202
203 return GetPrimaryDisplay();
128 } 204 }
129 205
130 gfx::Display DesktopScreenX11::GetDisplayMatching( 206 gfx::Display DesktopScreenX11::GetDisplayMatching(
131 const gfx::Rect& match_rect) const { 207 const gfx::Rect& match_rect) const {
132 // TODO(erg): Do the right thing once we know what that is. 208 if (!has_xrandr_)
133 return gfx::Display(0, gfx::Rect(GetPrimaryDisplaySize())); 209 return GetFallbackDisplay();
210
211 int max_area = 0;
212 const gfx::Display* matching = NULL;
213 for (std::vector<gfx::Display>::const_iterator it = displays_.begin();
214 it != displays_.end(); ++it) {
215 gfx::Rect intersect = gfx::IntersectRects(it->bounds(), match_rect);
216 int area = intersect.width() * intersect.height();
217 if (area > max_area) {
218 max_area = area;
219 matching = &*it;
220 }
221 }
222 // Fallback to the primary display if there is no matching display.
223 return matching ? *matching : GetPrimaryDisplay();
134 } 224 }
135 225
136 gfx::Display DesktopScreenX11::GetPrimaryDisplay() const { 226 gfx::Display DesktopScreenX11::GetPrimaryDisplay() const {
137 // TODO(erg): Do the right thing once we know what that is. 227 if (has_xrandr_ && !displays_.empty())
138 return gfx::Display(0, gfx::Rect(GetPrimaryDisplaySize())); 228 return displays_.front();
229
230 return GetFallbackDisplay();
139 } 231 }
140 232
141 void DesktopScreenX11::AddObserver(gfx::DisplayObserver* observer) { 233 void DesktopScreenX11::AddObserver(gfx::DisplayObserver* observer) {
142 // TODO(erg|oshima): Do the right thing once we know what that is. 234 observer_list_.AddObserver(observer);
143 // crbug.com/122863 235 }
144 } 236
145 void DesktopScreenX11::RemoveObserver(gfx::DisplayObserver* observer) { 237 void DesktopScreenX11::RemoveObserver(gfx::DisplayObserver* observer) {
146 // TODO(erg|oshima): Do the right thing once we know what that is. 238 observer_list_.RemoveObserver(observer);
147 // crbug.com/122863 239 }
148 } 240
149 241 bool DesktopScreenX11::Dispatch(const base::NativeEvent& event) {
150 } // namespace 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 DLOG(ERROR) << "DesktopScreenX11::Dispatch() -> RRNotify";
249
250 if (configure_timer_.get()) {
251 configure_timer_->Reset();
252 } else {
253 configure_timer_.reset(new base::OneShotTimer<DesktopScreenX11>());
254 configure_timer_->Start(
255 FROM_HERE,
256 base::TimeDelta::FromMilliseconds(kConfigureDelayMs),
257 this,
258 &DesktopScreenX11::ConfigureTimerFired);
259 }
260 }
261
262 return true;
263 }
151 264
152 //////////////////////////////////////////////////////////////////////////////// 265 ////////////////////////////////////////////////////////////////////////////////
153 266 // DesktopScreenX11, private:
154 namespace views { 267
268 DesktopScreenX11::DesktopScreenX11(
269 const std::vector<gfx::Display>& test_displays)
270 : xdisplay_(base::MessagePumpX11::GetDefaultXDisplay()),
271 x_root_window_(DefaultRootWindow(xdisplay_)),
272 has_xrandr_(false),
273 randr_version_major_(0),
274 randr_version_minor_(0),
275 xrandr_event_base_(0),
276 displays_(test_displays) {
277 }
278
279 std::vector<gfx::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
280 std::vector<gfx::Display> displays;
281 XRRScreenResources* resources =
282 XRRGetScreenResourcesCurrent(xdisplay_, x_root_window_);
283 if (!resources) {
284 NOTIMPLEMENTED();
Daniel Erat 2013/09/19 22:13:04 maybe log an error instead? notimplemented seems s
285 return displays;
286 }
287
288 bool has_work_area = false;
289 gfx::Rect work_area;
290 std::vector<int> value;
291 if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
Daniel Erat 2013/09/19 22:13:04 there should be a separate 4-tuple for each deskto
Elliot Glaysher 2013/09/19 23:08:34 All the documentation that I can find says that _N
Daniel Erat 2013/09/19 23:32:37 the spec (http://standards.freedesktop.org/wm-spec
292 value.size() >= 4) {
293 work_area = gfx::Rect(value[0], value[1], value[2], value[3]);
294 has_work_area = true;
295 }
296
297 for (int i = 0; i < resources->noutput; ++i) {
298 RROutput output_id = resources->outputs[i];
299 XRROutputInfo* output_info =
300 XRRGetOutputInfo(xdisplay_, resources, output_id);
301
302 bool is_connected = (output_info->connection == RR_Connected);
303 if (!is_connected) {
304 XRRFreeOutputInfo(output_info);
305 continue;
306 }
307
308 if (output_info->crtc) {
309 XRRCrtcInfo *crtc = XRRGetCrtcInfo(xdisplay_,
310 resources,
311 output_info->crtc);
312
313 int64 display_id = -1;
314 if (!base::GetDisplayId(output_id, 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;
318 }
319
320 gfx::Rect crtc_bounds(crtc->x, crtc->y, crtc->width, crtc->height);
321 gfx::Display display(display_id, crtc_bounds);
322 if (has_work_area) {
323 gfx::Rect intersection = crtc_bounds;
324 intersection.Intersect(work_area);
325 display.set_work_area(intersection);
326 }
327
328 displays.push_back(display);
329
330 XRRFreeCrtcInfo(crtc);
331 }
332
333 XRRFreeOutputInfo(output_info);
334 }
335
336 XRRFreeScreenResources(resources);
337
338 return displays;
339 }
340
341 void DesktopScreenX11::ConfigureTimerFired() {
342 std::vector<gfx::Display> new_displays = BuildDisplaysFromXRandRInfo();
343 ProcessDisplayChange(new_displays);
344 }
345
346 ////////////////////////////////////////////////////////////////////////////////
155 347
156 gfx::Screen* CreateDesktopScreen() { 348 gfx::Screen* CreateDesktopScreen() {
157 return new DesktopScreenX11; 349 return new DesktopScreenX11;
158 } 350 }
159 351
160 } // namespace views 352 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698