Signed-off-by: Quanxian Wang <quanxian.w...@intel.com> Reviewed-by: Zhang, Xiong Y <xiong.y.zh...@intel.com> --- clients/Makefile.am | 9 + clients/wrandr.c | 642 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 651 insertions(+) create mode 100644 clients/wrandr.c
diff --git a/clients/Makefile.am b/clients/Makefile.am index 4f8d4a6..cc509e9 100644 --- a/clients/Makefile.am +++ b/clients/Makefile.am @@ -60,6 +60,7 @@ libexec_PROGRAMS = \ weston-desktop-shell \ weston-screenshooter \ $(screensaver) \ + weston-wrandr \ weston-keyboard \ weston-simple-im @@ -101,6 +102,12 @@ libtoytoolkit_la_LIBADD = \ weston_flower_SOURCES = flower.c weston_flower_LDADD = libtoytoolkit.la +weston_wrandr_SOURCES = \ + wrandr.c \ + randr-protocol.c \ + randr-client-protocol.h +weston_wrandr_LDADD = $(CLIENT_LIBS) + weston_screenshooter_SOURCES = \ screenshot.c \ screenshooter-protocol.c \ @@ -211,6 +218,8 @@ BUILT_SOURCES = \ text-cursor-position-protocol.c \ text-protocol.c \ text-client-protocol.h \ + randr-protocol.c \ + randr-client-protocol.h \ input-method-protocol.c \ input-method-client-protocol.h \ desktop-shell-client-protocol.h \ diff --git a/clients/wrandr.c b/clients/wrandr.c new file mode 100644 index 0000000..cc14a8d --- /dev/null +++ b/clients/wrandr.c @@ -0,0 +1,642 @@ +/* + * Copyright © 2011 Benjamin Franzke + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <assert.h> +#include <signal.h> + +#include "randr-client-protocol.h" +#include <wayland-client.h> +#include <wayland-server.h> + +#ifndef HZ +#define HZ 1000 +#endif + +static int running = 1; + +struct randr { + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_randr *randr; + struct wl_list output_list; +}; + +struct mode { + struct wl_list link; + int height; + int width; + int refresh; + uint32_t flags; +}; + +struct output { + struct wl_list link; + struct wl_list mode_list; + struct randr *randr; + struct wl_output *output; + char *name; + int x; + int y; + int physical_width; + int physical_height; + int subpixel; + char *make; + char *model; + int transform; + int scale; + int server_output_id; +}; + +struct argument { + char *output; + char *leftof; + char *rightof; + int query; + int mode; + int transform; +}; + +static void +get_disoutputs(void *data, + struct wl_randr *wl_randr, + const char *output) +{ + running = 0; + printf("%s\n", output); +} + +static void +get_action_done(void *data, + struct wl_randr *wl_randr, + uint32_t flags, + int ret) +{ + char *result; + char *action; + + switch (ret) { + case WL_RANDR_RESULT_FAIL: + result = "Fail"; + break; + case WL_RANDR_RESULT_SUCCESS: + result = "Success"; + break; + case WL_RANDR_RESULT_NOACT: + result = "Same as before, no action happens."; + break; + default: + result = "Success"; + } + + if (flags & (1<<WL_RANDR_ACTION_MOVE)) + action = "MOVING:"; + else if (flags & (1<<WL_RANDR_ACTION_TRANSFORM)) + action = "TRANSFORM:"; + else if (flags & (1<<WL_RANDR_ACTION_MODE)) + action = "MODE:"; + + printf("%s %s\n", action, result); + + running = 0; +} + +static void +get_output_name(void *data, + struct wl_randr *wl_randr, + struct wl_output *output, + const char *name) +{ + struct randr *randr = data; + struct output *randr_output; + + wl_list_for_each(randr_output, &randr->output_list, link) + if (randr_output->output == output) + randr_output->name = strdup(name); +} + +static const struct wl_randr_listener wrandr_listener = { + get_output_name, + get_action_done, + get_disoutputs +}; + +static void +output_handle_geometry(void *data, + struct wl_output *wl_output, + int x, int y, + int physical_width, + int physical_height, + int subpixel, + const char *make, + const char *model, + int transform) +{ + struct output *output = data; + + output->output = wl_output; + output->x = x; + output->y = y; + output->physical_height = physical_height; + output->physical_width = physical_width; + output->subpixel = subpixel; + output->make = strdup(make); + output->model = strdup(model); + output->transform = transform; +} + +static void +output_handle_done(void *data, + struct wl_output *wl_output) +{ +} + +static void +output_handle_scale(void *data, + struct wl_output *wl_output, + int32_t scale) +{ + struct output *output = data; + + output->scale = scale; +} + +static void +output_handle_mode(void *data, + struct wl_output *wl_output, + uint32_t flags, + int width, + int height, + int refresh) +{ + struct output *output = data; + struct mode *mode; + + wl_list_for_each(mode, &output->mode_list, link) { + if (mode->width == width && + mode->height == height && + mode->refresh == refresh) { + if (flags != mode->flags) + mode->flags = flags; + return; + } + } + + mode = (struct mode *)malloc(sizeof(*mode)); + if (!mode) + return; + + mode->width = width; + mode->height = height; + mode->refresh = refresh; + mode->flags = flags; + + wl_list_insert(output->mode_list.prev, &mode->link); +} + +static const struct wl_output_listener output_listener = { + output_handle_geometry, + output_handle_mode, + output_handle_done, + output_handle_scale +}; + +static void +randr_add_output(struct randr *randr, uint32_t id) +{ + struct output *output; + + output = (struct output *)malloc(sizeof(*output)); + if (!output) + return; + + output->randr = randr; + output->scale = 1; + output->name = NULL; + output->output = wl_registry_bind(randr->registry, + id, + &wl_output_interface, + 2); + output->server_output_id = id; + + wl_list_init(&output->mode_list); + wl_list_insert(randr->output_list.prev, &output->link); + + wl_output_add_listener(output->output, &output_listener, output); +} + +static void +mode_destroy(struct mode *mode) +{ + wl_list_remove(&mode->link); + free(mode); +} + +static void +output_destroy(struct output *output) +{ + struct mode *mode; + + wl_list_for_each(mode, &output->mode_list, link) + mode_destroy(mode); + + wl_list_remove(&output->link); + + free(output->name); + free(output->make); + free(output->model); + free(output); +} + +static void +randr_destroy_output(struct randr *randr) +{ + struct output *output; + + wl_list_for_each(output, &randr->output_list, link) + output_destroy(output); +} + +static void +registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, + const char *interface, uint32_t version) +{ + struct randr *randr = data; + + if (strcmp(interface, "wl_randr") == 0) { + randr->randr = wl_registry_bind(registry, id, + &wl_randr_interface, + 1); + wl_randr_add_listener(randr->randr, + &wrandr_listener, randr); + } else if (strcmp(interface, "wl_compositor") == 0) { + randr->compositor = wl_registry_bind(registry, id, + &wl_compositor_interface, + 3); + } else if (strcmp(interface, "wl_output") == 0) { + randr_add_output(randr, id); + } +} + +static void +registry_handle_global_remove(void *data, + struct wl_registry *registry, + uint32_t name) +{ + struct randr *randr = data; + + randr_destroy_output(randr); +} + +static const struct wl_registry_listener registry_listener = { + registry_handle_global, + registry_handle_global_remove +}; + +static void +transform_usage(void) +{ + fprintf(stderr, + " -R (0-7)\n" + " 0: TRANSFORM NORMAL\n" + " 1: TRANSFORM 90\n" + " 2: TRANSFORM 180\n" + " 3: TRANSFORM 270\n" + " 4: TRANSFORM FLIP 0\n" + " 5: TRANSFORM FLIP 90\n" + " 6: TRANSFORM FLIP 180\n" + " 7: TRANSFORM FLIP 270\n"); +} + +static void +usage(int error_code) +{ + fprintf(stderr, "Usage: weston-randr [OPTIONS]\n\n" + " --leftof \tleft output\n" + " --rightof \tright output\n" + " --output \ttarget output\n" + " -q \tquery all outputs\n" + " -m \tthe number of mode to be set" + "(Firstly use -q to get mode list and find number).\n" + " -R \toutput trasform(0-7)\n" + " -h\tThis help text\n\n"); + + transform_usage(); + exit(error_code); +} + +static void +randr_init(struct randr *randr) +{ + wl_list_init(&randr->output_list); + randr->display = wl_display_connect(NULL); + assert(randr->display); + + randr->registry = wl_display_get_registry(randr->display); + wl_registry_add_listener(randr->registry, + ®istry_listener, randr); + + wl_display_dispatch(randr->display); +} + +static void +randr_query(struct randr *randr) +{ + struct output *output; + struct mode *mode; + char *state; + int i; + + wl_list_for_each(output, &randr->output_list, link) { + printf("%s\n", output->name); + i = 1; + + wl_list_for_each(mode, &output->mode_list, link) { + if (mode->flags & WL_OUTPUT_MODE_CURRENT) + state = "(current)"; + else if (mode->flags & WL_OUTPUT_MODE_PREFERRED) + state = "(preferred)"; + else + state = ""; + + printf("%d)%dx%d@%d%s\n", + i++, + mode->width, + mode->height, + (mode->refresh + HZ/2)/HZ, + state); + } + printf("\n"); + } + + wl_randr_get_disoutputs(randr->randr); +} + +static void +randr_set_mode(struct randr *randr, + struct wl_output *wayland_output, + struct output *target_output, int num) +{ + int found = 0; + int i = 0; + struct mode *mode; + + wl_list_for_each(mode, &target_output->mode_list, link) { + i++; + if (i == num) { + found = 1; + break; + } + } + + if (found) { + wl_randr_set_mode(randr->randr, + wayland_output, + mode->width, + mode->height, + mode->refresh); + } else { + printf("Mode parameter exceeds max mode number %d.\n", i); + running = 0; + } +} + +static void +randr_query_mode(struct output *target_output) +{ + struct mode *mode; + char *state; + int i = 1; + + printf("%s\n", target_output->name); + wl_list_for_each(mode, &target_output->mode_list, link) { + if (mode->flags & WL_OUTPUT_MODE_CURRENT) + state = "(current)"; + else if (mode->flags & WL_OUTPUT_MODE_PREFERRED) + state = "(preferred)"; + else + state = ""; + printf("%d)%dx%d@%d%s\n", + i++, + mode->width, + mode->height, + (mode->refresh + HZ/2)/HZ, + state); + } +} + +static int +is_digit(const char *str) +{ + int len = strlen(str); + + while (len > 0) { + if (*str < '0' || *str > '9') + return -1; + str++; + len--; + } + + return 0; +} + +static void +parse_args(struct argument *argument, int argc, char **argv) +{ + int i; + + for (i = 1; i < argc; i++) { + if (strcmp("--output", argv[i]) == 0) { + if ((i + 1) >= argc) { + printf("output should have parameter.\n"); + exit(EXIT_FAILURE); + } + + argument->output = strdup(argv[++i]); + } else if (strcmp("--leftof", argv[i]) == 0) { + if ((i + 1) >= argc) { + printf("leftof should have parameter.\n"); + exit(EXIT_FAILURE); + } + + argument->leftof = strdup(argv[++i]); + } else if (strcmp("--rightof", argv[i]) == 0) { + if ((i + 1) >= argc) { + printf("rightof should have parameter.\n"); + exit(EXIT_FAILURE); + } + + argument->rightof = strdup(argv[++i]); + } else if (strcmp("-q", argv[i]) == 0) + argument->query = 1; + else if (strcmp("-R", argv[i]) == 0) { + if ((i + 1) >= argc) { + printf("-R should have numeric parameter.\n"); + exit(EXIT_FAILURE); + } + + if (is_digit(argv[i + 1]) == 0) { + argument->transform = + atoi(argv[++i]); + if (argument->transform <= 7) + continue; + } + + printf("-R parameter should be numeric(0-7).\n"); + transform_usage(); + exit(EXIT_FAILURE); + } else if (strcmp("-m", argv[i]) == 0) { + if ((i + 1) >= argc) { + printf("-m should have numeric parameter.\n"); + exit(EXIT_FAILURE); + } + + if (is_digit(argv[i + 1]) == 0) { + argument->mode = + atoi(argv[++i]); + continue; + } + + printf("-m parameter should be numeric.\n"); + exit(EXIT_FAILURE); + } else if (strcmp("-h", argv[i]) == 0) + usage(EXIT_SUCCESS); + else + usage(EXIT_FAILURE); + } +} + +int +main(int argc, char **argv) +{ + struct randr randr = { 0 }; + struct argument argument = {NULL, NULL, NULL, -1, -1, -1}; + int ret = 0; + struct output *output, *target_output; + struct wl_output *left_output = NULL; + struct wl_output *right_output = NULL; + struct wl_output *wayland_output = NULL; + + parse_args(&argument, argc, argv); + + randr_init(&randr); + + /* Get output name for every wl_output. */ + wl_list_for_each(output, &randr.output_list, link) { + wl_randr_get_output_name(randr.randr, output->output); + + while (!output->name && ret != -1) + ret = wl_display_dispatch(randr.display); + } + + /* Currently we got the randr handle. */ + if (argument.query > 0) { + randr_query(&randr); + goto wait; + } + + wl_list_for_each(output, &randr.output_list, link) { + if (argument.leftof && + !strcmp(output->name, argument.leftof)) + left_output = output->output; + + if (argument.rightof && + !strcmp(output->name, argument.rightof)) + right_output = output->output; + + if (argument.output && + !strcmp(output->name, argument.output)) { + target_output = output; + wayland_output = output->output; + } + } + + if (!wayland_output) { + printf("%s does not exists or not connected.\n", + argument.output); + goto exit; + } + + if (argument.mode > 0 && target_output) { + randr_set_mode(&randr, + wayland_output, + target_output, + argument.mode); + goto wait; + } + + if (argument.transform >= 0 && wayland_output) { + wl_randr_set_transform(randr.randr, + wayland_output, + argument.transform); + goto wait; + } + + if (argument.leftof && wayland_output) { + if (!left_output) { + printf("%s not exists\n", argument.leftof); + goto exit; + } + + wl_randr_move(randr.randr, + wayland_output, + left_output, + WL_RANDR_MOVE_LEFTOF); + + goto wait; + } + + if (argument.rightof && wayland_output) { + if (!right_output) { + printf("%s not exists\n", argument.rightof); + goto exit; + } + + wl_randr_move(randr.randr, + wayland_output, + right_output, + WL_RANDR_MOVE_RIGHTOF); + + goto wait; + } + + if (target_output) { + /* List modes of target output. */ + randr_query_mode(target_output); + goto exit; + } + +wait: + while (running && ret != -1) + ret = wl_display_dispatch(randr.display); + +exit: + wl_registry_destroy(randr.registry); + wl_display_flush(randr.display); + wl_display_disconnect(randr.display); + + return 0; +} -- 1.8.1.2 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel