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.
5 #include "ui/display/chromeos/x11/native_display_delegate_x11.h"
9 #include <X11/extensions/dpms.h>
10 #include <X11/extensions/Xrandr.h>
11 #include <X11/extensions/XInput2.h>
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"
33 const float kMmInInch
= 25.4;
34 const float kDpi96
= 96.0;
35 const float kPixelsToMmScale
= kMmInInch
/ kDpi96
;
37 const char kContentProtectionAtomName
[] = "Content Protection";
38 const char kProtectionUndesiredAtomName
[] = "Undesired";
39 const char kProtectionDesiredAtomName
[] = "Desired";
40 const char kProtectionEnabledAtomName
[] = "Enabled";
42 RRMode
GetOutputNativeMode(const XRROutputInfo
* output_info
) {
43 return output_info
->nmode
> 0 ? output_info
->modes
[0] : None
;
46 XRRCrtcGamma
* ResampleGammaRamp(XRRCrtcGamma
* gamma_ramp
, int gamma_ramp_size
) {
47 if (gamma_ramp
->size
== gamma_ramp_size
)
50 #define RESAMPLE(array, i, r) \
51 array[i] + (array[i + 1] - array[i]) * r / gamma_ramp_size
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
);
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];
69 XRRFreeGamma(gamma_ramp
);
75 ////////////////////////////////////////////////////////////////////////////////
76 // NativeDisplayDelegateX11::HelperDelegateX11
78 class NativeDisplayDelegateX11::HelperDelegateX11
79 : public NativeDisplayDelegateX11::HelperDelegate
{
81 HelperDelegateX11(NativeDisplayDelegateX11
* delegate
) : delegate_(delegate
) {}
82 virtual ~HelperDelegateX11() {}
84 // NativeDisplayDelegateX11::HelperDelegate overrides:
85 virtual void UpdateXRandRConfiguration(const base::NativeEvent
& event
)
87 XRRUpdateConfiguration(event
);
89 virtual const std::vector
<DisplaySnapshot
*>& GetCachedDisplays() const
91 return delegate_
->cached_outputs_
.get();
93 virtual void NotifyDisplayObservers() OVERRIDE
{
95 NativeDisplayObserver
, delegate_
->observers_
, OnConfigurationChanged());
99 NativeDisplayDelegateX11
* delegate_
;
101 DISALLOW_COPY_AND_ASSIGN(HelperDelegateX11
);
104 ////////////////////////////////////////////////////////////////////////////////
105 // NativeDisplayDelegateX11::PlatformEventObserverX11
107 class NativeDisplayDelegateX11::PlatformEventObserverX11
108 : public PlatformEventObserver
{
110 PlatformEventObserverX11(HelperDelegate
* delegate
);
111 virtual ~PlatformEventObserverX11();
113 // PlatformEventObserverX11:
114 virtual void WillProcessEvent(const ui::PlatformEvent
& event
) OVERRIDE
;
115 virtual void DidProcessEvent(const ui::PlatformEvent
& event
) OVERRIDE
;
118 HelperDelegate
* delegate_
; // Not owned.
120 DISALLOW_COPY_AND_ASSIGN(PlatformEventObserverX11
);
123 NativeDisplayDelegateX11::PlatformEventObserverX11::PlatformEventObserverX11(
124 HelperDelegate
* delegate
)
125 : delegate_(delegate
) {}
127 NativeDisplayDelegateX11::PlatformEventObserverX11::
128 ~PlatformEventObserverX11() {}
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();
143 void NativeDisplayDelegateX11::PlatformEventObserverX11::DidProcessEvent(
144 const ui::PlatformEvent
& event
) {}
146 ////////////////////////////////////////////////////////////////////////////////
147 // NativeDisplayDelegateX11 implementation:
149 NativeDisplayDelegateX11::NativeDisplayDelegateX11()
150 : display_(gfx::GetXDisplay()),
151 window_(DefaultRootWindow(display_
)),
153 background_color_argb_(0) {}
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());
163 STLDeleteContainerPairSecondPointers(modes_
.begin(), modes_
.end());
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
);
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()));
177 if (ui::PlatformEventSource::GetInstance()) {
178 ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(
179 platform_event_dispatcher_
.get());
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());
188 void NativeDisplayDelegateX11::GrabServer() {
189 CHECK(!screen_
) << "Server already grabbed";
190 XGrabServer(display_
);
191 screen_
= XRRGetScreenResources(display_
, window_
);
195 void NativeDisplayDelegateX11::UngrabServer() {
196 CHECK(screen_
) << "Server not grabbed";
197 XRRFreeScreenResources(screen_
);
199 XUngrabServer(display_
);
204 void NativeDisplayDelegateX11::SyncWithServer() { XSync(display_
, 0); }
206 void NativeDisplayDelegateX11::SetBackgroundColor(uint32_t color_argb
) {
207 background_color_argb_
= color_argb
;
210 void NativeDisplayDelegateX11::ForceDPMSOn() {
211 CHECK(DPMSEnable(display_
));
212 CHECK(DPMSForceLevel(display_
, DPMSModeOn
));
215 std::vector
<DisplaySnapshot
*> NativeDisplayDelegateX11::GetDisplays() {
216 CHECK(screen_
) << "Server not grabbed";
218 cached_outputs_
.clear();
219 RRCrtc last_used_crtc
= None
;
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
);
230 XRRFreeOutputInfo(output_info
);
233 return cached_outputs_
.get();
236 void NativeDisplayDelegateX11::AddMode(const DisplaySnapshot
& output
,
237 const DisplayMode
* mode
) {
238 CHECK(screen_
) << "Server not grabbed";
239 CHECK(mode
) << "Must add valid mode";
241 const DisplaySnapshotX11
& x11_output
=
242 static_cast<const DisplaySnapshotX11
&>(output
);
243 RRMode mode_id
= static_cast<const DisplayModeX11
*>(mode
)->mode_id();
245 VLOG(1) << "AddDisplayMode: output=" << x11_output
.output()
246 << " mode=" << mode_id
;
247 XRRAddOutputMode(display_
, x11_output
.output(), mode_id
);
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
;
257 mode_id
= static_cast<const DisplayModeX11
*>(mode
)->mode_id();
259 return ConfigureCrtc(
260 x11_output
.crtc(), mode_id
, x11_output
.output(), origin
.x(), origin
.y());
263 bool NativeDisplayDelegateX11::ConfigureCrtc(RRCrtc crtc
,
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_
,
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
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
;
300 DestroyUnusedCrtcs(size
);
302 if (size
.width() == current_width
&& size
.height() == current_height
)
305 int mm_width
= size
.width() * kPixelsToMmScale
;
306 int mm_height
= size
.height() * kPixelsToMmScale
;
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.
313 // Don't redraw the background upon framebuffer change again. This should
314 // happen only once after boot.
315 background_color_argb_
= 0;
318 void NativeDisplayDelegateX11::AddObserver(NativeDisplayObserver
* observer
) {
319 observers_
.AddObserver(observer
);
322 void NativeDisplayDelegateX11::RemoveObserver(NativeDisplayObserver
* observer
) {
323 observers_
.RemoveObserver(observer
);
326 void NativeDisplayDelegateX11::InitModes() {
327 CHECK(screen_
) << "Server not grabbed";
329 STLDeleteContainerPairSecondPointers(modes_
.begin(), modes_
.end());
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
) {
337 static_cast<float>(info
.dotClock
) /
338 (static_cast<float>(info
.hTotal
) * static_cast<float>(info
.vTotal
));
342 std::make_pair(info
.id
,
343 new DisplayModeX11(gfx::Size(info
.width
, info
.height
),
344 info
.modeFlags
& RR_Interlace
,
350 DisplaySnapshotX11
* NativeDisplayDelegateX11::InitDisplaySnapshot(
353 RRCrtc
* last_used_crtc
,
355 int64_t display_id
= 0;
356 bool has_display_id
= GetDisplayId(
357 id
, static_cast<uint8_t>(index
), &display_id
);
359 bool has_overscan
= false;
360 GetOutputOverscanFlag(id
, &has_overscan
);
362 DisplayConnectionType type
= GetDisplayConnectionTypeFromName(info
->name
);
363 if (type
== DISPLAY_CONNECTION_TYPE_UNKNOWN
)
364 LOG(ERROR
) << "Unknown link type: " << info
->name
;
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;
373 // Fallback to output index.
377 RRMode native_mode_id
= GetOutputNativeMode(info
);
378 RRMode current_mode_id
= None
;
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
);
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
;
397 const DisplayMode
* current_mode
= NULL
;
398 const DisplayMode
* native_mode
= NULL
;
399 std::vector
<const DisplayMode
*> display_modes
;
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
));
406 if (mode
== current_mode_id
)
407 current_mode
= display_modes
.back();
408 if (mode
== native_mode_id
)
409 native_mode
= display_modes
.back();
411 LOG(WARNING
) << "Unable to find XRRModeInfo for mode " << mode
;
415 DisplaySnapshotX11
* output
=
416 new DisplaySnapshotX11(display_id
,
419 gfx::Size(info
->mm_width
, info
->mm_height
),
421 IsOutputAspectPreservingScaling(id
),
431 VLOG(2) << "Found display " << cached_outputs_
.size() << ":"
432 << " output=" << output
<< " crtc=" << crtc
433 << " current_mode=" << current_mode_id
;
438 bool NativeDisplayDelegateX11::GetHDCPState(const DisplaySnapshot
& output
,
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
;
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
);
451 // TODO(kcwu): Move this to x11_util (similar method calls in this file and
453 success
= XRRGetOutputProperty(display_
,
466 if (actual_type
== None
) {
467 LOG(ERROR
) << "Property '" << kContentProtectionAtomName
468 << "' does not exist";
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
;
476 XInternAtom(display_
, kProtectionDesiredAtomName
, False
)) {
477 *state
= HDCP_STATE_DESIRED
;
479 XInternAtom(display_
, kProtectionEnabledAtomName
, False
)) {
480 *state
= HDCP_STATE_ENABLED
;
482 LOG(ERROR
) << "Unknown " << kContentProtectionAtomName
483 << " value: " << value
;
487 LOG(ERROR
) << "XRRGetOutputProperty failed";
493 VLOG(3) << "HDCP state: " << ok
<< "," << *state
;
497 bool NativeDisplayDelegateX11::SetHDCPState(const DisplaySnapshot
& output
,
499 Atom name
= XInternAtom(display_
, kContentProtectionAtomName
, False
);
502 case HDCP_STATE_UNDESIRED
:
503 value
= XInternAtom(display_
, kProtectionUndesiredAtomName
, False
);
505 case HDCP_STATE_DESIRED
:
506 value
= XInternAtom(display_
, kProtectionDesiredAtomName
, False
);
509 NOTREACHED() << "Invalid HDCP state: " << state
;
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";
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
];
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();
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();
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
) {
573 ConfigureCrtc(crtc
, mode
, output
, 0, 0);
577 bool NativeDisplayDelegateX11::IsOutputAspectPreservingScaling(RROutput id
) {
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
)
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
;
592 unsigned long nitems
;
593 unsigned long bytes_after
;
597 success
= XRRGetOutputProperty(display_
,
610 if (success
== Success
&& actual_type
== XA_ATOM
&& actual_format
== 32 &&
612 Atom value
= reinterpret_cast<Atom
*>(values
)[0];
613 if (full_aspect_atom
== value
)
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
>();
635 bool NativeDisplayDelegateX11::SetColorCalibrationProfile(
636 const DisplaySnapshot
& output
,
637 ColorCalibrationProfile new_profile
) {
638 const DisplaySnapshotX11
& x11_output
=
639 static_cast<const DisplaySnapshotX11
&>(output
);
641 XRRCrtcGamma
* gamma_ramp
= CreateGammaRampForProfile(x11_output
, new_profile
);
646 int gamma_ramp_size
= XRRGetCrtcGammaSize(display_
, x11_output
.crtc());
647 XRRSetCrtcGamma(display_
,
649 ResampleGammaRamp(gamma_ramp
, gamma_ramp_size
));
650 XRRFreeGamma(gamma_ramp
);
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.
662 void NativeDisplayDelegateX11::DrawBackground() {
663 if (!background_color_argb_
)
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.
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
);
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);