1/*
2 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/modules/desktop_capture/mac/desktop_configuration_monitor.h"
12
13#include "webrtc/modules/desktop_capture/mac/desktop_configuration.h"
14#include "webrtc/system_wrappers/include/event_wrapper.h"
15#include "webrtc/system_wrappers/include/logging.h"
16
17namespace webrtc {
18
19// The amount of time allowed for displays to reconfigure.
20static const int64_t kDisplayConfigurationEventTimeoutMs = 10 * 1000;
21
22DesktopConfigurationMonitor::DesktopConfigurationMonitor()
23    : ref_count_(0),
24      display_configuration_capture_event_(EventWrapper::Create()) {
25  CGError err = CGDisplayRegisterReconfigurationCallback(
26      DesktopConfigurationMonitor::DisplaysReconfiguredCallback, this);
27  if (err != kCGErrorSuccess) {
28    LOG(LS_ERROR) << "CGDisplayRegisterReconfigurationCallback " << err;
29    abort();
30  }
31  display_configuration_capture_event_->Set();
32
33  desktop_configuration_ = MacDesktopConfiguration::GetCurrent(
34      MacDesktopConfiguration::TopLeftOrigin);
35}
36
37DesktopConfigurationMonitor::~DesktopConfigurationMonitor() {
38  CGError err = CGDisplayRemoveReconfigurationCallback(
39      DesktopConfigurationMonitor::DisplaysReconfiguredCallback, this);
40  if (err != kCGErrorSuccess)
41    LOG(LS_ERROR) << "CGDisplayRemoveReconfigurationCallback " << err;
42}
43
44void DesktopConfigurationMonitor::Lock() {
45  if (!display_configuration_capture_event_->Wait(
46              kDisplayConfigurationEventTimeoutMs)) {
47    LOG_F(LS_ERROR) << "Event wait timed out.";
48    abort();
49  }
50}
51
52void DesktopConfigurationMonitor::Unlock() {
53  display_configuration_capture_event_->Set();
54}
55
56// static
57void DesktopConfigurationMonitor::DisplaysReconfiguredCallback(
58    CGDirectDisplayID display,
59    CGDisplayChangeSummaryFlags flags,
60    void *user_parameter) {
61  DesktopConfigurationMonitor* monitor =
62      reinterpret_cast<DesktopConfigurationMonitor*>(user_parameter);
63  monitor->DisplaysReconfigured(display, flags);
64}
65
66void DesktopConfigurationMonitor::DisplaysReconfigured(
67    CGDirectDisplayID display,
68    CGDisplayChangeSummaryFlags flags) {
69  if (flags & kCGDisplayBeginConfigurationFlag) {
70    if (reconfiguring_displays_.empty()) {
71      // If this is the first display to start reconfiguring then wait on
72      // |display_configuration_capture_event_| to block the capture thread
73      // from accessing display memory until the reconfiguration completes.
74      if (!display_configuration_capture_event_->Wait(
75              kDisplayConfigurationEventTimeoutMs)) {
76        LOG_F(LS_ERROR) << "Event wait timed out.";
77        abort();
78      }
79    }
80    reconfiguring_displays_.insert(display);
81  } else {
82    reconfiguring_displays_.erase(display);
83    if (reconfiguring_displays_.empty()) {
84      desktop_configuration_ = MacDesktopConfiguration::GetCurrent(
85          MacDesktopConfiguration::TopLeftOrigin);
86      display_configuration_capture_event_->Set();
87    }
88  }
89}
90
91}  // namespace webrtc
92