blob: df869e3bcdc71d8cddd88927a9617f93353b0e09 [file] [log] [blame]
Philipp Brüschweiler585acb02012-08-15 17:12:00 +02001/*
2 * Copyright © 2012 Philipp Brüschweiler
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
U. Artie Eoff86c68b32014-01-15 13:02:28 -080023#include "config.h"
24
25#include <errno.h>
Philipp Brüschweiler585acb02012-08-15 17:12:00 +020026#include <stdbool.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
Philipp Brüschweiler585acb02012-08-15 17:12:00 +020030
31#include <wayland-client.h>
32
33#include "../shared/os-compatibility.h"
34
35typedef void (*print_info_t)(void *info);
U. Artie Eoff86c68b32014-01-15 13:02:28 -080036typedef void (*destroy_info_t)(void *info);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +020037
38struct global_info {
39 struct wl_list link;
40
41 uint32_t id;
42 uint32_t version;
43 char *interface;
44
45 print_info_t print;
U. Artie Eoff86c68b32014-01-15 13:02:28 -080046 destroy_info_t destroy;
Philipp Brüschweiler585acb02012-08-15 17:12:00 +020047};
48
Philipp Brüschweiler97cb62a2012-08-15 21:57:24 +020049struct output_mode {
50 struct wl_list link;
51
52 uint32_t flags;
53 int32_t width, height;
54 int32_t refresh;
55};
56
Philipp Brüschweiler585acb02012-08-15 17:12:00 +020057struct output_info {
58 struct global_info global;
59
60 struct wl_output *output;
61
62 struct {
63 int32_t x, y;
64 int32_t physical_width, physical_height;
65 enum wl_output_subpixel subpixel;
66 enum wl_output_transform output_transform;
67 char *make;
68 char *model;
69 } geometry;
70
Philipp Brüschweiler97cb62a2012-08-15 21:57:24 +020071 struct wl_list modes;
Philipp Brüschweiler585acb02012-08-15 17:12:00 +020072};
73
74struct shm_format {
75 struct wl_list link;
76
77 uint32_t format;
78};
79
80struct shm_info {
81 struct global_info global;
82 struct wl_shm *shm;
83
84 struct wl_list formats;
85};
86
87struct seat_info {
88 struct global_info global;
89 struct wl_seat *seat;
90
91 uint32_t capabilities;
Rob Bradford14a76012013-05-31 18:09:52 +010092 char *name;
Philipp Brüschweiler585acb02012-08-15 17:12:00 +020093};
94
95struct weston_info {
96 struct wl_display *display;
Kristian Høgsbergfa80e112012-10-10 21:34:26 -040097 struct wl_registry *registry;
Philipp Brüschweiler585acb02012-08-15 17:12:00 +020098
Philipp Brüschweiler585acb02012-08-15 17:12:00 +020099 struct wl_list infos;
Philipp Brüschweilerbb0d4b92012-08-15 21:57:23 +0200100 bool roundtrip_needed;
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200101};
102
Kristian Høgsberg06b16c22013-08-15 14:20:53 -0700103static void *
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800104fail_on_null(void *p)
Kristian Høgsberg06b16c22013-08-15 14:20:53 -0700105{
Kristian Høgsberg06b16c22013-08-15 14:20:53 -0700106 if (p == NULL) {
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800107 fprintf(stderr, "%s: out of memory\n", program_invocation_short_name);
108 exit(EXIT_FAILURE);
Kristian Høgsberg06b16c22013-08-15 14:20:53 -0700109 }
110
111 return p;
112}
113
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800114static void *
115xmalloc(size_t s)
116{
117 return fail_on_null(malloc(s));
118}
119
120static void *
121xzalloc(size_t s)
122{
123 return fail_on_null(calloc(1, s));
124}
125
126static char *
127xstrdup(const char *s)
128{
129 return fail_on_null(strdup(s));
130}
131
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200132static void
133print_global_info(void *data)
134{
135 struct global_info *global = data;
136
137 printf("interface: '%s', version: %u, name: %u\n",
138 global->interface, global->version, global->id);
139}
140
141static void
142init_global_info(struct weston_info *info,
143 struct global_info *global, uint32_t id,
144 const char *interface, uint32_t version)
145{
146 global->id = id;
147 global->version = version;
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800148 global->interface = xstrdup(interface);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200149
150 wl_list_insert(info->infos.prev, &global->link);
151}
152
153static void
154print_output_info(void *data)
155{
156 struct output_info *output = data;
Philipp Brüschweiler97cb62a2012-08-15 21:57:24 +0200157 struct output_mode *mode;
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200158 const char *subpixel_orientation;
159 const char *transform;
160
161 print_global_info(data);
162
163 switch (output->geometry.subpixel) {
164 case WL_OUTPUT_SUBPIXEL_UNKNOWN:
165 subpixel_orientation = "unknown";
166 break;
167 case WL_OUTPUT_SUBPIXEL_NONE:
168 subpixel_orientation = "none";
169 break;
170 case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
171 subpixel_orientation = "horizontal rgb";
172 break;
173 case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
174 subpixel_orientation = "horizontal bgr";
175 break;
176 case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
177 subpixel_orientation = "vertical rgb";
178 break;
179 case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
180 subpixel_orientation = "vertical bgr";
181 break;
182 default:
183 fprintf(stderr, "unknown subpixel orientation %u\n",
184 output->geometry.subpixel);
185 subpixel_orientation = "unexpected value";
186 break;
187 }
188
189 switch (output->geometry.output_transform) {
190 case WL_OUTPUT_TRANSFORM_NORMAL:
191 transform = "normal";
192 break;
193 case WL_OUTPUT_TRANSFORM_90:
194 transform = "90°";
195 break;
196 case WL_OUTPUT_TRANSFORM_180:
197 transform = "180°";
198 break;
199 case WL_OUTPUT_TRANSFORM_270:
200 transform = "270°";
201 break;
202 case WL_OUTPUT_TRANSFORM_FLIPPED:
203 transform = "flipped";
204 break;
205 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
206 transform = "flipped 90°";
207 break;
208 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
209 transform = "flipped 180°";
210 break;
211 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
212 transform = "flipped 270°";
213 break;
214 default:
215 fprintf(stderr, "unknown output transform %u\n",
216 output->geometry.output_transform);
217 transform = "unexpected value";
218 break;
219 }
220
Philipp Brüschweiler97cb62a2012-08-15 21:57:24 +0200221 printf("\tx: %d, y: %d,\n",
222 output->geometry.x, output->geometry.y);
223 printf("\tphysical_width: %d mm, physical_height: %d mm,\n",
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200224 output->geometry.physical_width,
Philipp Brüschweiler97cb62a2012-08-15 21:57:24 +0200225 output->geometry.physical_height);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200226 printf("\tmake: '%s', model: '%s',\n",
227 output->geometry.make, output->geometry.model);
U. Artie Eoffcb0e3572014-04-18 09:30:07 -0700228 printf("\tsubpixel_orientation: %s, output_transform: %s,\n",
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200229 subpixel_orientation, transform);
Philipp Brüschweiler97cb62a2012-08-15 21:57:24 +0200230
231 wl_list_for_each(mode, &output->modes, link) {
232 printf("\tmode:\n");
233
234 printf("\t\twidth: %d px, height: %d px, refresh: %.f Hz,\n",
235 mode->width, mode->height,
236 (float) mode->refresh / 1000);
237
238 printf("\t\tflags:");
239 if (mode->flags & WL_OUTPUT_MODE_CURRENT)
240 printf(" current");
241 if (mode->flags & WL_OUTPUT_MODE_PREFERRED)
242 printf(" preferred");
243 printf("\n");
244 }
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200245}
246
247static void
248print_shm_info(void *data)
249{
250 struct shm_info *shm = data;
251 struct shm_format *format;
252
253 print_global_info(data);
254
255 printf("\tformats:");
256
257 wl_list_for_each(format, &shm->formats, link)
Kristian Høgsberg8b66ebd2013-11-20 13:54:00 -0800258 switch (format->format) {
259 case WL_SHM_FORMAT_ARGB8888:
260 printf(" ARGB8888");
261 break;
262 case WL_SHM_FORMAT_XRGB8888:
263 printf(" XRGB8888");
264 break;
265 case WL_SHM_FORMAT_RGB565:
266 printf(" RGB565");
267 break;
268 default:
269 printf(" unknown(%08x)", format->format);
270 break;
271 }
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200272
273 printf("\n");
274}
275
276static void
277print_seat_info(void *data)
278{
279 struct seat_info *seat = data;
280
281 print_global_info(data);
282
Rob Bradford14a76012013-05-31 18:09:52 +0100283 printf("\tname: %s\n", seat->name);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200284 printf("\tcapabilities:");
285
286 if (seat->capabilities & WL_SEAT_CAPABILITY_POINTER)
287 printf(" pointer");
288 if (seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD)
289 printf(" keyboard");
290 if (seat->capabilities & WL_SEAT_CAPABILITY_TOUCH)
291 printf(" touch");
292
293 printf("\n");
294}
295
296static void
297seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
298 enum wl_seat_capability caps)
299{
300 struct seat_info *seat = data;
301 seat->capabilities = caps;
302}
303
Rob Bradford14a76012013-05-31 18:09:52 +0100304static void
305seat_handle_name(void *data, struct wl_seat *wl_seat,
306 const char *name)
307{
308 struct seat_info *seat = data;
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800309 seat->name = xstrdup(name);
Rob Bradford14a76012013-05-31 18:09:52 +0100310}
311
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200312static const struct wl_seat_listener seat_listener = {
313 seat_handle_capabilities,
Rob Bradford14a76012013-05-31 18:09:52 +0100314 seat_handle_name,
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200315};
316
317static void
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800318destroy_seat_info(void *data)
319{
320 struct seat_info *seat = data;
321
322 wl_seat_destroy(seat->seat);
323
324 if (seat->name != NULL)
325 free(seat->name);
326}
327
328static void
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200329add_seat_info(struct weston_info *info, uint32_t id, uint32_t version)
330{
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800331 struct seat_info *seat = xzalloc(sizeof *seat);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200332
333 init_global_info(info, &seat->global, id, "wl_seat", version);
334 seat->global.print = print_seat_info;
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800335 seat->global.destroy = destroy_seat_info;
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200336
Kristian Høgsbergfa80e112012-10-10 21:34:26 -0400337 seat->seat = wl_registry_bind(info->registry,
Rob Bradford14a76012013-05-31 18:09:52 +0100338 id, &wl_seat_interface, 2);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200339 wl_seat_add_listener(seat->seat, &seat_listener, seat);
Philipp Brüschweilerbb0d4b92012-08-15 21:57:23 +0200340
341 info->roundtrip_needed = true;
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200342}
343
344static void
345shm_handle_format(void *data, struct wl_shm *wl_shm, uint32_t format)
346{
347 struct shm_info *shm = data;
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800348 struct shm_format *shm_format = xzalloc(sizeof *shm_format);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200349
350 wl_list_insert(&shm->formats, &shm_format->link);
351 shm_format->format = format;
352}
353
354static const struct wl_shm_listener shm_listener = {
355 shm_handle_format,
356};
357
358static void
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800359destroy_shm_info(void *data)
360{
361 struct shm_info *shm = data;
362 struct shm_format *format, *tmp;
363
364 wl_list_for_each_safe(format, tmp, &shm->formats, link) {
365 wl_list_remove(&format->link);
366 free(format);
367 }
368
369 wl_shm_destroy(shm->shm);
370}
371
372static void
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200373add_shm_info(struct weston_info *info, uint32_t id, uint32_t version)
374{
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800375 struct shm_info *shm = xzalloc(sizeof *shm);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200376
377 init_global_info(info, &shm->global, id, "wl_shm", version);
378 shm->global.print = print_shm_info;
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800379 shm->global.destroy = destroy_shm_info;
380
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200381 wl_list_init(&shm->formats);
382
Kristian Høgsbergfa80e112012-10-10 21:34:26 -0400383 shm->shm = wl_registry_bind(info->registry,
384 id, &wl_shm_interface, 1);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200385 wl_shm_add_listener(shm->shm, &shm_listener, shm);
Philipp Brüschweilerbb0d4b92012-08-15 21:57:23 +0200386
387 info->roundtrip_needed = true;
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200388}
389
390static void
391output_handle_geometry(void *data, struct wl_output *wl_output,
392 int32_t x, int32_t y,
393 int32_t physical_width, int32_t physical_height,
394 int32_t subpixel,
395 const char *make, const char *model,
396 int32_t output_transform)
397{
398 struct output_info *output = data;
399
400 output->geometry.x = x;
401 output->geometry.y = y;
402 output->geometry.physical_width = physical_width;
403 output->geometry.physical_height = physical_height;
404 output->geometry.subpixel = subpixel;
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800405 output->geometry.make = xstrdup(make);
406 output->geometry.model = xstrdup(model);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200407 output->geometry.output_transform = output_transform;
408}
409
410static void
411output_handle_mode(void *data, struct wl_output *wl_output,
412 uint32_t flags, int32_t width, int32_t height,
413 int32_t refresh)
414{
415 struct output_info *output = data;
Kristian Høgsberg06b16c22013-08-15 14:20:53 -0700416 struct output_mode *mode = xmalloc(sizeof *mode);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200417
Philipp Brüschweiler97cb62a2012-08-15 21:57:24 +0200418 mode->flags = flags;
419 mode->width = width;
420 mode->height = height;
421 mode->refresh = refresh;
422
423 wl_list_insert(output->modes.prev, &mode->link);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200424}
425
426static const struct wl_output_listener output_listener = {
427 output_handle_geometry,
428 output_handle_mode,
429};
430
431static void
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800432destroy_output_info(void *data)
433{
434 struct output_info *output = data;
435 struct output_mode *mode, *tmp;
436
437 wl_output_destroy(output->output);
438
439 if (output->geometry.make != NULL)
440 free(output->geometry.make);
441 if (output->geometry.model != NULL)
442 free(output->geometry.model);
443
444 wl_list_for_each_safe(mode, tmp, &output->modes, link) {
445 wl_list_remove(&mode->link);
446 free(mode);
447 }
448}
449
450static void
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200451add_output_info(struct weston_info *info, uint32_t id, uint32_t version)
452{
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800453 struct output_info *output = xzalloc(sizeof *output);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200454
455 init_global_info(info, &output->global, id, "wl_output", version);
456 output->global.print = print_output_info;
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800457 output->global.destroy = destroy_output_info;
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200458
Philipp Brüschweiler97cb62a2012-08-15 21:57:24 +0200459 wl_list_init(&output->modes);
460
Kristian Høgsbergfa80e112012-10-10 21:34:26 -0400461 output->output = wl_registry_bind(info->registry, id,
462 &wl_output_interface, 1);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200463 wl_output_add_listener(output->output, &output_listener,
464 output);
Philipp Brüschweilerbb0d4b92012-08-15 21:57:23 +0200465
466 info->roundtrip_needed = true;
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200467}
468
469static void
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800470destroy_global_info(void *data)
471{
472}
473
474static void
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200475add_global_info(struct weston_info *info, uint32_t id,
476 const char *interface, uint32_t version)
477{
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800478 struct global_info *global = xzalloc(sizeof *global);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200479
480 init_global_info(info, global, id, interface, version);
481 global->print = print_global_info;
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800482 global->destroy = destroy_global_info;
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200483}
484
485static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -0400486global_handler(void *data, struct wl_registry *registry, uint32_t id,
487 const char *interface, uint32_t version)
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200488{
489 struct weston_info *info = data;
490
491 if (!strcmp(interface, "wl_seat"))
492 add_seat_info(info, id, version);
493 else if (!strcmp(interface, "wl_shm"))
494 add_shm_info(info, id, version);
495 else if (!strcmp(interface, "wl_output"))
496 add_output_info(info, id, version);
497 else
498 add_global_info(info, id, interface, version);
499}
500
Pekka Paalanen0eab05d2013-01-22 14:53:55 +0200501static void
502global_remove_handler(void *data, struct wl_registry *registry, uint32_t name)
503{
504}
505
Kristian Høgsbergfa80e112012-10-10 21:34:26 -0400506static const struct wl_registry_listener registry_listener = {
Pekka Paalanen0eab05d2013-01-22 14:53:55 +0200507 global_handler,
508 global_remove_handler
Kristian Høgsbergfa80e112012-10-10 21:34:26 -0400509};
510
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200511static void
512print_infos(struct wl_list *infos)
513{
514 struct global_info *info;
515
516 wl_list_for_each(info, infos, link)
517 info->print(info);
518}
519
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800520static void
521destroy_info(void *data)
522{
523 struct global_info *global = data;
524
525 global->destroy(data);
526 wl_list_remove(&global->link);
527 free(global->interface);
528 free(data);
529}
530
531static void
532destroy_infos(struct wl_list *infos)
533{
534 struct global_info *info, *tmp;
535 wl_list_for_each_safe(info, tmp, infos, link)
536 destroy_info(info);
537}
538
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200539int
540main(int argc, char **argv)
541{
542 struct weston_info info;
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200543
544 info.display = wl_display_connect(NULL);
545 if (!info.display) {
546 fprintf(stderr, "failed to create display: %m\n");
547 return -1;
548 }
549
550 wl_list_init(&info.infos);
551
Kristian Høgsbergfa80e112012-10-10 21:34:26 -0400552 info.registry = wl_display_get_registry(info.display);
553 wl_registry_add_listener(info.registry, &registry_listener, &info);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200554
Philipp Brüschweilerbb0d4b92012-08-15 21:57:23 +0200555 do {
556 info.roundtrip_needed = false;
557 wl_display_roundtrip(info.display);
558 } while (info.roundtrip_needed);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200559
560 print_infos(&info.infos);
U. Artie Eoff86c68b32014-01-15 13:02:28 -0800561 destroy_infos(&info.infos);
562
563 wl_registry_destroy(info.registry);
564 wl_display_disconnect(info.display);
Philipp Brüschweiler585acb02012-08-15 17:12:00 +0200565
566 return 0;
567}