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

Side by Side Diff: chromeos/display/native_display_delegate_x11.cc

Issue 192483007: Move chromeos/display/* to ui/display/chromeos (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Include display.gyp into ChromeOS builds only Created 6 years, 9 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
(Empty)
1 // Copyright 2014 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 "chromeos/display/native_display_delegate_x11.h"
6
7 #include <X11/Xatom.h>
8 #include <X11/Xlib.h>
9 #include <X11/extensions/dpms.h>
10 #include <X11/extensions/Xrandr.h>
11 #include <X11/extensions/XInput2.h>
12
13 #include <utility>
14
15 #include "base/logging.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/message_loop/message_pump_x11.h"
18 #include "base/x11/edid_parser_x11.h"
19 #include "base/x11/x11_error_tracker.h"
20 #include "chromeos/display/native_display_event_dispatcher_x11.h"
21 #include "chromeos/display/native_display_observer.h"
22 #include "chromeos/display/output_util.h"
23
24 namespace chromeos {
25
26 namespace {
27
28 // DPI measurements.
29 const float kMmInInch = 25.4;
30 const float kDpi96 = 96.0;
31 const float kPixelsToMmScale = kMmInInch / kDpi96;
32
33 // Prefixes of output name
34 const char kOutputName_VGA[] = "VGA";
35 const char kOutputName_HDMI[] = "HDMI";
36 const char kOutputName_DVI[] = "DVI";
37 const char kOutputName_DisplayPort[] = "DP";
38
39 const char kContentProtectionAtomName[] = "Content Protection";
40 const char kProtectionUndesiredAtomName[] = "Undesired";
41 const char kProtectionDesiredAtomName[] = "Desired";
42 const char kProtectionEnabledAtomName[] = "Enabled";
43
44 bool IsInternalOutput(const XRROutputInfo* output_info) {
45 return IsInternalOutputName(std::string(output_info->name));
46 }
47
48 RRMode GetOutputNativeMode(const XRROutputInfo* output_info) {
49 return output_info->nmode > 0 ? output_info->modes[0] : None;
50 }
51
52 } // namespace
53
54 ////////////////////////////////////////////////////////////////////////////////
55 // NativeDisplayDelegateX11::HelperDelegateX11
56
57 class NativeDisplayDelegateX11::HelperDelegateX11
58 : public NativeDisplayDelegateX11::HelperDelegate {
59 public:
60 HelperDelegateX11(NativeDisplayDelegateX11* delegate)
61 : delegate_(delegate) {}
62 virtual ~HelperDelegateX11() {}
63
64 // NativeDisplayDelegateX11::HelperDelegate overrides:
65 virtual void UpdateXRandRConfiguration(
66 const base::NativeEvent& event) OVERRIDE {
67 XRRUpdateConfiguration(event);
68 }
69 virtual const std::vector<OutputConfigurator::OutputSnapshot>&
70 GetCachedOutputs() const OVERRIDE {
71 return delegate_->cached_outputs_;
72 }
73 virtual void NotifyDisplayObservers() OVERRIDE {
74 FOR_EACH_OBSERVER(NativeDisplayObserver,
75 delegate_->observers_,
76 OnConfigurationChanged());
77 }
78
79 private:
80 NativeDisplayDelegateX11* delegate_;
81
82 DISALLOW_COPY_AND_ASSIGN(HelperDelegateX11);
83 };
84
85 ////////////////////////////////////////////////////////////////////////////////
86 // NativeDisplayDelegateX11::MessagePumpObserverX11
87
88 class NativeDisplayDelegateX11::MessagePumpObserverX11
89 : public base::MessagePumpObserver {
90 public:
91 MessagePumpObserverX11(HelperDelegate* delegate);
92 virtual ~MessagePumpObserverX11();
93
94 // base::MessagePumpObserver overrides:
95 virtual base::EventStatus WillProcessEvent(
96 const base::NativeEvent& event) OVERRIDE;
97 virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE;
98
99 private:
100 HelperDelegate* delegate_; // Not owned.
101
102 DISALLOW_COPY_AND_ASSIGN(MessagePumpObserverX11);
103 };
104
105 NativeDisplayDelegateX11::MessagePumpObserverX11::MessagePumpObserverX11(
106 HelperDelegate* delegate) : delegate_(delegate) {}
107
108 NativeDisplayDelegateX11::MessagePumpObserverX11::~MessagePumpObserverX11() {}
109
110 base::EventStatus
111 NativeDisplayDelegateX11::MessagePumpObserverX11::WillProcessEvent(
112 const base::NativeEvent& event) {
113 // XI_HierarchyChanged events are special. There is no window associated with
114 // these events. So process them directly from here.
115 if (event->type == GenericEvent &&
116 event->xgeneric.evtype == XI_HierarchyChanged) {
117 VLOG(1) << "Received XI_HierarchyChanged event";
118 // Defer configuring outputs to not stall event processing.
119 // This also takes care of same event being received twice.
120 delegate_->NotifyDisplayObservers();
121 }
122
123 return base::EVENT_CONTINUE;
124 }
125
126 void NativeDisplayDelegateX11::MessagePumpObserverX11::DidProcessEvent(
127 const base::NativeEvent& event) {
128 }
129
130 ////////////////////////////////////////////////////////////////////////////////
131 // NativeDisplayDelegateX11 implementation:
132
133 NativeDisplayDelegateX11::NativeDisplayDelegateX11()
134 : display_(base::MessagePumpX11::GetDefaultXDisplay()),
135 window_(DefaultRootWindow(display_)),
136 screen_(NULL) {}
137
138 NativeDisplayDelegateX11::~NativeDisplayDelegateX11() {
139 base::MessagePumpX11::Current()->RemoveDispatcherForRootWindow(
140 message_pump_dispatcher_.get());
141 base::MessagePumpX11::Current()->RemoveObserver(message_pump_observer_.get());
142 }
143
144 void NativeDisplayDelegateX11::Initialize() {
145 int error_base_ignored = 0;
146 int xrandr_event_base = 0;
147 XRRQueryExtension(display_, &xrandr_event_base, &error_base_ignored);
148
149 helper_delegate_.reset(new HelperDelegateX11(this));
150 message_pump_dispatcher_.reset(new NativeDisplayEventDispatcherX11(
151 helper_delegate_.get(), xrandr_event_base));
152 message_pump_observer_.reset(new MessagePumpObserverX11(
153 helper_delegate_.get()));
154
155 base::MessagePumpX11::Current()->AddDispatcherForRootWindow(
156 message_pump_dispatcher_.get());
157 // We can't do this with a root window listener because XI_HierarchyChanged
158 // messages don't have a target window.
159 base::MessagePumpX11::Current()->AddObserver(message_pump_observer_.get());
160 }
161
162 void NativeDisplayDelegateX11::GrabServer() {
163 CHECK(!screen_) << "Server already grabbed";
164 XGrabServer(display_);
165 screen_ = XRRGetScreenResources(display_, window_);
166 CHECK(screen_);
167 }
168
169 void NativeDisplayDelegateX11::UngrabServer() {
170 CHECK(screen_) << "Server not grabbed";
171 XRRFreeScreenResources(screen_);
172 screen_ = NULL;
173 XUngrabServer(display_);
174 }
175
176 void NativeDisplayDelegateX11::SyncWithServer() { XSync(display_, 0); }
177
178 void NativeDisplayDelegateX11::SetBackgroundColor(uint32 color_argb) {
179 // Configuring CRTCs/Framebuffer clears the boot screen image. Set the
180 // same background color while configuring the display to minimize the
181 // duration of black screen at boot time. The background is filled with
182 // black later in ash::DisplayManager. crbug.com/171050.
183 XSetWindowAttributes swa = {0};
184 XColor color;
185 Colormap colormap = DefaultColormap(display_, 0);
186 // XColor uses 16 bits per color.
187 color.red = (color_argb & 0x00FF0000) >> 8;
188 color.green = (color_argb & 0x0000FF00);
189 color.blue = (color_argb & 0x000000FF) << 8;
190 color.flags = DoRed | DoGreen | DoBlue;
191 XAllocColor(display_, colormap, &color);
192 swa.background_pixel = color.pixel;
193 XChangeWindowAttributes(display_, window_, CWBackPixel, &swa);
194 XFreeColors(display_, colormap, &color.pixel, 1, 0);
195 }
196
197 void NativeDisplayDelegateX11::ForceDPMSOn() {
198 CHECK(DPMSEnable(display_));
199 CHECK(DPMSForceLevel(display_, DPMSModeOn));
200 }
201
202 std::vector<OutputConfigurator::OutputSnapshot>
203 NativeDisplayDelegateX11::GetOutputs() {
204 CHECK(screen_) << "Server not grabbed";
205
206 cached_outputs_.clear();
207 RRCrtc last_used_crtc = None;
208
209 for (int i = 0; i < screen_->noutput && cached_outputs_.size() < 2; ++i) {
210 RROutput output_id = screen_->outputs[i];
211 XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_, output_id);
212 if (output_info->connection == RR_Connected) {
213 OutputConfigurator::OutputSnapshot output =
214 InitOutputSnapshot(output_id, output_info, &last_used_crtc, i);
215 VLOG(2) << "Found display " << cached_outputs_.size() << ":"
216 << " output=" << output.output << " crtc=" << output.crtc
217 << " current_mode=" << output.current_mode;
218 cached_outputs_.push_back(output);
219 }
220 XRRFreeOutputInfo(output_info);
221 }
222
223 return cached_outputs_;
224 }
225
226 void NativeDisplayDelegateX11::AddMode(
227 const OutputConfigurator::OutputSnapshot& output, RRMode mode) {
228 CHECK(screen_) << "Server not grabbed";
229 VLOG(1) << "AddOutputMode: output=" << output.output << " mode=" << mode;
230 XRRAddOutputMode(display_, output.output, mode);
231 }
232
233 bool NativeDisplayDelegateX11::Configure(
234 const OutputConfigurator::OutputSnapshot& output,
235 RRMode mode,
236 int x,
237 int y) {
238 return ConfigureCrtc(output.crtc, mode, output.output, x, y);
239 }
240
241 bool NativeDisplayDelegateX11::ConfigureCrtc(
242 RRCrtc crtc,
243 RRMode mode,
244 RROutput output,
245 int x,
246 int y) {
247 CHECK(screen_) << "Server not grabbed";
248 VLOG(1) << "ConfigureCrtc: crtc=" << crtc << " mode=" << mode
249 << " output=" << output << " x=" << x << " y=" << y;
250 // Xrandr.h is full of lies. XRRSetCrtcConfig() is defined as returning a
251 // Status, which is typically 0 for failure and 1 for success. In
252 // actuality it returns a RRCONFIGSTATUS, which uses 0 for success.
253 return XRRSetCrtcConfig(display_,
254 screen_,
255 crtc,
256 CurrentTime,
257 x,
258 y,
259 mode,
260 RR_Rotate_0,
261 (output && mode) ? &output : NULL,
262 (output && mode) ? 1 : 0) == RRSetConfigSuccess;
263 }
264
265 void NativeDisplayDelegateX11::CreateFrameBuffer(
266 int width,
267 int height,
268 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) {
269 CHECK(screen_) << "Server not grabbed";
270 int current_width = DisplayWidth(display_, DefaultScreen(display_));
271 int current_height = DisplayHeight(display_, DefaultScreen(display_));
272 VLOG(1) << "CreateFrameBuffer: new=" << width << "x" << height
273 << " current=" << current_width << "x" << current_height;
274 if (width == current_width && height == current_height)
275 return;
276
277 DestroyUnusedCrtcs(outputs);
278 int mm_width = width * kPixelsToMmScale;
279 int mm_height = height * kPixelsToMmScale;
280 XRRSetScreenSize(display_, window_, width, height, mm_width, mm_height);
281 }
282
283 bool NativeDisplayDelegateX11::InitModeInfo(
284 RRMode mode,
285 OutputConfigurator::ModeInfo* mode_info) {
286 DCHECK(mode_info);
287 CHECK(screen_) << "Server not grabbed";
288 // TODO: Determine if we need to organize modes in a way which provides
289 // better than O(n) lookup time. In many call sites, for example, the
290 // "next" mode is typically what we are looking for so using this
291 // helper might be too expensive.
292 for (int i = 0; i < screen_->nmode; ++i) {
293 if (mode == screen_->modes[i].id) {
294 const XRRModeInfo& info = screen_->modes[i];
295 mode_info->width = info.width;
296 mode_info->height = info.height;
297 mode_info->interlaced = info.modeFlags & RR_Interlace;
298 if (info.hTotal && info.vTotal) {
299 mode_info->refresh_rate =
300 static_cast<float>(info.dotClock) /
301 (static_cast<float>(info.hTotal) * static_cast<float>(info.vTotal));
302 } else {
303 mode_info->refresh_rate = 0.0f;
304 }
305 return true;
306 }
307 }
308 return false;
309 }
310
311 OutputConfigurator::OutputSnapshot NativeDisplayDelegateX11::InitOutputSnapshot(
312 RROutput id,
313 XRROutputInfo* info,
314 RRCrtc* last_used_crtc,
315 int index) {
316 OutputConfigurator::OutputSnapshot output;
317 output.output = id;
318 output.width_mm = info->mm_width;
319 output.height_mm = info->mm_height;
320 output.has_display_id = base::GetDisplayId(id, index, &output.display_id);
321 output.index = index;
322 bool is_internal = IsInternalOutput(info);
323
324 // Use the index as a valid display ID even if the internal
325 // display doesn't have valid EDID because the index
326 // will never change.
327 if (!output.has_display_id && is_internal)
328 output.has_display_id = true;
329
330 if (info->crtc) {
331 XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(display_, screen_, info->crtc);
332 output.current_mode = crtc_info->mode;
333 output.x = crtc_info->x;
334 output.y = crtc_info->y;
335 XRRFreeCrtcInfo(crtc_info);
336 }
337
338 // Assign a CRTC that isn't already in use.
339 for (int i = 0; i < info->ncrtc; ++i) {
340 if (info->crtcs[i] != *last_used_crtc) {
341 output.crtc = info->crtcs[i];
342 *last_used_crtc = output.crtc;
343 break;
344 }
345 }
346
347 output.native_mode = GetOutputNativeMode(info);
348 output.is_aspect_preserving_scaling = IsOutputAspectPreservingScaling(id);
349 output.touch_device_id = None;
350
351 for (int i = 0; i < info->nmode; ++i) {
352 const RRMode mode = info->modes[i];
353 OutputConfigurator::ModeInfo mode_info;
354 if (InitModeInfo(mode, &mode_info))
355 output.mode_infos.insert(std::make_pair(mode, mode_info));
356 else
357 LOG(WARNING) << "Unable to find XRRModeInfo for mode " << mode;
358 }
359
360 std::string name(info->name);
361 if (is_internal) {
362 output.type = ui::OUTPUT_TYPE_INTERNAL;
363 } else if (name.find(kOutputName_VGA) == 0) {
364 output.type = ui::OUTPUT_TYPE_VGA;
365 } else if (name.find(kOutputName_HDMI) == 0) {
366 output.type = ui::OUTPUT_TYPE_HDMI;
367 } else if (name.find(kOutputName_DVI) == 0) {
368 output.type = ui::OUTPUT_TYPE_DVI;
369 } else if (name.find(kOutputName_DisplayPort) == 0) {
370 output.type = ui::OUTPUT_TYPE_DISPLAYPORT;
371 } else {
372 LOG(ERROR) << "Unknown link type: " << name;
373 output.type = ui::OUTPUT_TYPE_UNKNOWN;
374 }
375
376 return output;
377 }
378
379 bool NativeDisplayDelegateX11::GetHDCPState(
380 const OutputConfigurator::OutputSnapshot& output, ui::HDCPState* state) {
381 unsigned char* values = NULL;
382 int actual_format = 0;
383 unsigned long nitems = 0;
384 unsigned long bytes_after = 0;
385 Atom actual_type = None;
386 int success = 0;
387 // TODO(kcwu): Use X11AtomCache to save round trip time of XInternAtom.
388 Atom prop = XInternAtom(display_, kContentProtectionAtomName, False);
389
390 bool ok = true;
391 // TODO(kcwu): Move this to x11_util (similar method calls in this file and
392 // output_util.cc)
393 success = XRRGetOutputProperty(display_,
394 output.output,
395 prop,
396 0,
397 100,
398 False,
399 False,
400 AnyPropertyType,
401 &actual_type,
402 &actual_format,
403 &nitems,
404 &bytes_after,
405 &values);
406 if (actual_type == None) {
407 LOG(ERROR) << "Property '" << kContentProtectionAtomName
408 << "' does not exist";
409 ok = false;
410 } else if (success == Success && actual_type == XA_ATOM &&
411 actual_format == 32 && nitems == 1) {
412 Atom value = reinterpret_cast<Atom*>(values)[0];
413 if (value == XInternAtom(display_, kProtectionUndesiredAtomName, False)) {
414 *state = ui::HDCP_STATE_UNDESIRED;
415 } else if (value ==
416 XInternAtom(display_, kProtectionDesiredAtomName, False)) {
417 *state = ui::HDCP_STATE_DESIRED;
418 } else if (value ==
419 XInternAtom(display_, kProtectionEnabledAtomName, False)) {
420 *state = ui::HDCP_STATE_ENABLED;
421 } else {
422 LOG(ERROR) << "Unknown " << kContentProtectionAtomName
423 << " value: " << value;
424 ok = false;
425 }
426 } else {
427 LOG(ERROR) << "XRRGetOutputProperty failed";
428 ok = false;
429 }
430 if (values)
431 XFree(values);
432
433 VLOG(3) << "HDCP state: " << ok << "," << *state;
434 return ok;
435 }
436
437 bool NativeDisplayDelegateX11::SetHDCPState(
438 const OutputConfigurator::OutputSnapshot& output, ui::HDCPState state) {
439 Atom name = XInternAtom(display_, kContentProtectionAtomName, False);
440 Atom value = None;
441 switch (state) {
442 case ui::HDCP_STATE_UNDESIRED:
443 value = XInternAtom(display_, kProtectionUndesiredAtomName, False);
444 break;
445 case ui::HDCP_STATE_DESIRED:
446 value = XInternAtom(display_, kProtectionDesiredAtomName, False);
447 break;
448 default:
449 NOTREACHED() << "Invalid HDCP state: " << state;
450 return false;
451 }
452 base::X11ErrorTracker err_tracker;
453 unsigned char* data = reinterpret_cast<unsigned char*>(&value);
454 XRRChangeOutputProperty(
455 display_, output.output, name, XA_ATOM, 32, PropModeReplace, data, 1);
456 if (err_tracker.FoundNewError()) {
457 LOG(ERROR) << "XRRChangeOutputProperty failed";
458 return false;
459 } else {
460 return true;
461 }
462 }
463
464 void NativeDisplayDelegateX11::DestroyUnusedCrtcs(
465 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) {
466 CHECK(screen_) << "Server not grabbed";
467 // Setting the screen size will fail if any CRTC doesn't fit afterwards.
468 // At the same time, turning CRTCs off and back on uses up a lot of time.
469 // This function tries to be smart to avoid too many off/on cycles:
470 // - We disable all the CRTCs we won't need after the FB resize.
471 // - We set the new modes on CRTCs, if they fit in both the old and new
472 // FBs, and park them at (0,0)
473 // - We disable the CRTCs we will need but don't fit in the old FB. Those
474 // will be reenabled after the resize.
475 // We don't worry about the cached state of the outputs here since we are
476 // not interested in the state we are setting - we just try to get the CRTCs
477 // out of the way so we can rebuild the frame buffer.
478 for (int i = 0; i < screen_->ncrtc; ++i) {
479 // Default config is to disable the crtcs.
480 RRCrtc crtc = screen_->crtcs[i];
481 RRMode mode = None;
482 RROutput output = None;
483 const OutputConfigurator::ModeInfo* mode_info = NULL;
484 for (std::vector<OutputConfigurator::OutputSnapshot>::const_iterator it =
485 outputs.begin();
486 it != outputs.end();
487 ++it) {
488 if (crtc == it->crtc) {
489 mode = it->current_mode;
490 output = it->output;
491 if (mode != None)
492 mode_info = OutputConfigurator::GetModeInfo(*it, mode);
493 break;
494 }
495 }
496
497 if (mode_info) {
498 // In case our CRTC doesn't fit in our current framebuffer, disable it.
499 // It'll get reenabled after we resize the framebuffer.
500 int current_width = DisplayWidth(display_, DefaultScreen(display_));
501 int current_height = DisplayHeight(display_, DefaultScreen(display_));
502 if (mode_info->width > current_width ||
503 mode_info->height > current_height) {
504 mode = None;
505 output = None;
506 mode_info = NULL;
507 }
508 }
509
510 ConfigureCrtc(crtc, mode, output, 0, 0);
511 }
512 }
513
514 bool NativeDisplayDelegateX11::IsOutputAspectPreservingScaling(RROutput id) {
515 bool ret = false;
516
517 Atom scaling_prop = XInternAtom(display_, "scaling mode", False);
518 Atom full_aspect_atom = XInternAtom(display_, "Full aspect", False);
519 if (scaling_prop == None || full_aspect_atom == None)
520 return false;
521
522 int nprop = 0;
523 Atom* props = XRRListOutputProperties(display_, id, &nprop);
524 for (int j = 0; j < nprop && !ret; j++) {
525 Atom prop = props[j];
526 if (scaling_prop == prop) {
527 unsigned char* values = NULL;
528 int actual_format;
529 unsigned long nitems;
530 unsigned long bytes_after;
531 Atom actual_type;
532 int success;
533
534 success = XRRGetOutputProperty(display_,
535 id,
536 prop,
537 0,
538 100,
539 False,
540 False,
541 AnyPropertyType,
542 &actual_type,
543 &actual_format,
544 &nitems,
545 &bytes_after,
546 &values);
547 if (success == Success && actual_type == XA_ATOM && actual_format == 32 &&
548 nitems == 1) {
549 Atom value = reinterpret_cast<Atom*>(values)[0];
550 if (full_aspect_atom == value)
551 ret = true;
552 }
553 if (values)
554 XFree(values);
555 }
556 }
557 if (props)
558 XFree(props);
559
560 return ret;
561 }
562
563 void NativeDisplayDelegateX11::AddObserver(NativeDisplayObserver* observer) {
564 observers_.AddObserver(observer);
565 }
566
567 void NativeDisplayDelegateX11::RemoveObserver(NativeDisplayObserver* observer) {
568 observers_.RemoveObserver(observer);
569 }
570
571 } // namespace chromeos
OLDNEW
« no previous file with comments | « chromeos/display/native_display_delegate_x11.h ('k') | chromeos/display/native_display_event_dispatcher_x11.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698