Index: chromeos/monitor/output_configurator.cc |
diff --git a/chromeos/monitor/output_configurator.cc b/chromeos/monitor/output_configurator.cc |
deleted file mode 100644 |
index 8e47f07fe80ac4f8db177c465c6e41c96cc47143..0000000000000000000000000000000000000000 |
--- a/chromeos/monitor/output_configurator.cc |
+++ /dev/null |
@@ -1,804 +0,0 @@ |
-// 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 "chromeos/monitor/output_configurator.h" |
- |
-#include <X11/Xlib.h> |
-#include <X11/extensions/dpms.h> |
-#include <X11/extensions/Xrandr.h> |
- |
-// Xlib defines Status as int which causes our include of dbus/bus.h to fail |
-// when it tries to name an enum Status. Thus, we need to undefine it (note |
-// that this will cause a problem if code needs to use the Status type). |
-// RootWindow causes similar problems in that there is a Chromium type with that |
-// name. |
-#undef Status |
-#undef RootWindow |
- |
-#include "base/chromeos/chromeos_version.h" |
-#include "base/logging.h" |
-#include "base/message_pump_aurax11.h" |
-#include "chromeos/dbus/dbus_thread_manager.h" |
-#include "dbus/bus.h" |
-#include "dbus/exported_object.h" |
-#include "dbus/message.h" |
-#include "dbus/object_path.h" |
-#include "dbus/object_proxy.h" |
-#include "third_party/cros_system_api/dbus/service_constants.h" |
- |
-namespace chromeos { |
- |
-namespace { |
-// DPI measurements. |
-const float kMmInInch = 25.4; |
-const float kDpi96 = 96.0; |
-const float kPixelsToMmScale = kMmInInch / kDpi96; |
- |
-// The DPI threshold to detech high density screen. |
-// Higher DPI than this will use device_scale_factor=2 |
-// Should be kept in sync with monitor_change_observer_x11.cc |
-const unsigned int kHighDensityDIPThreshold = 160; |
- |
-// Prefixes for the built-in displays. |
-const char kInternal_LVDS[] = "LVDS"; |
-const char kInternal_eDP[] = "eDP"; |
- |
-// Gap between screens so cursor at bottom of active monitor doesn't partially |
-// appear on top of inactive monitor. Higher numbers guard against larger |
-// cursors, but also waste more memory. We will double this gap for screens |
-// with a device_scale_factor of 2. While this gap will not guard against all |
-// possible cursors in X, it should handle the ones we actually use. See |
-// crbug.com/130188 |
-const int kVerticalGap = 30; |
- |
-// TODO: Determine if we need to organize modes in a way which provides better |
-// than O(n) lookup time. In many call sites, for example, the "next" mode is |
-// typically what we are looking for so using this helper might be too |
-// expensive. |
-static XRRModeInfo* ModeInfoForID(XRRScreenResources* screen, RRMode modeID) { |
- XRRModeInfo* result = NULL; |
- for (int i = 0; (i < screen->nmode) && (result == NULL); i++) |
- if (modeID == screen->modes[i].id) |
- result = &screen->modes[i]; |
- |
- // We can't fail to find a mode referenced from the same screen. |
- CHECK(result != NULL); |
- return result; |
-} |
- |
-// Identifies the modes which will be used by the respective outputs when in a |
-// mirror mode. This means that the two modes will have the same resolution. |
-// The RROutput IDs |one| and |two| are used to look up the modes and |
-// |out_one_mode| and |out_two_mode| are the out-parameters for the respective |
-// modes. |
-// Returns false if it fails to find a compatible set of modes. |
-static bool FindMirrorModeForOutputs(Display* display, |
- XRRScreenResources* screen, |
- RROutput one, |
- RROutput two, |
- RRMode* out_one_mode, |
- RRMode* out_two_mode) { |
- XRROutputInfo* primary = XRRGetOutputInfo(display, screen, one); |
- XRROutputInfo* secondary = XRRGetOutputInfo(display, screen, two); |
- |
- int one_index = 0; |
- int two_index = 0; |
- bool found = false; |
- while (!found && |
- (one_index < primary->nmode) && |
- (two_index < secondary->nmode)) { |
- RRMode one_id = primary->modes[one_index]; |
- RRMode two_id = secondary->modes[two_index]; |
- XRRModeInfo* one_mode = ModeInfoForID(screen, one_id); |
- XRRModeInfo* two_mode = ModeInfoForID(screen, two_id); |
- int one_width = one_mode->width; |
- int one_height = one_mode->height; |
- int two_width = two_mode->width; |
- int two_height = two_mode->height; |
- if ((one_width == two_width) && (one_height == two_height)) { |
- *out_one_mode = one_id; |
- *out_two_mode = two_id; |
- found = true; |
- } else { |
- // The sort order of the modes is NOT by mode area but is sorted by width, |
- // then by height within each like width. |
- if (one_width > two_width) { |
- one_index += 1; |
- } else if (one_width < two_width) { |
- two_index += 1; |
- } else { |
- if (one_height > two_height) { |
- one_index += 1; |
- } else { |
- two_index += 1; |
- } |
- } |
- } |
- } |
- XRRFreeOutputInfo(primary); |
- XRRFreeOutputInfo(secondary); |
- return found; |
-} |
- |
-// A helper to call XRRSetCrtcConfig with the given options but some of our |
-// default output count and rotation arguments. |
-static void ConfigureCrtc(Display *display, |
- XRRScreenResources* screen, |
- RRCrtc crtc, |
- int x, |
- int y, |
- RRMode mode, |
- RROutput output) { |
- const Rotation kRotate = RR_Rotate_0; |
- RROutput* outputs = NULL; |
- int num_outputs = 0; |
- |
- // Check the output and mode argument - if either are None, we should disable. |
- if ((output != None) && (mode != None)) { |
- outputs = &output; |
- num_outputs = 1; |
- } |
- |
- XRRSetCrtcConfig(display, |
- screen, |
- crtc, |
- CurrentTime, |
- x, |
- y, |
- mode, |
- kRotate, |
- outputs, |
- num_outputs); |
- if (num_outputs == 1) { |
- // We are enabling a display so make sure it is turned on. |
- CHECK(DPMSEnable(display)); |
- CHECK(DPMSForceLevel(display, DPMSModeOn)); |
- } |
-} |
- |
-// Called to set the frame buffer (underling XRR "screen") size. Has a |
-// side-effect of disabling all CRTCs. |
-static void CreateFrameBuffer(Display* display, |
- XRRScreenResources* screen, |
- Window window, |
- int width, |
- int height) { |
- // Note that setting the screen size fails if any CRTCs are currently |
- // pointing into it so disable them all. |
- for (int i = 0; i < screen->ncrtc; ++i) { |
- const int x = 0; |
- const int y = 0; |
- const RRMode kMode = None; |
- const RROutput kOutput = None; |
- |
- ConfigureCrtc(display, |
- screen, |
- screen->crtcs[i], |
- x, |
- y, |
- kMode, |
- kOutput); |
- } |
- int mm_width = width * kPixelsToMmScale; |
- int mm_height = height * kPixelsToMmScale; |
- XRRSetScreenSize(display, window, width, height, mm_width, mm_height); |
-} |
- |
-// A helper to get the current CRTC, Mode, and height for a given output. This |
-// is read from the XRandR configuration and not any of our caches. |
-static void GetOutputConfiguration(Display* display, |
- XRRScreenResources* screen, |
- RROutput output, |
- RRCrtc* crtc, |
- RRMode* mode, |
- int* height) { |
- XRROutputInfo* output_info = XRRGetOutputInfo(display, screen, output); |
- CHECK(output_info != NULL); |
- *crtc = output_info->crtc; |
- XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(display, screen, *crtc); |
- if (crtc_info != NULL) { |
- *mode = crtc_info->mode; |
- *height = crtc_info->height; |
- XRRFreeCrtcInfo(crtc_info); |
- } |
- XRRFreeOutputInfo(output_info); |
-} |
- |
-// A helper to determine the device_scale_factor given pixel width and mm_width. |
-// This currently only reports two scale factors (1.0 and 2.0) |
-static float ComputeDeviceScaleFactor(unsigned int width, |
- unsigned long mm_width) { |
- float device_scale_factor = 1.0f; |
- if (mm_width > 0 && (kMmInInch * width / mm_width) > kHighDensityDIPThreshold) |
- device_scale_factor = 2.0f; |
- return device_scale_factor; |
-} |
- |
-} // namespace |
- |
-bool OutputConfigurator::TryRecacheOutputs(Display* display, |
- XRRScreenResources* screen) { |
- bool outputs_did_change = false; |
- int previous_connected_count = 0; |
- int new_connected_count = 0; |
- |
- if (output_count_ != screen->noutput) { |
- outputs_did_change = true; |
- } else { |
- // The outputs might have changed so compare the connected states in the |
- // screen to our existing cache. |
- for (int i = 0; (i < output_count_) && !outputs_did_change; ++i) { |
- RROutput thisID = screen->outputs[i]; |
- XRROutputInfo* output = XRRGetOutputInfo(display, screen, thisID); |
- bool now_connected = (RR_Connected == output->connection); |
- outputs_did_change = (now_connected != output_cache_[i].is_connected); |
- XRRFreeOutputInfo(output); |
- |
- if (output_cache_[i].is_connected) |
- previous_connected_count += 1; |
- if (now_connected) |
- new_connected_count += 1; |
- } |
- } |
- |
- if (outputs_did_change) { |
- // We now know that we need to recache so free and re-alloc the buffer. |
- output_count_ = screen->noutput; |
- if (output_count_ == 0) { |
- output_cache_.reset(NULL); |
- } else { |
- // Ideally, this would be allocated inline in the OutputConfigurator |
- // instance since we support at most 2 connected outputs but this dynamic |
- // allocation was specifically requested. |
- output_cache_.reset(new CachedOutputDescription[output_count_]); |
- } |
- |
- // TODO: This approach to finding CRTCs only supports two. Expand on this. |
- RRCrtc used_crtc = None; |
- primary_output_index_ = -1; |
- secondary_output_index_ = -1; |
- |
- for (int i = 0; i < output_count_; ++i) { |
- RROutput this_id = screen->outputs[i]; |
- XRROutputInfo* output = XRRGetOutputInfo(display, screen, this_id); |
- bool is_connected = (RR_Connected == output->connection); |
- RRCrtc crtc = None; |
- RRMode ideal_mode = None; |
- int x = 0; |
- int y = 0; |
- unsigned long mm_width = output->mm_width; |
- unsigned long mm_height = output->mm_height; |
- bool is_internal = false; |
- |
- if (is_connected) { |
- for (int j = 0; (j < output->ncrtc) && (None == crtc); ++j) { |
- RRCrtc possible = output->crtcs[j]; |
- if (possible != used_crtc) { |
- crtc = possible; |
- used_crtc = possible; |
- } |
- } |
- |
- const char* name = output->name; |
- is_internal = |
- (strncmp(kInternal_LVDS, |
- name, |
- arraysize(kInternal_LVDS) - 1) == 0) || |
- (strncmp(kInternal_eDP, |
- name, |
- arraysize(kInternal_eDP) - 1) == 0); |
- if (output->nmode > 0) |
- ideal_mode = output->modes[0]; |
- |
- if (crtc != None) { |
- XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(display, screen, crtc); |
- x = crtcInfo->x; |
- y = crtcInfo->y; |
- XRRFreeCrtcInfo(crtcInfo); |
- } |
- |
- // Save this for later mirror mode detection. |
- if (primary_output_index_ == -1) |
- primary_output_index_ = i; |
- else if (secondary_output_index_ == -1) |
- secondary_output_index_ = i; |
- } |
- XRRFreeOutputInfo(output); |
- |
- // Now save the cached state for this output (we will default to mirror |
- // disabled and detect that after we have identified the first two |
- // connected outputs). |
- VLOG(1) << "Recache output index: " << i |
- << ", output id: " << this_id |
- << ", crtc id: " << crtc |
- << ", ideal mode id: " << ideal_mode |
- << ", x: " << x |
- << ", y: " << y |
- << ", is connected: " << is_connected |
- << ", is_internal: " << is_internal |
- << ", mm_width: " << mm_width |
- << ", mm_height: " << mm_height; |
- output_cache_[i].output = this_id; |
- output_cache_[i].crtc = crtc; |
- output_cache_[i].mirror_mode = None; |
- output_cache_[i].ideal_mode = ideal_mode; |
- output_cache_[i].x = x; |
- output_cache_[i].y = y; |
- output_cache_[i].is_connected = is_connected; |
- output_cache_[i].is_powered_on = true; |
- output_cache_[i].is_internal = is_internal; |
- output_cache_[i].mm_width = mm_width; |
- output_cache_[i].mm_height = mm_height; |
- } |
- |
- // Now, detect the mirror modes if we have two connected outputs. |
- if ((primary_output_index_ != -1) && (secondary_output_index_ != -1)) { |
- mirror_supported_ = FindMirrorModeForOutputs( |
- display, |
- screen, |
- output_cache_[primary_output_index_].output, |
- output_cache_[secondary_output_index_].output, |
- &output_cache_[primary_output_index_].mirror_mode, |
- &output_cache_[secondary_output_index_].mirror_mode); |
- |
- RRMode primary_mode = output_cache_[primary_output_index_].mirror_mode; |
- RRMode second_mode = output_cache_[secondary_output_index_].mirror_mode; |
- VLOG(1) << "Mirror mode supported " << mirror_supported_ |
- << " primary " << primary_mode |
- << " secondary " << second_mode; |
- } |
- } |
- return outputs_did_change; |
-} |
- |
-OutputConfigurator::OutputConfigurator() |
- : is_running_on_chrome_os_(base::chromeos::IsRunningOnChromeOS()), |
- output_count_(0), |
- output_cache_(NULL), |
- mirror_supported_(false), |
- primary_output_index_(-1), |
- secondary_output_index_(-1), |
- xrandr_event_base_(0), |
- output_state_(STATE_INVALID) { |
- if (is_running_on_chrome_os_) { |
- // Send the signal to powerd to tell it that we will take over output |
- // control. |
- // Note that this can be removed once the legacy powerd support is removed. |
- chromeos::DBusThreadManager* manager = chromeos::DBusThreadManager::Get(); |
- dbus::Bus* bus = manager->GetSystemBus(); |
- dbus::ExportedObject* remote_object = bus->GetExportedObject( |
- dbus::ObjectPath(power_manager::kPowerManagerServicePath)); |
- dbus::Signal signal(power_manager::kPowerManagerInterface, |
- power_manager::kUseNewMonitorConfigSignal); |
- CHECK(signal.raw_message() != NULL); |
- remote_object->SendSignal(&signal); |
- |
- // Cache the initial output state. |
- Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay(); |
- CHECK(display != NULL); |
- XGrabServer(display); |
- Window window = DefaultRootWindow(display); |
- XRRScreenResources* screen = XRRGetScreenResources(display, window); |
- CHECK(screen != NULL); |
- bool did_detect_outputs = TryRecacheOutputs(display, screen); |
- CHECK(did_detect_outputs); |
- State current_state = InferCurrentState(display, screen); |
- if (current_state == STATE_INVALID) { |
- // Unknown state. Transition into the default state. |
- State state = GetDefaultState(); |
- UpdateCacheAndXrandrToState(display, screen, window, state); |
- } else { |
- // This is a valid state so just save it to |output_state_|. |
- output_state_ = current_state; |
- } |
- // Find xrandr_event_base_ since we need it to interpret events, later. |
- int error_base_ignored = 0; |
- XRRQueryExtension(display, &xrandr_event_base_, &error_base_ignored); |
- // Relinquish X resources. |
- XRRFreeScreenResources(screen); |
- XUngrabServer(display); |
- CheckIsProjectingAndNotify(); |
- } |
-} |
- |
-OutputConfigurator::~OutputConfigurator() { |
-} |
- |
-void OutputConfigurator::UpdateCacheAndXrandrToState( |
- Display* display, |
- XRRScreenResources* screen, |
- Window window, |
- State new_state) { |
- // Default rules: |
- // - single display = rebuild framebuffer and set to ideal_mode. |
- // - multi display = rebuild framebuffer and set to mirror_mode. |
- |
- // First, calculate the width and height of the framebuffer (we could retain |
- // the existing buffer, if it isn't resizing, but that causes an odd display |
- // state where the CRTCs are repositioned over the root windows before Chrome |
- // can move them). It is a feature worth considering, though, and wouldn't |
- // be difficult to implement (just check the current framebuffer size before |
- // changing it). |
- int width = 0; |
- int height = 0; |
- int primary_height = 0; |
- int secondary_height = 0; |
- int vertical_gap = 0; |
- if (new_state == STATE_SINGLE) { |
- CHECK_NE(-1, primary_output_index_); |
- |
- XRRModeInfo* ideal_mode = ModeInfoForID( |
- screen, |
- output_cache_[primary_output_index_].ideal_mode); |
- width = ideal_mode->width; |
- height = ideal_mode->height; |
- } else if (new_state == STATE_DUAL_MIRROR) { |
- CHECK_NE(-1, primary_output_index_); |
- CHECK_NE(-1, secondary_output_index_); |
- |
- XRRModeInfo* mirror_mode = ModeInfoForID( |
- screen, |
- output_cache_[primary_output_index_].mirror_mode); |
- width = mirror_mode->width; |
- height = mirror_mode->height; |
- } else if ((new_state == STATE_DUAL_PRIMARY_ONLY) || |
- (new_state == STATE_DUAL_SECONDARY_ONLY)) { |
- CHECK_NE(-1, primary_output_index_); |
- CHECK_NE(-1, secondary_output_index_); |
- |
- XRRModeInfo* one_ideal = ModeInfoForID( |
- screen, |
- output_cache_[primary_output_index_].ideal_mode); |
- XRRModeInfo* two_ideal = ModeInfoForID( |
- screen, |
- output_cache_[secondary_output_index_].ideal_mode); |
- |
- // Compute the device scale factor for the topmost display. We only need |
- // to take this device's scale factor into account as we are creating a gap |
- // to avoid the cursor drawing onto the second (unused) display when the |
- // cursor is near the bottom of the topmost display. |
- float top_scale_factor; |
- if (new_state == STATE_DUAL_PRIMARY_ONLY) { |
- top_scale_factor = ComputeDeviceScaleFactor(one_ideal->width, |
- output_cache_[primary_output_index_].mm_width); |
- } else { |
- top_scale_factor = ComputeDeviceScaleFactor(two_ideal->width, |
- output_cache_[secondary_output_index_].mm_width); |
- } |
- vertical_gap = kVerticalGap * top_scale_factor; |
- |
- width = std::max<int>(one_ideal->width, two_ideal->width); |
- height = one_ideal->height + two_ideal->height + vertical_gap; |
- primary_height = one_ideal->height; |
- secondary_height = two_ideal->height; |
- } |
- CreateFrameBuffer(display, screen, window, width, height); |
- |
- // Now, tile the outputs appropriately. |
- const int x = 0; |
- const int y = 0; |
- switch (new_state) { |
- case STATE_SINGLE: |
- ConfigureCrtc(display, |
- screen, |
- output_cache_[primary_output_index_].crtc, |
- x, |
- y, |
- output_cache_[primary_output_index_].ideal_mode, |
- output_cache_[primary_output_index_].output); |
- break; |
- case STATE_DUAL_MIRROR: |
- case STATE_DUAL_PRIMARY_ONLY: |
- case STATE_DUAL_SECONDARY_ONLY: { |
- RRMode primary_mode = output_cache_[primary_output_index_].mirror_mode; |
- RRMode secondary_mode = |
- output_cache_[secondary_output_index_].mirror_mode; |
- int primary_y = y; |
- int secondary_y = y; |
- |
- if (new_state != STATE_DUAL_MIRROR) { |
- primary_mode = output_cache_[primary_output_index_].ideal_mode; |
- secondary_mode = output_cache_[secondary_output_index_].ideal_mode; |
- } |
- if (new_state == STATE_DUAL_PRIMARY_ONLY) |
- secondary_y = y + primary_height + vertical_gap; |
- if (new_state == STATE_DUAL_SECONDARY_ONLY) |
- primary_y = y + secondary_height + vertical_gap; |
- |
- ConfigureCrtc(display, |
- screen, |
- output_cache_[primary_output_index_].crtc, |
- x, |
- primary_y, |
- primary_mode, |
- output_cache_[primary_output_index_].output); |
- ConfigureCrtc(display, |
- screen, |
- output_cache_[secondary_output_index_].crtc, |
- x, |
- secondary_y, |
- secondary_mode, |
- output_cache_[secondary_output_index_].output); |
- } |
- break; |
- case STATE_HEADLESS: |
- // Do nothing. |
- break; |
- default: |
- NOTREACHED() << "Unhandled state " << new_state; |
- } |
- output_state_ = new_state; |
-} |
- |
-bool OutputConfigurator::RecacheAndUseDefaultState() { |
- Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay(); |
- CHECK(display != NULL); |
- XGrabServer(display); |
- Window window = DefaultRootWindow(display); |
- XRRScreenResources* screen = XRRGetScreenResources(display, window); |
- CHECK(screen != NULL); |
- |
- bool did_detect_change = TryRecacheOutputs(display, screen); |
- if (did_detect_change) { |
- State state = GetDefaultState(); |
- UpdateCacheAndXrandrToState(display, screen, window, state); |
- } |
- XRRFreeScreenResources(screen); |
- XUngrabServer(display); |
- return did_detect_change; |
-} |
- |
-State OutputConfigurator::GetDefaultState() const { |
- State state = STATE_HEADLESS; |
- if (-1 != primary_output_index_) { |
- if (-1 != secondary_output_index_) |
- state = mirror_supported_ ? STATE_DUAL_MIRROR : STATE_DUAL_PRIMARY_ONLY; |
- else |
- state = STATE_SINGLE; |
- } |
- return state; |
-} |
- |
-State OutputConfigurator::InferCurrentState(Display* display, |
- XRRScreenResources* screen) const { |
- // STATE_INVALID will be our default or "unknown" state. |
- State state = STATE_INVALID; |
- // First step: count the number of connected outputs. |
- if (secondary_output_index_ == -1) { |
- // No secondary display. |
- if (primary_output_index_ == -1) { |
- // No primary display implies HEADLESS. |
- state = STATE_HEADLESS; |
- } else { |
- // The common case of primary-only. |
- // The only sanity check we require in this case is that the current mode |
- // of the output's CRTC is the ideal mode we determined for it. |
- RRCrtc primary_crtc = None; |
- RRMode primary_mode = None; |
- int primary_height = 0; |
- GetOutputConfiguration(display, |
- screen, |
- output_cache_[primary_output_index_].output, |
- &primary_crtc, |
- &primary_mode, |
- &primary_height); |
- if (primary_mode == output_cache_[primary_output_index_].ideal_mode) |
- state = STATE_SINGLE; |
- } |
- } else { |
- // We have two displays attached so we need to look at their configuration. |
- // Note that, for simplicity, we will only detect the states that we would |
- // have used and will assume anything unexpected is INVALID (which should |
- // not happen in any expected usage scenario). |
- RRCrtc primary_crtc = None; |
- RRMode primary_mode = None; |
- int primary_height = 0; |
- GetOutputConfiguration(display, |
- screen, |
- output_cache_[primary_output_index_].output, |
- &primary_crtc, |
- &primary_mode, |
- &primary_height); |
- RRCrtc secondary_crtc = None; |
- RRMode secondary_mode = None; |
- int secondary_height = 0; |
- GetOutputConfiguration(display, |
- screen, |
- output_cache_[secondary_output_index_].output, |
- &secondary_crtc, |
- &secondary_mode, |
- &secondary_height); |
- // Make sure the CRTCs are matched to the expected outputs. |
- if ((output_cache_[primary_output_index_].crtc == primary_crtc) && |
- (output_cache_[secondary_output_index_].crtc == secondary_crtc)) { |
- // Check the mode matching: either both mirror or both ideal. |
- if ((output_cache_[primary_output_index_].mirror_mode == primary_mode) && |
- (output_cache_[secondary_output_index_].mirror_mode == |
- secondary_mode)) { |
- // We are already in mirror mode. |
- state = STATE_DUAL_MIRROR; |
- } else if ((output_cache_[primary_output_index_].ideal_mode == |
- primary_mode) && |
- (output_cache_[secondary_output_index_].ideal_mode == |
- secondary_mode)) { |
- // Both outputs are in their "ideal" mode so check their Y-offsets to |
- // see which "ideal" configuration this is. |
- if (primary_height == output_cache_[secondary_output_index_].y) { |
- // Secondary is tiled first. |
- state = STATE_DUAL_SECONDARY_ONLY; |
- } else if (secondary_height == output_cache_[primary_output_index_].y) { |
- // Primary is tiled first. |
- state = STATE_DUAL_PRIMARY_ONLY; |
- } |
- } |
- } |
- } |
- |
- return state; |
-} |
- |
-bool OutputConfigurator::CycleDisplayMode() { |
- VLOG(1) << "CycleDisplayMode"; |
- bool did_change = false; |
- if (is_running_on_chrome_os_) { |
- // Rules: |
- // - if there are 0 or 1 displays, do nothing and return false. |
- // - use y-coord of CRTCs to determine if we are mirror, primary-first, or |
- // secondary-first. The cycle order is: |
- // mirror->primary->secondary->mirror. |
- State new_state = STATE_INVALID; |
- switch (output_state_) { |
- case STATE_DUAL_MIRROR: |
- new_state = STATE_DUAL_PRIMARY_ONLY; |
- break; |
- case STATE_DUAL_PRIMARY_ONLY: |
- new_state = STATE_DUAL_SECONDARY_ONLY; |
- break; |
- case STATE_DUAL_SECONDARY_ONLY: |
- new_state = mirror_supported_ ? |
- STATE_DUAL_MIRROR : |
- STATE_DUAL_PRIMARY_ONLY; |
- break; |
- default: |
- // Do nothing - we aren't in a mode which we can rotate. |
- break; |
- } |
- if (STATE_INVALID != new_state) |
- did_change = SetDisplayMode(new_state); |
- } |
- return did_change; |
-} |
- |
-bool OutputConfigurator::ScreenPowerSet(bool power_on, bool all_displays) { |
- VLOG(1) << "OutputConfigurator::SetScreensOn " << power_on |
- << " all displays " << all_displays; |
- bool success = false; |
- if (is_running_on_chrome_os_) { |
- Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay(); |
- CHECK(display != NULL); |
- XGrabServer(display); |
- Window window = DefaultRootWindow(display); |
- XRRScreenResources* screen = XRRGetScreenResources(display, window); |
- CHECK(screen != NULL); |
- |
- // Set the CRTCs based on whether we want to turn the power on or off and |
- // select the outputs to operate on by name or all_displays. |
- for (int i = 0; i < output_count_; ++i) { |
- if (all_displays || output_cache_[i].is_internal) { |
- const int x = output_cache_[i].x; |
- const int y = output_cache_[i].y; |
- RROutput output = output_cache_[i].output; |
- RRCrtc crtc = output_cache_[i].crtc; |
- RRMode mode = None; |
- if (power_on) { |
- mode = (STATE_DUAL_MIRROR == output_state_) ? |
- output_cache_[i].mirror_mode : |
- output_cache_[i].ideal_mode; |
- } |
- |
- VLOG(1) << "SET POWER crtc: " << crtc |
- << ", mode " << mode |
- << ", output " << output |
- << ", x " << x |
- << ", y " << y; |
- ConfigureCrtc(display, |
- screen, |
- crtc, |
- x, |
- y, |
- mode, |
- output); |
- output_cache_[i].is_powered_on = power_on; |
- success = true; |
- } |
- } |
- |
- // Force the DPMS on since the driver doesn't always detect that it should |
- // turn on. |
- if (power_on) { |
- CHECK(DPMSEnable(display)); |
- CHECK(DPMSForceLevel(display, DPMSModeOn)); |
- } |
- |
- XRRFreeScreenResources(screen); |
- XUngrabServer(display); |
- } |
- return success; |
-} |
- |
-bool OutputConfigurator::SetDisplayMode(State new_state) { |
- if (output_state_ == STATE_INVALID || |
- output_state_ == STATE_HEADLESS || |
- output_state_ == STATE_SINGLE) |
- return false; |
- |
- Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay(); |
- CHECK(display != NULL); |
- XGrabServer(display); |
- Window window = DefaultRootWindow(display); |
- XRRScreenResources* screen = XRRGetScreenResources(display, window); |
- CHECK(screen != NULL); |
- |
- UpdateCacheAndXrandrToState(display, |
- screen, |
- window, |
- new_state); |
- XRRFreeScreenResources(screen); |
- XUngrabServer(display); |
- return true; |
-} |
- |
-bool OutputConfigurator::Dispatch(const base::NativeEvent& event) { |
- // Ignore this event if the Xrandr extension isn't supported. |
- if (is_running_on_chrome_os_ && |
- (event->type - xrandr_event_base_ == RRNotify)) { |
- XEvent* xevent = static_cast<XEvent*>(event); |
- XRRNotifyEvent* notify_event = |
- reinterpret_cast<XRRNotifyEvent*>(xevent); |
- if (notify_event->subtype == RRNotify_OutputChange) { |
- XRROutputChangeNotifyEvent* output_change_event = |
- reinterpret_cast<XRROutputChangeNotifyEvent*>(xevent); |
- if ((output_change_event->connection == RR_Connected) || |
- (output_change_event->connection == RR_Disconnected)) { |
- RecacheAndUseDefaultState(); |
- CheckIsProjectingAndNotify(); |
- } |
- // Ignore the case of RR_UnkownConnection. |
- } |
- } |
- return true; |
-} |
- |
-void OutputConfigurator::CheckIsProjectingAndNotify() { |
- // Determine if there is an "internal" output and how many outputs are |
- // connected. |
- bool has_internal_output = false; |
- int connected_output_count = 0; |
- for (int i = 0; i < output_count_; ++i) { |
- if (output_cache_[i].is_connected) { |
- connected_output_count += 1; |
- has_internal_output |= output_cache_[i].is_internal; |
- } |
- } |
- |
- // "Projecting" is defined as having more than 1 output connected while at |
- // least one of them is an internal output. |
- bool is_projecting = has_internal_output && (connected_output_count > 1); |
- chromeos::DBusThreadManager* manager = chromeos::DBusThreadManager::Get(); |
- dbus::Bus* bus = manager->GetSystemBus(); |
- dbus::ObjectProxy* power_manager_proxy = bus->GetObjectProxy( |
- power_manager::kPowerManagerServiceName, |
- dbus::ObjectPath(power_manager::kPowerManagerServicePath)); |
- dbus::MethodCall method_call( |
- power_manager::kPowerManagerInterface, |
- power_manager::kSetIsProjectingMethod); |
- dbus::MessageWriter writer(&method_call); |
- writer.AppendBool(is_projecting); |
- power_manager_proxy->CallMethod( |
- &method_call, |
- dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
- dbus::ObjectProxy::EmptyResponseCallback()); |
-} |
- |
-} // namespace chromeos |