Roll WebRTC 5699->5721.
[chromium-blink-merge.git] / remoting / host / desktop_resizer_mac.cc
blobef4659f2378e31dabadddb417cab3cb6e10b063a
1 // Copyright (c) 2012 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 "remoting/host/desktop_resizer.h"
7 #include <Carbon/Carbon.h>
9 #include "base/basictypes.h"
10 #include "base/mac/foundation_util.h"
11 #include "base/mac/mac_util.h"
12 #include "base/mac/scoped_cftyperef.h"
13 #include "remoting/base/logging.h"
15 namespace {
16 // TODO(jamiewalch): Use the correct DPI for the mode: http://crbug.com/172405.
17 const int kDefaultDPI = 96;
18 } // namespace
20 namespace remoting {
22 class DesktopResizerMac : public DesktopResizer {
23 public:
24 DesktopResizerMac();
26 // DesktopResizer interface
27 virtual ScreenResolution GetCurrentResolution() OVERRIDE;
28 virtual std::list<ScreenResolution> GetSupportedResolutions(
29 const ScreenResolution& preferred) OVERRIDE;
30 virtual void SetResolution(const ScreenResolution& resolution) OVERRIDE;
31 virtual void RestoreResolution(const ScreenResolution& original) OVERRIDE;
33 private:
34 // If there is a single display, get its id and return true, otherwise return
35 // false. We don't currently support resize-to-client on multi-monitor Macs.
36 bool GetSoleDisplayId(CGDirectDisplayID* display);
38 void GetSupportedModesAndResolutions(
39 base::ScopedCFTypeRef<CFMutableArrayRef>* modes,
40 std::list<ScreenResolution>* resolutions);
42 DISALLOW_COPY_AND_ASSIGN(DesktopResizerMac);
45 DesktopResizerMac::DesktopResizerMac() {}
47 ScreenResolution DesktopResizerMac::GetCurrentResolution() {
48 CGDirectDisplayID display;
49 if (!base::mac::IsOSSnowLeopard() && GetSoleDisplayId(&display)) {
50 CGRect rect = CGDisplayBounds(display);
51 return ScreenResolution(
52 webrtc::DesktopSize(rect.size.width, rect.size.height),
53 webrtc::DesktopVector(kDefaultDPI, kDefaultDPI));
55 return ScreenResolution();
58 std::list<ScreenResolution> DesktopResizerMac::GetSupportedResolutions(
59 const ScreenResolution& preferred) {
60 base::ScopedCFTypeRef<CFMutableArrayRef> modes;
61 std::list<ScreenResolution> resolutions;
62 GetSupportedModesAndResolutions(&modes, &resolutions);
63 return resolutions;
66 void DesktopResizerMac::SetResolution(const ScreenResolution& resolution) {
67 CGDirectDisplayID display;
68 if (base::mac::IsOSSnowLeopard() || !GetSoleDisplayId(&display)) {
69 return;
72 base::ScopedCFTypeRef<CFMutableArrayRef> modes;
73 std::list<ScreenResolution> resolutions;
74 GetSupportedModesAndResolutions(&modes, &resolutions);
75 // There may be many modes with the requested resolution. Pick the one with
76 // the highest color depth.
77 int index = 0, best_depth = 0;
78 CGDisplayModeRef best_mode = NULL;
79 for (std::list<ScreenResolution>::const_iterator i = resolutions.begin();
80 i != resolutions.end(); ++i, ++index) {
81 if (i->Equals(resolution)) {
82 CGDisplayModeRef mode = const_cast<CGDisplayModeRef>(
83 static_cast<const CGDisplayMode*>(
84 CFArrayGetValueAtIndex(modes, index)));
85 int depth = 0;
86 base::ScopedCFTypeRef<CFStringRef> encoding(
87 CGDisplayModeCopyPixelEncoding(mode));
88 if (CFStringCompare(encoding, CFSTR(IO32BitDirectPixels),
89 kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
90 depth = 32;
91 } else if (CFStringCompare(
92 encoding, CFSTR(IO16BitDirectPixels),
93 kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
94 depth = 16;
95 } else if(CFStringCompare(
96 encoding, CFSTR(IO8BitIndexedPixels),
97 kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
98 depth = 8;
100 if (depth > best_depth) {
101 best_depth = depth;
102 best_mode = mode;
106 if (best_mode) {
107 HOST_LOG << "Changing mode to " << best_mode << " ("
108 << resolution.dimensions().width() << "x"
109 << "x" << resolution.dimensions().height() << "x"
110 << best_depth << " @ "
111 << resolution.dpi().x() << "x" << resolution.dpi().y() << " dpi)";
112 CGDisplaySetDisplayMode(display, best_mode, NULL);
116 void DesktopResizerMac::RestoreResolution(const ScreenResolution& original) {
117 SetResolution(original);
120 void DesktopResizerMac::GetSupportedModesAndResolutions(
121 base::ScopedCFTypeRef<CFMutableArrayRef>* modes,
122 std::list<ScreenResolution>* resolutions) {
123 CGDirectDisplayID display;
124 if (!GetSoleDisplayId(&display)) {
125 return;
128 base::ScopedCFTypeRef<CFArrayRef> all_modes(
129 CGDisplayCopyAllDisplayModes(display, NULL));
130 if (!all_modes) {
131 return;
134 modes->reset(CFArrayCreateMutableCopy(NULL, 0, all_modes));
135 CFIndex count = CFArrayGetCount(*modes);
136 for (CFIndex i = 0; i < count; ++i) {
137 CGDisplayModeRef mode = const_cast<CGDisplayModeRef>(
138 static_cast<const CGDisplayMode*>(
139 CFArrayGetValueAtIndex(*modes, i)));
140 if (CGDisplayModeIsUsableForDesktopGUI(mode)) {
141 // TODO(jamiewalch): Get the correct DPI: http://crbug.com/172405.
142 ScreenResolution resolution(
143 webrtc::DesktopSize(CGDisplayModeGetWidth(mode),
144 CGDisplayModeGetHeight(mode)),
145 webrtc::DesktopVector(kDefaultDPI, kDefaultDPI));
146 resolutions->push_back(resolution);
147 } else {
148 CFArrayRemoveValueAtIndex(*modes, i);
149 --count;
150 --i;
155 bool DesktopResizerMac::GetSoleDisplayId(CGDirectDisplayID* display) {
156 // This code only supports a single display, but allocates space for two
157 // to allow the multi-monitor case to be detected.
158 CGDirectDisplayID displays[2];
159 uint32_t num_displays;
160 CGError err = CGGetActiveDisplayList(arraysize(displays),
161 displays, &num_displays);
162 if (err != kCGErrorSuccess || num_displays != 1) {
163 return false;
165 *display = displays[0];
166 return true;
169 scoped_ptr<DesktopResizer> DesktopResizer::Create() {
170 return scoped_ptr<DesktopResizer>(new DesktopResizerMac);
173 } // namespace remoting