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