blob: c819f04f625e90947895fbf8ad104555d4fb377b [file] [log] [blame]
// Copyright 2018 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 "components/exo/wayland/wayland_display_observer.h"
#include <wayland-server-core.h>
#include "components/exo/wm_helper.h"
#include "ui/display/manager/managed_display_info.h"
#include "ui/display/screen.h"
namespace exo {
namespace wayland {
WaylandDisplayObserver::WaylandDisplayObserver(int64_t id,
wl_resource* output_resource)
: id_(id), output_resource_(output_resource) {
display::Screen::GetScreen()->AddObserver(this);
SendDisplayMetrics();
}
WaylandDisplayObserver::~WaylandDisplayObserver() {
display::Screen::GetScreen()->RemoveObserver(this);
}
void WaylandDisplayObserver::SetScaleObserver(
base::WeakPtr<ScaleObserver> scale_observer) {
scale_observer_ = scale_observer;
SendDisplayMetrics();
}
bool WaylandDisplayObserver::HasScaleObserver() const {
return !!scale_observer_;
}
void WaylandDisplayObserver::OnDisplayMetricsChanged(
const display::Display& display,
uint32_t changed_metrics) {
if (id_ != display.id())
return;
// There is no need to check DISPLAY_METRIC_PRIMARY because when primary
// changes, bounds always changes. (new primary should have had non
// 0,0 origin).
// Only exception is when switching to newly connected primary with
// the same bounds. This happens whenyou're in docked mode, suspend,
// unplug the dislpay, then resume to the internal display which has
// the same resolution. Since metrics does not change, there is no need
// to notify clients.
if (changed_metrics &
(DISPLAY_METRIC_BOUNDS | DISPLAY_METRIC_DEVICE_SCALE_FACTOR |
DISPLAY_METRIC_ROTATION)) {
SendDisplayMetrics();
}
}
void WaylandDisplayObserver::SendDisplayMetrics() {
display::Display display;
bool rv =
display::Screen::GetScreen()->GetDisplayWithDisplayId(id_, &display);
DCHECK(rv);
const display::ManagedDisplayInfo& info =
WMHelper::GetInstance()->GetDisplayInfo(display.id());
const float kInchInMm = 25.4f;
const char* kUnknown = "unknown";
const std::string& make = info.manufacturer_id();
const std::string& model = info.product_id();
gfx::Rect bounds = info.bounds_in_native();
wl_output_send_geometry(
output_resource_, bounds.x(), bounds.y(),
static_cast<int>(kInchInMm * bounds.width() / info.device_dpi()),
static_cast<int>(kInchInMm * bounds.height() / info.device_dpi()),
WL_OUTPUT_SUBPIXEL_UNKNOWN, make.empty() ? kUnknown : make.c_str(),
model.empty() ? kUnknown : model.c_str(),
OutputTransform(display.rotation()));
if (wl_resource_get_version(output_resource_) >=
WL_OUTPUT_SCALE_SINCE_VERSION) {
wl_output_send_scale(output_resource_, display.device_scale_factor());
}
// TODO(reveman): Send real list of modes.
wl_output_send_mode(output_resource_,
WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED,
bounds.width(), bounds.height(), static_cast<int>(60000));
if (HasScaleObserver())
scale_observer_->OnDisplayScalesChanged(display);
if (wl_resource_get_version(output_resource_) >=
WL_OUTPUT_DONE_SINCE_VERSION) {
wl_output_send_done(output_resource_);
}
wl_client_flush(wl_resource_get_client(output_resource_));
}
wl_output_transform WaylandDisplayObserver::OutputTransform(
display::Display::Rotation rotation) {
// Note: |rotation| describes the counter clockwise rotation that a
// display's output is currently adjusted for, which is the inverse
// of what we need to return.
switch (rotation) {
case display::Display::ROTATE_0:
return WL_OUTPUT_TRANSFORM_NORMAL;
case display::Display::ROTATE_90:
return WL_OUTPUT_TRANSFORM_270;
case display::Display::ROTATE_180:
return WL_OUTPUT_TRANSFORM_180;
case display::Display::ROTATE_270:
return WL_OUTPUT_TRANSFORM_90;
}
NOTREACHED();
return WL_OUTPUT_TRANSFORM_NORMAL;
}
} // namespace wayland
} // namespace exo