Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ui / display / chromeos / x11 / native_display_delegate_x11.cc
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 "ui/display/chromeos/x11/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/stl_util.h"
17 #include "ui/display/chromeos/x11/display_mode_x11.h"
18 #include "ui/display/chromeos/x11/display_snapshot_x11.h"
19 #include "ui/display/chromeos/x11/display_util_x11.h"
20 #include "ui/display/chromeos/x11/native_display_event_dispatcher_x11.h"
21 #include "ui/display/types/chromeos/native_display_observer.h"
22 #include "ui/display/util/x11/edid_parser_x11.h"
23 #include "ui/events/platform/platform_event_observer.h"
24 #include "ui/events/platform/platform_event_source.h"
25 #include "ui/gfx/x/x11_error_tracker.h"
26 #include "ui/gfx/x/x11_types.h"
27
28 namespace ui {
29
30 namespace {
31
32 // DPI measurements.
33 const float kMmInInch = 25.4;
34 const float kDpi96 = 96.0;
35 const float kPixelsToMmScale = kMmInInch / kDpi96;
36
37 const char kContentProtectionAtomName[] = "Content Protection";
38 const char kProtectionUndesiredAtomName[] = "Undesired";
39 const char kProtectionDesiredAtomName[] = "Desired";
40 const char kProtectionEnabledAtomName[] = "Enabled";
41
42 RRMode GetOutputNativeMode(const XRROutputInfo* output_info) {
43   return output_info->nmode > 0 ? output_info->modes[0] : None;
44 }
45
46 XRRCrtcGamma* ResampleGammaRamp(XRRCrtcGamma* gamma_ramp, int gamma_ramp_size) {
47   if (gamma_ramp->size == gamma_ramp_size)
48     return gamma_ramp;
49
50 #define RESAMPLE(array, i, r) \
51   array[i] + (array[i + 1] - array[i]) * r / gamma_ramp_size
52
53   XRRCrtcGamma* resampled = XRRAllocGamma(gamma_ramp_size);
54   for (int i = 0; i < gamma_ramp_size; ++i) {
55     int base_index = gamma_ramp->size * i / gamma_ramp_size;
56     int remaining = gamma_ramp->size * i % gamma_ramp_size;
57     if (base_index < gamma_ramp->size - 1) {
58       resampled->red[i] = RESAMPLE(gamma_ramp->red, base_index, remaining);
59       resampled->green[i] = RESAMPLE(gamma_ramp->green, base_index, remaining);
60       resampled->blue[i] = RESAMPLE(gamma_ramp->blue, base_index, remaining);
61     } else {
62       resampled->red[i] = gamma_ramp->red[gamma_ramp->size - 1];
63       resampled->green[i] = gamma_ramp->green[gamma_ramp->size - 1];
64       resampled->blue[i] = gamma_ramp->blue[gamma_ramp->size - 1];
65     }
66   }
67
68 #undef RESAMPLE
69   XRRFreeGamma(gamma_ramp);
70   return resampled;
71 }
72
73 }  // namespace
74
75 ////////////////////////////////////////////////////////////////////////////////
76 // NativeDisplayDelegateX11::HelperDelegateX11
77
78 class NativeDisplayDelegateX11::HelperDelegateX11
79     : public NativeDisplayDelegateX11::HelperDelegate {
80  public:
81   HelperDelegateX11(NativeDisplayDelegateX11* delegate) : delegate_(delegate) {}
82   virtual ~HelperDelegateX11() {}
83
84   // NativeDisplayDelegateX11::HelperDelegate overrides:
85   virtual void UpdateXRandRConfiguration(const base::NativeEvent& event)
86       OVERRIDE {
87     XRRUpdateConfiguration(event);
88   }
89   virtual const std::vector<DisplaySnapshot*>& GetCachedDisplays() const
90       OVERRIDE {
91     return delegate_->cached_outputs_.get();
92   }
93   virtual void NotifyDisplayObservers() OVERRIDE {
94     FOR_EACH_OBSERVER(
95         NativeDisplayObserver, delegate_->observers_, OnConfigurationChanged());
96   }
97
98  private:
99   NativeDisplayDelegateX11* delegate_;
100
101   DISALLOW_COPY_AND_ASSIGN(HelperDelegateX11);
102 };
103
104 ////////////////////////////////////////////////////////////////////////////////
105 // NativeDisplayDelegateX11::PlatformEventObserverX11
106
107 class NativeDisplayDelegateX11::PlatformEventObserverX11
108     : public PlatformEventObserver {
109  public:
110   PlatformEventObserverX11(HelperDelegate* delegate);
111   virtual ~PlatformEventObserverX11();
112
113   // PlatformEventObserverX11:
114   virtual void WillProcessEvent(const ui::PlatformEvent& event) OVERRIDE;
115   virtual void DidProcessEvent(const ui::PlatformEvent& event) OVERRIDE;
116
117  private:
118   HelperDelegate* delegate_;  // Not owned.
119
120   DISALLOW_COPY_AND_ASSIGN(PlatformEventObserverX11);
121 };
122
123 NativeDisplayDelegateX11::PlatformEventObserverX11::PlatformEventObserverX11(
124     HelperDelegate* delegate)
125     : delegate_(delegate) {}
126
127 NativeDisplayDelegateX11::PlatformEventObserverX11::
128     ~PlatformEventObserverX11() {}
129
130 void NativeDisplayDelegateX11::PlatformEventObserverX11::WillProcessEvent(
131     const ui::PlatformEvent& event) {
132   // XI_HierarchyChanged events are special. There is no window associated with
133   // these events. So process them directly from here.
134   if (event->type == GenericEvent &&
135       event->xgeneric.evtype == XI_HierarchyChanged) {
136     VLOG(1) << "Received XI_HierarchyChanged event";
137     // Defer configuring outputs to not stall event processing.
138     // This also takes care of same event being received twice.
139     delegate_->NotifyDisplayObservers();
140   }
141 }
142
143 void NativeDisplayDelegateX11::PlatformEventObserverX11::DidProcessEvent(
144     const ui::PlatformEvent& event) {}
145
146 ////////////////////////////////////////////////////////////////////////////////
147 // NativeDisplayDelegateX11 implementation:
148
149 NativeDisplayDelegateX11::NativeDisplayDelegateX11()
150     : display_(gfx::GetXDisplay()),
151       window_(DefaultRootWindow(display_)),
152       screen_(NULL),
153       background_color_argb_(0) {}
154
155 NativeDisplayDelegateX11::~NativeDisplayDelegateX11() {
156   if (ui::PlatformEventSource::GetInstance()) {
157     ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(
158         platform_event_dispatcher_.get());
159     ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(
160         platform_event_observer_.get());
161   }
162
163   STLDeleteContainerPairSecondPointers(modes_.begin(), modes_.end());
164 }
165
166 void NativeDisplayDelegateX11::Initialize() {
167   int error_base_ignored = 0;
168   int xrandr_event_base = 0;
169   XRRQueryExtension(display_, &xrandr_event_base, &error_base_ignored);
170
171   helper_delegate_.reset(new HelperDelegateX11(this));
172   platform_event_dispatcher_.reset(new NativeDisplayEventDispatcherX11(
173       helper_delegate_.get(), xrandr_event_base));
174   platform_event_observer_.reset(
175       new PlatformEventObserverX11(helper_delegate_.get()));
176
177   if (ui::PlatformEventSource::GetInstance()) {
178     ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(
179         platform_event_dispatcher_.get());
180
181     // We can't do this with a root window listener because XI_HierarchyChanged
182     // messages don't have a target window.
183     ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(
184         platform_event_observer_.get());
185   }
186 }
187
188 void NativeDisplayDelegateX11::GrabServer() {
189   CHECK(!screen_) << "Server already grabbed";
190   XGrabServer(display_);
191   screen_ = XRRGetScreenResources(display_, window_);
192   CHECK(screen_);
193 }
194
195 void NativeDisplayDelegateX11::UngrabServer() {
196   CHECK(screen_) << "Server not grabbed";
197   XRRFreeScreenResources(screen_);
198   screen_ = NULL;
199   XUngrabServer(display_);
200   // crbug.com/366125
201   XFlush(display_);
202 }
203
204 void NativeDisplayDelegateX11::SyncWithServer() { XSync(display_, 0); }
205
206 void NativeDisplayDelegateX11::SetBackgroundColor(uint32_t color_argb) {
207   background_color_argb_ = color_argb;
208 }
209
210 void NativeDisplayDelegateX11::ForceDPMSOn() {
211   CHECK(DPMSEnable(display_));
212   CHECK(DPMSForceLevel(display_, DPMSModeOn));
213 }
214
215 std::vector<DisplaySnapshot*> NativeDisplayDelegateX11::GetDisplays() {
216   CHECK(screen_) << "Server not grabbed";
217
218   cached_outputs_.clear();
219   RRCrtc last_used_crtc = None;
220
221   InitModes();
222   for (int i = 0; i < screen_->noutput && cached_outputs_.size() < 2; ++i) {
223     RROutput output_id = screen_->outputs[i];
224     XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_, output_id);
225     if (output_info->connection == RR_Connected) {
226       DisplaySnapshotX11* output =
227           InitDisplaySnapshot(output_id, output_info, &last_used_crtc, i);
228       cached_outputs_.push_back(output);
229     }
230     XRRFreeOutputInfo(output_info);
231   }
232
233   return cached_outputs_.get();
234 }
235
236 void NativeDisplayDelegateX11::AddMode(const DisplaySnapshot& output,
237                                        const DisplayMode* mode) {
238   CHECK(screen_) << "Server not grabbed";
239   CHECK(mode) << "Must add valid mode";
240
241   const DisplaySnapshotX11& x11_output =
242       static_cast<const DisplaySnapshotX11&>(output);
243   RRMode mode_id = static_cast<const DisplayModeX11*>(mode)->mode_id();
244
245   VLOG(1) << "AddDisplayMode: output=" << x11_output.output()
246           << " mode=" << mode_id;
247   XRRAddOutputMode(display_, x11_output.output(), mode_id);
248 }
249
250 bool NativeDisplayDelegateX11::Configure(const DisplaySnapshot& output,
251                                          const DisplayMode* mode,
252                                          const gfx::Point& origin) {
253   const DisplaySnapshotX11& x11_output =
254       static_cast<const DisplaySnapshotX11&>(output);
255   RRMode mode_id = None;
256   if (mode)
257     mode_id = static_cast<const DisplayModeX11*>(mode)->mode_id();
258
259   return ConfigureCrtc(
260       x11_output.crtc(), mode_id, x11_output.output(), origin.x(), origin.y());
261 }
262
263 bool NativeDisplayDelegateX11::ConfigureCrtc(RRCrtc crtc,
264                                              RRMode mode,
265                                              RROutput output,
266                                              int x,
267                                              int y) {
268   CHECK(screen_) << "Server not grabbed";
269   VLOG(1) << "ConfigureCrtc: crtc=" << crtc << " mode=" << mode
270           << " output=" << output << " x=" << x << " y=" << y;
271   // Xrandr.h is full of lies. XRRSetCrtcConfig() is defined as returning a
272   // Status, which is typically 0 for failure and 1 for success. In
273   // actuality it returns a RRCONFIGSTATUS, which uses 0 for success.
274   if (XRRSetCrtcConfig(display_,
275                        screen_,
276                        crtc,
277                        CurrentTime,
278                        x,
279                        y,
280                        mode,
281                        RR_Rotate_0,
282                        (output && mode) ? &output : NULL,
283                        (output && mode) ? 1 : 0) != RRSetConfigSuccess) {
284     LOG(WARNING) << "Unable to configure CRTC " << crtc << ":"
285                  << " mode=" << mode << " output=" << output << " x=" << x
286                  << " y=" << y;
287     return false;
288   }
289
290   return true;
291 }
292
293 void NativeDisplayDelegateX11::CreateFrameBuffer(const gfx::Size& size) {
294   CHECK(screen_) << "Server not grabbed";
295   int current_width = DisplayWidth(display_, DefaultScreen(display_));
296   int current_height = DisplayHeight(display_, DefaultScreen(display_));
297   VLOG(1) << "CreateFrameBuffer: new=" << size.width() << "x" << size.height()
298           << " current=" << current_width << "x" << current_height;
299
300   DestroyUnusedCrtcs(size);
301
302   if (size.width() == current_width && size.height() == current_height)
303     return;
304
305   int mm_width = size.width() * kPixelsToMmScale;
306   int mm_height = size.height() * kPixelsToMmScale;
307   XRRSetScreenSize(
308       display_, window_, size.width(), size.height(), mm_width, mm_height);
309   // We don't wait for root window resize, therefore this end up with drawing
310   // in the old window size, which we care during the boot.
311   DrawBackground();
312
313   // Don't redraw the background upon framebuffer change again. This should
314   // happen only once after boot.
315   background_color_argb_ = 0;
316 }
317
318 void NativeDisplayDelegateX11::AddObserver(NativeDisplayObserver* observer) {
319   observers_.AddObserver(observer);
320 }
321
322 void NativeDisplayDelegateX11::RemoveObserver(NativeDisplayObserver* observer) {
323   observers_.RemoveObserver(observer);
324 }
325
326 void NativeDisplayDelegateX11::InitModes() {
327   CHECK(screen_) << "Server not grabbed";
328
329   STLDeleteContainerPairSecondPointers(modes_.begin(), modes_.end());
330   modes_.clear();
331
332   for (int i = 0; i < screen_->nmode; ++i) {
333     const XRRModeInfo& info = screen_->modes[i];
334     float refresh_rate = 0.0f;
335     if (info.hTotal && info.vTotal) {
336       refresh_rate =
337           static_cast<float>(info.dotClock) /
338           (static_cast<float>(info.hTotal) * static_cast<float>(info.vTotal));
339     }
340
341     modes_.insert(
342         std::make_pair(info.id,
343                        new DisplayModeX11(gfx::Size(info.width, info.height),
344                                           info.modeFlags & RR_Interlace,
345                                           refresh_rate,
346                                           info.id)));
347   }
348 }
349
350 DisplaySnapshotX11* NativeDisplayDelegateX11::InitDisplaySnapshot(
351     RROutput id,
352     XRROutputInfo* info,
353     RRCrtc* last_used_crtc,
354     int index) {
355   int64_t display_id = 0;
356   bool has_display_id = GetDisplayId(
357       id, static_cast<uint8_t>(index), &display_id);
358
359   bool has_overscan = false;
360   GetOutputOverscanFlag(id, &has_overscan);
361
362   DisplayConnectionType type = GetDisplayConnectionTypeFromName(info->name);
363   if (type == DISPLAY_CONNECTION_TYPE_UNKNOWN)
364     LOG(ERROR) << "Unknown link type: " << info->name;
365
366   // Use the index as a valid display ID even if the internal
367   // display doesn't have valid EDID because the index
368   // will never change.
369   if (!has_display_id) {
370     if (type == DISPLAY_CONNECTION_TYPE_INTERNAL)
371       has_display_id = true;
372
373     // Fallback to output index.
374     display_id = index;
375   }
376
377   RRMode native_mode_id = GetOutputNativeMode(info);
378   RRMode current_mode_id = None;
379   gfx::Point origin;
380   if (info->crtc) {
381     XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(display_, screen_, info->crtc);
382     current_mode_id = crtc_info->mode;
383     origin.SetPoint(crtc_info->x, crtc_info->y);
384     XRRFreeCrtcInfo(crtc_info);
385   }
386
387   RRCrtc crtc = None;
388   // Assign a CRTC that isn't already in use.
389   for (int i = 0; i < info->ncrtc; ++i) {
390     if (info->crtcs[i] != *last_used_crtc) {
391       crtc = info->crtcs[i];
392       *last_used_crtc = crtc;
393       break;
394     }
395   }
396
397   const DisplayMode* current_mode = NULL;
398   const DisplayMode* native_mode = NULL;
399   std::vector<const DisplayMode*> display_modes;
400
401   for (int i = 0; i < info->nmode; ++i) {
402     const RRMode mode = info->modes[i];
403     if (modes_.find(mode) != modes_.end()) {
404       display_modes.push_back(modes_.at(mode));
405
406       if (mode == current_mode_id)
407         current_mode = display_modes.back();
408       if (mode == native_mode_id)
409         native_mode = display_modes.back();
410     } else {
411       LOG(WARNING) << "Unable to find XRRModeInfo for mode " << mode;
412     }
413   }
414
415   DisplaySnapshotX11* output =
416       new DisplaySnapshotX11(display_id,
417                              has_display_id,
418                              origin,
419                              gfx::Size(info->mm_width, info->mm_height),
420                              type,
421                              IsOutputAspectPreservingScaling(id),
422                              has_overscan,
423                              GetDisplayName(id),
424                              display_modes,
425                              current_mode,
426                              native_mode,
427                              id,
428                              crtc,
429                              index);
430
431   VLOG(2) << "Found display " << cached_outputs_.size() << ":"
432           << " output=" << output << " crtc=" << crtc
433           << " current_mode=" << current_mode_id;
434
435   return output;
436 }
437
438 bool NativeDisplayDelegateX11::GetHDCPState(const DisplaySnapshot& output,
439                                             HDCPState* state) {
440   unsigned char* values = NULL;
441   int actual_format = 0;
442   unsigned long nitems = 0;
443   unsigned long bytes_after = 0;
444   Atom actual_type = None;
445   int success = 0;
446   RROutput output_id = static_cast<const DisplaySnapshotX11&>(output).output();
447   // TODO(kcwu): Use X11AtomCache to save round trip time of XInternAtom.
448   Atom prop = XInternAtom(display_, kContentProtectionAtomName, False);
449
450   bool ok = true;
451   // TODO(kcwu): Move this to x11_util (similar method calls in this file and
452   // output_util.cc)
453   success = XRRGetOutputProperty(display_,
454                                  output_id,
455                                  prop,
456                                  0,
457                                  100,
458                                  False,
459                                  False,
460                                  AnyPropertyType,
461                                  &actual_type,
462                                  &actual_format,
463                                  &nitems,
464                                  &bytes_after,
465                                  &values);
466   if (actual_type == None) {
467     LOG(ERROR) << "Property '" << kContentProtectionAtomName
468                << "' does not exist";
469     ok = false;
470   } else if (success == Success && actual_type == XA_ATOM &&
471              actual_format == 32 && nitems == 1) {
472     Atom value = reinterpret_cast<Atom*>(values)[0];
473     if (value == XInternAtom(display_, kProtectionUndesiredAtomName, False)) {
474       *state = HDCP_STATE_UNDESIRED;
475     } else if (value ==
476                XInternAtom(display_, kProtectionDesiredAtomName, False)) {
477       *state = HDCP_STATE_DESIRED;
478     } else if (value ==
479                XInternAtom(display_, kProtectionEnabledAtomName, False)) {
480       *state = HDCP_STATE_ENABLED;
481     } else {
482       LOG(ERROR) << "Unknown " << kContentProtectionAtomName
483                  << " value: " << value;
484       ok = false;
485     }
486   } else {
487     LOG(ERROR) << "XRRGetOutputProperty failed";
488     ok = false;
489   }
490   if (values)
491     XFree(values);
492
493   VLOG(3) << "HDCP state: " << ok << "," << *state;
494   return ok;
495 }
496
497 bool NativeDisplayDelegateX11::SetHDCPState(const DisplaySnapshot& output,
498                                             HDCPState state) {
499   Atom name = XInternAtom(display_, kContentProtectionAtomName, False);
500   Atom value = None;
501   switch (state) {
502     case HDCP_STATE_UNDESIRED:
503       value = XInternAtom(display_, kProtectionUndesiredAtomName, False);
504       break;
505     case HDCP_STATE_DESIRED:
506       value = XInternAtom(display_, kProtectionDesiredAtomName, False);
507       break;
508     default:
509       NOTREACHED() << "Invalid HDCP state: " << state;
510       return false;
511   }
512   gfx::X11ErrorTracker err_tracker;
513   unsigned char* data = reinterpret_cast<unsigned char*>(&value);
514   RROutput output_id = static_cast<const DisplaySnapshotX11&>(output).output();
515   XRRChangeOutputProperty(
516       display_, output_id, name, XA_ATOM, 32, PropModeReplace, data, 1);
517   if (err_tracker.FoundNewError()) {
518     LOG(ERROR) << "XRRChangeOutputProperty failed";
519     return false;
520   } else {
521     return true;
522   }
523 }
524
525 void NativeDisplayDelegateX11::DestroyUnusedCrtcs(const gfx::Size& new_size) {
526   CHECK(screen_) << "Server not grabbed";
527   // Setting the screen size will fail if any CRTC doesn't fit afterwards.
528   // At the same time, turning CRTCs off and back on uses up a lot of time.
529   // This function tries to be smart to avoid too many off/on cycles:
530   // - We disable all the CRTCs we won't need after the FB resize.
531   // - We set the new modes on CRTCs, if they fit in both the old and new
532   //   FBs, and park them at (0,0)
533   // - We disable the CRTCs we will need but don't fit in the old FB. Those
534   //   will be reenabled after the resize.
535   // We don't worry about the cached state of the outputs here since we are
536   // not interested in the state we are setting - we just try to get the CRTCs
537   // out of the way so we can rebuild the frame buffer.
538   for (int i = 0; i < screen_->ncrtc; ++i) {
539     // Default config is to disable the crtcs.
540     RRCrtc crtc = screen_->crtcs[i];
541     RRMode mode = None;
542     RROutput output = None;
543     const DisplayMode* mode_info = NULL;
544     for (ScopedVector<DisplaySnapshot>::const_iterator it =
545              cached_outputs_.begin();
546          it != cached_outputs_.end();
547          ++it) {
548       DisplaySnapshotX11* x11_output = static_cast<DisplaySnapshotX11*>(*it);
549       if (crtc == x11_output->crtc()) {
550         mode_info = x11_output->current_mode();
551         output = x11_output->output();
552         break;
553       }
554     }
555
556     if (mode_info) {
557       mode = static_cast<const DisplayModeX11*>(mode_info)->mode_id();
558       // In case our CRTC doesn't fit in common area of our current and about
559       // to be resized framebuffer, disable it.
560       // It'll get reenabled after we resize the framebuffer.
561       int max_width = std::min(DisplayWidth(display_,
562                                DefaultScreen(display_)), new_size.width());
563       int max_height = std::min(DisplayHeight(display_,
564                                 DefaultScreen(display_)), new_size.height());
565       if (mode_info->size().width() > max_width ||
566           mode_info->size().height() > max_height) {
567         mode = None;
568         output = None;
569         mode_info = NULL;
570       }
571     }
572
573     ConfigureCrtc(crtc, mode, output, 0, 0);
574   }
575 }
576
577 bool NativeDisplayDelegateX11::IsOutputAspectPreservingScaling(RROutput id) {
578   bool ret = false;
579
580   Atom scaling_prop = XInternAtom(display_, "scaling mode", False);
581   Atom full_aspect_atom = XInternAtom(display_, "Full aspect", False);
582   if (scaling_prop == None || full_aspect_atom == None)
583     return false;
584
585   int nprop = 0;
586   Atom* props = XRRListOutputProperties(display_, id, &nprop);
587   for (int j = 0; j < nprop && !ret; j++) {
588     Atom prop = props[j];
589     if (scaling_prop == prop) {
590       unsigned char* values = NULL;
591       int actual_format;
592       unsigned long nitems;
593       unsigned long bytes_after;
594       Atom actual_type;
595       int success;
596
597       success = XRRGetOutputProperty(display_,
598                                      id,
599                                      prop,
600                                      0,
601                                      100,
602                                      False,
603                                      False,
604                                      AnyPropertyType,
605                                      &actual_type,
606                                      &actual_format,
607                                      &nitems,
608                                      &bytes_after,
609                                      &values);
610       if (success == Success && actual_type == XA_ATOM && actual_format == 32 &&
611           nitems == 1) {
612         Atom value = reinterpret_cast<Atom*>(values)[0];
613         if (full_aspect_atom == value)
614           ret = true;
615       }
616       if (values)
617         XFree(values);
618     }
619   }
620   if (props)
621     XFree(props);
622
623   return ret;
624 }
625
626
627 std::vector<ColorCalibrationProfile>
628 NativeDisplayDelegateX11::GetAvailableColorCalibrationProfiles(
629     const DisplaySnapshot& output) {
630   // TODO(mukai|marcheu): Checks the system data and fills the result.
631   // Note that the order would be Dynamic -> Standard -> Movie -> Reading.
632   return std::vector<ColorCalibrationProfile>();
633 }
634
635 bool NativeDisplayDelegateX11::SetColorCalibrationProfile(
636     const DisplaySnapshot& output,
637     ColorCalibrationProfile new_profile) {
638   const DisplaySnapshotX11& x11_output =
639       static_cast<const DisplaySnapshotX11&>(output);
640
641   XRRCrtcGamma* gamma_ramp = CreateGammaRampForProfile(x11_output, new_profile);
642
643   if (!gamma_ramp)
644     return false;
645
646   int gamma_ramp_size = XRRGetCrtcGammaSize(display_, x11_output.crtc());
647   XRRSetCrtcGamma(display_,
648                   x11_output.crtc(),
649                   ResampleGammaRamp(gamma_ramp, gamma_ramp_size));
650   XRRFreeGamma(gamma_ramp);
651   return true;
652 }
653
654 XRRCrtcGamma* NativeDisplayDelegateX11::CreateGammaRampForProfile(
655     const DisplaySnapshotX11& x11_output,
656     ColorCalibrationProfile new_profile) {
657   // TODO(mukai|marcheu): Creates the appropriate gamma ramp data from the
658   // profile enum. It would be served by the vendor.
659   return NULL;
660 }
661
662 void NativeDisplayDelegateX11::DrawBackground() {
663   if (!background_color_argb_)
664     return;
665   // Configuring CRTCs/Framebuffer clears the boot screen image.  Paint the
666   // same background color after updating framebuffer to minimize the
667   // duration of black screen at boot time.
668   XColor color;
669   Colormap colormap = DefaultColormap(display_, 0);
670   // XColor uses 16 bits per color.
671   color.red = (background_color_argb_ & 0x00FF0000) >> 8;
672   color.green = (background_color_argb_ & 0x0000FF00);
673   color.blue = (background_color_argb_ & 0x000000FF) << 8;
674   color.flags = DoRed | DoGreen | DoBlue;
675   XAllocColor(display_, colormap, &color);
676
677   GC gc = XCreateGC(display_, window_, 0, 0);
678   XSetForeground(display_, gc, color.pixel);
679   XSetFillStyle(display_, gc, FillSolid);
680   int width = DisplayWidth(display_, DefaultScreen(display_));
681   int height = DisplayHeight(display_, DefaultScreen(display_));
682   XFillRectangle(display_, window_, gc, 0, 0, width, height);
683   XFreeGC(display_, gc);
684   XFreeColors(display_, colormap, &color.pixel, 1, 0);
685 }
686
687 }  // namespace ui