[PATCH V2 5/8] weston:Add the weston randr protocol implementation

Quanxian Wang quanxian.wang at intel.com
Mon Mar 24 04:39:17 PDT 2014


Signed-off-by: Quanxian Wang <quanxian.wang at intel.com>
---
 module/Makefile.am        |   3 +
 module/wrandr/Makefile.am |  32 ++
 module/wrandr/wrandr.c    | 792 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 827 insertions(+)
 create mode 100644 module/Makefile.am
 create mode 100644 module/wrandr/Makefile.am
 create mode 100644 module/wrandr/wrandr.c

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..b0f2e6b
--- /dev/null
+++ b/module/wrandr/Makefile.am
@@ -0,0 +1,32 @@
+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				\
+	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/wrandr.c b/module/wrandr/wrandr.c
new file mode 100644
index 0000000..b97d101
--- /dev/null
+++ b/module/wrandr/wrandr.c
@@ -0,0 +1,792 @@
+/*
+ * Copyright © 2012-2013 Collabora, Ltd.
+
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "compositor.h"
+#include "randr-server-protocol.h"
+
+#define RESULT_MASK 0x3
+
+struct randr_request {
+	struct wl_list link;
+	int flags;
+	struct wl_resource *callback;
+
+	/* Client and output compose unique id
+	 * of these request.*/
+	struct wl_client *client;
+	struct weston_output *output;
+
+	/* output move */
+	struct weston_output *loutput;
+	struct weston_output *routput;
+
+	/* mode set */
+	int height;
+	int width;
+	int refresh;
+
+	int scale;
+	int32_t transform;
+
+	struct {
+		int clock;
+		int hdisplay;
+		int hsync_start;
+		int hsync_end;
+		int htotal;
+		int vdisplay;
+		int vsync_start;
+		int vsync_end;
+		int vtotal;
+		char *hsync;
+		char *vsync;
+	} newmode;
+
+	struct {
+		int height;
+		int width;
+		int refresh;
+	} delmode;
+};
+
+static void
+del_request(struct randr_request *request)
+{
+	wl_list_remove(&request->link);
+
+	if (request->callback)
+		wl_resource_destroy(request->callback);
+
+	if (request->newmode.hsync)
+		free(request->newmode.hsync);
+
+	if (request->newmode.vsync)
+		free(request->newmode.vsync);
+
+	free(request);
+}
+
+static struct randr_request *
+get_request(struct wl_resource *resource,
+	    struct wl_client *client,
+	    struct weston_output *output,
+	    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 &&
+		    request->output == output)
+			return request;
+	}
+
+	if (create) {
+		request = zalloc(sizeof(*request));
+		if (request == NULL) {
+			wl_resource_post_no_memory(resource);
+			return NULL;
+		}
+		memset(request, 0x0, sizeof(*request));
+
+		request->client = client;
+		request->output = output;
+		wl_list_insert(&randr->pending.request_list, &request->link);
+		return request;
+	} else
+		return NULL;
+}
+
+static 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);
+	}
+}
+
+static 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);
+	}
+}
+
+static void
+randr_destroy(struct wl_client *client,
+	      struct wl_resource *resource)
+{
+	wl_resource_destroy(resource);
+	return;
+}
+
+static struct weston_mode *
+randr_found_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 void
+update_region(struct weston_compositor *ec,
+	      struct weston_output *target_output)
+{
+	pixman_region32_t old_output_region;
+
+	/* Update output region and transformation matrix. */
+	pixman_region32_init(&old_output_region);
+	pixman_region32_copy(&old_output_region, &target_output->region);
+	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);
+
+	adjust_pointer(target_output, &old_output_region);
+	pixman_region32_fini(&old_output_region);
+
+	/* 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 int32_t
+randr_modeset(struct wrandr *randr,
+	      struct randr_request *request)
+{
+	struct weston_compositor *ec = randr->compositor;
+	struct weston_output *output = NULL;
+	struct weston_mode *mode = NULL;
+	int move = 0, offset = 0;
+	uint32_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;
+
+	/* Mode Setting Operation */
+	if (request->width > 0 && request->height > 0) {
+		mode = randr_found_mode(toutput,
+					request->width,
+					request->height,
+					request->refresh);
+
+		if (!mode)
+			result = WRANDR_CALLBACK_RESULT_FAIL;
+		else {
+			if (!(mode->flags & WL_OUTPUT_MODE_CURRENT) &&
+			    toutput->switch_mode) {
+				result = toutput->switch_mode(toutput, mode);
+				if (result < 0)
+					result = WRANDR_CALLBACK_RESULT_FAIL;
+				else
+					result = WRANDR_CALLBACK_RESULT_SUCCESS;
+			} else
+				result = WRANDR_CALLBACK_RESULT_NOACT;
+		}
+
+		results |= result<<(WRANDR_CALLBACK_ACTION_MODE * 2);
+	}
+
+	/* Transform Operation */
+	if (request->transform >= 0) {
+		if ((uint32_t)request->transform != toutput->transform) {
+			toutput->transform = (uint32_t)request->transform;
+			result = WRANDR_CALLBACK_RESULT_SUCCESS;
+		} else
+			result = WRANDR_CALLBACK_RESULT_NOACT;
+
+		results |= result<<(WRANDR_CALLBACK_ACTION_TRANSFORM * 2);
+	}
+
+	/* Scale Operation */
+	if (request->scale > 0) {
+		if (request->scale && request->scale !=
+		    toutput->current_scale) {
+			toutput->current_scale = request->scale;
+			result = WRANDR_CALLBACK_RESULT_SUCCESS;
+		} else
+			result = WRANDR_CALLBACK_RESULT_NOACT;
+
+		results |= result<<(WRANDR_CALLBACK_ACTION_SCALE * 2);
+	}
+
+	/* Move Operation */
+	if (request->loutput || request->routput) {
+		if (request->loutput == toutput ||
+		    request->routput == toutput)
+			result = WRANDR_CALLBACK_RESULT_FAIL;
+		else {
+			if (request->loutput &&
+			    &toutput->link !=
+			    request->loutput->link.prev) {
+				wl_list_remove(&toutput->link);
+				wl_list_insert(request->loutput->link.prev,
+					       &toutput->link);
+				move = 1;
+			}
+
+			if (request->routput &&
+			    &toutput->link !=
+			    request->routput->link.next) {
+				wl_list_remove(&toutput->link);
+				wl_list_insert(&request->routput->link,
+					       &toutput->link);
+				move = 1;
+			}
+
+			if (move != 1)
+				result = WRANDR_CALLBACK_RESULT_NOACT;
+			else
+				result = WRANDR_CALLBACK_RESULT_SUCCESS;
+		}
+		results |= result<<(WRANDR_CALLBACK_ACTION_MOVE * 2);
+	}
+
+	/* Check if any action to be done. */
+	mode_change = (results>>(WRANDR_CALLBACK_ACTION_MODE * 2) &
+		      RESULT_MASK) == WRANDR_CALLBACK_RESULT_SUCCESS;
+	scale_change = (results>>(WRANDR_CALLBACK_ACTION_SCALE * 2) &
+		       RESULT_MASK) == WRANDR_CALLBACK_RESULT_SUCCESS;
+	trans_change = (results>>(WRANDR_CALLBACK_ACTION_TRANSFORM * 2) &
+		       RESULT_MASK) == WRANDR_CALLBACK_RESULT_SUCCESS;
+	move_change = (results>>(WRANDR_CALLBACK_ACTION_MOVE * 2) &
+		       RESULT_MASK) == WRANDR_CALLBACK_RESULT_SUCCESS;
+
+	if (!move_change && !scale_change &&
+	    !trans_change && !mode_change)
+		return results;
+
+	update_region(randr->compositor, toutput);
+
+	/* Adjust all outputs. */
+	wl_list_for_each(output, &ec->output_list, link) {
+		weston_output_move(output, offset, 0);
+		offset += output->width;
+		pixman_region32_union(&randr->compositor->primary_plane.damage,
+				      &randr->compositor->primary_plane.damage,
+				      &output->region);
+	}
+
+	/* Notify clients of the changes. */
+	notify_change(toutput, mode_change,
+		      scale_change, trans_change);
+
+	return results;
+}
+
+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_request *request;
+
+	request = get_request(resource, client, output, 1);
+	if (request) {
+		request->flags |= 1<<WRANDR_CALLBACK_ACTION_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_request *request;
+
+	request = get_request(resource, client, output, 1);
+	if (request) {
+		request->flags |= 1<<WRANDR_CALLBACK_ACTION_TRANSFORM;
+		request->transform = transform % 8;
+	}
+}
+
+static void
+randr_start(struct wl_client *client,
+	    struct wl_resource *resource,
+	    struct wl_resource *output_resource,
+	    uint32_t callback)
+{
+	struct weston_output *output =
+		wl_resource_get_user_data(output_resource);
+	struct randr_request *request;
+
+	request = get_request(resource, client, output, 1);
+	if (!request) {
+		wl_resource_post_no_memory(resource);
+		return;
+	}
+
+	request->callback =
+		wl_resource_create(client, &wrandr_callback_interface, 1,
+				   callback);
+	if (request->callback == NULL) {
+		free(request);
+		wl_resource_post_no_memory(request->callback);
+		return;
+	}
+}
+
+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_request *request;
+
+	request = get_request(resource, client, output, 1);
+	if (request) {
+		request->flags |= 1<<WRANDR_CALLBACK_ACTION_MODE;
+		request->width = width;
+		request->height = height;
+		request->refresh = refresh;
+	}
+}
+
+static void
+randr_move(struct wl_client *client,
+	   struct wl_resource *resource,
+	   struct wl_resource *target_resource,
+	   struct wl_resource *source_resource, int move)
+{
+	struct weston_output *output =
+		wl_resource_get_user_data(target_resource);
+	struct randr_request *request;
+
+	request = get_request(resource, client, output, 1);
+	if (request) {
+		request->flags |= 1<<WRANDR_CALLBACK_ACTION_MOVE;
+		if (move == WESTON_RANDR_MOVE_LEFTOF) {
+			request->loutput =
+				wl_resource_get_user_data(source_resource);
+		} else {
+			request->routput =
+				wl_resource_get_user_data(source_resource);
+		}
+	}
+}
+
+static int
+output_newmode(struct weston_output *output,
+	       int clock,
+	       int hdisplay,
+	       int hsync_start,
+	       int hsync_end,
+	       int htotal,
+	       int vdisplay,
+	       int vsync_start,
+	       int vsync_end,
+	       int vtotal,
+	       const char *hsync,
+	       const char *vsync)
+{
+	struct weston_mode *mode = NULL;
+	struct wl_resource *resource;
+	uint64_t refresh;
+
+	if ((strcmp(hsync, "+hsync") != 0 &&
+	    strcmp(hsync, "-hsync") != 0) ||
+	    (strcmp(vsync, "+vsync") != 0 &&
+	    strcmp(vsync, "-vsync") != 0)) {
+		weston_log("Invalid hsync format:%s.\n", hsync);
+		return WRANDR_CALLBACK_RESULT_FAIL;
+	}
+
+	/* Calculate higher precision (mHz) refresh rate */
+	refresh = (clock * 1000 * 1000000LL / htotal +
+		   vtotal / 2) / vtotal;
+
+	/* Same width, height and refresh in mode list */
+	mode = randr_found_mode(output, hdisplay, vdisplay, refresh);
+	if (mode)
+		return WRANDR_CALLBACK_RESULT_NOACT;
+
+	if (output->new_mode) {
+		mode = output->new_mode(output,
+					clock,
+					hdisplay,
+					hsync_start,
+					hsync_end,
+					htotal,
+					vdisplay,
+					vsync_start,
+					vsync_end,
+					vtotal,
+					hsync,
+					vsync);
+		if (mode) {
+			mode->flags |= WESTON_RANDR_MODE_CUSTOM;
+			/* Notify clients of the change. */
+			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_CALLBACK_RESULT_SUCCESS;
+		}
+	}
+
+	return WRANDR_CALLBACK_RESULT_FAIL;
+}
+
+static void
+randr_newmode(struct wl_client *client,
+	      struct wl_resource *resource,
+	      struct wl_resource *target_resource,
+	      int clock,
+	      int hdisplay,
+	      int hsync_start,
+	      int hsync_end,
+	      int htotal,
+	      int vdisplay,
+	      int vsync_start,
+	      int vsync_end,
+	      int vtotal,
+	      const char *hsync,
+	      const char *vsync)
+{
+	struct weston_output *output =
+		wl_resource_get_user_data(target_resource);
+	struct randr_request *request;
+
+	request = get_request(resource, client, output, 1);
+	if (request) {
+		request->flags |= 1<<WRANDR_CALLBACK_ACTION_NEWMODE;
+		request->newmode.clock = clock;
+		request->newmode.hdisplay = hdisplay;
+		request->newmode.hsync_start = hsync_start;
+		request->newmode.hsync_end = hsync_end;
+		request->newmode.htotal = htotal;
+		request->newmode.vdisplay = vdisplay;
+		request->newmode.vsync_start = vsync_start;
+		request->newmode.vsync_end = vsync_end;
+		request->newmode.vtotal = vtotal;
+		request->newmode.hsync = strdup(hsync);
+		request->newmode.vsync = strdup(vsync);
+	}
+}
+
+static int
+output_delmode(struct weston_output *output,
+	       int width,
+	       int height,
+	       int refresh)
+{
+	struct wl_resource *resource;
+	struct weston_mode *mode =
+		randr_found_mode(output, width, height, refresh);
+
+	if (!mode)
+		return WRANDR_CALLBACK_RESULT_FAIL;
+	else {
+		mode->flags |= WESTON_RANDR_MODE_DEL;
+		/* Notify clients of the change. */
+		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);
+		return WRANDR_CALLBACK_RESULT_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_request *request;
+
+	request = get_request(resource, client, output, 1);
+	if (request) {
+		request->flags |= 1<<WRANDR_CALLBACK_ACTION_DELMODE;
+		request->delmode.width = width;
+		request->delmode.height = height;
+		request->delmode.refresh = refresh;
+	}
+}
+
+static void
+randr_commit(struct wl_client *client,
+	     struct wl_resource *resource,
+	     struct wl_resource *target_resource)
+{
+	struct wrandr *randr = wl_resource_get_user_data(resource);
+	struct weston_output *output =
+		wl_resource_get_user_data(target_resource);
+	struct randr_request *request;
+	int results = 0;
+	int result = 0;
+
+	/* process pending request for this client */
+	request = get_request(resource, client, output, 0);
+	if (!request) {
+		weston_log("No action happens when commit?!\n");
+	} else {
+		if (request->flags & 1<<WRANDR_CALLBACK_ACTION_NEWMODE) {
+			result = output_newmode(output,
+						request->newmode.clock,
+						request->newmode.hdisplay,
+						request->newmode.hsync_start,
+						request->newmode.hsync_end,
+						request->newmode.htotal,
+						request->newmode.vdisplay,
+						request->newmode.vsync_start,
+						request->newmode.vsync_end,
+						request->newmode.vtotal,
+						request->newmode.hsync,
+						request->newmode.vsync);
+			results |= result<<(WRANDR_CALLBACK_ACTION_NEWMODE * 2);
+		}
+
+		if (request->flags & 1<<WRANDR_CALLBACK_ACTION_DELMODE) {
+			result = output_delmode(output,
+						request->delmode.width,
+						request->delmode.height,
+						request->delmode.refresh);
+			results |= result<<(WRANDR_CALLBACK_ACTION_DELMODE * 2);
+		}
+
+		if (request->width || request->height ||
+		    request->scale || request->transform >= 0 ||
+		    request->loutput || request->routput)
+			results |= randr_modeset(randr, request);
+	}
+
+	wrandr_callback_send_done(request->callback,
+				  request->flags, results);
+	del_request(request);
+}
+
+static const struct weston_randr_interface randr_interface = {
+	randr_destroy,
+	randr_start,
+	randr_set_mode,
+	randr_set_transform,
+	randr_set_scale,
+	randr_move,
+	randr_delmode,
+	randr_newmode,
+	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)
+{
+	/* Initialize randr */
+	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_list_init(&ec->randr->pending.randr_callback_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;
+}
-- 
1.8.1.2



More information about the wayland-devel mailing list