blob: 4604bbf192c943efea392af431f3f1e5bd79f9e9 [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
23#include <stdbool.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <sys/epoll.h>
28#include <sys/timerfd.h>
29
30#include <wayland-client.h>
31
32#include "../shared/os-compatibility.h"
33
34typedef void (*print_info_t)(void *info);
35
36struct global_info {
37 struct wl_list link;
38
39 uint32_t id;
40 uint32_t version;
41 char *interface;
42
43 print_info_t print;
44};
45
46struct output_info {
47 struct global_info global;
48
49 struct wl_output *output;
50
51 struct {
52 int32_t x, y;
53 int32_t physical_width, physical_height;
54 enum wl_output_subpixel subpixel;
55 enum wl_output_transform output_transform;
56 char *make;
57 char *model;
58 } geometry;
59
60 struct {
61 uint32_t flags;
62 int32_t width, height;
63 int32_t refresh;
64 } mode;
65};
66
67struct shm_format {
68 struct wl_list link;
69
70 uint32_t format;
71};
72
73struct shm_info {
74 struct global_info global;
75 struct wl_shm *shm;
76
77 struct wl_list formats;
78};
79
80struct seat_info {
81 struct global_info global;
82 struct wl_seat *seat;
83
84 uint32_t capabilities;
85};
86
87struct weston_info {
88 struct wl_display *display;
89
90 int epoll_fd;
91 int timer_fd;
92 int display_fd;
93 uint32_t mask;
94
95 struct wl_list infos;
96};
97
98static void
99print_global_info(void *data)
100{
101 struct global_info *global = data;
102
103 printf("interface: '%s', version: %u, name: %u\n",
104 global->interface, global->version, global->id);
105}
106
107static void
108init_global_info(struct weston_info *info,
109 struct global_info *global, uint32_t id,
110 const char *interface, uint32_t version)
111{
112 global->id = id;
113 global->version = version;
114 global->interface = strdup(interface);
115
116 wl_list_insert(info->infos.prev, &global->link);
117}
118
119static void
120print_output_info(void *data)
121{
122 struct output_info *output = data;
123 const char *subpixel_orientation;
124 const char *transform;
125
126 print_global_info(data);
127
128 switch (output->geometry.subpixel) {
129 case WL_OUTPUT_SUBPIXEL_UNKNOWN:
130 subpixel_orientation = "unknown";
131 break;
132 case WL_OUTPUT_SUBPIXEL_NONE:
133 subpixel_orientation = "none";
134 break;
135 case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
136 subpixel_orientation = "horizontal rgb";
137 break;
138 case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
139 subpixel_orientation = "horizontal bgr";
140 break;
141 case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
142 subpixel_orientation = "vertical rgb";
143 break;
144 case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
145 subpixel_orientation = "vertical bgr";
146 break;
147 default:
148 fprintf(stderr, "unknown subpixel orientation %u\n",
149 output->geometry.subpixel);
150 subpixel_orientation = "unexpected value";
151 break;
152 }
153
154 switch (output->geometry.output_transform) {
155 case WL_OUTPUT_TRANSFORM_NORMAL:
156 transform = "normal";
157 break;
158 case WL_OUTPUT_TRANSFORM_90:
159 transform = "90°";
160 break;
161 case WL_OUTPUT_TRANSFORM_180:
162 transform = "180°";
163 break;
164 case WL_OUTPUT_TRANSFORM_270:
165 transform = "270°";
166 break;
167 case WL_OUTPUT_TRANSFORM_FLIPPED:
168 transform = "flipped";
169 break;
170 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
171 transform = "flipped 90°";
172 break;
173 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
174 transform = "flipped 180°";
175 break;
176 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
177 transform = "flipped 270°";
178 break;
179 default:
180 fprintf(stderr, "unknown output transform %u\n",
181 output->geometry.output_transform);
182 transform = "unexpected value";
183 break;
184 }
185
186 printf("\tx: %d, y: %d, width: %d px, height %d px,\n",
187 output->geometry.x, output->geometry.y,
188 output->mode.width, output->mode.height);
189 printf("\tphysical_width: %d mm, physical_height: %d mm, refresh: %.f Hz,\n",
190 output->geometry.physical_width,
191 output->geometry.physical_height,
192 (float) output->mode.refresh / 1000);
193 printf("\tmake: '%s', model: '%s',\n",
194 output->geometry.make, output->geometry.model);
195 printf("\tsubpixel_orientation: %s, output_tranform: %s,\n",
196 subpixel_orientation, transform);
197 printf("\tflags:");
198 if (output->mode.flags & WL_OUTPUT_MODE_CURRENT)
199 printf(" current");
200 if (output->mode.flags & WL_OUTPUT_MODE_PREFERRED)
201 printf(" preferred");
202 printf("\n");
203}
204
205static void
206print_shm_info(void *data)
207{
208 struct shm_info *shm = data;
209 struct shm_format *format;
210
211 print_global_info(data);
212
213 printf("\tformats:");
214
215 wl_list_for_each(format, &shm->formats, link)
216 printf(" %s", (format->format == WL_SHM_FORMAT_ARGB8888) ?
217 "ARGB8888" : "XRGB8888");
218
219 printf("\n");
220}
221
222static void
223print_seat_info(void *data)
224{
225 struct seat_info *seat = data;
226
227 print_global_info(data);
228
229 printf("\tcapabilities:");
230
231 if (seat->capabilities & WL_SEAT_CAPABILITY_POINTER)
232 printf(" pointer");
233 if (seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD)
234 printf(" keyboard");
235 if (seat->capabilities & WL_SEAT_CAPABILITY_TOUCH)
236 printf(" touch");
237
238 printf("\n");
239}
240
241static void
242seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
243 enum wl_seat_capability caps)
244{
245 struct seat_info *seat = data;
246 seat->capabilities = caps;
247}
248
249static const struct wl_seat_listener seat_listener = {
250 seat_handle_capabilities,
251};
252
253static void
254add_seat_info(struct weston_info *info, uint32_t id, uint32_t version)
255{
256 struct seat_info *seat = malloc(sizeof *seat);
257
258 init_global_info(info, &seat->global, id, "wl_seat", version);
259 seat->global.print = print_seat_info;
260
261 seat->seat = wl_display_bind(info->display, id, &wl_seat_interface);
262 wl_seat_add_listener(seat->seat, &seat_listener, seat);
263}
264
265static void
266shm_handle_format(void *data, struct wl_shm *wl_shm, uint32_t format)
267{
268 struct shm_info *shm = data;
269 struct shm_format *shm_format = malloc(sizeof *shm_format);
270
271 wl_list_insert(&shm->formats, &shm_format->link);
272 shm_format->format = format;
273}
274
275static const struct wl_shm_listener shm_listener = {
276 shm_handle_format,
277};
278
279static void
280add_shm_info(struct weston_info *info, uint32_t id, uint32_t version)
281{
282 struct shm_info *shm = malloc(sizeof *shm);
283
284 init_global_info(info, &shm->global, id, "wl_shm", version);
285 shm->global.print = print_shm_info;
286 wl_list_init(&shm->formats);
287
288 shm->shm = wl_display_bind(info->display, id, &wl_shm_interface);
289 wl_shm_add_listener(shm->shm, &shm_listener, shm);
290}
291
292static void
293output_handle_geometry(void *data, struct wl_output *wl_output,
294 int32_t x, int32_t y,
295 int32_t physical_width, int32_t physical_height,
296 int32_t subpixel,
297 const char *make, const char *model,
298 int32_t output_transform)
299{
300 struct output_info *output = data;
301
302 output->geometry.x = x;
303 output->geometry.y = y;
304 output->geometry.physical_width = physical_width;
305 output->geometry.physical_height = physical_height;
306 output->geometry.subpixel = subpixel;
307 output->geometry.make = strdup(make);
308 output->geometry.model = strdup(model);
309 output->geometry.output_transform = output_transform;
310}
311
312static void
313output_handle_mode(void *data, struct wl_output *wl_output,
314 uint32_t flags, int32_t width, int32_t height,
315 int32_t refresh)
316{
317 struct output_info *output = data;
318
319 output->mode.flags = flags;
320 output->mode.width = width;
321 output->mode.height = height;
322 output->mode.refresh = refresh;
323}
324
325static const struct wl_output_listener output_listener = {
326 output_handle_geometry,
327 output_handle_mode,
328};
329
330static void
331add_output_info(struct weston_info *info, uint32_t id, uint32_t version)
332{
333 struct output_info *output = malloc(sizeof *output);
334
335 init_global_info(info, &output->global, id, "wl_output", version);
336 output->global.print = print_output_info;
337
338 output->output = wl_display_bind(info->display, id,
339 &wl_output_interface);
340 wl_output_add_listener(output->output, &output_listener,
341 output);
342}
343
344static void
345add_global_info(struct weston_info *info, uint32_t id,
346 const char *interface, uint32_t version)
347{
348 struct global_info *global = malloc(sizeof *global);
349
350 init_global_info(info, global, id, interface, version);
351 global->print = print_global_info;
352}
353
354static void
355global_handler(struct wl_display *display, uint32_t id,
356 const char *interface, uint32_t version, void *data)
357{
358 struct weston_info *info = data;
359
360 if (!strcmp(interface, "wl_seat"))
361 add_seat_info(info, id, version);
362 else if (!strcmp(interface, "wl_shm"))
363 add_shm_info(info, id, version);
364 else if (!strcmp(interface, "wl_output"))
365 add_output_info(info, id, version);
366 else
367 add_global_info(info, id, interface, version);
368}
369
370static void
371print_infos(struct wl_list *infos)
372{
373 struct global_info *info;
374
375 wl_list_for_each(info, infos, link)
376 info->print(info);
377}
378
379static int
380event_mask_update(uint32_t mask, void *data)
381{
382 struct weston_info *info = data;
383
384 info->mask = mask;
385
386 return 0;
387}
388
389enum epoll_source_type {
390 TYPE_DISPLAY,
391 TYPE_TIMERFD
392};
393
394static void
395main_loop(struct weston_info *info)
396{
397 bool running;
398 struct epoll_event ep[16];
399 int i, count;
400 uint32_t tag;
401
402 running = true;
403
404 while (running) {
405 wl_display_flush(info->display);
406
407 count = epoll_wait(info->epoll_fd,
408 ep, ARRAY_LENGTH(ep), -1);
409
410 for (i = 0; i < count; i++) {
411 tag = ep[i].data.u32;
412
413 if (tag == TYPE_DISPLAY) {
414 wl_display_iterate(info->display,
415 info->mask);
416 } else if (tag == TYPE_TIMERFD) {
417 running = false;
418 } else {
419 fprintf(stderr, "unexpected fd type %u\n",
420 tag);
421 abort();
422 }
423 }
424 }
425}
426
427int
428main(int argc, char **argv)
429{
430 struct weston_info info;
431 struct epoll_event ep;
432 struct itimerspec spec;
433
434 info.display = wl_display_connect(NULL);
435 if (!info.display) {
436 fprintf(stderr, "failed to create display: %m\n");
437 return -1;
438 }
439
440 wl_list_init(&info.infos);
441
442 info.epoll_fd = os_epoll_create_cloexec();
443 info.display_fd = wl_display_get_fd(info.display, event_mask_update,
444 &info);
445
446 ep.events = EPOLLIN;
447 ep.data.u32 = TYPE_DISPLAY;
448 epoll_ctl(info.epoll_fd, EPOLL_CTL_ADD, info.display_fd, &ep);
449
450 info.timer_fd = timerfd_create(CLOCK_REALTIME, 0);
451 if (info.timer_fd < 0) {
452 fprintf(stderr, "failed to create timer fd: %m\n");
453 return -1;
454 }
455
456 ep.events = EPOLLIN;
457 ep.data.u32 = TYPE_TIMERFD;
458 epoll_ctl(info.epoll_fd, EPOLL_CTL_ADD, info.timer_fd, &ep);
459
460 wl_display_add_global_listener(info.display,
461 global_handler,
462 &info);
463
464 spec.it_interval.tv_sec = 0;
465 spec.it_interval.tv_nsec = 0;
466 spec.it_value.tv_sec = 0;
467 spec.it_value.tv_nsec = 200 * 1000 * 1000;
468 timerfd_settime(info.timer_fd, 0, &spec, NULL);
469
470 main_loop(&info);
471
472 print_infos(&info.infos);
473
474 return 0;
475}