| // Copyright 2017 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 <iomanip> |
| #include <iostream> |
| #include <string> |
| #include <vector> |
| |
| #include "base/logging.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "components/exo/wayland/clients/client_helper.h" |
| |
| // Client that retreives output related properties (modes, scales, etc.) from |
| // a compositor and prints them to standard output. |
| |
| namespace { |
| |
| // This struct contains all the fields that will be set by output |
| // interface listener callbacks. |
| struct Info { |
| int32_t connection; |
| int32_t device_scale_factor; |
| struct { |
| int32_t x, y; |
| int32_t physical_width, physical_height; |
| int32_t subpixel; |
| std::string make; |
| std::string model; |
| int32_t transform; |
| } geometry; |
| struct Mode { |
| uint32_t flags; |
| int32_t width, height; |
| int32_t refresh; |
| }; |
| // |next_modes| are swapped with |modes| after receiving output done event. |
| std::vector<Mode> modes, next_modes; |
| struct Scale { |
| uint32_t flags; |
| int32_t scale; |
| }; |
| // |next_scales| are swapped with |scales| after receiving output done event. |
| std::vector<Scale> scales, next_scales; |
| std::unique_ptr<wl_output> output; |
| std::unique_ptr<zaura_output> aura_output; |
| }; |
| |
| // This struct contains globals and all outputs. |
| struct Globals { |
| std::unique_ptr<zaura_shell> aura_shell; |
| std::vector<Info> outputs; |
| }; |
| |
| void RegistryHandler(void* data, |
| wl_registry* registry, |
| uint32_t id, |
| const char* interface, |
| uint32_t version) { |
| Globals* globals = static_cast<Globals*>(data); |
| |
| if (strcmp(interface, "wl_output") == 0) { |
| globals->outputs.push_back( |
| {.connection = ZAURA_OUTPUT_CONNECTION_TYPE_UNKNOWN, |
| .device_scale_factor = ZAURA_OUTPUT_SCALE_FACTOR_1000, |
| .geometry = {.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN, |
| .make = "unknown", |
| .model = "unknown", |
| .transform = WL_OUTPUT_TRANSFORM_NORMAL}}); |
| globals->outputs.back().output.reset(static_cast<wl_output*>( |
| wl_registry_bind(registry, id, &wl_output_interface, 2))); |
| } else if (strcmp(interface, "zaura_shell") == 0) { |
| if (version >= 2) { |
| globals->aura_shell.reset(static_cast<zaura_shell*>( |
| wl_registry_bind(registry, id, &zaura_shell_interface, 5))); |
| } |
| } |
| } |
| |
| void RegistryRemover(void* data, wl_registry* registry, uint32_t id) { |
| LOG(WARNING) << "Got a registry losing event for " << id; |
| } |
| |
| void OutputGeometry(void* data, |
| wl_output* output, |
| int x, |
| int y, |
| int physical_width, |
| int physical_height, |
| int subpixel, |
| const char* make, |
| const char* model, |
| int transform) { |
| Info* info = static_cast<Info*>(data); |
| |
| info->geometry.x = x; |
| info->geometry.y = y; |
| info->geometry.physical_width = physical_width; |
| info->geometry.physical_height = physical_height; |
| info->geometry.subpixel = subpixel; |
| info->geometry.make = make; |
| info->geometry.model = model; |
| info->geometry.transform = transform; |
| } |
| |
| void OutputMode(void* data, |
| wl_output* output, |
| uint32_t flags, |
| int width, |
| int height, |
| int refresh) { |
| Info* info = static_cast<Info*>(data); |
| |
| info->next_modes.push_back({flags, width, height, refresh}); |
| } |
| |
| void OutputDone(void* data, wl_output* output) { |
| Info* info = static_cast<Info*>(data); |
| |
| std::swap(info->modes, info->next_modes); |
| info->next_modes.clear(); |
| std::swap(info->scales, info->next_scales); |
| info->next_scales.clear(); |
| } |
| |
| void OutputScale(void* data, wl_output* output, int32_t scale) { |
| Info* info = static_cast<Info*>(data); |
| |
| info->device_scale_factor = scale * 1000; |
| } |
| |
| void AuraOutputScale(void* data, |
| zaura_output* output, |
| uint32_t flags, |
| uint32_t scale) { |
| Info* info = static_cast<Info*>(data); |
| |
| info->next_scales.push_back({flags, scale}); |
| } |
| |
| void AuraOutputConnection(void* data, |
| zaura_output* output, |
| uint32_t connection) { |
| Info* info = static_cast<Info*>(data); |
| |
| info->connection = connection; |
| } |
| |
| void AuraOutputDeviceScaleFactor(void* data, |
| zaura_output* output, |
| uint32_t device_scale_factor) { |
| Info* info = static_cast<Info*>(data); |
| |
| info->device_scale_factor = device_scale_factor; |
| } |
| |
| std::string OutputSubpixelToString(int32_t subpixel) { |
| switch (subpixel) { |
| case WL_OUTPUT_SUBPIXEL_UNKNOWN: |
| return "unknown"; |
| case WL_OUTPUT_SUBPIXEL_NONE: |
| return "none"; |
| case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB: |
| return "horizontal rgb"; |
| case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR: |
| return "horizontal bgr"; |
| case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB: |
| return "vertical rgb"; |
| case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR: |
| return "vertical bgr"; |
| default: |
| return base::StringPrintf("unknown (%d)", subpixel); |
| } |
| } |
| |
| std::string OutputTransformToString(int32_t transform) { |
| switch (transform) { |
| case WL_OUTPUT_TRANSFORM_NORMAL: |
| return "normal"; |
| case WL_OUTPUT_TRANSFORM_90: |
| return "90°"; |
| case WL_OUTPUT_TRANSFORM_180: |
| return "180°"; |
| case WL_OUTPUT_TRANSFORM_270: |
| return "270°"; |
| case WL_OUTPUT_TRANSFORM_FLIPPED: |
| return "flipped"; |
| case WL_OUTPUT_TRANSFORM_FLIPPED_90: |
| return "flipped 90°"; |
| case WL_OUTPUT_TRANSFORM_FLIPPED_180: |
| return "flipped 180°"; |
| case WL_OUTPUT_TRANSFORM_FLIPPED_270: |
| return "flipped 270°"; |
| default: |
| return base::StringPrintf("unknown (%d)", transform); |
| } |
| } |
| |
| std::string OutputModeFlagsToString(uint32_t flags) { |
| std::string string; |
| if (flags & WL_OUTPUT_MODE_CURRENT) |
| string += "current "; |
| if (flags & WL_OUTPUT_MODE_PREFERRED) |
| string += "preferred"; |
| base::TrimWhitespaceASCII(string, base::TRIM_TRAILING, &string); |
| return string; |
| } |
| |
| std::string AuraOutputScaleFlagsToString(uint32_t flags) { |
| std::string string; |
| if (flags & ZAURA_OUTPUT_SCALE_PROPERTY_CURRENT) |
| string += "current "; |
| if (flags & ZAURA_OUTPUT_SCALE_PROPERTY_PREFERRED) |
| string += "preferred"; |
| base::TrimWhitespaceASCII(string, base::TRIM_TRAILING, &string); |
| return string; |
| } |
| |
| std::string AuraOutputScaleFactorToString(int32_t scale) { |
| switch (scale) { |
| case ZAURA_OUTPUT_SCALE_FACTOR_0400: |
| case ZAURA_OUTPUT_SCALE_FACTOR_0500: |
| case ZAURA_OUTPUT_SCALE_FACTOR_0550: |
| case ZAURA_OUTPUT_SCALE_FACTOR_0600: |
| case ZAURA_OUTPUT_SCALE_FACTOR_0625: |
| case ZAURA_OUTPUT_SCALE_FACTOR_0650: |
| case ZAURA_OUTPUT_SCALE_FACTOR_0700: |
| case ZAURA_OUTPUT_SCALE_FACTOR_0750: |
| case ZAURA_OUTPUT_SCALE_FACTOR_0800: |
| case ZAURA_OUTPUT_SCALE_FACTOR_0850: |
| case ZAURA_OUTPUT_SCALE_FACTOR_0900: |
| case ZAURA_OUTPUT_SCALE_FACTOR_0950: |
| case ZAURA_OUTPUT_SCALE_FACTOR_1000: |
| case ZAURA_OUTPUT_SCALE_FACTOR_1050: |
| case ZAURA_OUTPUT_SCALE_FACTOR_1100: |
| case ZAURA_OUTPUT_SCALE_FACTOR_1150: |
| case ZAURA_OUTPUT_SCALE_FACTOR_1125: |
| case ZAURA_OUTPUT_SCALE_FACTOR_1200: |
| case ZAURA_OUTPUT_SCALE_FACTOR_1250: |
| case ZAURA_OUTPUT_SCALE_FACTOR_1300: |
| case ZAURA_OUTPUT_SCALE_FACTOR_1400: |
| case ZAURA_OUTPUT_SCALE_FACTOR_1450: |
| case ZAURA_OUTPUT_SCALE_FACTOR_1500: |
| case ZAURA_OUTPUT_SCALE_FACTOR_1600: |
| case ZAURA_OUTPUT_SCALE_FACTOR_1750: |
| case ZAURA_OUTPUT_SCALE_FACTOR_1800: |
| case ZAURA_OUTPUT_SCALE_FACTOR_2000: |
| case ZAURA_OUTPUT_SCALE_FACTOR_2200: |
| case ZAURA_OUTPUT_SCALE_FACTOR_2250: |
| case ZAURA_OUTPUT_SCALE_FACTOR_2500: |
| case ZAURA_OUTPUT_SCALE_FACTOR_2750: |
| case ZAURA_OUTPUT_SCALE_FACTOR_3000: |
| case ZAURA_OUTPUT_SCALE_FACTOR_3500: |
| case ZAURA_OUTPUT_SCALE_FACTOR_4000: |
| case ZAURA_OUTPUT_SCALE_FACTOR_4500: |
| case ZAURA_OUTPUT_SCALE_FACTOR_5000: |
| return base::StringPrintf("%.3f", scale / 1000.0); |
| default: |
| return base::StringPrintf("unknown (%g)", scale / 1000.0); |
| } |
| } |
| |
| std::string AuraOutputConnectionToString(uint32_t connection_type) { |
| switch (connection_type) { |
| case ZAURA_OUTPUT_CONNECTION_TYPE_UNKNOWN: |
| return "unknown"; |
| case ZAURA_OUTPUT_CONNECTION_TYPE_INTERNAL: |
| return "internal"; |
| default: |
| return "invalid"; |
| } |
| } |
| |
| } // namespace |
| |
| int main(int argc, char* argv[]) { |
| std::unique_ptr<wl_display> display(wl_display_connect(nullptr)); |
| if (!display) { |
| LOG(ERROR) << "Failed to connect to display"; |
| return 1; |
| } |
| |
| Globals globals; |
| |
| wl_registry_listener registry_listener = {RegistryHandler, RegistryRemover}; |
| wl_registry* registry = wl_display_get_registry(display.get()); |
| wl_registry_add_listener(registry, ®istry_listener, &globals); |
| |
| wl_display_roundtrip(display.get()); |
| |
| wl_output_listener output_listener = {OutputGeometry, OutputMode, OutputDone, |
| OutputScale}; |
| |
| zaura_output_listener aura_output_listener = { |
| AuraOutputScale, AuraOutputConnection, AuraOutputDeviceScaleFactor}; |
| for (auto& info : globals.outputs) { |
| wl_output_add_listener(info.output.get(), &output_listener, &info); |
| if (globals.aura_shell) { |
| info.aura_output.reset( |
| static_cast<zaura_output*>(zaura_shell_get_aura_output( |
| globals.aura_shell.get(), info.output.get()))); |
| zaura_output_add_listener(info.aura_output.get(), &aura_output_listener, |
| &info); |
| } |
| } |
| |
| wl_display_roundtrip(display.get()); |
| |
| for (auto& info : globals.outputs) { |
| int id = &info - &globals.outputs[0]; |
| if (id) |
| std::cout << std::endl; |
| std::cout << "OUTPUT" << id << ":" << std::endl << std::endl; |
| std::cout << " connection: " |
| << AuraOutputConnectionToString(info.connection) << std::endl; |
| std::cout << " device scale factor: " |
| << AuraOutputScaleFactorToString(info.device_scale_factor) |
| << std::endl |
| << std::endl; |
| std::cout << " geometry:" << std::endl |
| << " x: " << info.geometry.x << std::endl |
| << " y: " << info.geometry.y << std::endl |
| << " physical width: " << info.geometry.physical_width |
| << " mm" << std::endl |
| << " physical height: " << info.geometry.physical_height |
| << " mm" << std::endl |
| << " subpixel: " |
| << OutputSubpixelToString(info.geometry.subpixel) << std::endl |
| << " make: " << info.geometry.make << std::endl |
| << " model: " << info.geometry.model << std::endl |
| << " transform: " |
| << OutputTransformToString(info.geometry.transform) << std::endl |
| << std::endl; |
| std::cout << " modes:" << std::endl; |
| for (auto& mode : info.modes) { |
| std::cout << " " << std::left << std::setw(19) |
| << base::StringPrintf("%dx%d:", mode.width, mode.height) |
| << std::left << std::setw(14) |
| << base::StringPrintf("%.2f Hz", mode.refresh / 1000.0) |
| << OutputModeFlagsToString(mode.flags) << std::endl; |
| } |
| if (!info.scales.empty()) { |
| std::cout << std::endl; |
| std::cout << " scales:" << std::endl; |
| for (auto& scale : info.scales) { |
| std::cout << " " << std::left << std::setw(19) |
| << (AuraOutputScaleFactorToString(scale.scale) + ":") |
| << AuraOutputScaleFlagsToString(scale.flags) << std::endl; |
| } |
| } |
| } |
| |
| return 0; |
| } |