123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "remoting/host/desktop_resizer.h"
- #include <Carbon/Carbon.h>
- #include <stdint.h>
- #include "base/mac/foundation_util.h"
- #include "base/mac/mac_util.h"
- #include "base/mac/scoped_cftyperef.h"
- #include "base/memory/ptr_util.h"
- #include "remoting/base/logging.h"
- namespace {
- // TODO(jamiewalch): Use the correct DPI for the mode: http://crbug.com/172405.
- const int kDefaultDPI = 96;
- } // namespace
- namespace remoting {
- class DesktopResizerMac : public DesktopResizer {
- public:
- DesktopResizerMac() = default;
- DesktopResizerMac(const DesktopResizerMac&) = delete;
- DesktopResizerMac& operator=(const DesktopResizerMac&) = delete;
- // DesktopResizer interface
- ScreenResolution GetCurrentResolution(webrtc::ScreenId screen_id) override;
- std::list<ScreenResolution> GetSupportedResolutions(
- const ScreenResolution& preferred,
- webrtc::ScreenId screen_id) override;
- void SetResolution(const ScreenResolution& resolution,
- webrtc::ScreenId screen_id) override;
- void RestoreResolution(const ScreenResolution& original,
- webrtc::ScreenId screen_id) override;
- private:
- // If there is a single display, get its id and return true, otherwise return
- // false. We don't currently support resize-to-client on multi-monitor Macs.
- bool GetSoleDisplayId(CGDirectDisplayID* display);
- void GetSupportedModesAndResolutions(
- base::ScopedCFTypeRef<CFMutableArrayRef>* modes,
- std::list<ScreenResolution>* resolutions);
- };
- ScreenResolution DesktopResizerMac::GetCurrentResolution(
- webrtc::ScreenId screen_id) {
- CGDirectDisplayID display;
- if (GetSoleDisplayId(&display)) {
- CGRect rect = CGDisplayBounds(display);
- return ScreenResolution(
- webrtc::DesktopSize(rect.size.width, rect.size.height),
- webrtc::DesktopVector(kDefaultDPI, kDefaultDPI));
- }
- return ScreenResolution();
- }
- std::list<ScreenResolution> DesktopResizerMac::GetSupportedResolutions(
- const ScreenResolution& preferred,
- webrtc::ScreenId screen_id) {
- base::ScopedCFTypeRef<CFMutableArrayRef> modes;
- std::list<ScreenResolution> resolutions;
- GetSupportedModesAndResolutions(&modes, &resolutions);
- return resolutions;
- }
- void DesktopResizerMac::SetResolution(const ScreenResolution& resolution,
- webrtc::ScreenId screen_id) {
- CGDirectDisplayID display;
- if (!GetSoleDisplayId(&display)) {
- return;
- }
- base::ScopedCFTypeRef<CFMutableArrayRef> modes;
- std::list<ScreenResolution> resolutions;
- GetSupportedModesAndResolutions(&modes, &resolutions);
- // There may be many modes with the requested resolution. Pick the one with
- // the highest color depth.
- int index = 0, best_depth = 0;
- CGDisplayModeRef best_mode = nullptr;
- for (std::list<ScreenResolution>::const_iterator i = resolutions.begin();
- i != resolutions.end(); ++i, ++index) {
- if (i->Equals(resolution)) {
- CGDisplayModeRef mode = const_cast<CGDisplayModeRef>(
- static_cast<const CGDisplayMode*>(
- CFArrayGetValueAtIndex(modes, index)));
- int depth = 0;
- base::ScopedCFTypeRef<CFStringRef> encoding(
- CGDisplayModeCopyPixelEncoding(mode));
- if (CFStringCompare(encoding, CFSTR(IO32BitDirectPixels),
- kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
- depth = 32;
- } else if (CFStringCompare(
- encoding, CFSTR(IO16BitDirectPixels),
- kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
- depth = 16;
- } else if(CFStringCompare(
- encoding, CFSTR(IO8BitIndexedPixels),
- kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
- depth = 8;
- }
- if (depth > best_depth) {
- best_depth = depth;
- best_mode = mode;
- }
- }
- }
- if (best_mode) {
- HOST_LOG << "Changing mode to " << best_mode << " ("
- << resolution.dimensions().width() << "x"
- << "x" << resolution.dimensions().height() << "x"
- << best_depth << " @ "
- << resolution.dpi().x() << "x" << resolution.dpi().y() << " dpi)";
- CGDisplaySetDisplayMode(display, best_mode, nullptr);
- }
- }
- void DesktopResizerMac::RestoreResolution(const ScreenResolution& original,
- webrtc::ScreenId screen_id) {
- SetResolution(original, screen_id);
- }
- void DesktopResizerMac::GetSupportedModesAndResolutions(
- base::ScopedCFTypeRef<CFMutableArrayRef>* modes,
- std::list<ScreenResolution>* resolutions) {
- CGDirectDisplayID display;
- if (!GetSoleDisplayId(&display)) {
- return;
- }
- base::ScopedCFTypeRef<CFArrayRef> all_modes(
- CGDisplayCopyAllDisplayModes(display, nullptr));
- if (!all_modes) {
- return;
- }
- modes->reset(CFArrayCreateMutableCopy(nullptr, 0, all_modes));
- CFIndex count = CFArrayGetCount(*modes);
- for (CFIndex i = 0; i < count; ++i) {
- CGDisplayModeRef mode = const_cast<CGDisplayModeRef>(
- static_cast<const CGDisplayMode*>(
- CFArrayGetValueAtIndex(*modes, i)));
- if (CGDisplayModeIsUsableForDesktopGUI(mode)) {
- // TODO(jamiewalch): Get the correct DPI: http://crbug.com/172405.
- ScreenResolution resolution(
- webrtc::DesktopSize(CGDisplayModeGetWidth(mode),
- CGDisplayModeGetHeight(mode)),
- webrtc::DesktopVector(kDefaultDPI, kDefaultDPI));
- resolutions->push_back(resolution);
- } else {
- CFArrayRemoveValueAtIndex(*modes, i);
- --count;
- --i;
- }
- }
- }
- bool DesktopResizerMac::GetSoleDisplayId(CGDirectDisplayID* display) {
- // This code only supports a single display, but allocates space for two
- // to allow the multi-monitor case to be detected.
- CGDirectDisplayID displays[2];
- uint32_t num_displays;
- CGError err =
- CGGetActiveDisplayList(std::size(displays), displays, &num_displays);
- if (err != kCGErrorSuccess || num_displays != 1) {
- return false;
- }
- *display = displays[0];
- return true;
- }
- std::unique_ptr<DesktopResizer> DesktopResizer::Create() {
- return base::WrapUnique(new DesktopResizerMac);
- }
- } // namespace remoting
|