[PATCH V4 7/7] Apps: Add weston-randr application

Quanxian Wang quanxian.wang at intel.com
Thu Apr 24 00:50:11 PDT 2014


Functions implemented in this application
1) Query output mode list
2) Scaling and Transform
   Scale the output to be more than 1.
   Rotate output to be 8 type of angles.
   0, 90, 180, 270, flip-0, flip-90, flip-180, flip-270
3) Mode Set
   Fuzzy set: First matched, first active.
   Exact set:
      a) Exact Timing set
      b) Exact mode number set (select the nth mode from mode list)
4) New a mode of output
   a) newmode for RDP
      RDP developers should add additional newmode backend interface for that.
   b) newtiming for drm backend
5) Delete a mode of output
   All matched, all deleted.
   Fuzzy and exact match are supported as described above
6) Re-position of output
   Primary, auto, leftof, rightof, above, below are supported.
   Primary: let output to the top left most output (x=0, y=0).
   Auto: re-organize all outputs to be horizontal with extended mode.
   leftof: left of relative output. So rightof, above, and below.
7) Support configure file
   Client could put all configure request in one file with
   defined format and submit it from randr interface.
8) Provide a set of actions above in one commit
9) Support multiple outputs operations in configure file

More details, please run "weston-wrandr -h"

Signed-off-by: Quanxian Wang <quanxian.wang at intel.com>
---
 clients/Makefile.am |    9 +
 clients/wrandr.c    | 1314 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1323 insertions(+)
 create mode 100644 clients/wrandr.c

diff --git a/clients/Makefile.am b/clients/Makefile.am
index 6052503..9116b02 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
 
@@ -103,6 +104,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		\
@@ -213,6 +220,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..2409788
--- /dev/null
+++ b/clients/wrandr.c
@@ -0,0 +1,1314 @@
+/*
+ * 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,
+};
+
+#ifndef MOVE_LEFTOF
+enum randr_output_rel_motion {
+	MOVE_LEFTOF,
+	MOVE_RIGHTOF,
+	MOVE_ABOVE,
+	MOVE_BELOW
+};
+#endif
+
+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 timing *timing;
+	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 *timing;
+	char *newmode;
+	char *newtiming;
+	char *delmode;
+	char *config_file;
+	int query;
+	int scale;
+	int transform;
+	int help;
+	int auto_layout;
+	int primary;
+};
+
+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, uint64_t 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("Same as current, No change!\n");
+		break;
+	case WRANDR_TYPE_RET_NOSUPP:
+		printf("Sorry, not supported currently.\n");
+		break;
+	default:
+		printf("Sorry, no results!\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 result1,
+	   uint32_t result2)
+{
+	struct randr *randr = data;
+	struct output *output;
+	uint64_t results = result1 | (uint64_t)result2<<32;
+
+	if (woutput) {
+		output = get_output(randr, woutput);
+	} else {
+		/* Compositor level.*/
+		if (flags)
+			printf("\n*** Compositor ***\n");
+
+		print_line(flags, results,
+			   WRANDR_TYPE_WOP_CONFIGURE,
+			   "Analyze Configure File");
+		print_line(flags, results,
+			   WRANDR_TYPE_WOP_AUTO,
+			   "Auto Layout");
+		running = 0;
+		return;
+	}
+
+	/* Output level.*/
+	if (!output) {
+		printf("No result happens?");
+		return;
+	}
+
+	if (flags)
+		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_TIMING, "TIMING");
+	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_CLONE, "CLONE");
+	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");
+	print_line(flags, results,
+		   WRANDR_TYPE_OOP_PRIMARY, "PRIMARY");
+	print_line(flags, results,
+		   WRANDR_TYPE_OOP_SWITCH, "SWITCH");
+	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"
+		"\t  --auto \tLayout all outputs automatically\n\n"
+		"\t  --output=<output>\n"
+		"\t      --leftof=<output>\n"
+		"\t      --rightof=<output>\n"
+		"\t      --above=<output>\n"
+		"\t      --below=<output>\n"
+		"\t      --primary\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) {
+		fprintf(stderr, "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) {
+			fprintf(stderr, "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) {
+		fprintf(stderr, "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) {
+				fprintf(stderr, "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) {
+		fprintf(stderr, "Failed to get mode!\n");
+		return WRANDR_TYPE_RET_FAIL;
+	}
+
+	return WRANDR_TYPE_RET_SUCCESS;
+}
+
+static int
+verify_timing(struct randr *randr, char *timing)
+{
+	randr->timing = str2timing(timing);
+
+	if (randr->timing == NULL) {
+		fprintf(stderr, "Failed to get timing!\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) {
+		fprintf(stderr, "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) {
+		fprintf(stderr, "%s not exists\n", modestr);
+		return WRANDR_TYPE_RET_FAIL;
+	} else {
+		if (randr->delmode.m_flags &
+		    WL_OUTPUT_MODE_CURRENT) {
+			fprintf(stderr, "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) {
+		fprintf(stderr, "%s not exists\n", modestr);
+		return WRANDR_TYPE_RET_FAIL;
+	} else {
+		if (randr->mode.m_flags &
+		    WL_OUTPUT_MODE_CURRENT) {
+			fprintf(stderr, "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) {
+		fprintf(stderr, "%s not exists\n", output_name);
+		return WRANDR_TYPE_RET_FAIL;
+	} else {
+		if (output == randr->output->output) {
+			fprintf(stderr, "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) {
+		fprintf(stderr, "Scale %d should be great than 0.\n",
+		       scale);
+		return WRANDR_TYPE_RET_FAIL;
+	}
+
+	if (scale == randr->output->scale) {
+		fprintf(stderr, "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) {
+		fprintf(stderr, "Transform %d should be between 0-7.\n",
+		       transform);
+		transform_usage();
+		return WRANDR_TYPE_RET_FAIL;
+	}
+
+	if (transform == randr->output->transform) {
+		fprintf(stderr, "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) {
+			fprintf(stderr, "%s doesn't exist.\n",
+			       argument->config_file);
+			failed = WRANDR_TYPE_RET_FAIL;
+		}
+	}
+
+	if (argument->mode ||
+	    argument->timing ||
+	    argument->newtiming ||
+	    argument->newmode ||
+	    argument->delmode ||
+	    argument->scale != -1 ||
+	    argument->transform != -1 ||
+	    argument->leftof ||
+	    argument->rightof ||
+	    argument->above ||
+	    argument->below ||
+	    argument->primary) {
+		if (!argument->output) {
+			fprintf(stderr, "Output must be defined!\n");
+			return WRANDR_TYPE_RET_FAIL;
+		}
+	}
+
+	if (argument->output && !randr->wayland_output) {
+		fprintf(stderr, "%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->timing) {
+		ret = verify_timing(randr, argument->timing);
+		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_change(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 (randr->timing) {
+		weston_randr_set_timing(randr->randr,
+					randr->wayland_output,
+					randr->timing->clock,
+					randr->timing->hdisplay,
+					randr->timing->hsync_start,
+					randr->timing->hsync_end,
+					randr->timing->htotal,
+					randr->timing->vdisplay,
+					randr->timing->vsync_start,
+					randr->timing->vsync_end,
+					randr->timing->vtotal,
+					randr->timing->vscan,
+					randr->timing->i_flags);
+		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,
+				  MOVE_LEFTOF);
+		ret = RANDR_COMMIT;
+	}
+
+	if (randr->routput) {
+		weston_randr_move(randr->randr,
+				  randr->wayland_output,
+				  randr->routput,
+				  MOVE_RIGHTOF);
+		ret = RANDR_COMMIT;
+	}
+
+	if (randr->aoutput) {
+		weston_randr_move(randr->randr,
+				  randr->wayland_output,
+				  randr->aoutput,
+				  MOVE_ABOVE);
+		ret = RANDR_COMMIT;
+	}
+
+	if (randr->boutput) {
+		weston_randr_move(randr->randr,
+				  randr->wayland_output,
+				  randr->boutput,
+				  MOVE_BELOW);
+		ret = RANDR_COMMIT;
+	}
+
+	if (argument->primary == 1) {
+		weston_randr_primary(randr->randr,
+				     randr->wayland_output);
+		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, NULL,
+				    -1, -1, -1, -1, 0, 0};
+	int ret = 0;
+	int commit = 0;
+
+	const struct weston_option randr_options[] = {
+		{ WESTON_OPTION_BOOLEAN, "query", 'q', &argument.query},
+		{ WESTON_OPTION_STRING, "configure", 0, &argument.config_file},
+		{ WESTON_OPTION_BOOLEAN, "auto", 0, &argument.auto_layout},
+		{ WESTON_OPTION_BOOLEAN, "help", 'h', &argument.help },
+		{ WESTON_OPTION_STRING, "output", 0, &argument.output},
+		{ WESTON_OPTION_STRING, "mode", 0, &argument.mode},
+		{ WESTON_OPTION_STRING, "timing", 0, &argument.timing},
+		{ 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_BOOLEAN, "primary", 0, &argument.primary},
+		{ WESTON_OPTION_INTEGER, "scale", 0, &argument.scale},
+		{ WESTON_OPTION_INTEGER, "transform", 0, &argument.transform},
+	};
+
+	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) {
+		fprintf(stderr, "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 (argument.auto_layout) {
+		weston_randr_auto_layout(randr.randr);
+		commit += 1;
+	}
+
+	if (randr_mode_delnew(&randr, &argument) == RANDR_COMMIT)
+		commit += 1;
+
+	if (randr_change(&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