1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <iomanip>
6 #include <iostream>
7 #include <string>
8 #include <vector>
9
10 #include "base/logging.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "components/exo/wayland/clients/client_helper.h"
14
15 // Client that retreives output related properties (modes, scales, etc.) from
16 // a compositor and prints them to standard output.
17
18 namespace {
19
20 // This struct contains all the fields that will be set by output
21 // interface listener callbacks.
22 struct Info {
23 int32_t connection;
24 int32_t device_scale_factor;
25 struct {
26 int32_t x, y;
27 int32_t physical_width, physical_height;
28 int32_t subpixel;
29 std::string make;
30 std::string model;
31 int32_t transform;
32 } geometry;
33 struct Mode {
34 uint32_t flags;
35 int32_t width, height;
36 int32_t refresh;
37 };
38 // |next_modes| are swapped with |modes| after receiving output done event.
39 std::vector<Mode> modes, next_modes;
40 struct Scale {
41 uint32_t flags;
42 int32_t scale;
43 };
44 // |next_scales| are swapped with |scales| after receiving output done event.
45 std::vector<Scale> scales, next_scales;
46 std::unique_ptr<wl_output> output;
47 std::unique_ptr<zaura_output> aura_output;
48 };
49
50 // This struct contains globals and all outputs.
51 struct Globals {
52 std::unique_ptr<zaura_shell> aura_shell;
53 std::vector<Info> outputs;
54 };
55
RegistryHandler(void * data,wl_registry * registry,uint32_t id,const char * interface,uint32_t version)56 void RegistryHandler(void* data,
57 wl_registry* registry,
58 uint32_t id,
59 const char* interface,
60 uint32_t version) {
61 Globals* globals = static_cast<Globals*>(data);
62
63 if (strcmp(interface, "wl_output") == 0) {
64 globals->outputs.push_back(
65 {.connection = ZAURA_OUTPUT_CONNECTION_TYPE_UNKNOWN,
66 .device_scale_factor = ZAURA_OUTPUT_SCALE_FACTOR_1000,
67 .geometry = {.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN,
68 .make = "unknown",
69 .model = "unknown",
70 .transform = WL_OUTPUT_TRANSFORM_NORMAL}});
71 globals->outputs.back().output.reset(static_cast<wl_output*>(
72 wl_registry_bind(registry, id, &wl_output_interface, 2)));
73 } else if (strcmp(interface, "zaura_shell") == 0) {
74 if (version >= 2) {
75 globals->aura_shell.reset(static_cast<zaura_shell*>(
76 wl_registry_bind(registry, id, &zaura_shell_interface, 5)));
77 }
78 }
79 }
80
RegistryRemover(void * data,wl_registry * registry,uint32_t id)81 void RegistryRemover(void* data, wl_registry* registry, uint32_t id) {
82 LOG(WARNING) << "Got a registry losing event for " << id;
83 }
84
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)85 void OutputGeometry(void* data,
86 wl_output* output,
87 int x,
88 int y,
89 int physical_width,
90 int physical_height,
91 int subpixel,
92 const char* make,
93 const char* model,
94 int transform) {
95 Info* info = static_cast<Info*>(data);
96
97 info->geometry.x = x;
98 info->geometry.y = y;
99 info->geometry.physical_width = physical_width;
100 info->geometry.physical_height = physical_height;
101 info->geometry.subpixel = subpixel;
102 info->geometry.make = make;
103 info->geometry.model = model;
104 info->geometry.transform = transform;
105 }
106
OutputMode(void * data,wl_output * output,uint32_t flags,int width,int height,int refresh)107 void OutputMode(void* data,
108 wl_output* output,
109 uint32_t flags,
110 int width,
111 int height,
112 int refresh) {
113 Info* info = static_cast<Info*>(data);
114
115 info->next_modes.push_back({flags, width, height, refresh});
116 }
117
OutputDone(void * data,wl_output * output)118 void OutputDone(void* data, wl_output* output) {
119 Info* info = static_cast<Info*>(data);
120
121 std::swap(info->modes, info->next_modes);
122 info->next_modes.clear();
123 std::swap(info->scales, info->next_scales);
124 info->next_scales.clear();
125 }
126
OutputScale(void * data,wl_output * output,int32_t scale)127 void OutputScale(void* data, wl_output* output, int32_t scale) {
128 Info* info = static_cast<Info*>(data);
129
130 info->device_scale_factor = scale * 1000;
131 }
132
AuraOutputScale(void * data,zaura_output * output,uint32_t flags,uint32_t scale)133 void AuraOutputScale(void* data,
134 zaura_output* output,
135 uint32_t flags,
136 uint32_t scale) {
137 Info* info = static_cast<Info*>(data);
138
139 info->next_scales.push_back({flags, scale});
140 }
141
AuraOutputConnection(void * data,zaura_output * output,uint32_t connection)142 void AuraOutputConnection(void* data,
143 zaura_output* output,
144 uint32_t connection) {
145 Info* info = static_cast<Info*>(data);
146
147 info->connection = connection;
148 }
149
AuraOutputDeviceScaleFactor(void * data,zaura_output * output,uint32_t device_scale_factor)150 void AuraOutputDeviceScaleFactor(void* data,
151 zaura_output* output,
152 uint32_t device_scale_factor) {
153 Info* info = static_cast<Info*>(data);
154
155 info->device_scale_factor = device_scale_factor;
156 }
157
OutputSubpixelToString(int32_t subpixel)158 std::string OutputSubpixelToString(int32_t subpixel) {
159 switch (subpixel) {
160 case WL_OUTPUT_SUBPIXEL_UNKNOWN:
161 return "unknown";
162 case WL_OUTPUT_SUBPIXEL_NONE:
163 return "none";
164 case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
165 return "horizontal rgb";
166 case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
167 return "horizontal bgr";
168 case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
169 return "vertical rgb";
170 case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
171 return "vertical bgr";
172 default:
173 return base::StringPrintf("unknown (%d)", subpixel);
174 }
175 }
176
OutputTransformToString(int32_t transform)177 std::string OutputTransformToString(int32_t transform) {
178 switch (transform) {
179 case WL_OUTPUT_TRANSFORM_NORMAL:
180 return "normal";
181 case WL_OUTPUT_TRANSFORM_90:
182 return "90°";
183 case WL_OUTPUT_TRANSFORM_180:
184 return "180°";
185 case WL_OUTPUT_TRANSFORM_270:
186 return "270°";
187 case WL_OUTPUT_TRANSFORM_FLIPPED:
188 return "flipped";
189 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
190 return "flipped 90°";
191 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
192 return "flipped 180°";
193 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
194 return "flipped 270°";
195 default:
196 return base::StringPrintf("unknown (%d)", transform);
197 }
198 }
199
OutputModeFlagsToString(uint32_t flags)200 std::string OutputModeFlagsToString(uint32_t flags) {
201 std::string string;
202 if (flags & WL_OUTPUT_MODE_CURRENT)
203 string += "current ";
204 if (flags & WL_OUTPUT_MODE_PREFERRED)
205 string += "preferred";
206 base::TrimWhitespaceASCII(string, base::TRIM_TRAILING, &string);
207 return string;
208 }
209
AuraOutputScaleFlagsToString(uint32_t flags)210 std::string AuraOutputScaleFlagsToString(uint32_t flags) {
211 std::string string;
212 if (flags & ZAURA_OUTPUT_SCALE_PROPERTY_CURRENT)
213 string += "current ";
214 if (flags & ZAURA_OUTPUT_SCALE_PROPERTY_PREFERRED)
215 string += "preferred";
216 base::TrimWhitespaceASCII(string, base::TRIM_TRAILING, &string);
217 return string;
218 }
219
AuraOutputScaleFactorToString(int32_t scale)220 std::string AuraOutputScaleFactorToString(int32_t scale) {
221 switch (scale) {
222 case ZAURA_OUTPUT_SCALE_FACTOR_0400:
223 case ZAURA_OUTPUT_SCALE_FACTOR_0500:
224 case ZAURA_OUTPUT_SCALE_FACTOR_0550:
225 case ZAURA_OUTPUT_SCALE_FACTOR_0600:
226 case ZAURA_OUTPUT_SCALE_FACTOR_0625:
227 case ZAURA_OUTPUT_SCALE_FACTOR_0650:
228 case ZAURA_OUTPUT_SCALE_FACTOR_0700:
229 case ZAURA_OUTPUT_SCALE_FACTOR_0750:
230 case ZAURA_OUTPUT_SCALE_FACTOR_0800:
231 case ZAURA_OUTPUT_SCALE_FACTOR_0850:
232 case ZAURA_OUTPUT_SCALE_FACTOR_0900:
233 case ZAURA_OUTPUT_SCALE_FACTOR_0950:
234 case ZAURA_OUTPUT_SCALE_FACTOR_1000:
235 case ZAURA_OUTPUT_SCALE_FACTOR_1050:
236 case ZAURA_OUTPUT_SCALE_FACTOR_1100:
237 case ZAURA_OUTPUT_SCALE_FACTOR_1150:
238 case ZAURA_OUTPUT_SCALE_FACTOR_1125:
239 case ZAURA_OUTPUT_SCALE_FACTOR_1200:
240 case ZAURA_OUTPUT_SCALE_FACTOR_1250:
241 case ZAURA_OUTPUT_SCALE_FACTOR_1300:
242 case ZAURA_OUTPUT_SCALE_FACTOR_1400:
243 case ZAURA_OUTPUT_SCALE_FACTOR_1450:
244 case ZAURA_OUTPUT_SCALE_FACTOR_1500:
245 case ZAURA_OUTPUT_SCALE_FACTOR_1600:
246 case ZAURA_OUTPUT_SCALE_FACTOR_1750:
247 case ZAURA_OUTPUT_SCALE_FACTOR_1800:
248 case ZAURA_OUTPUT_SCALE_FACTOR_2000:
249 case ZAURA_OUTPUT_SCALE_FACTOR_2200:
250 case ZAURA_OUTPUT_SCALE_FACTOR_2250:
251 case ZAURA_OUTPUT_SCALE_FACTOR_2500:
252 case ZAURA_OUTPUT_SCALE_FACTOR_2750:
253 case ZAURA_OUTPUT_SCALE_FACTOR_3000:
254 case ZAURA_OUTPUT_SCALE_FACTOR_3500:
255 case ZAURA_OUTPUT_SCALE_FACTOR_4000:
256 case ZAURA_OUTPUT_SCALE_FACTOR_4500:
257 case ZAURA_OUTPUT_SCALE_FACTOR_5000:
258 return base::StringPrintf("%.3f", scale / 1000.0);
259 default:
260 return base::StringPrintf("unknown (%g)", scale / 1000.0);
261 }
262 }
263
AuraOutputConnectionToString(uint32_t connection_type)264 std::string AuraOutputConnectionToString(uint32_t connection_type) {
265 switch (connection_type) {
266 case ZAURA_OUTPUT_CONNECTION_TYPE_UNKNOWN:
267 return "unknown";
268 case ZAURA_OUTPUT_CONNECTION_TYPE_INTERNAL:
269 return "internal";
270 default:
271 return "invalid";
272 }
273 }
274
275 } // namespace
276
main(int argc,char * argv[])277 int main(int argc, char* argv[]) {
278 std::unique_ptr<wl_display> display(wl_display_connect(nullptr));
279 if (!display) {
280 LOG(ERROR) << "Failed to connect to display";
281 return 1;
282 }
283
284 Globals globals;
285
286 wl_registry_listener registry_listener = {RegistryHandler, RegistryRemover};
287 wl_registry* registry = wl_display_get_registry(display.get());
288 wl_registry_add_listener(registry, ®istry_listener, &globals);
289
290 wl_display_roundtrip(display.get());
291
292 wl_output_listener output_listener = {OutputGeometry, OutputMode, OutputDone,
293 OutputScale};
294
295 zaura_output_listener aura_output_listener = {
296 AuraOutputScale, AuraOutputConnection, AuraOutputDeviceScaleFactor};
297 for (auto& info : globals.outputs) {
298 wl_output_add_listener(info.output.get(), &output_listener, &info);
299 if (globals.aura_shell) {
300 info.aura_output.reset(
301 static_cast<zaura_output*>(zaura_shell_get_aura_output(
302 globals.aura_shell.get(), info.output.get())));
303 zaura_output_add_listener(info.aura_output.get(), &aura_output_listener,
304 &info);
305 }
306 }
307
308 wl_display_roundtrip(display.get());
309
310 for (auto& info : globals.outputs) {
311 int id = &info - &globals.outputs[0];
312 if (id)
313 std::cout << std::endl;
314 std::cout << "OUTPUT" << id << ":" << std::endl << std::endl;
315 std::cout << " connection: "
316 << AuraOutputConnectionToString(info.connection) << std::endl;
317 std::cout << " device scale factor: "
318 << AuraOutputScaleFactorToString(info.device_scale_factor)
319 << std::endl
320 << std::endl;
321 std::cout << " geometry:" << std::endl
322 << " x: " << info.geometry.x << std::endl
323 << " y: " << info.geometry.y << std::endl
324 << " physical width: " << info.geometry.physical_width
325 << " mm" << std::endl
326 << " physical height: " << info.geometry.physical_height
327 << " mm" << std::endl
328 << " subpixel: "
329 << OutputSubpixelToString(info.geometry.subpixel) << std::endl
330 << " make: " << info.geometry.make << std::endl
331 << " model: " << info.geometry.model << std::endl
332 << " transform: "
333 << OutputTransformToString(info.geometry.transform) << std::endl
334 << std::endl;
335 std::cout << " modes:" << std::endl;
336 for (auto& mode : info.modes) {
337 std::cout << " " << std::left << std::setw(19)
338 << base::StringPrintf("%dx%d:", mode.width, mode.height)
339 << std::left << std::setw(14)
340 << base::StringPrintf("%.2f Hz", mode.refresh / 1000.0)
341 << OutputModeFlagsToString(mode.flags) << std::endl;
342 }
343 if (!info.scales.empty()) {
344 std::cout << std::endl;
345 std::cout << " scales:" << std::endl;
346 for (auto& scale : info.scales) {
347 std::cout << " " << std::left << std::setw(19)
348 << (AuraOutputScaleFactorToString(scale.scale) + ":")
349 << AuraOutputScaleFlagsToString(scale.flags) << std::endl;
350 }
351 }
352 }
353
354 return 0;
355 }
356