| OLD | NEW |
| (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 | |
| OLD | NEW |