[PATCH V4 5/7] weston:Add the weston randr protocol implementation

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


Signed-off-by: Quanxian Wang <quanxian.wang at intel.com>
---
 module/Makefile.am                     |    3 +
 module/wrandr/Makefile.am              |   37 +
 module/wrandr/monitors.txt             |   19 +
 module/wrandr/randr_layout_algorithm.c |  693 ++++++++++++
 module/wrandr/randr_layout_algorithm.h |  217 ++++
 module/wrandr/randr_parser.c           |  169 +++
 module/wrandr/randr_parser.h           |   57 +
 module/wrandr/wrandr.c                 | 1915 ++++++++++++++++++++++++++++++++
 module/wrandr/wrandr.h                 |  133 +++
 9 files changed, 3243 insertions(+)
 create mode 100644 module/Makefile.am
 create mode 100644 module/wrandr/Makefile.am
 create mode 100644 module/wrandr/monitors.txt
 create mode 100644 module/wrandr/randr_layout_algorithm.c
 create mode 100644 module/wrandr/randr_layout_algorithm.h
 create mode 100644 module/wrandr/randr_parser.c
 create mode 100644 module/wrandr/randr_parser.h
 create mode 100644 module/wrandr/wrandr.c
 create mode 100644 module/wrandr/wrandr.h

diff --git a/module/Makefile.am b/module/Makefile.am
new file mode 100644
index 0000000..1a10e65
--- /dev/null
+++ b/module/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS =
+
+SUBDIRS += wrandr
diff --git a/module/wrandr/Makefile.am b/module/wrandr/Makefile.am
new file mode 100644
index 0000000..1a604e9
--- /dev/null
+++ b/module/wrandr/Makefile.am
@@ -0,0 +1,37 @@
+moduledir = $(libdir)/weston
+module_LTLIBRARIES = $(wrandr)
+
+AM_CPPFLAGS =					\
+	-I$(top_srcdir)/shared			\
+	-I$(top_srcdir)/src			\
+	-I$(top_builddir)/src			\
+	-DDATADIR='"$(datadir)"'		\
+	-DMODULEDIR='"$(moduledir)"'		\
+	-DLIBEXECDIR='"$(libexecdir)"'		\
+	-DIN_WESTON
+
+if BUILD_WRANDR
+wrandr = wrandr.la
+wrandr_la_LDFLAGS = -module -avoid-version
+wrandr_la_LIBADD = $(COMPOSITOR_LIBS)	\
+	$(top_srcdir)/shared/libshared.la
+wrandr_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
+wrandr_la_SOURCES =			\
+	wrandr.c				\
+	wrandr.h				\
+	randr_parser.c				\
+	randr_parser.h				\
+	randr_layout_algorithm.c		\
+	randr_layout_algorithm.h		\
+	randr-protocol.c			\
+	randr-server-protocol.h
+endif
+
+BUILT_SOURCES =					\
+	randr-protocol.c			\
+	randr-server-protocol.h
+
+CLEANFILES = $(BUILT_SOURCES)
+
+wayland_protocoldir = $(top_srcdir)/protocol
+include $(top_srcdir)/wayland-scanner.mk
diff --git a/module/wrandr/monitors.txt b/module/wrandr/monitors.txt
new file mode 100644
index 0000000..4b1f451
--- /dev/null
+++ b/module/wrandr/monitors.txt
@@ -0,0 +1,19 @@
+[compositor]
+auto=1
+
+[HDMI3]
+#timing=40000,800,840,968,1056,600,601,605,628,0,+hsync
+#clone=VGA1
+#primary=1
+rightof=VGA1
+mode=2
+transform=1
+scale=2
+[VGA1]
+#primary=1
+#mode=1024x768
+#switch=1
+#clone=HDMI3
+mode=2
+transform=1
+scale=2
diff --git a/module/wrandr/randr_layout_algorithm.c b/module/wrandr/randr_layout_algorithm.c
new file mode 100644
index 0000000..56e40a8
--- /dev/null
+++ b/module/wrandr/randr_layout_algorithm.c
@@ -0,0 +1,693 @@
+/*
+ * 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 "randr_layout_algorithm.h"
+
+/* Output layout algorithm */
+
+/* The function will move parent's vlink
+ * to child's vlink until hlink child is null.
+ */
+
+void
+node_repos_hlink(randr_node *node)
+{
+	randr_node *vchild;
+	randr_node *hchild;
+	randr_node *parent;
+
+	if (node->hlink.prev) {
+		parent = container_of(node->hlink.prev,
+				      randr_node, hlink);
+	} else if (node->vlink.prev) {
+		parent = container_of(node->vlink.prev,
+				      randr_node, vlink);
+	} else
+		return;
+
+	if (node->hlink.next) {
+		/* Continue its hlink child */
+		hchild = container_of(node->hlink.next,
+				      randr_node, hlink);
+		node_repos_hlink(hchild);
+	} else if (node->vlink.next) {
+		/* This part will turn node vlink
+		 * to hlink based on the rule.
+		 */
+		vchild = container_of(node->vlink.next,
+				      randr_node, vlink);
+		node->hlink.next = &vchild->hlink;
+		vchild->hlink.prev = &node->hlink;
+		vchild->vlink.prev = NULL;
+		node->vlink.next = NULL;
+	}
+
+	/* Output's vlink is null and
+	 * move parent vlink to node's vlink,
+	 * vlink of child has been moved to
+	 * its child's vlink.
+	 */
+	if (parent->vlink.next) {
+		node->vlink.next = parent->vlink.next;
+		(node->vlink.next)->prev = &node->vlink;
+
+		/* Clean up parent vlink */
+		parent->vlink.next = NULL;
+	}
+}
+
+/* The function will initialize all
+ * nodes with extended mode.
+ */
+
+static void
+clean_links(randr_node *node)
+{
+	node->clink.next = NULL;
+	node->clink.prev = NULL;
+	node->hlink.next = NULL;
+	node->hlink.prev = NULL;
+	node->vlink.next = NULL;
+	node->vlink.prev = NULL;
+}
+
+static void
+clean_hvlinks(randr_node *node)
+{
+	node->vlink.prev = NULL;
+	node->vlink.next = NULL;
+	node->hlink.prev = NULL;
+	node->hlink.next = NULL;
+}
+
+/* Remove node from original position.
+ * Before deletion, find the replacer and
+ * inherit all links of this node.
+ */
+
+static void
+remove_node(randr_node *node, int clone)
+{
+	randr_node *replacer = NULL;
+	randr_compositor *ec = node->compositor;
+
+	/* Allow clone link to take node's place. */
+	if (clone && node->clink.next) {
+		/* The node is a master which has more clone links. */
+		replacer = container_of(node->clink.next,
+					randr_node,
+					clink);
+		/* Inherit child links */
+		replacer->hlink.next = node->hlink.next;
+		if (node->hlink.next)
+			(node->hlink.next)->prev = &replacer->hlink;
+
+		replacer->vlink.next = node->vlink.next;
+		if (node->vlink.next)
+			(node->vlink.next)->prev = &replacer->vlink;
+
+		/* Inherit parent links and
+		 * turns to be the master.
+		 */
+		replacer->clink.prev = NULL;
+
+		replacer->hlink.prev = node->hlink.prev;
+		if (node->hlink.prev)
+			(node->hlink.prev)->next = &replacer->hlink;
+
+		replacer->vlink.prev = node->vlink.prev;
+		if (node->vlink.prev)
+			(node->vlink.prev)->next = &replacer->vlink;
+
+		if (ec->primary == node)
+			ec->primary = replacer;
+
+		clean_links(node);
+		return;
+	}
+
+	/* This part will adjust node to exist only one child
+	 * which is also the replacer. Therefore don't
+	 * inherit node's children.
+	 */
+
+	if (node->hlink.next && node->vlink.next) {
+		replacer = container_of(node->hlink.next,
+					randr_node,
+					hlink);
+
+		/* Binary tree replace rules to make node has
+		 * only one child.
+		 */
+		node_repos_hlink(replacer);
+	} else if (node->vlink.next || node->hlink.next) {
+		if (node->vlink.next) {
+			replacer =
+			container_of(node->vlink.next,
+				     randr_node,
+				     vlink);
+		} else {
+			replacer =
+			container_of(node->hlink.next,
+				     randr_node,
+				     hlink);
+		}
+	}
+
+	if (!replacer) {
+		/* Parent has not any child.
+		 * Reset grand parent's next link.
+		 */
+		if (node->hlink.prev) {
+			(node->hlink.prev)->next = NULL;
+			node->hlink.prev = NULL;
+		} else if (node->vlink.prev) {
+			(node->vlink.prev)->next = NULL;
+			node->vlink.prev = NULL;
+		} else
+			randr_log("Only one node?\n");
+		return;
+	}
+
+	/* Replacer inherits node's parent links. */
+
+	if (node->hlink.prev) {
+		(node->hlink.prev)->next = &replacer->hlink;
+		replacer->hlink.prev = node->hlink.prev;
+		replacer->vlink.prev = NULL;
+	} else if (node->vlink.prev) {
+		(node->vlink.prev)->next =
+			&replacer->vlink;
+		replacer->vlink.prev =
+			node->vlink.prev;
+		replacer->hlink.prev = NULL;
+	} else {
+		/* No parent means it is primary. */
+		replacer->vlink.prev = NULL;
+		replacer->hlink.prev = NULL;
+	}
+
+	if (ec->primary == node)
+		ec->primary = replacer;
+
+	/* Clean up horizontal and vertical links of node.
+	 * Clone link cleanup depends on the replace rules. If clone
+	 * link could replace the node, it will be clean up in remove_node.
+	 * Otherwise just keep it.
+	 */
+	clean_hvlinks(node);
+}
+
+void
+clean_node(randr_node *node)
+{
+	/* Find the replacer node */
+	if (node->clink.prev) {
+		/* This is a clone node.
+		 * Just replace it and clean other links of replacer.
+		 */
+		(node->clink.prev)->next = node->clink.next;
+		if (node->clink.next)
+			(node->clink.next)->prev = node->clink.prev;
+		clean_links(node);
+	} else {
+		/* The parameter 0 of remove_node means
+		 * replacer order will be when removing node:
+		 * horizontal link, vertical link.
+		 */
+		remove_node(node, 0);
+	}
+}
+
+void
+enable_node(randr_node *node)
+{
+	randr_compositor *ec = node->compositor;
+	struct wl_list *hlink;
+
+	hlink = &ec->primary->hlink;
+	while (hlink->next)
+		hlink = hlink->next;
+
+	hlink->next = &node->hlink;
+	node->hlink.prev = hlink;
+
+	node->hlink.next = NULL;
+	node->vlink.next = NULL;
+	node->clink.next = NULL;
+	node->vlink.prev = NULL;
+	node->clink.prev = NULL;
+	node_layout_child(node);
+}
+
+void
+disable_node(randr_node *node)
+{
+	/* Remove the node */
+	if (node->clink.prev) {
+		/* This is a clone node.
+		 * Just replace it and clean up links of node.
+		 */
+		(node->clink.prev)->next = node->clink.next;
+		if (node->clink.next)
+			(node->clink.next)->prev = node->clink.prev;
+
+		clean_links(node);
+	} else {
+		/* The parameter 1 of remove_node means
+		 * replacer order will be when removing node:
+		 * clone link, horizontal link, vertical link.
+		 */
+		remove_node(node, 1);
+	}
+}
+
+void
+replace_node(randr_node *replacer, randr_node *replaced)
+{
+	randr_compositor *ec = replacer->compositor;
+
+	/* Basic Rules for replacement:
+	 * Replacer node will be very clean without any relation except
+	 * clone link. That means replaced node's
+	 * clone link will be kept original without change.
+	 * Replacer node takes the position of replaced except clone link.
+	 */
+	replacer->hlink.prev = replaced->hlink.prev;
+	replacer->hlink.next = replaced->hlink.next;
+	replacer->vlink.prev = replaced->vlink.prev;
+	replacer->vlink.next = replaced->vlink.next;
+
+	if (replaced->hlink.prev)
+		(replaced->hlink.prev)->next = &replacer->hlink;
+	if (replaced->hlink.next)
+		(replaced->hlink.next)->prev = &replacer->hlink;
+	if (replaced->vlink.prev)
+		(replaced->vlink.prev)->next = &replacer->vlink;
+	if (replaced->vlink.next)
+		(replaced->vlink.next)->prev = &replacer->vlink;
+
+	/* Clean up all links of replaced node. */
+	replaced->hlink.prev = NULL;
+	replaced->hlink.next = NULL;
+	replaced->vlink.prev = NULL;
+	replaced->vlink.next = NULL;
+
+	if (ec->primary == replaced)
+		ec->primary = replacer;
+}
+
+int
+clone_node(randr_node *fixed,
+	   randr_node *move)
+{
+	randr_node *master;
+	struct wl_list *clist;
+
+	/* ToDo: Not Supported!
+	 * Compositor clone feature is not ready.
+	 * Clone code here just process clone link,
+	 * however it needs compositor's clone feature support.
+	 * The real operation should be done in compositor_layout.
+	 */
+	return 2;
+
+	if (!move || !fixed || fixed == move)
+		return 1;
+
+	/* Firstly check if fixed is in cloning status.
+	 * If yes, just convert fixed to its master.
+	 */
+
+	clist = &fixed->clink;
+	while (clist->prev)
+		clist = clist->prev;
+	master = container_of(clist, randr_node, clink);
+
+	/* Make sure move is not in master cloned list.
+	 * Note: move maybe the master.
+	 */
+	clist = &master->clink;
+	while (clist) {
+		if (clist == &move->clink)
+			return 1;
+		clist = clist->next;
+	}
+
+	/* Completely delete the move node link */
+	clean_node(move);
+
+	/* Move may has its own clone link */
+	clist = &master->clink;
+	while (clist->next)
+		clist = clist->next;
+
+	move->clink.prev = clist;
+	clist->next = &move->clink;
+
+	return 0;
+}
+
+int
+primary_node(randr_node *node)
+{
+	/* Possible start point */
+	randr_compositor *ec = node->compositor;
+	randr_node *orig_primary = ec->primary;
+
+	if (!node || node == orig_primary)
+		return 1;
+
+	/* Completely delete the link */
+	clean_node(node);
+
+	/* Take the position of orig primary including its link */
+	replace_node(node, orig_primary);
+
+	/* Now position orig primary rightof node */
+	orig_primary->hlink.next = node->hlink.next;
+	if (node->hlink.next)
+		(node->hlink.next)->prev = &orig_primary->hlink;
+	node->hlink.next = &orig_primary->hlink;
+	orig_primary->hlink.prev = &node->hlink;
+
+	ec->primary = node;
+
+	return 0;
+}
+
+int
+relmove_node(randr_node *fixed,
+	     randr_node *move, int direct)
+{
+	randr_node *master;
+	struct wl_list *clist;
+
+	if (!move || !fixed || fixed == move)
+		return 1;
+
+	/* Firstly check if fixed node is in cloning status.
+	 * If yes, just convert fixed node to its master.
+	 */
+
+	clist = &fixed->clink;
+	while (clist->prev)
+		clist = clist->prev;
+	master = container_of(clist, randr_node, clink);
+
+	/* One special case:
+	 * If fixed is in move's clone link,
+	 * in this case, master is equal to move. Select closest one
+	 * in clink as master.
+	 */
+	if (master == move) {
+		clist = master->clink.next;
+		master = container_of(clist, randr_node, clink);
+		/* Fake master will take all relations of move
+		 * including clone link and turn to be a real master.
+		 */
+		master->clink.prev = NULL;
+		move->clink.next = NULL;
+		replace_node(master, move);
+	}
+
+	/* Note: When node is move,
+	 * the master node will be changed also.
+	 * Fortunately, the position could be
+	 * easily calculated out.
+	 */
+
+	switch (direct) {
+	case MOVE_LEFTOF:
+		if (move->hlink.next == &master->hlink)
+			return 1;
+
+		/* Completely delete the move node link */
+		clean_node(move);
+
+		/* Take the position of master including its link */
+		replace_node(move, master);
+
+		/* Now place the move node leftof master */
+		master->hlink.next = move->hlink.next;
+		if (move->hlink.next)
+			(move->hlink.next)->prev = &master->hlink;
+
+		move->hlink.next = &master->hlink;
+		master->hlink.prev = &move->hlink;
+
+		break;
+	case MOVE_RIGHTOF:
+		if (move->hlink.prev == &master->hlink)
+			return 1;
+
+		/* Completely delete the move node link */
+		clean_node(move);
+
+		/* Now place move node rightof master */
+		move->hlink.next = master->hlink.next;
+		if (master->hlink.next)
+			(master->hlink.next)->prev = &move->hlink;
+		master->hlink.next = &move->hlink;
+		move->hlink.prev = &master->hlink;
+
+		break;
+	case MOVE_ABOVE:
+		if (move->vlink.next == &master->vlink)
+			return 1;
+
+		/* Completely delete the move node link */
+		clean_node(move);
+		/* Take the position of master including its link */
+		replace_node(move, master);
+
+		/* Now place master node below the move */
+		master->vlink.next = move->vlink.next;
+		if (move->vlink.next)
+			(move->vlink.next)->prev = &move->vlink;
+		move->vlink.next = &master->vlink;
+		master->vlink.prev = &move->vlink;
+
+		break;
+	case MOVE_BELOW:
+		if (move->vlink.prev == &master->vlink)
+			return 1;
+
+		/* Completely delete the move node link */
+		clean_node(move);
+
+		/* Now place move node below master */
+		move->vlink.next = master->vlink.next;
+		if (master->vlink.next)
+			(master->vlink.next)->prev = &move->vlink;
+		master->vlink.next = &move->vlink;
+		move->vlink.prev = &master->vlink;
+
+		break;
+	default:
+		/* Never happens! */
+		return -1;
+	}
+
+	if (direct == MOVE_LEFTOF ||
+	    direct == MOVE_ABOVE) {
+		if (master->compositor->primary == master)
+			master->compositor->primary = move;
+	}
+
+	return 0;
+}
+
+void
+node_layout_clone(randr_node *node)
+{
+	randr_node *next, *parent;
+	randr_compositor *ec = node->compositor;
+	int changex, changey;
+
+	parent = container_of(node->clink.prev,
+			      randr_node, clink);
+	changex = parent->x;
+	changey = parent->y;
+
+	randr_node_move(node, changex, changey);
+	pixman_region32_union(&ec->primary_plane.damage,
+			      &ec->primary_plane.damage,
+			      &node->region);
+	/* TODO:
+	 * More process to be done for clone.
+	 * It is up to compositor clone process.
+	 */
+
+	/* Continue its clone link */
+	if (node->clink.next) {
+		next = container_of(node->clink.next,
+				    randr_node, clink);
+		node_layout_clone(next);
+	}
+}
+
+/* Calculate child position
+ * based on parent's. Then move the child node and
+ * continue to process its grand children.
+ */
+void
+node_layout_child(randr_node *node)
+{
+	randr_compositor *ec = node->compositor;
+	randr_node *parent;
+	randr_node *child;
+	int changex, changey;
+
+	if (!node)
+		return;
+
+	/* Get parent node:
+	 * Weston layout tree has a characteristic which
+	 * every node only has one parent. Maybe vlink or hlink.
+	 */
+	if (node->vlink.prev) {
+		parent = container_of(node->vlink.prev,
+				      randr_node, vlink);
+		changex = parent->x;
+		changey = parent->y + parent->height;
+	} else if (node->hlink.prev) {
+		parent = container_of(node->hlink.prev,
+				      randr_node, hlink);
+		changex = parent->x + parent->width;
+		changey = parent->y;
+	} else {
+		randr_log("Some thing causes layout crashed!\n");
+		return;
+	}
+
+	randr_node_move(node, changex, changey);
+	pixman_region32_union(&ec->primary_plane.damage,
+			      &ec->primary_plane.damage,
+			      &node->region);
+
+#if 0
+	/* Clone is currently not supported in compositor.
+	 */
+	if (node->clink.next) {
+		child = container_of(node->clink.next,
+				     randr_node, clink);
+		node_layout_clone(child);
+	}
+#endif
+
+	/* Continue its children */
+	if (node->hlink.next) {
+		child = container_of(node->hlink.next,
+				     randr_node, hlink);
+		node_layout_child(child);
+	}
+
+	if (node->vlink.next) {
+		child = container_of(node->vlink.next,
+				     randr_node, vlink);
+		node_layout_child(child);
+	}
+}
+
+uint64_t
+compositor_layout_init(randr_compositor *ec)
+{
+	randr_node *node;
+	randr_node *parent;
+
+	/* Initialize all nodes from primary node. */
+
+	ec->primary = container_of(ec->output_list.next,
+				   randr_node,
+				   link);
+	parent = ec->primary;
+	clean_links(parent);
+	wl_list_for_each(node, &ec->output_list, link) {
+		if (node == ec->primary)
+			continue;
+		clean_links(node);
+		parent->hlink.next = &node->hlink;
+		node->hlink.prev = &parent->hlink;
+		parent = node;
+	}
+
+	compositor_layout(ec);
+	return WRANDR_TYPE_RET_SUCCESS;
+}
+
+/* The function will re-position all nodes.
+ * Basically when one node's mode is changed including
+ * scale, transform, mode, or original position, it will
+ * affects the other nodes. But we don't make sure how
+ * many are affected.
+ * The basic rules:
+ * If no movement, just change its vlink and hlink children.
+ * If movement happens, select common closest ancestor of
+ * updated nodes and change its vlink and hlink children.
+ */
+
+void
+compositor_layout(randr_compositor *ec)
+{
+	randr_node *node, *child;
+
+	/* Process all nodes from primary node.
+	 * This will recalculate all the position of node.
+	 * Most of time, when position one node, it will
+	 * affect more nodes even if all of them.
+	 */
+
+	node = ec->primary;
+	randr_node_move(node, 0, 0);
+	pixman_region32_union(&ec->primary_plane.damage,
+			      &ec->primary_plane.damage,
+			      &node->region);
+
+
+#if 0
+	/* Clone is currently not supported in compositor.
+	 */
+	if (node->clink.next) {
+		child = container_of(node->clink.next,
+				     randr_node, clink);
+		node_layout_clone(child);
+	}
+#endif
+
+	/* Continue its grand children */
+	if (node->hlink.next) {
+		child = container_of(node->hlink.next,
+				     randr_node, hlink);
+		node_layout_child(child);
+	}
+
+	if (node->vlink.next) {
+		child = container_of(node->vlink.next,
+				     randr_node, vlink);
+		node_layout_child(child);
+	}
+}
diff --git a/module/wrandr/randr_layout_algorithm.h b/module/wrandr/randr_layout_algorithm.h
new file mode 100644
index 0000000..be518ea
--- /dev/null
+++ b/module/wrandr/randr_layout_algorithm.h
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+#ifndef RANDR_LAYOUT_ALGORITHM
+#define RANDR_LAYOUT_ALGORITHM
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include "compositor.h"
+#include "randr-server-protocol.h"
+
+/* Weston Layout Tree
+ *  1) Be similar with binary tree. Here are some related features.
+ *     a. Every output is one tree node.
+ *     b. Every node have one parent at most.
+ *         Also the parent maybe from vertical and
+ *         maybe from horizontal(it is different with binary tree).
+ *         But never has two parents.
+ *     c. Every node have 3 children at most. One is for vertical,
+ *         another is for horizontal and the last one is for clone.
+ *         For clone, it will be processed specially not like vertical
+ *         or horizontal link. So the tree is still be thought as binary
+ *         tree instead of tri-tree.
+ *     d. The tree links all outputs. If some output is not in link,
+ *        link is lost.
+ *     e. Only exists one start point (root) whose coordinate is x=0 and y=0.
+ *        From that, all other outputs could be addressed to right down most.
+ *     f. Every sub branch will never cross each other.
+ *  2)   The tree is double linked.
+ *  3)   The only have-to interrupt is when one node is deleted,
+ *       which child takes its place. Currently the replace order is
+ *       hlink, vlink.
+ */
+
+/* Output layout algorithm
+ * Link definition:
+ *     vlink: vertical child
+ *     hlink: horizontal child
+ *     clink: clone child(master's clink)
+ *            or brothers(clone's clink)
+ *     Example:
+ *        Supposed B is beside A. B maybe leftof, rightof,
+ *        above, or below A.
+ *        If leftof, output(B) is the horizontal parent of A.
+ *        If above, output(B) is the vertical parent of A.
+ *        If rightof, output(B) is the horizontal child of A.
+ *        If below, output(B) is the vertical child of A.
+ *
+ * Primary of layout:
+ *     Define the primary output(x=0, y=0) as the start
+ *     point to calculated the x and y coordinate of
+ *     other outputs.
+ *
+ * Move Node Rules:
+ *     1) Clean up the moved output links except clone link.
+ *        before moving.
+ *     2) If the movement is above or leftof, moved output will
+ *        replace the relative output's original position. At the
+ *        same time relative output will be clean up except clone link.
+ *
+ *     Special Case:
+ *      a. When moving master relate with its clone output,
+ *         select closest clone output to replace master's position.
+ *         And then convert the movement to be move original master
+ *         relative with new master.
+ *      b. When moving, the relative output is a clone output.
+ *         the movement should be relative with its master.
+ *
+ * Clean Node Rules:
+ *     1) Clean means delete all links except clone link and for
+ *        next movement. The node is clean and the place is
+ *        replaced by others.
+ *     2) Define the order to take the place of parent:
+ *        hlink and then vlink.
+ *     3) If the moved node is a clone output, clean it and
+ *        its all links.
+ *     4) If the moved node isn't a clone output, don't
+ *        touch its clone link. It will be moved at the same time.
+ *     5) if hlink is the replacer,
+ *        a. parent's vlink will be vlink of horizontal child.
+ *        b. replacer's hlink keeps original except last hlink.
+ *           The last has no hlink child and its vlink child
+ *           will be converted to hlink.
+ *
+ *   Special Case:
+ *        Delete a clone output. It has no any child except clone link.
+ *        Just delete it from clone link and clean it up.
+ *
+ * Disable Node Rules:
+ *     1) The node is deleted and the place is replaced by others.
+ *     2) The order to take the place of parent:
+ *        clink, hlink and then vlink.
+ *     Others are the same as clean_node.
+ *
+ * Enable Node Rules:
+ *     1) This node is disabled before. Therefore when enabled,
+ *        it will link to the tail of primary hlink.
+ *
+ * Replace Node Rules:
+ *     Replacer output will be very clean without any relation except
+ *     clone link. That means replaced output's
+ *     clone link will be kept original without any change.
+ *     Replacer output takes the position of replaced except clone link.
+ *
+ * Clone Node Rules:
+ *     Clone output has not any vlink and hlink child and parent
+ *     called master. It can only have one parent and clone link
+ *     which links others clone brothers.
+ *     Any movement relative with clone output will be converted
+ *     to the movement relative with its master.
+ *
+ * Primary Node Rules:
+ * Set the node to be top left most node (x=0, y=0).
+ * The action turns to be move node
+ * to the left of original primary.
+ *
+ * Notice:
+ *       1) Every action may affect primary output.
+ *          For example, delete, replace, clone, or move.
+ *          Therefore when do such operation, need check
+ *          primary change.
+ *       2) After output layout operation is done, re-calculated
+ *          the x, y of outputs.
+ *          There may exist more movements happen at the same
+ *          time and should be an algorithm to calculate the leftup most.
+ *          Currently very lazy way is from primary output.
+ */
+
+/* Type definition */
+#define randr_node_move weston_output_move
+#define randr_log weston_log
+typedef struct weston_output randr_node;
+typedef struct weston_compositor randr_compositor;
+
+/* The function will move parent's vlink
+ * to child's vlink until hlink child is null.
+ */
+
+void node_repos_hlink(randr_node *node);
+
+/* The function will clean node hlink and vlink.
+ * When node is clean, the binary tree structure
+ * of node should be adjusted consistently to keep
+ * the tree's integrity.
+ */
+
+void clean_node(randr_node *node);
+
+/* The function will replace replaced node with replacer including
+ * hlink and vlink. Replaced node will be clean up for next movement.
+ */
+
+void replace_node(randr_node *replacer,
+		  randr_node *replaced);
+
+int clone_node(randr_node *fixed,
+	       randr_node *move);
+
+/* The function implemented node relative motion.
+ * Currently it supports leftof, rightof, above
+ * and below.
+ */
+
+int relmove_node(randr_node *fixed,
+		 randr_node *move, int direct);
+
+void node_layout_clone(randr_node *clone);
+
+/* Parent is in place and calculate child position
+ * based on parent's. Then move the child node and
+ * continue to process its grand children.
+ */
+void node_layout_child(randr_node *child);
+
+/* The function will re-position all nodes.
+ * Basically when one node's mode is changed including
+ * scale, transform, mode, or original position, it will
+ * affects the other nodes. But we don't make sure how
+ * many are affected.
+ * The basic rules:
+ * If no movement, just change its vlink and hlink children.
+ * If movement happens, select common closest ancestor of
+ * updated nodes and change its vlink and hlink children.
+ */
+
+void compositor_layout(randr_compositor *ec);
+uint64_t compositor_layout_init(randr_compositor *ec);
+void disable_node(randr_node *node);
+void enable_node(randr_node *node);
+int primary_node(randr_node *node);
+#endif
diff --git a/module/wrandr/randr_parser.c b/module/wrandr/randr_parser.c
new file mode 100644
index 0000000..c77f0b4
--- /dev/null
+++ b/module/wrandr/randr_parser.c
@@ -0,0 +1,169 @@
+/*
+ * 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 "randr_parser.h"
+
+static struct randr_config_entry *
+randr_config_addentry(struct randr_config_section *section,
+		      const char *key, const char *value)
+{
+	struct randr_config_entry *entry;
+
+	entry = zalloc(sizeof(*entry));
+	if (!entry) {
+		weston_log("Allocate entry failed!.\n");
+		return NULL;
+	}
+
+	entry->key = strdup(key);
+	entry->value = strdup(value);
+	wl_list_insert(section->entry_list.prev, &entry->link);
+
+	return entry;
+}
+
+static struct randr_config_section *
+randr_config_addsect(struct randr_config *config, const char *name)
+{
+	struct randr_config_section *section;
+
+	/* First check if there are the same section. */
+	wl_list_for_each(section, &config->section_list, link) {
+		if (strcmp(section->name, name) == 0)
+			return section;
+	}
+
+	section = zalloc(sizeof(*section));
+	if (!section) {
+		weston_log("Allocate section failed!.\n");
+		return NULL;
+	}
+
+	section->name = strdup(name);
+	wl_list_init(&section->entry_list);
+	wl_list_insert(config->section_list.prev, &section->link);
+
+	return section;
+}
+
+void
+randr_config_destroy(struct randr_config *config)
+{
+	struct randr_config_section *section, *next_s;
+	struct randr_config_entry *entry, *next_e;
+
+	if (config == NULL)
+		return;
+
+	wl_list_for_each_safe(section, next_s, &config->section_list, link) {
+		wl_list_for_each_safe(entry, next_e,
+				      &section->entry_list, link) {
+			free(entry->key);
+			free(entry->value);
+			free(entry);
+		}
+		free(section->name);
+		free(section);
+	}
+
+	free(config);
+}
+
+/* This function parses the randr configure file. */
+
+struct randr_config *
+randr_config_parse(const char *name)
+{
+	FILE *fp;
+	char line[RANDR_MAXLEN], *ptr;
+	struct randr_config *config;
+	struct randr_config_section *section = NULL;
+	int i;
+
+	if (!name)
+		return NULL;
+
+	fp = fopen(name, "r");
+	if (fp == NULL)
+		return NULL;
+
+	config = malloc(sizeof(*config));
+	if (config == NULL) {
+		fclose(fp);
+		return NULL;
+	}
+
+	wl_list_init(&config->section_list);
+
+	/* Firstly create a compositor settion */
+	while (fgets(line, sizeof(line), fp)) {
+		switch (line[0]) {
+		case '#':
+		case '\n':
+			continue;
+		case '[':
+			/* Get output name */
+			ptr = strchr(&line[1], ']');
+			if (!ptr || ptr[1] != '\n') {
+				weston_log("Malformed section header: %s\n",
+					   line);
+				fclose(fp);
+				randr_config_destroy(config);
+				return NULL;
+			}
+
+			ptr[0] = '\0';
+			section = randr_config_addsect(config, &line[1]);
+
+			continue;
+		default:
+			ptr = strchr(line, '=');
+			if (!ptr || ptr == line || !section) {
+				weston_log("Malformed config line: %s\n",
+					   line);
+				fclose(fp);
+				randr_config_destroy(config);
+				return NULL;
+			}
+
+			ptr[0] = '\0';
+			ptr++;
+			while (isspace(*ptr))
+				ptr++;
+			i = strlen(ptr);
+			while (i > 0 && isspace(ptr[i - 1])) {
+				ptr[i - 1] = '\0';
+				i--;
+			}
+
+			randr_config_addentry(section, line, ptr);
+			continue;
+		}
+	}
+
+	fclose(fp);
+	return config;
+}
diff --git a/module/wrandr/randr_parser.h b/module/wrandr/randr_parser.h
new file mode 100644
index 0000000..8ab9324
--- /dev/null
+++ b/module/wrandr/randr_parser.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#ifndef RANDR_CONFIG_PARSER
+#define RANDR_CONFIG_PARSER
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include "compositor.h"
+#define RANDR_MAXLEN 512
+#define RANDR_NAMELEN 256
+
+struct randr_config_entry {
+	char *key;
+	char *value;
+	struct wl_list link;
+};
+
+struct randr_config_section {
+	char *name;
+	struct wl_list entry_list;
+	struct wl_list link;
+};
+
+struct randr_config {
+	struct wl_list section_list;
+	char name[RANDR_NAMELEN];
+};
+
+void randr_config_destroy(struct randr_config *config);
+struct randr_config *randr_config_parse(const char *name);
+#endif
diff --git a/module/wrandr/wrandr.c b/module/wrandr/wrandr.c
new file mode 100644
index 0000000..a00440f
--- /dev/null
+++ b/module/wrandr/wrandr.c
@@ -0,0 +1,1915 @@
+/*
+ * 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 "wrandr.h"
+
+/* 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
+del_orequest(struct randr_output_request *orequest)
+{
+	wl_list_remove(&orequest->link);
+
+	if (orequest->mode)
+		free(orequest->mode);
+
+	if (orequest->delmode)
+		free(orequest->delmode);
+
+	if (orequest->newmode)
+		free(orequest->newmode);
+
+	if (orequest->newtiming)
+		free(orequest->newtiming);
+
+	free(orequest);
+}
+
+static void
+del_request(struct randr_request *request)
+{
+	struct randr_output_request *output_request, *next;
+
+	wl_list_remove(&request->link);
+
+	if (request->config_file)
+		free(request->config_file);
+
+	wl_list_for_each_safe(output_request, next,
+			      &request->output_request_list, link)
+		del_orequest(output_request);
+
+	free(request);
+}
+
+static struct randr_output_request *
+create_randr_orequest(struct wl_resource *resource,
+		      struct randr_request *request,
+		      struct weston_output *output)
+{
+	struct randr_output_request *orequest;
+
+	orequest = zalloc(sizeof(*orequest));
+	if (orequest == NULL) {
+		wl_resource_post_no_memory(resource);
+		return NULL;
+	}
+	memset(orequest, 0x0, sizeof(*orequest));
+
+	orequest->output = output;
+	wl_list_insert(&request->output_request_list, &orequest->link);
+	return orequest;
+}
+
+static struct randr_request *
+create_randr_request(struct wl_client *client,
+		     struct wl_resource *resource)
+{
+	struct wrandr *randr =
+		wl_resource_get_user_data(resource);
+	struct randr_request *request;
+
+	request = zalloc(sizeof(*request));
+	if (request == NULL) {
+		wl_resource_post_no_memory(resource);
+		return NULL;
+	}
+	memset(request, 0x0, sizeof(*request));
+
+	request->client = client;
+	wl_list_init(&request->output_request_list);
+	wl_list_insert(&randr->pending.request_list, &request->link);
+	return request;
+}
+
+static struct randr_request *
+get_request(struct wl_client *client,
+	    struct wl_resource *resource,
+	    int create)
+{
+	struct wrandr *randr =
+		wl_resource_get_user_data(resource);
+	struct randr_request *request;
+
+	wl_list_for_each(request, &randr->pending.request_list, link)
+	{
+		if (request->client == client)
+			return request;
+	}
+
+	if (create)
+		return create_randr_request(client, resource);
+	else
+		return NULL;
+}
+
+static struct randr_output_request *
+get_orequest(struct wl_client *client,
+	     struct wl_resource *resource,
+	     struct weston_output *output,
+	     int create)
+{
+	struct randr_request *request;
+	struct randr_output_request *orequest;
+
+	request = get_request(client, resource, create);
+	if (!request)
+		return NULL;
+
+	wl_list_for_each(orequest, &request->output_request_list, link)
+		if (orequest->output == output)
+			return orequest;
+
+	if (create)
+		return create_randr_orequest(resource, request, output);
+	else
+		return NULL;
+}
+
+void
+adjust_pointer(struct weston_output *output,
+	       pixman_region32_t *old_output_region)
+{
+	struct weston_seat *seat;
+	int32_t x, y;
+	struct weston_pointer *pointer;
+
+	/* If a pointer falls outside the outputs new geometry, move it to its
+	 * lower-right corner. */
+	wl_list_for_each(seat, &output->compositor->seat_list, link) {
+		pointer = seat->pointer;
+		if (!pointer)
+			continue;
+
+		x = wl_fixed_to_int(pointer->x);
+		y = wl_fixed_to_int(pointer->y);
+
+		if (!pixman_region32_contains_point(old_output_region,
+						    x, y, NULL) ||
+		    pixman_region32_contains_point(&output->region,
+						   x, y, NULL))
+			continue;
+
+		if (x >= output->x + output->width)
+			x = output->x + output->width - 1;
+		if (y >= output->y + output->height)
+			y = output->y + output->height - 1;
+
+		pointer->x = wl_fixed_from_int(x);
+		pointer->y = wl_fixed_from_int(y);
+	}
+}
+
+void
+notify_change(struct weston_output *output,
+	      int mode_changed,
+	      int scale_changed,
+	      int transform_changed)
+{
+	struct wl_resource *resource;
+	struct weston_mode *mode = output->current_mode;
+
+	if (!mode_changed && !scale_changed &&
+		!transform_changed)
+		return;
+
+	/* Notify clients of the changes */
+	wl_resource_for_each(resource,
+			     &output->resource_list) {
+		if (mode_changed) {
+			wl_output_send_mode(resource,
+					    mode->flags |
+					    WL_OUTPUT_MODE_CURRENT,
+					    mode->width,
+					    mode->height,
+					    mode->refresh);
+		}
+
+		if (transform_changed) {
+			wl_output_send_geometry(resource,
+						output->x,
+						output->y,
+						output->mm_width,
+						output->mm_height,
+						output->subpixel,
+						output->make,
+						output->model,
+						output->transform);
+		}
+
+		if (scale_changed &&
+		    wl_resource_get_version(resource) >= 2)
+			wl_output_send_scale(resource,
+					     output->current_scale);
+
+		if (wl_resource_get_version(resource) >= 2)
+			wl_output_send_done(resource);
+	}
+}
+
+/* General functions for mode setting and movement */
+static void
+output_switch(struct randr_output_request *request, int on)
+{
+	if (!request)
+		return;
+
+	request->flags |= 1<<WRANDR_TYPE_OOP_SWITCH;
+	request->switch_output = on;
+}
+
+static void
+set_primary(struct randr_output_request *request)
+{
+	if (!request)
+		return;
+
+	request->flags |= 1<<WRANDR_TYPE_OOP_PRIMARY;
+
+	request->primary.modi_time = time(NULL);
+	request->primary.flag = WRANDR_TYPE_OOP_PRIMARY;
+}
+
+static void
+set_clone(struct randr_output_request *request,
+	  struct weston_output *output)
+{
+	if (!request)
+		return;
+
+	request->flags |= 1<<WRANDR_TYPE_OOP_CLONE;
+
+	request->clone.output = output;
+	request->clone.modi_time = time(NULL);
+	request->clone.flag = WRANDR_TYPE_OOP_CLONE;
+}
+
+static void
+set_movement(struct randr_output_request *request,
+	     struct weston_output *output,
+	     int direction)
+{
+	struct randr_movement *randr_move;
+
+	if (!request)
+		return;
+
+	switch (direction) {
+	case MOVE_LEFTOF:
+		randr_move = &request->leftof;
+		request->flags |= 1<<WRANDR_TYPE_OOP_MOVEL;
+		randr_move->direction = MOVE_LEFTOF;
+		randr_move->flag = WRANDR_TYPE_OOP_MOVEL;
+		break;
+	case MOVE_RIGHTOF:
+		randr_move = &request->rightof;
+		request->flags |= 1<<WRANDR_TYPE_OOP_MOVER;
+		randr_move->direction = MOVE_RIGHTOF;
+		randr_move->flag = WRANDR_TYPE_OOP_MOVER;
+		break;
+	case MOVE_ABOVE:
+		randr_move = &request->above;
+		request->flags |= 1<<WRANDR_TYPE_OOP_MOVEA;
+		randr_move->direction = MOVE_ABOVE;
+		randr_move->flag = WRANDR_TYPE_OOP_MOVEA;
+		break;
+	case MOVE_BELOW:
+		randr_move = &request->below;
+		request->flags |= 1<<WRANDR_TYPE_OOP_MOVEB;
+		randr_move->direction = MOVE_BELOW;
+		randr_move->flag = WRANDR_TYPE_OOP_MOVEB;
+		break;
+	default:
+		return;
+	}
+
+	randr_move->output = output;
+	randr_move->modi_time = time(NULL);
+}
+
+static void
+set_transform(struct randr_output_request *request,
+	      int transform)
+{
+	if (!request)
+		return;
+
+	request->flags |= 1<<WRANDR_TYPE_OOP_TRANSFORM;
+	request->transform = transform;
+}
+
+static void
+set_scale(struct randr_output_request *request,
+	  int scale)
+{
+	if (!request)
+		return;
+
+	request->flags |= 1<<WRANDR_TYPE_OOP_SCALE;
+	request->scale = scale;
+}
+
+static void
+set_modenum(struct randr_output_request *request,
+	    int num)
+{
+	request->flags |= 1<<WRANDR_TYPE_OOP_MODENUM;
+	request->modenum.num = num;
+	request->modenum.modi_time = time(NULL);
+}
+
+static void
+set_mode(struct randr_output_request *request,
+	 int width, int height, int refresh)
+{
+	if (!request)
+		return;
+
+	request->flags |= 1<<WRANDR_TYPE_OOP_MODE;
+
+	if (!request->mode) {
+		request->mode = zalloc(sizeof(*(request->mode)));
+		if (request->mode == NULL) {
+			weston_log("Allocate mode memory failed!\n");
+			return;
+		}
+	}
+
+	request->mode->width = width;
+	request->mode->height = height;
+	request->mode->refresh = refresh;
+	request->mode->modi_time = time(NULL);
+}
+
+/* Randr request callback */
+static void
+randr_destroy(struct wl_client *client,
+	      struct wl_resource *resource)
+{
+	wl_resource_destroy(resource);
+	return;
+}
+
+static void
+randr_set_scale(struct wl_client *client,
+		struct wl_resource *resource,
+		struct wl_resource *output_resource,
+		int32_t scale)
+{
+	struct weston_output *output =
+		wl_resource_get_user_data(output_resource);
+	struct randr_output_request *request;
+
+	request = get_orequest(client, resource, output, 1);
+	if (request) {
+		request->flags |= 1<<WRANDR_TYPE_OOP_SCALE;
+		request->scale = scale;
+	}
+}
+
+static void
+randr_set_transform(struct wl_client *client,
+		    struct wl_resource *resource,
+		    struct wl_resource *output_resource,
+		    uint32_t transform)
+{
+	struct weston_output *output =
+		wl_resource_get_user_data(output_resource);
+	struct randr_output_request *request;
+
+	request = get_orequest(client, resource, output, 1);
+	if (request) {
+		request->flags |= 1<<WRANDR_TYPE_OOP_TRANSFORM;
+		request->transform = transform % 8;
+	}
+}
+
+static void
+randr_clone(struct wl_client *client,
+	    struct wl_resource *resource,
+	    struct wl_resource *target_resource,
+	    struct wl_resource *source_resource)
+{
+	struct weston_output *move =
+		wl_resource_get_user_data(target_resource);
+	struct weston_output *clone =
+		wl_resource_get_user_data(source_resource);
+	struct randr_output_request *request;
+
+	request = get_orequest(client, resource, move, 1);
+	if (request)
+		set_clone(request, clone);
+}
+
+static void
+randr_auto(struct wl_client *client,
+	   struct wl_resource *resource)
+{
+	struct randr_request *request;
+
+	request = get_request(client, resource, 1);
+	if (request)
+		request->flags |= 1<<WRANDR_TYPE_WOP_AUTO;
+}
+
+static void
+randr_primary(struct wl_client *client,
+	      struct wl_resource *resource,
+	      struct wl_resource *target_resource)
+{
+	struct weston_output *primary =
+		wl_resource_get_user_data(target_resource);
+	struct randr_output_request *request;
+
+	request = get_orequest(client, resource, primary, 1);
+	if (request)
+		set_primary(request);
+}
+
+static void
+randr_switch_output(struct wl_client *client,
+		    struct wl_resource *resource,
+		    struct wl_resource *target_resource,
+		    int on)
+{
+	struct weston_output *output =
+		wl_resource_get_user_data(target_resource);
+	struct randr_output_request *request;
+
+	request = get_orequest(client, resource, output, 1);
+	if (request)
+		output_switch(request, on);
+}
+
+static void
+randr_move(struct wl_client *client,
+	   struct wl_resource *resource,
+	   struct wl_resource *target_resource,
+	   struct wl_resource *source_resource, int direction)
+{
+	struct weston_output *move =
+		wl_resource_get_user_data(target_resource);
+	struct weston_output *fixed =
+		wl_resource_get_user_data(source_resource);
+	struct randr_output_request *request;
+
+	request = get_orequest(client, resource, move, 1);
+	if (request)
+		set_movement(request, fixed, direction);
+}
+
+static struct weston_mode *
+randr_find_mode(struct weston_output *output,
+		int width, int height, int refresh)
+{
+	struct weston_mode *mode;
+
+	wl_list_for_each(mode, &output->mode_list, link) {
+		if (width != mode->width ||
+		    height != mode->height)
+			continue;
+
+		if (!refresh || refresh == (int)mode->refresh)
+			return mode;
+	}
+	return NULL;
+}
+
+static struct weston_mode *
+randr_find_timing(struct weston_output *output,
+		  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,
+		  int flags)
+{
+	struct weston_mode *mode;
+	int ret;
+
+	if (!output->compare_timing) {
+		weston_log("Timing compare is not supported\n");
+		return NULL;
+	}
+
+	wl_list_for_each(mode, &output->mode_list, link) {
+		ret = output->compare_timing(mode,
+					     clock,
+					     hdisplay,
+					     hsync_start,
+					     hsync_end,
+					     htotal,
+					     vdisplay,
+					     vsync_start,
+					     vsync_end,
+					     vtotal,
+					     vscan,
+					     flags);
+
+		if (ret > 0)
+			return mode;
+	}
+
+	return NULL;
+}
+
+static void
+update_region(struct weston_compositor *ec,
+	      struct weston_output *target_output)
+{
+	/* Update output region and transformation matrix. */
+	weston_output_transform_scale_init(target_output,
+					   target_output->transform,
+					   target_output->current_scale);
+
+	pixman_region32_init(&target_output->previous_damage);
+	pixman_region32_init_rect(&target_output->region,
+				  target_output->x, target_output->y,
+				  target_output->width, target_output->height);
+
+	weston_output_update_matrix(target_output);
+
+	/* Damage the output region in primary_plane */
+	pixman_region32_union(&ec->primary_plane.damage,
+			      &ec->primary_plane.damage,
+			      &target_output->region);
+
+	target_output->dirty = 1;
+}
+
+static uint64_t
+randr_switch_mode(struct randr_output_request *request)
+{
+	time_t time = 0;
+	int i = 0, found = 0;
+	int result = WRANDR_TYPE_RET_NOACT;
+	int timing_mode = 0;
+	int move_bits = 0;
+	uint64_t results = 0;
+	struct weston_mode *mode;
+	struct randr_timing *timing = request->timing;
+	struct weston_output *output = request->output;
+
+	if (request->flags & 1<<WRANDR_TYPE_OOP_MODENUM) {
+		timing_mode = 1;
+		time = request->modenum.modi_time;
+		results |= result<<
+			   (WRANDR_TYPE_OOP_MODENUM * 2);
+	}
+
+	if (request->flags & 1<<WRANDR_TYPE_OOP_MODE) {
+		results |= result<<
+			   (WRANDR_TYPE_OOP_MODE * 2);
+		if (request->mode->modi_time > time) {
+			time = request->mode->modi_time;
+			timing_mode = 2;
+		}
+	}
+
+	if (request->flags & 1<<WRANDR_TYPE_OOP_TIMING) {
+		results |= result<<
+			   (WRANDR_TYPE_OOP_TIMING * 2);
+		if (timing->modi_time > time) {
+			time = timing->modi_time;
+			timing_mode = 3;
+		}
+	}
+
+	switch (timing_mode) {
+	case 1:
+		i = 0;
+		wl_list_for_each(mode, &output->mode_list, link) {
+			i++;
+			if (i == request->modenum.num) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (found != 1)
+			mode = NULL;
+		break;
+	case 2:
+		mode = randr_find_mode(output,
+				       request->mode->width,
+				       request->mode->height,
+				       request->mode->refresh);
+		break;
+	case 3:
+		mode = randr_find_timing(output,
+					 timing->clock,
+					 timing->hdisplay,
+					 timing->hsync_start,
+					 timing->hsync_end,
+					 timing->htotal,
+					 timing->vdisplay,
+					 timing->vsync_start,
+					 timing->vsync_end,
+					 timing->vtotal,
+					 timing->vscan,
+					 timing->flags);
+
+		break;
+	default:
+		return results;
+	}
+
+
+	if (!mode) {
+		result = WRANDR_TYPE_RET_FAIL;
+	} else {
+		if (!(mode->flags & WL_OUTPUT_MODE_CURRENT) &&
+		    output->switch_mode) {
+			result = output->switch_mode(output, mode);
+			if (result < 0)
+				result = WRANDR_TYPE_RET_FAIL;
+			else
+				result = WRANDR_TYPE_RET_SUCCESS;
+		} else
+			result = WRANDR_TYPE_RET_NOACT;
+	}
+
+	move_bits = WRANDR_TYPE_OOP_MODENUM + timing_mode - 1;
+	results &= ~(RESULT_MASK<<(move_bits * 2));
+	results |= result<<(move_bits * 2);
+	return results;
+}
+
+/* Sort movement according to modified time. */
+
+static void
+put_list(struct wl_list *head, struct randr_movement *move)
+{
+	struct wl_list *tmp;
+	struct randr_movement *tmpmove;
+
+	if (!move || !move->modi_time)
+		return;
+
+	tmp = head;
+	while (tmp->next) {
+		tmpmove =
+			container_of(tmp->next,
+				     struct randr_movement, link);
+		if (tmpmove->modi_time > move->modi_time)
+			break;
+		tmp = tmp->next;
+	}
+	move->link.next = tmp->next;
+	tmp->next = &move->link;
+}
+
+/* Conver result to randr result */
+static int32_t
+convert_result(int32_t ret)
+{
+	switch (ret) {
+	case -1:
+		return WRANDR_TYPE_RET_FAIL;
+	case 0:
+		return WRANDR_TYPE_RET_SUCCESS;
+	case 1:
+		return WRANDR_TYPE_RET_NOACT;
+	case 2:
+		return WRANDR_TYPE_RET_NOSUPP;
+	default:
+		return WRANDR_TYPE_RET_FAIL;
+	}
+}
+
+static uint64_t
+output_change(struct wrandr *randr,
+	      struct randr_output_request *request)
+{
+	struct weston_compositor *ec = randr->compositor;
+	uint64_t results = 0;
+	int32_t result = 0;
+	uint32_t mode_change = 0, trans_change = 0;
+	uint32_t scale_change = 0;
+	uint32_t move_change = 0;
+	struct weston_output *toutput = request->output;
+	struct wl_list move_head; /* Move head */
+	struct wl_list *tmp; /* Move head */
+	struct randr_movement *move; /* Move head */
+	pixman_region32_t old_output_region;
+
+	/* Disable/Enable output */
+	if (request->flags & 1<<WRANDR_TYPE_OOP_SWITCH) {
+		/* TODO: this function is not supported. */
+		result = WRANDR_TYPE_RET_NOSUPP;
+		results |= result<<(WRANDR_TYPE_OOP_SWITCH * 2);
+	}
+
+	/* Switch Mode
+	 * Mode and Timing may be set in one commit.
+	 * The basic rule is who is the last, who will be
+	 * active.
+	 */
+
+	results |= randr_switch_mode(request);
+
+	/* Transform */
+	if (request->flags & 1<<WRANDR_TYPE_OOP_TRANSFORM) {
+		if ((uint32_t)request->transform != toutput->transform) {
+			toutput->transform = (uint32_t)request->transform;
+			result = WRANDR_TYPE_RET_SUCCESS;
+		} else
+			result = WRANDR_TYPE_RET_NOACT;
+
+		results |= result<<(WRANDR_TYPE_OOP_TRANSFORM * 2);
+	}
+
+	/* Scale */
+	if (request->flags & 1<<WRANDR_TYPE_OOP_SCALE) {
+		if (request->scale && request->scale !=
+		    toutput->current_scale) {
+			toutput->current_scale = request->scale;
+			result = WRANDR_TYPE_RET_SUCCESS;
+		} else
+			result = WRANDR_TYPE_RET_NOACT;
+
+		results |= result<<(WRANDR_TYPE_OOP_SCALE * 2);
+	}
+
+	/* Move, Clone, Primary
+	 * These operations will change x, y of output.
+	 */
+	memset(&move_head, 0x0, sizeof(move_head));
+	if (request->flags & 1<<WRANDR_TYPE_OOP_MOVEL)
+		put_list(&move_head, &request->leftof);
+	if (request->flags & 1<<WRANDR_TYPE_OOP_MOVER)
+		put_list(&move_head, &request->rightof);
+	if (request->flags & 1<<WRANDR_TYPE_OOP_MOVEA)
+		put_list(&move_head, &request->above);
+	if (request->flags & 1<<WRANDR_TYPE_OOP_MOVEB)
+		put_list(&move_head, &request->below);
+	if (request->flags & 1<<WRANDR_TYPE_OOP_PRIMARY)
+		put_list(&move_head, &request->primary);
+	if (request->flags & 1<<WRANDR_TYPE_OOP_CLONE)
+		put_list(&move_head, &request->clone);
+
+	tmp = &move_head;
+	while (tmp->next) {
+		move = container_of(tmp->next,
+				    struct randr_movement,
+				    link);
+
+		if (move->flag == WRANDR_TYPE_OOP_MOVEL ||
+		    move->flag == WRANDR_TYPE_OOP_MOVER ||
+		    move->flag == WRANDR_TYPE_OOP_MOVEA ||
+		    move->flag == WRANDR_TYPE_OOP_MOVEB) {
+			result = relmove_node(move->output,
+					      request->output,
+					      move->direction);
+		}
+
+		if (move->flag == WRANDR_TYPE_OOP_PRIMARY)
+			result = primary_node(request->output);
+
+		if (move->flag == WRANDR_TYPE_OOP_CLONE) {
+			result = clone_node(request->clone.output,
+					    request->output);
+		}
+
+		/* Convert result to randr result */
+		results |= convert_result(result) <<
+			   (move->flag * 2);
+		tmp = tmp->next;
+	}
+
+	/* Check if any action to be done. */
+	mode_change =
+		(results>>(WRANDR_TYPE_OOP_MODENUM * 2) &
+		RESULT_MASK) == WRANDR_TYPE_RET_SUCCESS ||
+		(results>>(WRANDR_TYPE_OOP_MODE * 2) &
+		RESULT_MASK) == WRANDR_TYPE_RET_SUCCESS ||
+		(results>>(WRANDR_TYPE_OOP_TIMING * 2) &
+		RESULT_MASK) == WRANDR_TYPE_RET_SUCCESS;
+
+	scale_change =
+		(results>>(WRANDR_TYPE_OOP_SCALE * 2) &
+		RESULT_MASK) == WRANDR_TYPE_RET_SUCCESS;
+
+	trans_change =
+		(results>>(WRANDR_TYPE_OOP_TRANSFORM * 2) &
+		RESULT_MASK) == WRANDR_TYPE_RET_SUCCESS;
+
+	move_change = move_head.next ? 1 : 0;
+
+	if (!move_change && !scale_change &&
+	    !trans_change && !mode_change)
+		return results;
+
+	pixman_region32_init(&old_output_region);
+	pixman_region32_copy(&old_output_region, &toutput->region);
+	update_region(ec, toutput);
+	/* Whatever scale, transform or mode setting,
+	 * the width or height of output will be changed.
+	 * consistently, other outputs behind this output
+	 * should be changed at the same time.
+	 */
+	compositor_layout(ec);
+	adjust_pointer(toutput, &old_output_region);
+	pixman_region32_fini(&old_output_region);
+
+	/* Notify clients of the changes. */
+	notify_change(toutput, mode_change,
+		      scale_change, trans_change);
+
+	return results;
+}
+
+static void
+randr_set_modenum(struct wl_client *client,
+	       struct wl_resource *resource,
+	       struct wl_resource *output_resource,
+	       int num)
+{
+	struct weston_output *output =
+		wl_resource_get_user_data(output_resource);
+	struct randr_output_request *request;
+
+	request = get_orequest(client, resource, output, 1);
+	if (request)
+		set_modenum(request, num);
+}
+
+static void
+randr_set_mode(struct wl_client *client,
+	       struct wl_resource *resource,
+	       struct wl_resource *output_resource,
+	       int width,
+	       int height,
+	       int refresh)
+{
+	struct weston_output *output =
+		wl_resource_get_user_data(output_resource);
+	struct randr_output_request *request;
+
+	request = get_orequest(client, resource, output, 1);
+	set_mode(request, width, height, refresh);
+}
+
+static void
+randr_set_timing(struct wl_client *client,
+		 struct wl_resource *resource,
+		 struct wl_resource *output_resource,
+		 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,
+		 int flags)
+{
+	struct weston_output *output =
+		wl_resource_get_user_data(output_resource);
+	struct randr_output_request *request;
+
+	request = get_orequest(client, resource, output, 1);
+	if (request) {
+		request->flags |= 1<<WRANDR_TYPE_OOP_TIMING;
+
+		if (!request->timing) {
+			request->timing = zalloc(sizeof(*(request->timing)));
+			if (request->timing == NULL) {
+				wl_resource_post_no_memory(resource);
+				return;
+			}
+		}
+
+		request->timing->clock = clock;
+		request->timing->hdisplay = hdisplay;
+		request->timing->hsync_start = hsync_start;
+		request->timing->hsync_end = hsync_end;
+		request->timing->htotal = htotal;
+		request->timing->vdisplay = vdisplay;
+		request->timing->vsync_start = vsync_start;
+		request->timing->vsync_end = vsync_end;
+		request->timing->vtotal = vtotal;
+		request->timing->vscan = vscan;
+		request->timing->flags = flags;
+		request->timing->modi_time = time(NULL);
+	}
+}
+
+static int
+output_newmode(struct wrandr *randr,
+	       struct wl_client *client,
+	       struct weston_output *output,
+	       int width,
+	       int height,
+	       int refresh)
+{
+	struct weston_mode *mode;
+	struct wl_resource *resource;
+
+	if (!output->new_mode) {
+		weston_log("No new mode callback!\n");
+		return WRANDR_TYPE_RET_FAIL;
+	}
+
+	mode = randr_find_mode(output, width, height, refresh);
+
+	if (mode) {
+		weston_log("New mode exists already!\n");
+		return WRANDR_TYPE_RET_NOACT;
+	}
+
+	mode = output->new_mode(width, height, refresh);
+	mode->flags |= WESTON_RANDR_MODE_CUSTOM;
+
+	/* Notify clients new mode. */
+	wl_resource_for_each(resource,
+			     &output->resource_list) {
+		wl_output_send_mode(resource,
+				    mode->flags,
+				    mode->width,
+				    mode->height,
+				    mode->refresh);
+		if (wl_resource_get_version(resource) >= 2)
+			wl_output_send_done(resource);
+	}
+
+	return WRANDR_TYPE_RET_SUCCESS;
+}
+
+static void
+randr_newmode(struct wl_client *client,
+	      struct wl_resource *resource,
+	      struct wl_resource *target_resource,
+	      int width,
+	      int height,
+	      int refresh)
+{
+	struct weston_output *output =
+		wl_resource_get_user_data(target_resource);
+	struct randr_output_request *request;
+
+	request = get_orequest(client, resource, output, 1);
+	if (request) {
+		request->flags |= 1<<WRANDR_TYPE_OOP_NEWMODE;
+
+		if (!request->newmode) {
+			request->newmode =
+				zalloc(sizeof(*(request->newmode)));
+			if (request->newmode == NULL) {
+				wl_resource_post_no_memory(resource);
+				return;
+			}
+			memset(request->newmode, 0x0,
+			       sizeof(*(request->newmode)));
+		}
+
+		request->newmode->width = width;
+		request->newmode->height = height;
+		request->newmode->refresh = refresh;
+	}
+}
+
+static int
+output_newtiming(struct wrandr *randr,
+		 struct wl_client *client,
+		 struct weston_output *output,
+		 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,
+		 int flags)
+{
+	struct weston_mode *mode;
+	struct wl_resource *resource;
+
+	if (!output->new_timing) {
+		weston_log("New timing is not supported!!\n");
+		return WRANDR_TYPE_RET_FAIL;
+	}
+
+	mode = randr_find_timing(output,
+				 clock,
+				 hdisplay,
+				 hsync_start,
+				 hsync_end,
+				 htotal,
+				 vdisplay,
+				 vsync_start,
+				 vsync_end,
+				 vtotal,
+				 vscan,
+				 flags);
+	if (mode) {
+		weston_log("New mode timing has existed!\n");
+		return WRANDR_TYPE_RET_NOACT;
+	}
+
+	mode = output->new_timing(output,
+				  clock,
+				  hdisplay,
+				  hsync_start,
+				  hsync_end,
+				  htotal,
+				  vdisplay,
+				  vsync_start,
+				  vsync_end,
+				  vtotal,
+				  vscan,
+				  flags);
+	if (mode) {
+		mode->flags |= WESTON_RANDR_MODE_CUSTOM;
+
+		/* Notify clients new mode. */
+		wl_resource_for_each(resource,
+				     &output->resource_list) {
+			wl_output_send_mode(resource,
+					    mode->flags,
+					    mode->width,
+					    mode->height,
+					    mode->refresh);
+			if (wl_resource_get_version(resource) >= 2)
+				wl_output_send_done(resource);
+		}
+
+		return WRANDR_TYPE_RET_SUCCESS;
+	}
+
+	return WRANDR_TYPE_RET_FAIL;
+}
+
+static void
+randr_newtiming(struct wl_client *client,
+	      struct wl_resource *resource,
+	      struct wl_resource *target_resource,
+	      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,
+	      int flags)
+{
+	struct weston_output *output =
+		wl_resource_get_user_data(target_resource);
+	struct randr_output_request *request;
+
+	request = get_orequest(client, resource, output, 1);
+	if (request) {
+		request->flags |= 1<<WRANDR_TYPE_OOP_NEWTIMING;
+
+		if (!request->newtiming) {
+			request->newtiming =
+				zalloc(sizeof(*(request->newtiming)));
+			if (request->newtiming == NULL) {
+				wl_resource_post_no_memory(resource);
+				return;
+			}
+		}
+
+		request->newtiming->clock = clock;
+		request->newtiming->hdisplay = hdisplay;
+		request->newtiming->hsync_start = hsync_start;
+		request->newtiming->hsync_end = hsync_end;
+		request->newtiming->htotal = htotal;
+		request->newtiming->vdisplay = vdisplay;
+		request->newtiming->vsync_start = vsync_start;
+		request->newtiming->vsync_end = vsync_end;
+		request->newtiming->vtotal = vtotal;
+		request->newtiming->vscan = vscan;
+		request->newtiming->flags = flags;
+	}
+}
+
+static void
+del_mode(struct weston_output *output, struct weston_mode *mode)
+{
+	struct wl_resource *resource;
+
+	mode->flags |= WESTON_RANDR_MODE_DEL;
+
+	wl_resource_for_each(resource, &output->resource_list) {
+		wl_output_send_mode(resource,
+				    mode->flags,
+				    mode->width,
+				    mode->height,
+				    mode->refresh);
+		if (wl_resource_get_version(resource) >= 2)
+			wl_output_send_done(resource);
+	}
+
+	wl_list_remove(&mode->link);
+	free(mode);
+}
+
+static int
+output_delmodenum(struct weston_output *output, int num)
+{
+	struct weston_mode *mode, *next;
+	int i = 0;
+	int found = 0;
+
+	wl_list_for_each_safe(mode, next, &output->mode_list, link) {
+		i++;
+		if (i != num)
+			continue;
+		found = 1;
+		if (mode->flags & WL_OUTPUT_MODE_CURRENT) {
+			weston_log("Don't delete active mode\n");
+			return WRANDR_TYPE_RET_FAIL;
+		}
+		del_mode(output, mode);
+		break;
+	}
+
+	if (found != 1)
+		return WRANDR_TYPE_RET_FAIL;
+
+	return WRANDR_TYPE_RET_SUCCESS;
+}
+
+static void
+randr_delmodenum(struct wl_client *client,
+		     struct wl_resource *resource,
+		     struct wl_resource *output_resource,
+		     int num)
+{
+	struct weston_output *output =
+		wl_resource_get_user_data(output_resource);
+	struct randr_output_request *request;
+
+	request = get_orequest(client, resource, output, 1);
+	if (request) {
+		request->flags |= 1<<WRANDR_TYPE_OOP_DELMODENUM;
+		request->delmodenum = num;
+	}
+}
+
+static int
+output_delmodes(struct weston_output *output,
+	       int width,
+	       int height,
+	       int refresh)
+{
+	struct weston_mode *mode, *next;
+	int found = 0;
+
+	/* Check if the mode is current active mode */
+	if (output->current_mode->width == width &&
+	    output->current_mode->height) {
+		if (!refresh ||
+		    refresh == (int) output->current_mode->refresh) {
+			weston_log("Could't delete active mode.\n");
+			return WRANDR_TYPE_RET_FAIL;
+		}
+	}
+
+	wl_list_for_each_safe(mode, next, &output->mode_list, link) {
+		if (mode->width == width && mode->height == height) {
+			if (!refresh ||
+			    refresh == (int)mode->refresh) {
+				found = 1;
+				del_mode(output, mode);
+			}
+		}
+	}
+
+	if (found != 1)
+		return WRANDR_TYPE_RET_FAIL;
+
+	return WRANDR_TYPE_RET_SUCCESS;
+}
+
+static void
+randr_delmode(struct wl_client *client,
+	      struct wl_resource *resource,
+	      struct wl_resource *target_resource,
+	      int width,
+	      int height,
+	      int refresh)
+{
+	struct weston_output *output =
+			wl_resource_get_user_data(target_resource);
+	struct randr_output_request *request;
+
+	request = get_orequest(client, resource, output, 1);
+	if (request) {
+		request->flags |= 1<<WRANDR_TYPE_OOP_DELMODE;
+
+		if (!request->delmode) {
+			request->delmode = zalloc(sizeof(*(request->delmode)));
+			if (request->delmode == NULL) {
+				wl_resource_post_no_memory(resource);
+				return;
+			}
+		}
+
+		request->delmode->width = width;
+		request->delmode->height = height;
+		request->delmode->refresh = refresh;
+	}
+}
+
+static void
+randr_output_commit(struct wrandr *randr,
+		    struct wl_client *client,
+		    struct randr_output_request *orequest,
+		    struct wl_resource *callback)
+{
+	struct wl_resource *output_resource;
+	struct wl_list *output_reslist = &orequest->output->resource_list;
+	struct weston_output *output = orequest->output;
+	uint64_t results = 0;
+	uint32_t result1 = 0;
+	int result = 0;
+
+	/* Process output pending orequests */
+	if (orequest->flags & 1<<WRANDR_TYPE_OOP_NEWTIMING) {
+		result = output_newtiming(randr, client, output,
+					  orequest->newtiming->clock,
+					  orequest->newtiming->hdisplay,
+					  orequest->newtiming->hsync_start,
+					  orequest->newtiming->hsync_end,
+					  orequest->newtiming->htotal,
+					  orequest->newtiming->vdisplay,
+					  orequest->newtiming->vsync_start,
+					  orequest->newtiming->vsync_end,
+					  orequest->newtiming->vtotal,
+					  orequest->newtiming->vscan,
+					  orequest->newtiming->flags);
+		results |= result<<(WRANDR_TYPE_OOP_NEWTIMING * 2);
+	}
+
+	if (orequest->flags & 1<<WRANDR_TYPE_OOP_NEWMODE) {
+		result = output_newmode(randr, client, output,
+					orequest->newmode->width,
+					orequest->newmode->height,
+					orequest->newmode->refresh);
+		results |= result<<(WRANDR_TYPE_OOP_NEWMODE * 2);
+	}
+
+	if (orequest->flags & 1<<WRANDR_TYPE_OOP_DELMODE) {
+		result = output_delmodes(output,
+					 orequest->delmode->width,
+					 orequest->delmode->height,
+					 orequest->delmode->refresh);
+		results |= result<<(WRANDR_TYPE_OOP_DELMODE * 2);
+	}
+
+	if (orequest->flags & 1<<WRANDR_TYPE_OOP_DELMODENUM) {
+		result = output_delmodenum(output,
+					   orequest->delmodenum);
+		results |= result<<(WRANDR_TYPE_OOP_DELMODENUM * 2);
+	}
+
+	if (orequest->flags & (
+	    1<<WRANDR_TYPE_OOP_MODENUM |
+	    1<<WRANDR_TYPE_OOP_MODE |
+	    1<<WRANDR_TYPE_OOP_TIMING |
+	    1<<WRANDR_TYPE_OOP_MOVEL |
+	    1<<WRANDR_TYPE_OOP_MOVER |
+	    1<<WRANDR_TYPE_OOP_MOVEA |
+	    1<<WRANDR_TYPE_OOP_MOVEB |
+	    1<<WRANDR_TYPE_OOP_CLONE |
+	    1<<WRANDR_TYPE_OOP_PRIMARY |
+	    1<<WRANDR_TYPE_OOP_SWITCH |
+	    1<<WRANDR_TYPE_OOP_SCALE |
+	    1<<WRANDR_TYPE_OOP_TRANSFORM))
+		results |= output_change(randr, orequest);
+
+	output_resource =
+		wl_resource_find_for_client(output_reslist, client);
+
+	result1 = results & 0xffffffff;
+	wrandr_callback_send_done(callback, output_resource,
+				  orequest->flags, result1, results>>32);
+}
+
+static void
+randr_configure(struct wl_client *client,
+		struct wl_resource *resource,
+		const char *config_file)
+{
+	struct randr_request *request;
+
+	request = get_request(client, resource, 1);
+	if (request) {
+		if (!request->config_file) {
+			request->flags |= 1<<WRANDR_TYPE_WOP_CONFIGURE;
+			request->config_file = strdup(config_file);
+		}
+	}
+}
+
+static struct weston_output *
+get_output(struct wrandr *randr, char *name)
+{
+	struct weston_compositor *ec = randr->compositor;
+	struct weston_output *output;
+
+	wl_list_for_each(output, &ec->output_list, link) {
+		if (strcmp(output->name, name) == 0)
+			return output;
+	}
+
+	return NULL;
+}
+
+static void
+str2flags(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 struct randr_timing *
+str2timing(char *timing_str)
+{
+	struct randr_timing *timing;
+	char flagstr[RANDR_NAMELEN];
+
+	timing = (struct randr_timing *)zalloc(sizeof(*timing));
+	if (timing == NULL) {
+		weston_log("No Memory is available\n");
+		return NULL;
+	}
+
+	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) {
+			weston_log("Invalid timing format!\n");
+			return NULL;
+	}
+
+	/* Get timing flags */
+	str2flags(&timing->flags, flagstr);
+	timing->modi_time = time(NULL);
+
+	return timing;
+}
+
+/* Verify configure request of weston compositor */
+static int
+weston_entry_verify(struct wrandr *randr,
+		    char *entry, char *value)
+{
+	int auto_output;
+
+	if (strcmp(entry, "auto") == 0) {
+		if (sscanf(value, "%d", &auto_output) != 1) {
+			weston_log("Malformed auto.\n");
+			return 1;
+		}
+		if (auto_output > 1 || auto_output < 0) {
+			weston_log("Malformed auto value.\n");
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+/* Check configure request of weston output */
+static int
+output_entry_verify(struct wrandr *randr,
+		    char *entry, char *value)
+{
+	int width = 0, height = 0, refresh = 0;
+	int scale, transform;
+	int switch_output, primary;
+	struct weston_output *output;
+	struct randr_timing *timing;
+
+	if (strcmp(entry, "mode") == 0) {
+		if (sscanf(value, "%dx%d@%d", &width, &height, &refresh) != 3) {
+			if (sscanf(value, "%dx%d", &width, &height) != 2) {
+				if (sscanf(value, "%d", &width) != 1) {
+					weston_log("Malformed mode.\n");
+					return 1;
+				}
+			}
+		}
+	}
+
+	if (strcmp(entry, "timing") == 0) {
+		timing = str2timing(value);
+		if (!timing)
+			return 1;
+
+		free(timing);
+	}
+
+	if (strcmp(entry, "switch") == 0) {
+		if (sscanf(value, "%d", &switch_output) != 1) {
+			weston_log("Malformed switch.\n");
+			return 1;
+		}
+
+		if (switch_output != 1 && switch_output != 0) {
+			weston_log("Malformed switch value.\n");
+			return 1;
+		}
+	}
+
+	if (strcmp(entry, "primary") == 0) {
+		if (sscanf(value, "%d", &primary) != 1) {
+			weston_log("Malformed primary.\n");
+			return 1;
+		}
+
+		if (primary != 1) {
+			weston_log("Malformed primary value.\n");
+			return 1;
+		}
+	}
+
+	if (strcmp(entry, "scale") == 0) {
+		if (sscanf(value, "%d", &scale) != 1) {
+			weston_log("Malformed scale.\n");
+			return 1;
+		}
+	}
+
+	if (strcmp(entry, "transform") == 0) {
+		if (sscanf(value, "%d", &transform) != 1) {
+			weston_log("Malformed transform.\n");
+			return 1;
+		}
+		if (transform < 0 || transform > 7) {
+			weston_log("Transform value should be [0-7].\n");
+			return 1;
+		}
+	}
+
+	if (strcmp(entry, "leftof") == 0 ||
+	    strcmp(entry, "rightof") == 0 ||
+	    strcmp(entry, "above") == 0 ||
+	    strcmp(entry, "below") == 0 ||
+	    strcmp(entry, "clone") == 0) {
+		output = get_output(randr, value);
+		if (!output) {
+			weston_log("%s:%s output doesn't exist.\n",
+				   entry, value);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static void
+weston_request_add(struct wrandr *randr,
+		   struct randr_request *request,
+		   char *entry, char *value)
+{
+	int auto_output;
+
+	if (strcmp(entry, "auto") == 0) {
+		sscanf(value, "%d", &auto_output);
+		if (auto_output == 1)
+			request->flags |= 1<<WRANDR_TYPE_WOP_AUTO;
+	}
+}
+
+static void
+output_request_add(struct wrandr *randr,
+		   struct randr_output_request *request,
+		   char *entry, char *value)
+{
+	int width = 0, height = 0, refresh = 0;
+	int scale, transform, modenum = 0;
+	int switch_output;
+	struct weston_output *output;
+	struct weston_mode *mode;
+
+	if (strcmp(entry, "mode") == 0) {
+		if (sscanf(value, "%dx%d@%d", &width, &height, &refresh) != 3)
+			if (sscanf(value, "%dx%d", &width, &height) != 2)
+				sscanf(value, "%d", &modenum);
+
+		if (modenum == 0)
+			set_mode(request, width, height, refresh);
+		else
+			set_modenum(request, modenum);
+
+		return;
+	}
+
+	if (strcmp(entry, "timing") == 0) {
+		request->flags |= 1<<WRANDR_TYPE_OOP_TIMING;
+		request->timing = str2timing(value);
+		if (!request->timing) {
+			weston_log("Failed to allocate memory for timing\n");
+			return;
+		}
+
+		/* Firstly check timing exist or not.
+		 * If exists, just set timing.
+		 * Otherwise, timing will be created and
+		 * then set it.
+		 */
+
+		mode = randr_find_timing(request->output,
+					 request->timing->clock,
+					 request->timing->hdisplay,
+					 request->timing->hsync_start,
+					 request->timing->hsync_end,
+					 request->timing->htotal,
+					 request->timing->vdisplay,
+					 request->timing->vsync_start,
+					 request->timing->vsync_end,
+					 request->timing->vtotal,
+					 request->timing->vscan,
+					 request->timing->flags);
+
+		if (!mode) {
+			request->flags |= 1<<WRANDR_TYPE_OOP_NEWTIMING;
+			request->newtiming = request->timing;
+		}
+
+		return;
+	}
+
+	if (strcmp(entry, "switch") == 0) {
+		sscanf(value, "%d", &switch_output);
+		output_switch(request, switch_output);
+	}
+
+	if (strcmp(entry, "primary") == 0)
+		set_primary(request);
+
+	if (strcmp(entry, "scale") == 0) {
+		sscanf(value, "%d", &scale);
+		set_scale(request, scale);
+		return;
+	}
+
+	if (strcmp(entry, "transform") == 0) {
+		sscanf(value, "%d", &transform);
+		set_transform(request, transform);
+		return;
+	}
+
+	if (strcmp(entry, "clone") == 0) {
+		output = get_output(randr, value);
+		set_clone(request, output);
+		return;
+	}
+
+	if (strcmp(entry, "leftof") == 0 ||
+	    strcmp(entry, "rightof") == 0 ||
+	    strcmp(entry, "above") == 0 ||
+	    strcmp(entry, "below") == 0) {
+		output = get_output(randr, value);
+		if (strcmp(entry, "leftof") == 0)
+			set_movement(request, output, MOVE_LEFTOF);
+		else if (strcmp(entry, "rightof") == 0)
+			set_movement(request, output, MOVE_RIGHTOF);
+		else if (strcmp(entry, "above") == 0)
+			set_movement(request, output, MOVE_ABOVE);
+		else if (strcmp(entry, "below") == 0)
+			set_movement(request, output, MOVE_BELOW);
+		return;
+	}
+}
+
+/* This function will convert config structure
+ * randr_request structure.
+ */
+static int
+config2request(struct wl_client *client,
+	       struct wl_resource *resource,
+	       struct randr_config *config)
+{
+	struct wrandr *randr =
+		wl_resource_get_user_data(resource);
+	struct weston_compositor *ec = randr->compositor;
+	struct randr_config_section *section, *next_s;
+	struct randr_config_entry *entry, *next_e;
+	struct randr_request *request;
+	struct randr_output_request *orequest;
+	struct weston_output *output;
+	int found = 0, result = 0;
+
+	if (config == NULL)
+		return WRANDR_TYPE_RET_FAIL;
+
+	/* Firstly make a whole check and return all the possible errors
+	 * in weston log and it will be helpful for user to address all
+	 * the issue at one time.
+	 */
+	wl_list_for_each_safe(section, next_s, &config->section_list, link) {
+		if (strcmp(section->name, "compositor") == 0) {
+			wl_list_for_each_safe(entry, next_e,
+					      &section->entry_list, link) {
+				result += weston_entry_verify(randr,
+							      entry->key,
+							      entry->value);
+			}
+			continue;
+		}
+
+		wl_list_for_each(output, &ec->output_list, link) {
+			if (strcmp(output->name, section->name) == 0) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (found == 0) {
+			result += 1;
+			weston_log("Output:%s does not exist!\n",
+				   section->name);
+			continue;
+		}
+
+		wl_list_for_each_safe(entry, next_e,
+				      &section->entry_list, link) {
+			result += output_entry_verify(randr,
+						      entry->key,
+						      entry->value);
+		}
+	}
+
+	if (result >= 1) {
+		weston_log("Your configure file has some errors!\n");
+		return WRANDR_TYPE_RET_FAIL;
+	}
+
+	request = get_request(client, resource, 1);
+	wl_list_for_each_safe(section, next_s, &config->section_list, link) {
+		/* Get the output name */
+		if (strcmp(section->name, "compositor") == 0) {
+			/* Currently no global setting */
+			wl_list_for_each_safe(entry,
+					      next_e,
+					      &section->entry_list, link) {
+				weston_request_add(randr, request,
+						   entry->key, entry->value);
+			}
+			continue;
+		}
+
+		wl_list_for_each(output, &ec->output_list, link)
+			if (strcmp(output->name, section->name) == 0)
+				break;
+
+		orequest = get_orequest(client, resource, output, 1);
+
+		wl_list_for_each_safe(entry,
+				      next_e,
+				      &section->entry_list, link) {
+			output_request_add(randr, orequest,
+					   entry->key, entry->value);
+		}
+	}
+
+	return WRANDR_TYPE_RET_SUCCESS;
+}
+
+static int
+parse_config_file(struct wl_client *client,
+		  struct wl_resource *resource,
+		  char *config_file)
+{
+	int result = 0;
+	struct randr_config *config;
+
+	config = randr_config_parse(config_file);
+
+	if (!config)
+		result = WRANDR_TYPE_RET_FAIL;
+	else {
+		result = config2request(client, resource, config);
+		randr_config_destroy(config);
+	}
+
+	return result<<(WRANDR_TYPE_WOP_CONFIGURE * 2);
+}
+
+static void
+randr_commit(struct wl_client *client,
+	     struct wl_resource *resource,
+	     uint32_t callback)
+{
+	struct wrandr *randr =
+		wl_resource_get_user_data(resource);
+	struct weston_compositor *ec = randr->compositor;
+	struct randr_request *request;
+	struct randr_output_request *orequest, *next;
+	struct wl_resource *cb;
+	uint64_t result = 0;
+	uint64_t results = 0;
+	uint64_t result1 = 0;
+
+	request = get_request(client, resource, 0);
+	if (!request) {
+		weston_log("No memory happens when commit?!\n");
+		return;
+	}
+
+	cb = wl_resource_create(client, &wrandr_callback_interface, 1,
+				callback);
+
+	if (cb == NULL) {
+		free(request);
+		wl_resource_post_no_memory(resource);
+		return;
+	}
+
+	if (request->flags & 1<<WRANDR_TYPE_WOP_AUTO) {
+		result = compositor_layout_init(ec);
+		results |= result << (WRANDR_TYPE_WOP_AUTO * 2);
+	}
+
+	if (request->flags & 1<<WRANDR_TYPE_WOP_CONFIGURE) {
+		results |= parse_config_file(client,
+					     resource,
+					     request->config_file);
+	}
+
+	wl_list_for_each_safe(orequest, next,
+			      &request->output_request_list, link)
+		randr_output_commit(randr, client, orequest, cb);
+
+	result1 = results & 0xffffffff;
+	wrandr_callback_send_done(cb, NULL,
+				  request->flags, result1, results>>32);
+	del_request(request);
+	wl_resource_destroy(cb);
+}
+
+static const struct weston_randr_interface randr_interface = {
+	randr_destroy,
+	randr_set_modenum,
+	randr_set_mode,
+	randr_set_timing,
+	randr_set_transform,
+	randr_set_scale,
+	randr_move,
+	randr_delmodenum,
+	randr_delmode,
+	randr_newmode,
+	randr_newtiming,
+	randr_configure,
+	randr_clone,
+	randr_auto,
+	randr_primary,
+	randr_switch_output,
+	randr_commit
+};
+
+static void
+bind_randr(struct wl_client *client,
+	   void *data, uint32_t version, uint32_t id)
+{
+	struct wrandr *randr = data;
+
+	randr->resource = wl_resource_create(client,
+					     &weston_randr_interface,
+					     1, id);
+
+	if (randr->resource == NULL) {
+		wl_client_post_no_memory(client);
+		return;
+	}
+
+	wl_resource_set_implementation(randr->resource,
+				       &randr_interface,
+				       randr, NULL);
+
+}
+
+static void
+handle_randr_destroy(struct wl_listener *listener, void *data)
+{
+	struct wrandr *randr =
+		container_of(listener, struct wrandr, destroy_listener);
+	struct randr_request *request;
+
+	if (randr) {
+		if (randr->global)
+			wl_global_destroy(randr->global);
+
+		wl_list_for_each(request, &randr->pending.request_list, link)
+			del_request(request);
+
+		free(randr);
+	}
+}
+
+static void
+weston_randr_init(struct weston_compositor *ec)
+{
+	ec->randr = zalloc(sizeof *(ec->randr));
+	if (!ec->randr) {
+		weston_log("No memory for wrandr in backend compositor.\n");
+		return;
+	}
+	memset(ec->randr, 0, sizeof *(ec->randr));
+
+	ec->randr->compositor = ec;
+
+	ec->randr->global = wl_global_create(ec->wl_display,
+					 &weston_randr_interface, 1,
+					 ec->randr, bind_randr);
+
+	if (ec->randr->global == NULL) {
+		weston_log("Failed to create global weston_randr_interface.\n");
+		return;
+	}
+
+	wl_list_init(&ec->randr->pending.request_list);
+}
+
+WL_EXPORT int
+module_init(struct weston_compositor *ec,
+	    int *argc, char *argv[])
+{
+	weston_randr_init(ec);
+	if (!ec->randr) {
+		weston_log("Failed to initialize wrandr module.\n");
+		return -1;
+	}
+	ec->randr->destroy_listener.notify = handle_randr_destroy;
+	wl_signal_add(&ec->destroy_signal, &ec->randr->destroy_listener);
+
+	return 0;
+}
diff --git a/module/wrandr/wrandr.h b/module/wrandr/wrandr.h
new file mode 100644
index 0000000..909f8f9
--- /dev/null
+++ b/module/wrandr/wrandr.h
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+#ifndef WRANDR_H
+#define WRANDR_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include "compositor.h"
+#include "randr-server-protocol.h"
+#include "randr_parser.h"
+#include "randr_layout_algorithm.h"
+
+#define RESULT_MASK 0x3
+
+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
+};
+
+struct randr_mode {
+	int width;
+	int height;
+	int refresh;
+	time_t modi_time;
+};
+
+struct randr_timing {
+	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 flags;
+	time_t modi_time;
+};
+
+struct randr_request {
+	struct wl_list link;
+	struct wl_client *client;
+	struct wl_list output_request_list;
+	char *config_file;
+	int flags;
+};
+
+struct randr_movement {
+	struct wl_list link;
+	struct weston_output *output;
+	time_t modi_time;
+	int direction;
+	int flag;
+};
+
+struct randr_output_request {
+	struct wl_list link;
+	struct weston_output *output;
+	int flags;
+
+	struct randr_movement leftof;
+	struct randr_movement rightof;
+	struct randr_movement above;
+	struct randr_movement below;
+	struct randr_movement primary;
+	struct randr_movement clone;
+
+	struct randr_mode *mode;
+	struct randr_timing *timing;
+
+	struct {
+		time_t modi_time;
+		int num;
+	} modenum;
+
+	int delmodenum;
+	struct randr_mode *delmode;
+
+	int scale;
+	int switch_output;
+	int32_t transform;
+	struct randr_mode *newmode;
+	struct randr_timing *newtiming;
+};
+
+void
+adjust_pointer(struct weston_output *output,
+	       pixman_region32_t *old_output_region);
+
+void
+notify_change(struct weston_output *output,
+	      int mode_changed,
+	      int scale_changed,
+	      int transform_changed);
+
+#endif
-- 
1.8.1.2



More information about the wayland-devel mailing list