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,
+                                &registry_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

Reply via email to