Functions implemented in this application 1) Query output mode list 2) Update properties of output (transform, scale, mode setting) 3) Position of output (leftof and rightof are supported.) 4) Custom a mode for output. 5) Delete mode of output. 6) Combination of above 2-5 in one shot.
More details, please run "weston-wrandr -h" Signed-off-by: Quanxian Wang <quanxian.w...@intel.com> --- clients/Makefile.am | 9 + clients/wrandr.c | 1213 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1222 insertions(+) create mode 100644 clients/wrandr.c diff --git a/clients/Makefile.am b/clients/Makefile.am index 4f8d4a6..757dba3 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 = libtoytoolkit.la $(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..57b7e0a --- /dev/null +++ b/clients/wrandr.c @@ -0,0 +1,1213 @@ +/* + * Copyright © 2014 Quanxian Wang + * Copyright © 2014 Intel Corporation + + * 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 <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "randr-client-protocol.h" +#include <wayland-client.h> +#include <wayland-server.h> +#include "../shared/config-parser.h" + +#define NAME_SIZE 64 +#define ARRAY_LENGTH(a) (sizeof(a) / sizeof(a)[0]) + +enum randr_next_action { + RANDR_EXIT = 0, + RANDR_COMMIT = 1, +}; + +static int running = 1; + +struct output; + +struct timing { + int refresh; + uint32_t clock; + int hdisplay; + int hsync_start; + int hsync_end; + int htotal; + int vdisplay; + int vsync_start; + int vsync_end; + int vtotal; + int vscan; + uint32_t i_flags; /* mode information flags */ +}; + +struct mode { + struct wl_list link; + int width; + int height; + int refresh; + uint32_t m_flags; +}; + +struct randr { + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct weston_randr *randr; + struct wl_list output_list; + struct wl_output *loutput; + struct wl_output *routput; + struct wl_output *aoutput; + struct wl_output *boutput; + struct output *output; + struct wl_output *wayland_output; + struct mode mode; + struct mode delmode; + struct mode *newmode; + struct timing *newtiming; + int mode_num; + int delmode_num; +}; + +struct output { + struct wl_list link; + struct wl_list mode_list; + struct wl_output *output; + char name[NAME_SIZE]; + 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; + char *above; + char *below; + char *mode; + char *newmode; + char *newtiming; + char *delmode; + char *config_file; + int query; + int scale; + int transform; + int help; +}; + +enum mode_flag { + M_HSYNCPLUS = 0x1, + M_HSYNCMINUS = 0x2, + M_VSYNCPLUS = 0x4, + M_VSYNCMINUS = 0x8, + M_INTERLACE = 0x10, + M_DBLSCAN = 0x20, + M_CYSNC = 0x40, + M_CSYNCPLUS = 0x80, + M_CSYNCMINUS = 0x100 +}; + +/* Fake randr proto definition for flag */ +const struct modeflag { + char *string; + uint32_t flag; +} mode_flags[] = { + { "+hsync", M_HSYNCPLUS}, + { "-hsync", M_HSYNCMINUS}, + { "+vsync", M_VSYNCPLUS}, + { "-vsync", M_VSYNCMINUS}, + { "interlace", M_INTERLACE}, + { "doublescang", M_DBLSCAN}, + { "csync", M_CYSNC}, + { "+csync", M_CSYNCPLUS}, + { "-csync", M_CSYNCMINUS}, + { NULL, 0} +}; + +static void +str_to_flags(uint32_t *flags, char *flagstr) +{ + char *delims = " ,"; + char *word; + int i; + + /* Get timing flags */ + word = strtok(flagstr, delims); + while (word) { + for (i = 0; mode_flags[i].string; i++) { + if (strcasecmp(word, + mode_flags[i].string) == 0) { + *flags |= mode_flags[i].flag; + break; + } + } + word = strtok(NULL, delims); + } +} + +static void +delete_argument(struct argument *argument) +{ + if (argument->output) + free(argument->output); + + if (argument->leftof) + free(argument->leftof); + + if (argument->rightof) + free(argument->rightof); + + if (argument->newmode) + free(argument->newmode); + + if (argument->newtiming) + free(argument->newtiming); + + if (argument->mode) + free(argument->mode); + + if (argument->delmode) + free(argument->delmode); + + if (argument->config_file) + free(argument->config_file); +} + +static void +print_line(int flags, int results, int flag, char *name) +{ + if (!(flags & 1<<flag)) + return; + + printf("%s:", name); + switch (results>>(flag * 2) & 0x3) { + case WRANDR_TYPE_RET_SUCCESS: + printf("SUCCESS!\n"); + break; + case WRANDR_TYPE_RET_FAIL: + printf("FAIL!\n"); + break; + case WRANDR_TYPE_RET_NOACT: + printf("No change happens!\n"); + break; + default: + printf("No results(not supported?)\n"); + break; + } +} + +static struct output * +get_output(struct randr *randr, + struct wl_output *woutput) +{ + struct output *output; + + wl_list_for_each(output, &randr->output_list, link) { + if (output->output == woutput) + return output; + } + + return NULL; +} + +static void +randr_done(void *data, + struct wrandr_callback *callback, + struct wl_output *woutput, + uint32_t flags, + uint32_t results) +{ + struct randr *randr = data; + struct output *output; + + if (woutput) { + output = get_output(randr, woutput); + } else { + /* Compositor level.*/ + print_line(flags, results, + WRANDR_TYPE_WOP_CONFIGURE, + "Configure File"); + return; + } + + /* Output level.*/ + if (!output) { + printf("No result happens?"); + return; + } + + printf("*** OUTPUT: %s ***\n", output->name); + + print_line(flags, results, + WRANDR_TYPE_OOP_MODENUM, "MODE NUM SET"); + print_line(flags, results, + WRANDR_TYPE_OOP_MODE, "MODE"); + print_line(flags, results, + WRANDR_TYPE_OOP_SCALE, "SCALE"); + print_line(flags, results, + WRANDR_TYPE_OOP_TRANSFORM, "TRANSFORM"); + print_line(flags, results, + WRANDR_TYPE_OOP_MOVEL, "MOVE LEFT"); + print_line(flags, results, + WRANDR_TYPE_OOP_MOVER, "MOVE RIGHT"); + print_line(flags, results, + WRANDR_TYPE_OOP_MOVEA, "MOVE ABOVE"); + print_line(flags, results, + WRANDR_TYPE_OOP_MOVEB, "MOVE BELOW"); + print_line(flags, results, + WRANDR_TYPE_OOP_NEWMODE, "NEWMODE"); + print_line(flags, results, + WRANDR_TYPE_OOP_NEWTIMING, "NEWTIMING"); + print_line(flags, results, + WRANDR_TYPE_OOP_DELMODENUM, "DELMODE"); + print_line(flags, results, + WRANDR_TYPE_OOP_DELMODE, "DELMODE"); + running = 0; +} + +static const struct wrandr_callback_listener wrandr_cb_listener = { + randr_done +}; + +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_name(void *data, + struct wl_output *wl_output, + const char *name) +{ + struct output *output = data; + int len = 0; + + if (name) { + len = strlen(name) > (NAME_SIZE - 1) ? + (NAME_SIZE - 1) : strlen(name); + strncpy(output->name, name, len); + output->name[len] = '\0'; + } +} + +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->m_flags) + mode->m_flags = flags; + return; + } + } + + mode = (struct mode *)malloc(sizeof(*mode)); + if (!mode) + return; + + mode->width = width; + mode->height = height; + mode->refresh = refresh; + mode->m_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, + output_handle_name +}; + +static void +randr_add_output(struct randr *randr, uint32_t id) +{ + struct output *output; + + output = (struct output *)malloc(sizeof(*output)); + if (!output) + return; + memset(output, 0x0, sizeof(*output)); + + output->scale = 1; + strcpy(output->name, "UNKNOWN"); + + output->server_output_id = id; + output->output = wl_registry_bind(randr->registry, + id, + &wl_output_interface, + 2); + + 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->make); + free(output->model); + free(output); +} + +static void +randr_destroy(struct randr *randr) +{ + struct output *output; + + wl_list_for_each(output, &randr->output_list, link) + output_destroy(output); + + if (randr->newmode) + free(randr->newmode); + + if (randr->newtiming) + free(randr->newtiming); +} + +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, "weston_randr") == 0) { + randr->randr = wl_registry_bind(registry, id, + &weston_randr_interface, + 1); + } 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(randr); +} + +static const struct wl_registry_listener registry_listener = { + registry_handle_global, + registry_handle_global_remove +}; + +static void +transform_usage(void) +{ + fprintf(stderr, + "\t Transform Value\n" + "\t --transform (0-7)\n" + "\t 0: TRANSFORM NORMAL\n" + "\t 1: TRANSFORM 90\n" + "\t 2: TRANSFORM 180\n" + "\t 3: TRANSFORM 270\n" + "\t 4: TRANSFORM FLIP 0\n" + "\t 5: TRANSFORM FLIP 90\n" + "\t 6: TRANSFORM FLIP 180\n" + "\t 7: TRANSFORM FLIP 270\n"); +} + +static void +mode_format(void) +{ + fprintf(stderr, + "\n\t <Timing Format>\n" + "\t <clock kHz>," + "<hdispay>,<hsync_start>,<hsync_end>,<htotal>," + "<vdispay>,<vsync_start>,<vsync_end>,<vtotal>,<vscan>,<flags>\n" + "\t [flags...]\n" + "\t Valid flags: +hsync -hsync +vsync -vsync\n" + "\t +csync -csync csync interlace doublescan\n" + "\t Complete format is like 'd,d,d,d,d,d,d,d,d,d,s'" + "(d:digit, s:string)\n"); +} +static void +usage(int error_code) +{ + + fprintf(stderr, "Usage: weston-randr [OPTIONS]\n\n" + "\t -q|--query \tquery modes\n" + "\t -h|--help \tThis help text\n\n" + "\t --output=<output>\n" + "\t --leftof=<output>\n" + "\t --rightof=<output>\n" + "\t --mode=<mode num>\n" + "\t --timing=<timing format>\n" + "\t --scale=<scale num>\n" + "\t --transform=<transform num>\n" + "\t --newmode='widthxheight[@refresh]'\n" + "\t --newtiming='<timing format>'\n" + "\t --delmode='<mode num>'\n" + "\t --deltiming=<timing format>\n"); + + fprintf(stderr, "\nAppendix A:\n"); + transform_usage(); + fprintf(stderr, "\nAppendix B:\n"); + mode_format(); + + 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 struct mode * +str2mode(char *modestr) +{ + struct mode *mode; + int width = -1, height = -1, refresh = -1; + + mode = (struct mode *)malloc(sizeof(*mode)); + if (mode == NULL) { + printf("No Memory is available\n"); + return NULL; + } + memset(mode, 0x0, sizeof(*mode)); + + if (sscanf(modestr, "%dx%d@%d", &width, &height, &refresh) != 3) { + if (sscanf(modestr, "%dx%d", &width, &height) != 2) { + printf("Error formatting for mode.\n"); + return NULL; + } + } + + mode->width = width; + mode->height = height; + mode->refresh = refresh < 0 ? 0 : refresh; + return mode; +} + +static struct timing * +str2timing(char *timing_str) +{ + struct timing *timing; + char flagstr[128]; + + timing = (struct timing *)malloc(sizeof(*timing)); + if (timing == NULL) { + printf("No Memory is available\n"); + return NULL; + } + memset(timing, 0x0, sizeof(*timing)); + + if (sscanf(timing_str, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%[^*]", + &timing->clock, + &timing->hdisplay, + &timing->hsync_start, + &timing->hsync_end, + &timing->htotal, + &timing->vdisplay, + &timing->vsync_start, + &timing->vsync_end, + &timing->vtotal, + &timing->vscan, + flagstr) != 11) { + fprintf(stderr, "Invalid format!\n"); + mode_format(); + return NULL; + } + + /* Get timing flags */ + str_to_flags(&timing->i_flags, flagstr); + + return timing; +} + +#define set_mode(first, second) \ + do {\ + first->width = second->width;\ + first->height = second->height;\ + first->m_flags = second->m_flags;\ + } while (0) + +static void +find_mode(struct randr *randr, + const char *modestr, + int del) +{ + int width = -1, height = -1, refresh = -1; + int num = -1; + int i = 0; + struct mode *mode = NULL; + struct mode *target_mode; + int *target_num; + + if (sscanf(modestr, "%dx%d@%d", &width, &height, &refresh) != 3) { + if (sscanf(modestr, "%dx%d", &width, &height) != 2) { + if (sscanf(modestr, "%d", &num) != 1) { + printf("Error formatting for mode.\n"); + return; + } + } + } + + target_mode = del == 1 ? &randr->delmode : &randr->mode; + target_num = del == 1 ? &randr->delmode_num : &randr->mode_num; + + if (num > 0) { + wl_list_for_each(mode, &randr->output->mode_list, link) { + i++; + if (i != num) + continue; + *target_num = num; + target_mode->m_flags = mode->m_flags; + break; + } + return; + } + + if (height <= 0) + return; + + target_mode->refresh = refresh < 0 ? 0 : refresh; + + wl_list_for_each(mode, &randr->output->mode_list, link) { + if (mode->width == width && + mode->height == height && + (refresh <= 0 || + mode->refresh == refresh)) { + if (mode->m_flags & WL_OUTPUT_MODE_CURRENT) { + set_mode(target_mode, mode); + break; + } + + if (target_mode->width <= 0) + set_mode(target_mode, mode); + } + } +} + +static void +get_output_handle(struct randr *randr, + struct argument *argument) +{ + struct output *output; + + /* Get all output handles. */ + wl_list_for_each(output, &randr->output_list, link) { + if (argument->leftof && + !strcmp(output->name, argument->leftof)) { + randr->loutput = output->output; + } + + if (argument->rightof && + !strcmp(output->name, argument->rightof)) { + randr->routput = output->output; + } + + if (argument->above && + !strcmp(output->name, argument->above)) { + randr->aoutput = output->output; + } + + if (argument->below && + !strcmp(output->name, argument->below)) { + randr->boutput = output->output; + } + + if (argument->output && + !strcmp(output->name, argument->output)) { + randr->output = output; + randr->wayland_output = output->output; + } + } +} + +static int +verify_newmode(struct randr *randr, char *newmode) +{ + randr->newmode = str2mode(newmode); + + if (randr->newmode == NULL) { + printf("Failed to get mode!\n"); + return WRANDR_TYPE_RET_FAIL; + } + + return WRANDR_TYPE_RET_SUCCESS; +} + +static int +verify_newtiming(struct randr *randr, char *newtiming) +{ + randr->newtiming = str2timing(newtiming); + + if (randr->newtiming == NULL) { + printf("Failed to get timing!\n"); + return WRANDR_TYPE_RET_FAIL; + } + + return WRANDR_TYPE_RET_SUCCESS; +} + +static int +verify_delmode(struct randr *randr, char *modestr) +{ + find_mode(randr, modestr, 1); + + if (randr->delmode_num <= 0 && randr->delmode.width <= 0) { + printf("%s not exists\n", modestr); + return WRANDR_TYPE_RET_FAIL; + } else { + if (randr->delmode.m_flags & + WL_OUTPUT_MODE_CURRENT) { + printf("Could not delete active mode %s.\n", + modestr); + + return WRANDR_TYPE_RET_FAIL; + } + } + + return WRANDR_TYPE_RET_SUCCESS; +} + +static int +verify_mode(struct randr *randr, char *modestr) +{ + find_mode(randr, modestr, 0); + + if (randr->mode_num <= 0 && randr->mode.width <= 0) { + printf("%s not exists\n", modestr); + return WRANDR_TYPE_RET_FAIL; + } else { + if (randr->mode.m_flags & + WL_OUTPUT_MODE_CURRENT) { + printf("The mode %s has been current.\n", + modestr); + + return WRANDR_TYPE_RET_FAIL; + } + } + + return WRANDR_TYPE_RET_SUCCESS; +} + +static int +verify_move_output(struct randr *randr, + struct wl_output *output, + char *output_name) +{ + if (!output) { + printf("%s not exists\n", output_name); + return WRANDR_TYPE_RET_FAIL; + } else { + if (output == randr->output->output) { + printf("Two outputs are same!\n"); + return WRANDR_TYPE_RET_FAIL; + } + } + + return WRANDR_TYPE_RET_SUCCESS; +} + +static int +verify_scale(struct randr *randr, int scale) +{ + if (scale <= 0) { + printf("Scale %d should be great than 0.\n", + scale); + return WRANDR_TYPE_RET_FAIL; + } + + if (scale == randr->output->scale) { + printf("Scale %d has been current.\n", + scale); + return WRANDR_TYPE_RET_FAIL; + } + + return WRANDR_TYPE_RET_SUCCESS; +} + +static int +verify_transform(struct randr *randr, int transform) +{ + if (transform < 0 || transform > 7) { + printf("Transform %d should be between 0-7.\n", + transform); + transform_usage(); + return WRANDR_TYPE_RET_FAIL; + } + + if (transform == randr->output->transform) { + printf("Transform %d has been current.\n", + transform); + return WRANDR_TYPE_RET_FAIL; + } + + return WRANDR_TYPE_RET_SUCCESS; +} + +static int +verify_params(struct randr *randr, + struct argument *argument) +{ + int ret; + int failed = WRANDR_TYPE_RET_SUCCESS; + struct stat buffer; + + /* Verify output paramerters */ + if (argument->config_file) { + ret = stat(argument->config_file, &buffer); + if (ret != 0) { + printf("%s doesn't exist.\n", + argument->config_file); + failed = WRANDR_TYPE_RET_FAIL; + } + } + + if (!argument->output) { + if (!argument->query) + printf("Output must be defined!\n"); + return WRANDR_TYPE_RET_FAIL; + } else { + if (argument->output && !randr->wayland_output) { + printf("%s doesn't exists or not connected.\n", + argument->output); + + /* Others depend on this parameter */ + return WRANDR_TYPE_RET_FAIL; + } + } + + if (argument->newmode) { + ret = verify_newmode(randr, argument->newmode); + if (ret == WRANDR_TYPE_RET_FAIL) + failed = WRANDR_TYPE_RET_FAIL; + } + + if (argument->newtiming) { + ret = verify_newtiming(randr, argument->newtiming); + if (ret == WRANDR_TYPE_RET_FAIL) + failed = WRANDR_TYPE_RET_FAIL; + } + + if (argument->mode) { + ret = verify_mode(randr, argument->mode); + if (ret == WRANDR_TYPE_RET_FAIL) + failed = WRANDR_TYPE_RET_FAIL; + } + + if (argument->delmode) { + ret = verify_delmode(randr, argument->delmode); + if (ret == WRANDR_TYPE_RET_FAIL) + failed = WRANDR_TYPE_RET_FAIL; + } + + if (argument->leftof) { + ret = verify_move_output(randr, + randr->loutput, + argument->leftof); + if (ret == WRANDR_TYPE_RET_FAIL) + failed = WRANDR_TYPE_RET_FAIL; + } + + if (argument->rightof) { + ret = verify_move_output(randr, + randr->routput, + argument->rightof); + if (ret == WRANDR_TYPE_RET_FAIL) + failed = WRANDR_TYPE_RET_FAIL; + } + + if (argument->above) { + ret = verify_move_output(randr, + randr->aoutput, + argument->above); + if (ret == WRANDR_TYPE_RET_FAIL) + failed = WRANDR_TYPE_RET_FAIL; + } + + if (argument->below) { + ret = verify_move_output(randr, + randr->boutput, + argument->below); + if (ret == WRANDR_TYPE_RET_FAIL) + failed = WRANDR_TYPE_RET_FAIL; + } + + if (argument->scale != -1) { + ret = verify_scale(randr, argument->scale); + if (ret == WRANDR_TYPE_RET_FAIL) + failed = WRANDR_TYPE_RET_FAIL; + } + + if (argument->transform != -1) { + ret = verify_transform(randr, argument->transform); + if (ret == WRANDR_TYPE_RET_FAIL) + failed = WRANDR_TYPE_RET_FAIL; + } + + return failed; +} + +static void +output_printmodes(struct output *output) +{ + struct mode *mode; + char *state; + int i = 1; + + printf("\n*** OUTPUT: %s ***\n\n", output->name); + wl_list_for_each(mode, &output->mode_list, link) { + if (mode->m_flags & WL_OUTPUT_MODE_CURRENT) + state = "(current)"; + else if (mode->m_flags & WL_OUTPUT_MODE_PREFERRED) + state = "(preferred)"; + else + state = ""; + + printf("%d)%dx%d@%d%s\n", + i++, + mode->width, + mode->height, + mode->refresh, + state); + } +} + +static void +all_printmodes(struct randr *randr) +{ + struct output *output; + + wl_list_for_each(output, &randr->output_list, link) { + output_printmodes(output); + printf("\n"); + } +} + +static void +randr_query(struct randr *randr, + struct argument *argument) +{ + if (argument->query > 0) { + if (randr->output) + output_printmodes(randr->output); + else + all_printmodes(randr); + } +} + +static int +randr_mode_delnew(struct randr *randr, + struct argument *argument) +{ + int ret = RANDR_EXIT; + + if (randr->delmode_num > 0) { + weston_randr_delmodenum(randr->randr, + randr->wayland_output, + randr->delmode_num); + ret = RANDR_COMMIT; + } else if (randr->delmode.width > 0) { + weston_randr_delmode(randr->randr, + randr->wayland_output, + randr->delmode.width, + randr->delmode.height, + randr->delmode.refresh); + ret = RANDR_COMMIT; + } + + if (randr->newmode) { + weston_randr_newmode(randr->randr, + randr->wayland_output, + randr->newmode->width, + randr->newmode->height, + randr->newmode->refresh); + ret = RANDR_COMMIT; + } + + if (randr->newtiming) { + weston_randr_newtiming(randr->randr, + randr->wayland_output, + randr->newtiming->clock, + randr->newtiming->hdisplay, + randr->newtiming->hsync_start, + randr->newtiming->hsync_end, + randr->newtiming->htotal, + randr->newtiming->vdisplay, + randr->newtiming->vsync_start, + randr->newtiming->vsync_end, + randr->newtiming->vtotal, + randr->newtiming->vscan, + randr->newtiming->i_flags); + + ret = RANDR_COMMIT; + } + + return ret; +} + +static int +randr_modeset(struct randr *randr, + struct argument *argument) +{ + int ret = RANDR_EXIT; + + if (randr->mode_num > 0) { + weston_randr_set_modenum(randr->randr, + randr->wayland_output, + randr->mode_num); + ret = RANDR_COMMIT; + } else if (randr->mode.width > 0) { + weston_randr_set_mode(randr->randr, + randr->wayland_output, + randr->mode.width, + randr->mode.height, + randr->mode.refresh); + ret = RANDR_COMMIT; + } + + if (argument->scale != -1) { + weston_randr_set_scale(randr->randr, + randr->wayland_output, + argument->scale); + ret = RANDR_COMMIT; + } + + if (argument->transform >= 0) { + weston_randr_set_transform(randr->randr, + randr->wayland_output, + argument->transform); + ret = RANDR_COMMIT; + + } + + if (randr->loutput) { + weston_randr_move(randr->randr, + randr->wayland_output, + randr->loutput, + WESTON_RANDR_MOVE_LEFTOF); + ret = RANDR_COMMIT; + } + + if (randr->routput) { + weston_randr_move(randr->randr, + randr->wayland_output, + randr->routput, + WESTON_RANDR_MOVE_RIGHTOF); + ret = RANDR_COMMIT; + } + + if (randr->aoutput) { + weston_randr_move(randr->randr, + randr->wayland_output, + randr->aoutput, + WESTON_RANDR_MOVE_ABOVE); + ret = RANDR_COMMIT; + } + + if (randr->boutput) { + weston_randr_move(randr->randr, + randr->wayland_output, + randr->boutput, + WESTON_RANDR_MOVE_BELOW); + ret = RANDR_COMMIT; + } + + return ret; +} + +static void +randr_commit(struct randr *randr, + struct wl_output *wayland_output) +{ + struct wrandr_callback *callback = + weston_randr_commit(randr->randr); + + wrandr_callback_add_listener(callback, + &wrandr_cb_listener, randr); +} + +int +main(int argc, char **argv) +{ + struct randr randr = { 0 }; + struct argument argument = {NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, + -1, -1, -1, -1}; + int ret = 0; + int commit = 0; + + const struct weston_option randr_options[] = { + { WESTON_OPTION_BOOLEAN, "query", 'q', &argument.query}, + { WESTON_OPTION_STRING, "output", 0, &argument.output}, + { WESTON_OPTION_BOOLEAN, "help", 'h', &argument.help }, + { WESTON_OPTION_STRING, "mode", 0, &argument.mode}, + { WESTON_OPTION_STRING, "newmode", 0, &argument.newmode}, + { WESTON_OPTION_STRING, "newtiming", 0, &argument.newtiming}, + { WESTON_OPTION_STRING, "delmode", 0, &argument.delmode}, + { WESTON_OPTION_STRING, "leftof", 0, &argument.leftof}, + { WESTON_OPTION_STRING, "rightof", 0, &argument.rightof}, + { WESTON_OPTION_STRING, "above", 0, &argument.above}, + { WESTON_OPTION_STRING, "below", 0, &argument.below}, + { WESTON_OPTION_INTEGER, "scale", 0, &argument.scale}, + { WESTON_OPTION_INTEGER, "transform", 0, &argument.transform}, + { WESTON_OPTION_BOOLEAN, "configure", 0, &argument.config_file}, + }; + + parse_options(randr_options, ARRAY_LENGTH(randr_options), &argc, argv); + + if (argument.help > 0) + usage(EXIT_SUCCESS); + + randr_init(&randr); + + wl_display_roundtrip(randr.display); + + /* Check if weston_randr is enable or not. */ + if (!randr.randr) { + printf("Weston randr interface isn't available.\n"); + goto exit; + } + + get_output_handle(&randr, &argument); + + randr_query(&randr, &argument); + + if (verify_params(&randr, &argument) == + WRANDR_TYPE_RET_FAIL) + goto exit; + + if (argument.config_file) { + weston_randr_configure(randr.randr, argument.config_file); + commit += 1; + } + + if (randr_mode_delnew(&randr, &argument) == RANDR_COMMIT) + commit += 1; + + if (randr_modeset(&randr, &argument) == RANDR_COMMIT) + commit += 1; + + if (commit > 0) { + randr_commit(&randr, + randr.wayland_output); + } else + goto exit; + + while (running && ret != -1) + ret = wl_display_dispatch(randr.display); + +exit: + delete_argument(&argument); + 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