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