Commit be448bda authored by Julie Jeongeun Kim's avatar Julie Jeongeun Kim Committed by Commit Bot

Reland "Move the APIs using XRANR to ui/base/x folder"

This is a reland of e14722dd

Original change's description:
> Move the APIs using XRANR to ui/base/x folder
> 
> It creates x11_display_util.cc/h files and moves the APIs to
> get display information using XRANR from DesktopScreenX11 to
> share the implementation with Ozone/X11.
> 
> 'GetXrandrVersion' is to get xrandr version,
> 'GetFallbackDisplayList' is to get a fallback display and
> 'BuildDisplaysFromXRandRInfo' is to get a list of displays from
> the current screen.
> 
> It also moves 'GetICCProfileForMonitor' from DesktopScreenX11
> to x11_util.cc.
> 
> These APIs are required for Ozone/X11 as well. This change doesn't
> bring any behavioral changes.
> 
> Bug: 891175
> Change-Id: Idb42b1929b7bfab4501ced4403fc176342ebdada
> Reviewed-on: https://chromium-review.googlesource.com/c/1295762
> Commit-Queue: Julie Jeongeun Kim <jkim@igalia.com>
> Reviewed-by: Dan Erat <derat@chromium.org>
> Reviewed-by: Thomas Anderson <thomasanderson@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#602634}

Bug: 891175
Change-Id: I742eec8285b023adda84d28d68a21f7545a87f8c
Reviewed-on: https://chromium-review.googlesource.com/c/1301036Reviewed-by: default avatarDan Erat <derat@chromium.org>
Reviewed-by: default avatarThomas Anderson <thomasanderson@chromium.org>
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
Cr-Commit-Position: refs/heads/master@{#603262}
parent 362d353a
...@@ -38,4 +38,15 @@ jumbo_component("x") { ...@@ -38,4 +38,15 @@ jumbo_component("x") {
"//ui/gfx", "//ui/gfx",
"//ui/gfx/x", "//ui/gfx/x",
] ]
if (!is_chromeos) {
sources += [
"x11_display_util.cc",
"x11_display_util.h",
]
configs += [ "//build/config/linux:xrandr" ]
deps += [ "//ui/display/util" ]
}
} }
// 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 "ui/base/x/x11_display_util.h"
#include <dlfcn.h>
#include "base/logging.h"
#include "base/memory/protected_memory_cfi.h"
#include "ui/base/x/x11_util.h"
#include "ui/display/util/display_util.h"
#include "ui/display/util/x11/edid_parser_x11.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/x/x11.h"
namespace ui {
namespace {
constexpr int kMinVersionXrandr = 103; // Need at least xrandr version 1.3.
typedef XRRMonitorInfo* (*XRRGetMonitors)(::Display*, Window, bool, int*);
typedef void (*XRRFreeMonitors)(XRRMonitorInfo*);
PROTECTED_MEMORY_SECTION base::ProtectedMemory<XRRGetMonitors>
g_XRRGetMonitors_ptr;
PROTECTED_MEMORY_SECTION base::ProtectedMemory<XRRFreeMonitors>
g_XRRFreeMonitors_ptr;
std::map<RROutput, int> GetMonitors(int version,
XDisplay* xdisplay,
GLXWindow window) {
std::map<RROutput, int> output_to_monitor;
if (version >= 105) {
void* xrandr_lib = dlopen(nullptr, RTLD_NOW);
if (xrandr_lib) {
static base::ProtectedMemory<XRRGetMonitors>::Initializer get_init(
&g_XRRGetMonitors_ptr, reinterpret_cast<XRRGetMonitors>(
dlsym(xrandr_lib, "XRRGetMonitors")));
static base::ProtectedMemory<XRRFreeMonitors>::Initializer free_init(
&g_XRRFreeMonitors_ptr, reinterpret_cast<XRRFreeMonitors>(
dlsym(xrandr_lib, "XRRFreeMonitors")));
if (*g_XRRGetMonitors_ptr && *g_XRRFreeMonitors_ptr) {
int nmonitors = 0;
XRRMonitorInfo* monitors = base::UnsanitizedCfiCall(
g_XRRGetMonitors_ptr)(xdisplay, window, false, &nmonitors);
for (int monitor = 0; monitor < nmonitors; monitor++) {
for (int j = 0; j < monitors[monitor].noutput; j++) {
output_to_monitor[monitors[monitor].outputs[j]] = monitor;
}
}
base::UnsanitizedCfiCall(g_XRRFreeMonitors_ptr)(monitors);
}
}
}
return output_to_monitor;
}
} // namespace
int GetXrandrVersion(XDisplay* xdisplay) {
int xrandr_version = 0;
// We only support 1.3+. There were library changes before this and we should
// use the new interface instead of the 1.2 one.
int randr_version_major = 0;
int randr_version_minor = 0;
if (XRRQueryVersion(xdisplay, &randr_version_major, &randr_version_minor)) {
xrandr_version = randr_version_major * 100 + randr_version_minor;
}
return xrandr_version;
}
std::vector<display::Display> GetFallbackDisplayList(float scale) {
XDisplay* display = gfx::GetXDisplay();
::Screen* screen = DefaultScreenOfDisplay(display);
gfx::Size physical_size(WidthMMOfScreen(screen), HeightMMOfScreen(screen));
int width = WidthOfScreen(screen);
int height = HeightOfScreen(screen);
gfx::Rect bounds_in_pixels(0, 0, width, height);
display::Display gfx_display(0, bounds_in_pixels);
if (!display::Display::HasForceDeviceScaleFactor() &&
!display::IsDisplaySizeBlackListed(physical_size)) {
DCHECK_LE(1.0f, scale);
gfx_display.SetScaleAndBounds(scale, bounds_in_pixels);
}
return {gfx_display};
}
std::vector<display::Display> BuildDisplaysFromXRandRInfo(
int version,
float scale,
int64_t* primary_display_index_out) {
DCHECK(primary_display_index_out);
DCHECK_GE(version, kMinVersionXrandr);
XDisplay* xdisplay = gfx::GetXDisplay();
GLXWindow x_root_window = DefaultRootWindow(xdisplay);
std::vector<display::Display> displays;
gfx::XScopedPtr<
XRRScreenResources,
gfx::XObjectDeleter<XRRScreenResources, void, XRRFreeScreenResources>>
resources(XRRGetScreenResourcesCurrent(xdisplay, x_root_window));
if (!resources) {
LOG(ERROR) << "XRandR returned no displays; falling back to root window";
return GetFallbackDisplayList(scale);
}
std::map<RROutput, int> output_to_monitor =
GetMonitors(version, xdisplay, x_root_window);
*primary_display_index_out = 0;
RROutput primary_display_id = XRRGetOutputPrimary(xdisplay, x_root_window);
int explicit_primary_display_index = -1;
int monitor_order_primary_display_index = -1;
bool has_work_area = false;
gfx::Rect work_area_in_pixels;
std::vector<int> value;
if (ui::GetIntArrayProperty(x_root_window, "_NET_WORKAREA", &value) &&
value.size() >= 4) {
work_area_in_pixels = gfx::Rect(value[0], value[1], value[2], value[3]);
has_work_area = true;
}
// As per-display scale factor is not supported right now,
// the X11 root window's scale factor is always used.
for (int i = 0; i < resources->noutput; ++i) {
RROutput output_id = resources->outputs[i];
gfx::XScopedPtr<XRROutputInfo,
gfx::XObjectDeleter<XRROutputInfo, void, XRRFreeOutputInfo>>
output_info(XRRGetOutputInfo(xdisplay, resources.get(), output_id));
bool is_connected = (output_info->connection == RR_Connected);
if (!is_connected)
continue;
bool is_primary_display = (output_id == primary_display_id);
if (output_info->crtc) {
gfx::XScopedPtr<XRRCrtcInfo,
gfx::XObjectDeleter<XRRCrtcInfo, void, XRRFreeCrtcInfo>>
crtc(XRRGetCrtcInfo(xdisplay, resources.get(), output_info->crtc));
int64_t display_id = -1;
if (!display::EDIDParserX11(output_id).GetDisplayId(
static_cast<uint8_t>(i), &display_id)) {
// It isn't ideal, but if we can't parse the EDID data, fall back on the
// display number.
display_id = i;
}
gfx::Rect crtc_bounds(crtc->x, crtc->y, crtc->width, crtc->height);
display::Display display(display_id, crtc_bounds);
if (!display::Display::HasForceDeviceScaleFactor()) {
display.SetScaleAndBounds(scale, crtc_bounds);
}
if (has_work_area) {
gfx::Rect intersection_in_pixels = crtc_bounds;
if (is_primary_display) {
intersection_in_pixels.Intersect(work_area_in_pixels);
}
// SetScaleAndBounds() above does the conversion from pixels to DIP for
// us, but set_work_area does not, so we need to do it here.
display.set_work_area(gfx::Rect(
gfx::ScaleToFlooredPoint(intersection_in_pixels.origin(),
1.0f / display.device_scale_factor()),
gfx::ScaleToFlooredSize(intersection_in_pixels.size(),
1.0f / display.device_scale_factor())));
}
switch (crtc->rotation) {
case RR_Rotate_0:
display.set_rotation(display::Display::ROTATE_0);
break;
case RR_Rotate_90:
display.set_rotation(display::Display::ROTATE_90);
break;
case RR_Rotate_180:
display.set_rotation(display::Display::ROTATE_180);
break;
case RR_Rotate_270:
display.set_rotation(display::Display::ROTATE_270);
break;
}
if (is_primary_display)
explicit_primary_display_index = displays.size();
auto monitor_iter = output_to_monitor.find(output_id);
if (monitor_iter != output_to_monitor.end() && monitor_iter->second == 0)
monitor_order_primary_display_index = displays.size();
if (!display::Display::HasForceDisplayColorProfile()) {
gfx::ICCProfile icc_profile = ui::GetICCProfileForMonitor(
monitor_iter == output_to_monitor.end() ? 0 : monitor_iter->second);
icc_profile.HistogramDisplay(display.id());
display.set_color_space(icc_profile.GetColorSpace());
}
displays.push_back(display);
}
}
if (explicit_primary_display_index != -1) {
*primary_display_index_out = explicit_primary_display_index;
} else if (monitor_order_primary_display_index != -1) {
*primary_display_index_out = monitor_order_primary_display_index;
}
if (displays.empty())
return GetFallbackDisplayList(scale);
return displays;
}
} // namespace ui
// 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.
#ifndef UI_BASE_X_X11_DISPLAY_UTIL_H_
#define UI_BASE_X_X11_DISPLAY_UTIL_H_
#include "ui/base/x/ui_base_x_export.h"
#include "ui/display/display.h"
#include "ui/gfx/x/x11_types.h"
namespace ui {
// Return the version for xrandr. It multiplies the major number by 100 and
// adds the minor like MAJOR * 100 + MINOR. It returns zero if no xrandr is
// present.
UI_BASE_X_EXPORT int GetXrandrVersion(XDisplay* xdisplay);
// Builds a list of displays for fallback.
UI_BASE_X_EXPORT std::vector<display::Display> GetFallbackDisplayList(
float scale);
// Builds a list of displays from the current screen information offered by
// the X server.
UI_BASE_X_EXPORT std::vector<display::Display> BuildDisplaysFromXRandRInfo(
int version,
float scale,
int64_t* primary_display_index_out);
} // namespace ui
#endif // UI_BASE_X_X11_DISPLAY_UTIL_H_
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <vector> #include <vector>
#include "base/bind.h" #include "base/bind.h"
#include "base/command_line.h"
#include "base/location.h" #include "base/location.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
...@@ -55,6 +56,7 @@ ...@@ -55,6 +56,7 @@
#include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_rep.h" #include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/skia_util.h" #include "ui/gfx/skia_util.h"
#include "ui/gfx/switches.h"
#include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h" #include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_error_tracker.h" #include "ui/gfx/x/x11_error_tracker.h"
...@@ -79,6 +81,10 @@ namespace { ...@@ -79,6 +81,10 @@ namespace {
constexpr int kNetWMStateAdd = 1; constexpr int kNetWMStateAdd = 1;
constexpr int kNetWMStateRemove = 0; constexpr int kNetWMStateRemove = 0;
// Length in 32-bit multiples of the data to be retrieved for
// XGetWindowProperty.
constexpr int kLongLength = 0x1FFFFFFF; /* MAXINT32 / 4 */
int DefaultX11ErrorHandler(XDisplay* d, XErrorEvent* e) { int DefaultX11ErrorHandler(XDisplay* d, XErrorEvent* e) {
// This callback can be invoked by drivers very late in thread destruction, // This callback can be invoked by drivers very late in thread destruction,
// when Chrome TLS is no longer usable. https://crbug.com/849225. // when Chrome TLS is no longer usable. https://crbug.com/849225.
...@@ -680,10 +686,9 @@ bool GetRawBytesOfProperty(XID window, ...@@ -680,10 +686,9 @@ bool GetRawBytesOfProperty(XID window,
XAtom prop_type = x11::None; XAtom prop_type = x11::None;
int prop_format = 0; int prop_format = 0;
unsigned char* property_data = NULL; unsigned char* property_data = NULL;
if (XGetWindowProperty(gfx::GetXDisplay(), window, property, 0, if (XGetWindowProperty(gfx::GetXDisplay(), window, property, 0, kLongLength,
0x1FFFFFFF /* MAXINT32 / 4 */, x11::False, x11::False, AnyPropertyType, &prop_type, &prop_format,
AnyPropertyType, &prop_type, &prop_format, &nitems, &nitems, &nbytes, &property_data) != x11::Success) {
&nbytes, &property_data) != x11::Success) {
return false; return false;
} }
gfx::XScopedPtr<unsigned char> scoped_property(property_data); gfx::XScopedPtr<unsigned char> scoped_property(property_data);
...@@ -1269,6 +1274,35 @@ bool WmSupportsHint(XAtom atom) { ...@@ -1269,6 +1274,35 @@ bool WmSupportsHint(XAtom atom) {
return base::ContainsValue(supported_atoms, atom); return base::ContainsValue(supported_atoms, atom);
} }
gfx::ICCProfile GetICCProfileForMonitor(int monitor) {
gfx::ICCProfile icc_profile;
if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless))
return icc_profile;
std::string atom_name;
if (monitor == 0) {
atom_name = "_ICC_PROFILE";
} else {
atom_name = base::StringPrintf("_ICC_PROFILE_%d", monitor);
}
Atom property = gfx::GetAtom(atom_name.c_str());
if (property != x11::None) {
Atom prop_type = x11::None;
int prop_format = 0;
unsigned long nitems = 0;
unsigned long nbytes = 0;
char* property_data = nullptr;
int result = XGetWindowProperty(
gfx::GetXDisplay(), DefaultRootWindow(gfx::GetXDisplay()), property, 0,
kLongLength, x11::False, AnyPropertyType, &prop_type, &prop_format,
&nitems, &nbytes, reinterpret_cast<unsigned char**>(&property_data));
if (result == x11::Success) {
icc_profile = gfx::ICCProfile::FromData(property_data, nitems);
XFree(property_data);
}
}
return icc_profile;
}
XRefcountedMemory::XRefcountedMemory(unsigned char* x11_data, size_t length) XRefcountedMemory::XRefcountedMemory(unsigned char* x11_data, size_t length)
: x11_data_(length ? x11_data : nullptr), length_(length) { : x11_data_(length ? x11_data : nullptr), length_(length) {
} }
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "ui/events/event_constants.h" #include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h" #include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/platform_event.h" #include "ui/events/platform_event.h"
#include "ui/gfx/icc_profile.h"
#include "ui/gfx/x/x11_types.h" #include "ui/gfx/x/x11_types.h"
typedef unsigned long XSharedMemoryId; // ShmSeg in the X headers. typedef unsigned long XSharedMemoryId; // ShmSeg in the X headers.
...@@ -297,6 +298,9 @@ UI_BASE_X_EXPORT bool IsX11WindowFullScreen(XID window); ...@@ -297,6 +298,9 @@ UI_BASE_X_EXPORT bool IsX11WindowFullScreen(XID window);
// Returns true if the window manager supports the given hint. // Returns true if the window manager supports the given hint.
UI_BASE_X_EXPORT bool WmSupportsHint(XAtom atom); UI_BASE_X_EXPORT bool WmSupportsHint(XAtom atom);
// Returns the ICCProfile corresponding to |monitor| using XGetWindowProperty.
UI_BASE_X_EXPORT gfx::ICCProfile GetICCProfileForMonitor(int monitor);
// Manages a piece of X11 allocated memory as a RefCountedMemory segment. This // Manages a piece of X11 allocated memory as a RefCountedMemory segment. This
// object takes ownership over the passed in memory and will free it with the // object takes ownership over the passed in memory and will free it with the
// X11 allocator when done. // X11 allocator when done.
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import("//build/config/jumbo.gni") import("//build/config/jumbo.gni")
import("//build/config/ui.gni") import("//build/config/ui.gni")
import("//testing/libfuzzer/fuzzer_test.gni") import("//testing/libfuzzer/fuzzer_test.gni")
import("//ui/ozone/ozone.gni")
jumbo_component("util") { jumbo_component("util") {
output_name = "display_util" output_name = "display_util"
...@@ -27,7 +28,7 @@ jumbo_component("util") { ...@@ -27,7 +28,7 @@ jumbo_component("util") {
"//ui/gfx/geometry", "//ui/gfx/geometry",
] ]
if (use_x11) { if (use_x11 || (ozone_platform_x11 && !is_chromeos)) {
sources += [ sources += [
"x11/edid_parser_x11.cc", "x11/edid_parser_x11.cc",
"x11/edid_parser_x11.h", "x11/edid_parser_x11.h",
......
...@@ -69,10 +69,6 @@ class VIEWS_EXPORT DesktopScreenX11 : public display::Screen, ...@@ -69,10 +69,6 @@ class VIEWS_EXPORT DesktopScreenX11 : public display::Screen,
// Constructor used in tests. // Constructor used in tests.
DesktopScreenX11(const std::vector<display::Display>& test_displays); DesktopScreenX11(const std::vector<display::Display>& test_displays);
// Builds a list of displays from the current screen information offered by
// the X server.
std::vector<display::Display> BuildDisplaysFromXRandRInfo();
// Removes |delayed_configuration_task_| from the task queue (if // Removes |delayed_configuration_task_| from the task queue (if
// it's in the queue) and adds it back at the end of the queue. // it's in the queue) and adds it back at the end of the queue.
void RestartDelayedConfigurationTask(); void RestartDelayedConfigurationTask();
...@@ -88,17 +84,17 @@ class VIEWS_EXPORT DesktopScreenX11 : public display::Screen, ...@@ -88,17 +84,17 @@ class VIEWS_EXPORT DesktopScreenX11 : public display::Screen,
::Window x_root_window_; ::Window x_root_window_;
// XRandR version. MAJOR * 100 + MINOR. Zero if no xrandr is present. // XRandR version. MAJOR * 100 + MINOR. Zero if no xrandr is present.
int xrandr_version_; const int xrandr_version_;
// The base of the event numbers used to represent XRandr events used in // The base of the event numbers used to represent XRandr events used in
// decoding events regarding output add/remove. // decoding events regarding output add/remove.
int xrandr_event_base_; int xrandr_event_base_ = 0;
// The display objects we present to chrome. // The display objects we present to chrome.
std::vector<display::Display> displays_; std::vector<display::Display> displays_;
// The index into displays_ that represents the primary display. // The index into displays_ that represents the primary display.
size_t primary_display_index_; int64_t primary_display_index_ = 0;
// The task to delay configuring outputs. We delay updating the // The task to delay configuring outputs. We delay updating the
// display so we can coalesce events. // display so we can coalesce events.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment