[PATCH V3 7/7] Apps: Add weston-randr application
Quanxian Wang
quanxian.wang at intel.com
Mon Apr 7 22:03:21 PDT 2014
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.wang at 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
More information about the wayland-devel
mailing list