[RFC] [PATCH weston v3] Implement output transformations.

Scott Moreau oreaus at gmail.com
Sat Aug 18 00:04:05 PDT 2012


This patch allows rotation and mirroring outputs for x11 and drm backends.
A new 'transform' key can be set in the [output] section. From the protocol:

"The flipped values correspond to an initial flip around a vertical axis
followed by rotation."

The transform key can be one of the following 8 strings:

normal
90
180
270
flipped
flipped-90
flipped-180
flipped-270

---
Hi Kristian,

Here is version 3 of this patch. There are some memory management changes to allow
for specifying either a mode or transform but mostly I added some paranoid checking
to avoid issues on shutdown in drm.

Changed in v3:

- Fixed zoom for transformed outputs
- Fixed config parsing
- Fixed output position for x11 backend
- Pulled in your fixes for not changing mode values
- Used your transform matrix algorithm

Screenshot seems to work for single output but for multiple output, it's a little
broken. Either the pixels written to the buffer need to be untransformed (in fact
this is what it computes the buffer size as) or screenshot needs to (re)build its
output list and recompute the offsets. I wrote some code to do the former but it
only works if only the first output is transformed. For the latter, it seems like
it would be useful to have an output list with the right offsets built upfront,
not sure. wcap doesn't work with transforms but I think you know why. Maybe we
could do some trick in screenshooter.c to handle these cases.

 src/compositor-android.c |   3 +-
 src/compositor-drm.c     | 112 +++++++++++++++++-------
 src/compositor-wayland.c |   3 +-
 src/compositor-x11.c     | 216 +++++++++++++++++++++++++++++++++++++----------
 src/compositor.c         | 110 +++++++++++++++++++++---
 src/compositor.h         |   5 +-
 src/shell.c              |  49 ++++++-----
 src/zoom.c               |  55 +++++++++++-
 weston.ini               |   3 +
 9 files changed, 438 insertions(+), 118 deletions(-)

diff --git a/src/compositor-android.c b/src/compositor-android.c
index a9c45d2..b095262 100644
--- a/src/compositor-android.c
+++ b/src/compositor-android.c
@@ -238,7 +238,8 @@ android_compositor_add_output(struct android_compositor *compositor,
 	mm_width  = output->fb->width / output->fb->xdpi * 25.4f;
 	mm_height = output->fb->height / output->fb->ydpi * 25.4f;
 	weston_output_init(&output->base, &compositor->base,
-			   0, 0, round(mm_width), round(mm_height));
+			   0, 0, round(mm_width), round(mm_height),
+			   WL_OUTPUT_TRANSFORM_NORMAL);
 	wl_list_insert(compositor->base.output_list.prev, &output->base.link);
 }
 
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 8c8c8c0..69aa4d1 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -46,6 +46,7 @@
 static int option_current_mode = 0;
 static char *output_name;
 static char *output_mode;
+static char *output_transform;
 static struct wl_list configured_output_list;
 
 enum output_config {
@@ -60,6 +61,7 @@ enum output_config {
 struct drm_configured_output {
 	char *name;
 	char *mode;
+	uint32_t transform;
 	int32_t width, height;
 	drmModeModeInfo crtc_mode;
 	enum output_config config;
@@ -1434,7 +1436,8 @@ create_output_for_connector(struct drm_compositor *ec,
 
 	wl_list_for_each(temp, &configured_output_list, link) {
 		if (strcmp(temp->name, output->name) == 0) {
-			weston_log("%s mode \"%s\" in config\n",
+			if (temp->mode)
+				weston_log("%s mode \"%s\" in config\n",
 							temp->name, temp->mode);
 			o = temp;
 			break;
@@ -1450,9 +1453,9 @@ create_output_for_connector(struct drm_compositor *ec,
 	}
 
 	wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
-		if (o && o->width == drm_mode->base.width &&
-			o->height == drm_mode->base.height &&
-			o->config == OUTPUT_CONFIG_MODE)
+		if (o && o->config == OUTPUT_CONFIG_MODE &&
+			o->width == drm_mode->base.width &&
+			o->height == drm_mode->base.height)
 			configured = drm_mode;
 		if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
 			current = drm_mode;
@@ -1528,7 +1531,8 @@ create_output_for_connector(struct drm_compositor *ec,
 	}
 
 	weston_output_init(&output->base, &ec->base, x, y,
-			   connector->mmWidth, connector->mmHeight);
+			   connector->mmWidth, connector->mmHeight,
+			   o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
 
 	wl_list_insert(ec->base.output_list.prev, &output->base.link);
 
@@ -1695,7 +1699,7 @@ create_outputs(struct drm_compositor *ec, uint32_t option_connector,
 
 			x += container_of(ec->base.output_list.prev,
 					  struct weston_output,
-					  link)->current->width;
+					  link)->width;
 		}
 
 		drmModeFreeConnector(connector);
@@ -1751,7 +1755,7 @@ update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
 
 			/* XXX: not yet needed, we die with 0 outputs */
 			if (!wl_list_empty(&ec->base.output_list))
-				x = last->x + last->current->width;
+				x = last->x + last->width;
 			else
 				x = 0;
 			y = 0;
@@ -1779,7 +1783,7 @@ update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
 				disconnects &= ~(1 << output->connector_id);
 				weston_log("connector %d disconnected\n",
 				       output->connector_id);
-				x_offset += output->base.current->width;
+				x_offset += output->base.width;
 				drm_output_destroy(&output->base);
 			}
 		}
@@ -2069,7 +2073,8 @@ static void
 drm_free_configured_output(struct drm_configured_output *output)
 {
 	free(output->name);
-	free(output->mode);
+	if (output->mode)
+		free(output->mode);
 	free(output);
 }
 
@@ -2412,17 +2417,57 @@ check_for_modeline(struct drm_configured_output *output)
 }
 
 static void
+drm_output_set_transform(struct drm_configured_output *output)
+{
+	if (!output_transform) {
+		output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
+		return;
+	}
+
+	if (!strcmp(output_transform, "normal"))
+		output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
+	else if (!strcmp(output_transform, "90"))
+		output->transform = WL_OUTPUT_TRANSFORM_90;
+	else if (!strcmp(output_transform, "180"))
+		output->transform = WL_OUTPUT_TRANSFORM_180;
+	else if (!strcmp(output_transform, "270"))
+		output->transform = WL_OUTPUT_TRANSFORM_270;
+	else if (!strcmp(output_transform, "flipped"))
+		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
+	else if (!strcmp(output_transform, "flipped-90"))
+		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
+	else if (!strcmp(output_transform, "flipped-180"))
+		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
+	else if (!strcmp(output_transform, "flipped-270"))
+		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
+	else {
+		weston_log("Invalid transform \"%s\" for output %s\n",
+						output_transform, output_name);
+		output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
+	}
+
+	free(output_transform);
+	output_transform = NULL;
+}
+
+static void
 output_section_done(void *data)
 {
 	struct drm_configured_output *output;
 
 	output = malloc(sizeof *output);
 
-	if (!output || !output_name || !output_mode) {
-		free(output_name);
+	if (!output || !output_name || (output_name[0] == 'X') ||
+					(!output_mode && !output_transform)) {
+		if (output_name)
+			free(output_name);
+		if (output_mode)
+			free(output_mode);
+		if (output_transform)
+			free(output_transform);
 		output_name = NULL;
-		free(output_mode);
 		output_mode = NULL;
+		output_transform = NULL;
 		return;
 	}
 
@@ -2430,24 +2475,32 @@ output_section_done(void *data)
 	output->name = output_name;
 	output->mode = output_mode;
 
-	if (strcmp(output_mode, "off") == 0)
-		output->config = OUTPUT_CONFIG_OFF;
-	else if (strcmp(output_mode, "preferred") == 0)
-		output->config = OUTPUT_CONFIG_PREFERRED;
-	else if (strcmp(output_mode, "current") == 0)
-		output->config = OUTPUT_CONFIG_CURRENT;
-	else if (sscanf(output_mode, "%dx%d", &output->width, &output->height) == 2)
-		output->config = OUTPUT_CONFIG_MODE;
-	else if (check_for_modeline(output) == 0)
-		output->config = OUTPUT_CONFIG_MODELINE;
-
-	if (output->config != OUTPUT_CONFIG_INVALID)
-		wl_list_insert(&configured_output_list, &output->link);
-	else {
-		weston_log("Invalid mode \"%s\" for output %s\n",
-						output_mode, output_name);
-		drm_free_configured_output(output);
+	if (output_mode) {
+		if (strcmp(output_mode, "off") == 0)
+			output->config = OUTPUT_CONFIG_OFF;
+		else if (strcmp(output_mode, "preferred") == 0)
+			output->config = OUTPUT_CONFIG_PREFERRED;
+		else if (strcmp(output_mode, "current") == 0)
+			output->config = OUTPUT_CONFIG_CURRENT;
+		else if (sscanf(output_mode, "%dx%d",
+					&output->width, &output->height) == 2)
+			output->config = OUTPUT_CONFIG_MODE;
+		else if (check_for_modeline(output) == 0)
+			output->config = OUTPUT_CONFIG_MODELINE;
+
+		if (output->config == OUTPUT_CONFIG_INVALID)
+			weston_log("Invalid mode \"%s\" for output %s\n",
+							output_mode, output_name);
+		output_mode = NULL;
 	}
+
+	drm_output_set_transform(output);
+
+	wl_list_insert(&configured_output_list, &output->link);
+
+	if (output_transform)
+		free(output_transform);
+	output_transform = NULL;
 }
 
 WL_EXPORT struct weston_compositor *
@@ -2471,6 +2524,7 @@ backend_init(struct wl_display *display, int argc, char *argv[],
 	const struct config_key drm_config_keys[] = {
 		{ "name", CONFIG_KEY_STRING, &output_name },
 		{ "mode", CONFIG_KEY_STRING, &output_mode },
+		{ "transform", CONFIG_KEY_STRING, &output_transform },
 	};
 
 	const struct config_section config_section[] = {
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index 4fc77f1..84eaf6c 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -395,7 +395,8 @@ wayland_compositor_create_output(struct wayland_compositor *c,
 	wl_list_insert(&output->base.mode_list, &output->mode.link);
 
 	output->base.current = &output->mode;
-	weston_output_init(&output->base, &c->base, 0, 0, width, height);
+	weston_output_init(&output->base, &c->base, 0, 0, width, height,
+						WL_OUTPUT_TRANSFORM_NORMAL);
 
 	output->base.border.top = c->border.top;
 	output->base.border.bottom = c->border.bottom;
diff --git a/src/compositor-x11.c b/src/compositor-x11.c
index c02911d..319ad3a 100644
--- a/src/compositor-x11.c
+++ b/src/compositor-x11.c
@@ -52,6 +52,7 @@
 
 static char *output_name;
 static char *output_mode;
+static char *output_transform;
 static int option_width;
 static int option_height;
 static int option_count;
@@ -60,6 +61,7 @@ static struct wl_list configured_output_list;
 struct x11_configured_output {
 	char *name;
 	int width, height;
+	uint32_t transform;
 	struct wl_list link;
 };
 
@@ -474,9 +476,12 @@ x11_output_set_icon(struct x11_compositor *c,
 static int
 x11_compositor_create_output(struct x11_compositor *c, int x, int y,
 			     int width, int height, int fullscreen,
-			     int no_input, const char *name)
+			     int no_input, char *configured_name,
+			     uint32_t transform)
 {
+	static const char name[] = "Weston Compositor";
 	static const char class[] = "weston-1\0Weston Compositor";
+	char title[32];
 	struct x11_output *output;
 	xcb_screen_iterator_t iter;
 	struct wm_normal_hints normal_hints;
@@ -488,6 +493,11 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
 		0
 	};
 
+	if (configured_name)
+		sprintf(title, "%s - %s", name, configured_name);
+	else
+		strcpy(title, name);
+
 	if (!no_input)
 		values[0] |=
 			XCB_EVENT_MASK_KEY_PRESS |
@@ -517,7 +527,8 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
 	output->base.current = &output->mode;
 	output->base.make = "xwayland";
 	output->base.model = "none";
-	weston_output_init(&output->base, &c->base, x, y, width, height);
+	weston_output_init(&output->base, &c->base,
+			   x, y, width, height, transform);
 
 	values[1] = c->null_cursor;
 	output->window = xcb_generate_id(c->conn);
@@ -550,7 +561,7 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
 	/* Set window name.  Don't bother with non-EWMH WMs. */
 	xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE, output->window,
 			    c->atom.net_wm_name, c->atom.utf8_string, 8,
-			    strlen(name), name);
+			    strlen(title), title);
 	xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE, output->window,
 			    c->atom.wm_class, c->atom.string, 8,
 			    sizeof class, class);
@@ -739,6 +750,98 @@ x11_compositor_deliver_button_event(struct x11_compositor *c,
 			      WL_POINTER_BUTTON_STATE_RELEASED);
 }
 
+static void
+x11_output_transform_coordinate(struct x11_output *x11_output,
+						wl_fixed_t *x, wl_fixed_t *y)
+{
+	struct weston_output *output = &x11_output->base;
+	wl_fixed_t tx, ty;
+	wl_fixed_t width = wl_fixed_from_int(output->width - 1);
+	wl_fixed_t height = wl_fixed_from_int(output->height - 1);
+
+	switch(output->transform) {
+	case WL_OUTPUT_TRANSFORM_NORMAL:
+	default:
+		tx = *x;
+		ty = *y;
+		break;
+	case WL_OUTPUT_TRANSFORM_90:
+		tx = *y;
+		ty = height - *x;
+		break;
+	case WL_OUTPUT_TRANSFORM_180:
+		tx = width - *x;
+		ty = height - *y;
+		break;
+	case WL_OUTPUT_TRANSFORM_270:
+		tx = width - *y;
+		ty = *x;
+		break;
+	case WL_OUTPUT_TRANSFORM_FLIPPED:
+		tx = width - *x;
+		ty = *y;
+		break;
+	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+		tx = width - *y;
+		ty = height - *x;
+		break;
+	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+		tx = *x;
+		ty = height - *y;
+		break;
+	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+		tx = *y;
+		ty = *x;
+		break;
+	}
+
+	tx += wl_fixed_from_int(output->x);
+	ty += wl_fixed_from_int(output->y);
+
+	*x = tx;
+	*y = ty;
+}
+
+static void
+x11_compositor_deliver_motion_event(struct x11_compositor *c,
+					xcb_generic_event_t *event)
+{
+	struct x11_output *output;
+	wl_fixed_t x, y;
+	xcb_motion_notify_event_t *motion_notify =
+			(xcb_motion_notify_event_t *) event;
+
+	if (!c->has_xkb)
+		update_xkb_state_from_core(c, motion_notify->state);
+	output = x11_compositor_find_output(c, motion_notify->event);
+	x = wl_fixed_from_int(motion_notify->event_x);
+	y = wl_fixed_from_int(motion_notify->event_y);
+	x11_output_transform_coordinate(output, &x, &y);
+
+	notify_motion(&c->core_seat, weston_compositor_get_time(), x, y);
+}
+
+static void
+x11_compositor_deliver_enter_event(struct x11_compositor *c,
+					xcb_generic_event_t *event)
+{
+	struct x11_output *output;
+	wl_fixed_t x, y;
+
+	xcb_enter_notify_event_t *enter_notify =
+			(xcb_enter_notify_event_t *) event;
+	if (enter_notify->state >= Button1Mask)
+		return;
+	if (!c->has_xkb)
+		update_xkb_state_from_core(c, enter_notify->state);
+	output = x11_compositor_find_output(c, enter_notify->event);
+	x = wl_fixed_from_int(enter_notify->event_x);
+	y = wl_fixed_from_int(enter_notify->event_y);
+	x11_output_transform_coordinate(output, &x, &y);
+
+	notify_pointer_focus(&c->core_seat, &output->base, x, y);
+}
+
 static int
 x11_compositor_next_event(struct x11_compositor *c,
 			  xcb_generic_event_t **event, uint32_t mask)
@@ -763,7 +866,6 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
 	struct x11_output *output;
 	xcb_generic_event_t *event, *prev;
 	xcb_client_message_event_t *client_message;
-	xcb_motion_notify_event_t *motion_notify;
 	xcb_enter_notify_event_t *enter_notify;
 	xcb_key_press_event_t *key_press, *key_release;
 	xcb_keymap_notify_event_t *keymap_notify;
@@ -772,7 +874,6 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
 	xcb_atom_t atom;
 	uint32_t *k;
 	uint32_t i, set;
-	wl_fixed_t x, y;
 	int count;
 
 	prev = NULL;
@@ -872,14 +973,7 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
 			x11_compositor_deliver_button_event(c, event, 0);
 			break;
 		case XCB_MOTION_NOTIFY:
-			motion_notify = (xcb_motion_notify_event_t *) event;
-			if (!c->has_xkb)
-				update_xkb_state_from_core(c, motion_notify->state);
-			output = x11_compositor_find_output(c, motion_notify->event);
-			x = wl_fixed_from_int(output->base.x + motion_notify->event_x);
-			y = wl_fixed_from_int(output->base.y + motion_notify->event_y);
-			notify_motion(&c->core_seat,
-				      weston_compositor_get_time(), x, y);
+			x11_compositor_deliver_motion_event(c, event);
 			break;
 
 		case XCB_EXPOSE:
@@ -889,17 +983,7 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
 			break;
 
 		case XCB_ENTER_NOTIFY:
-			enter_notify = (xcb_enter_notify_event_t *) event;
-			if (enter_notify->state >= Button1Mask)
-				break;
-			if (!c->has_xkb)
-				update_xkb_state_from_core(c, enter_notify->state);
-			output = x11_compositor_find_output(c, enter_notify->event);
-			x = wl_fixed_from_int(output->base.x + enter_notify->event_x);
-			y = wl_fixed_from_int(output->base.y + enter_notify->event_y);
-
-			notify_pointer_focus(&c->core_seat,
-					     &output->base, x, y);
+			x11_compositor_deliver_enter_event(c, event);
 			break;
 
 		case XCB_LEAVE_NOTIFY:
@@ -1063,8 +1147,6 @@ x11_compositor_create(struct wl_display *display,
 		      int no_input,
 		      int argc, char *argv[], const char *config_file)
 {
-	static const char name[] = "Weston Compositor";
-	char configured_name[32];
 	struct x11_compositor *c;
 	struct x11_configured_output *o;
 	xcb_screen_iterator_t s;
@@ -1117,16 +1199,17 @@ x11_compositor_create(struct wl_display *display,
 	count = option_count ? option_count : 1;
 
 	wl_list_for_each(o, &configured_output_list, link) {
-		sprintf(configured_name, "%s - %s", name, o->name);
 		if (x11_compositor_create_output(c, x, 0,
-						option_width ? option_width :
+						option_width ? width :
 						o->width,
-						option_height ? option_height :
+						option_height ? height :
 						o->height,
 						fullscreen, no_input,
-						configured_name) < 0)
+						o->name, o->transform) < 0)
 			goto err_x11_input;
-		x += option_width ? option_width : o->width;
+		x += (container_of(c->base.output_list.prev,
+				struct weston_output, link))->region.extents.x2;
+
 		output_count++;
 		if (option_count && output_count >= option_count)
 			break;
@@ -1134,9 +1217,11 @@ x11_compositor_create(struct wl_display *display,
 
 	for (i = output_count; i < count; i++) {
 		if (x11_compositor_create_output(c, x, 0, width, height,
-						 fullscreen, no_input, name) < 0)
+						 fullscreen, no_input, NULL,
+						 WL_OUTPUT_TRANSFORM_NORMAL) < 0)
 			goto err_x11_input;
-		x += width;
+		x += (container_of(c->base.output_list.prev,
+				struct weston_output, link))->region.extents.x2;
 	}
 
 	c->xcb_source =
@@ -1160,37 +1245,77 @@ err_free:
 }
 
 static void
+x11_output_set_transform(struct x11_configured_output *output)
+{
+	if (!output_transform) {
+		output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
+		return;
+	}
+
+	if (!strcmp(output_transform, "normal"))
+		output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
+	else if (!strcmp(output_transform, "90"))
+		output->transform = WL_OUTPUT_TRANSFORM_90;
+	else if (!strcmp(output_transform, "180"))
+		output->transform = WL_OUTPUT_TRANSFORM_180;
+	else if (!strcmp(output_transform, "270"))
+		output->transform = WL_OUTPUT_TRANSFORM_270;
+	else if (!strcmp(output_transform, "flipped"))
+		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
+	else if (!strcmp(output_transform, "flipped-90"))
+		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
+	else if (!strcmp(output_transform, "flipped-180"))
+		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
+	else if (!strcmp(output_transform, "flipped-270"))
+		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
+	else {
+		weston_log("Invalid transform \"%s\" for output %s\n",
+						output_transform, output_name);
+		output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
+	}
+}
+
+static void
 output_section_done(void *data)
 {
 	struct x11_configured_output *output;
 
 	output = malloc(sizeof *output);
 
-	if (!output || !output_name || !output_mode) {
-		free(output_name);
+	if (!output || !output_name || (output_name[0] != 'X') ||
+				(!output_mode && !output_transform)) {
+		if (output_name)
+			free(output_name);
 		output_name = NULL;
 		goto err_free;
 	}
 
 	output->name = output_name;
 
-	if (output_name[0] != 'X') {
-		x11_free_configured_output(output);
-		goto err_free;
+	if (output_mode) {
+		if (sscanf(output_mode, "%dx%d", &output->width,
+						&output->height) != 2) {
+			weston_log("Invalid mode \"%s\" for output %s\n",
+							output_mode, output_name);
+			x11_free_configured_output(output);
+			goto err_free;
+		}
+	} else {
+		output->width = 1024;
+		output->height = 640;
 	}
 
-	if (sscanf(output_mode, "%dx%d", &output->width, &output->height) != 2) {
-		weston_log("Invalid mode \"%s\" for output %s\n",
-						output_mode, output_name);
-		x11_free_configured_output(output);
-		goto err_free;
-	}
+	x11_output_set_transform(output);
 
 	wl_list_insert(configured_output_list.prev, &output->link);
 
 err_free:
-	free(output_mode);
+	if (output_mode)
+		free(output_mode);
+	if (output_transform)
+		free(output_transform);
 	output_mode = NULL;
+	output_transform = NULL;
 }
 
 WL_EXPORT struct weston_compositor *
@@ -1215,6 +1340,7 @@ backend_init(struct wl_display *display, int argc, char *argv[],
 	const struct config_key x11_config_keys[] = {
 		{ "name", CONFIG_KEY_STRING, &output_name },
 		{ "mode", CONFIG_KEY_STRING, &output_mode },
+		{ "transform", CONFIG_KEY_STRING, &output_transform },
 	};
 
 	const struct config_section config_section[] = {
diff --git a/src/compositor.c b/src/compositor.c
index 1bf7c96..df28cb7 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -1148,6 +1148,7 @@ weston_output_repaint(struct weston_output *output, uint32_t msecs)
 		output->border.left + output->border.right;
 	height = output->current->height +
 		output->border.top + output->border.bottom;
+
 	glViewport(0, 0, width, height);
 
 	/* Rebuild the surface list and update surface transforms up front. */
@@ -1731,14 +1732,14 @@ clip_pointer_motion(struct weston_seat *seat, wl_fixed_t *fx, wl_fixed_t *fy)
 	if (!valid) {
 		if (x < prev->x)
 			*fx = wl_fixed_from_int(prev->x);
-		else if (x >= prev->x + prev->current->width)
+		else if (x >= prev->x + prev->width)
 			*fx = wl_fixed_from_int(prev->x +
-						prev->current->width - 1);
+						prev->width - 1);
 		if (y < prev->y)
 			*fy = wl_fixed_from_int(prev->y);
 		else if (y >= prev->y + prev->current->height)
 			*fy = wl_fixed_from_int(prev->y +
-						prev->current->height - 1);
+						prev->height - 1);
 	}
 }
 
@@ -2972,6 +2973,62 @@ weston_output_destroy(struct weston_output *output)
 	wl_display_remove_global(c->wl_display, output->global);
 }
 
+static void
+weston_output_compute_transform(struct weston_output *output)
+{
+	struct weston_matrix transform;
+	int flip;
+
+	weston_matrix_init(&transform);
+
+	switch(output->transform) {
+	case WL_OUTPUT_TRANSFORM_FLIPPED:
+	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+		flip = -1;
+		break;
+	default:
+		flip = 1;
+		break;
+	}
+
+        switch(output->transform) {
+        case WL_OUTPUT_TRANSFORM_NORMAL:
+        case WL_OUTPUT_TRANSFORM_FLIPPED:
+                transform.d[0] = flip;
+                transform.d[1] = 0;
+                transform.d[4] = 0;
+                transform.d[5] = 1;
+                break;
+        case WL_OUTPUT_TRANSFORM_90:
+        case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+                transform.d[0] = 0;
+                transform.d[1] = -flip;
+                transform.d[4] = 1;
+                transform.d[5] = 0;
+                break;
+        case WL_OUTPUT_TRANSFORM_180:
+        case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+                transform.d[0] = -flip;
+                transform.d[1] = 0;
+                transform.d[4] = 0;
+                transform.d[5] = -1;
+                break;
+        case WL_OUTPUT_TRANSFORM_270:
+        case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+                transform.d[0] = 0;
+                transform.d[1] = flip;
+                transform.d[4] = -1;
+                transform.d[5] = 0;
+                break;
+        default:
+                break;
+        }
+
+	weston_matrix_multiply(&output->matrix, &transform);
+}
+
 WL_EXPORT void
 weston_output_update_matrix(struct weston_output *output)
 {
@@ -2981,12 +3038,14 @@ weston_output_update_matrix(struct weston_output *output)
 
 	weston_matrix_init(&output->matrix);
 	weston_matrix_translate(&output->matrix,
-				-(output->x + (output->border.right + output->current->width - output->border.left) / 2.0),
-				-(output->y + (output->border.bottom + output->current->height - output->border.top) / 2.0), 0);
+				-(output->x + (output->border.right + output->width - output->border.left) / 2.0),
+				-(output->y + (output->border.bottom + output->height - output->border.top) / 2.0), 0);
 
 	weston_matrix_scale(&output->matrix,
-			    2.0 / (output->current->width + output->border.left + output->border.right),
-			    -2.0 / (output->current->height + output->border.top + output->border.bottom), 1);
+			    2.0 / (output->width + output->border.left + output->border.right),
+			    -2.0 / (output->height + output->border.top + output->border.bottom), 1);
+
+	weston_output_compute_transform(output);
 
 	if (output->zoom.active) {
 		magnification = 1 / (1 - output->zoom.spring_z.current);
@@ -3003,6 +3062,32 @@ weston_output_update_matrix(struct weston_output *output)
 	output->dirty = 0;
 }
 
+static void
+weston_output_transform_init(struct weston_output *output, uint32_t transform)
+{
+	output->transform = transform;
+
+	switch (transform) {
+	case WL_OUTPUT_TRANSFORM_90:
+	case WL_OUTPUT_TRANSFORM_270:
+	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+		/* Swap width and height */
+		output->width = output->current->height;
+		output->height = output->current->width;
+		break;
+	case WL_OUTPUT_TRANSFORM_NORMAL:
+	case WL_OUTPUT_TRANSFORM_180:
+	case WL_OUTPUT_TRANSFORM_FLIPPED:
+	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+		output->width = output->current->width;
+		output->height = output->current->height;
+		break;
+	default:
+		break;
+	}
+}
+
 WL_EXPORT void
 weston_output_move(struct weston_output *output, int x, int y)
 {
@@ -3011,13 +3096,13 @@ weston_output_move(struct weston_output *output, int x, int y)
 
 	pixman_region32_init(&output->previous_damage);
 	pixman_region32_init_rect(&output->region, x, y,
-				  output->current->width,
-				  output->current->height);
+				  output->width,
+				  output->height);
 }
 
 WL_EXPORT void
 weston_output_init(struct weston_output *output, struct weston_compositor *c,
-		   int x, int y, int width, int height)
+		   int x, int y, int width, int height, uint32_t transform)
 {
 	output->compositor = c;
 	output->x = x;
@@ -3029,8 +3114,11 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,
 	output->mm_width = width;
 	output->mm_height = height;
 	output->dirty = 1;
-	output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
 
+	if (transform != WL_OUTPUT_TRANSFORM_NORMAL)
+		output->disable_planes++;
+
+	weston_output_transform_init(output, transform);
 	weston_output_init_zoom(output);
 
 	weston_output_move(output, x, y);
diff --git a/src/compositor.h b/src/compositor.h
index b8e767d..ac887ee 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -155,7 +155,8 @@ struct weston_output {
 	struct weston_compositor *compositor;
 	struct weston_matrix matrix;
 	struct wl_list animation_list;
-	int32_t x, y, mm_width, mm_height;
+	int32_t x, y, width, height;
+	int32_t mm_width, mm_height;
 	struct weston_border border;
 	pixman_region32_t region;
 	pixman_region32_t previous_damage;
@@ -678,7 +679,7 @@ void
 weston_output_move(struct weston_output *output, int x, int y);
 void
 weston_output_init(struct weston_output *output, struct weston_compositor *c,
-		   int x, int y, int width, int height);
+		   int x, int y, int width, int height, uint32_t transform);
 void
 weston_output_destroy(struct weston_output *output);
 
diff --git a/src/shell.c b/src/shell.c
index 4d6bc4f..2bd23fc 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -1373,8 +1373,8 @@ shell_surface_set_maximized(struct wl_client *client,
 	edges = WL_SHELL_SURFACE_RESIZE_TOP|WL_SHELL_SURFACE_RESIZE_LEFT;
 
 	shsurf->client->send_configure(shsurf->surface, edges,
-				       shsurf->output->current->width,
-				       shsurf->output->current->height - panel_height);
+				       shsurf->output->width,
+				       shsurf->output->height - panel_height);
 
 	shsurf->next_type = SHELL_SURFACE_MAXIMIZED;
 }
@@ -1419,8 +1419,8 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
 			create_black_surface(surface->compositor,
 					     surface,
 					     output->x, output->y,
-					     output->current->width,
-					     output->current->height);
+					     output->width,
+					     output->height);
 
 	wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
 	wl_list_insert(&surface->layer_link,
@@ -1436,23 +1436,23 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
 		matrix = &shsurf->fullscreen.transform.matrix;
 		weston_matrix_init(matrix);
 
-		output_aspect = (float) output->current->width /
-			(float) output->current->height;
+		output_aspect = (float) output->width /
+			(float) output->height;
 		surface_aspect = (float) surface->geometry.width /
 			(float) surface->geometry.height;
 		if (output_aspect < surface_aspect)
-			scale = (float) output->current->width /
+			scale = (float) output->width /
 				(float) surface->geometry.width;
 		else
-			scale = (float) output->current->height /
+			scale = (float) output->height /
 				(float) surface->geometry.height;
 
 		weston_matrix_scale(matrix, scale, scale, 1);
 		wl_list_remove(&shsurf->fullscreen.transform.link);
 		wl_list_insert(&surface->geometry.transformation_list,
 			       &shsurf->fullscreen.transform.link);
-		x = output->x + (output->current->width - surface->geometry.width * scale) / 2;
-		y = output->y + (output->current->height - surface->geometry.height * scale) / 2;
+		x = output->x + (output->width - surface->geometry.width * scale) / 2;
+		y = output->y + (output->height - surface->geometry.height * scale) / 2;
 		weston_surface_set_position(surface, x, y);
 
 		break;
@@ -1466,8 +1466,8 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
 			if (weston_output_switch_mode(output, &mode) == 0) {
 				weston_surface_configure(shsurf->fullscreen.black_surface, 
 					                 output->x, output->y,
-							 output->current->width,
-							 output->current->height);
+							 output->width,
+							 output->height);
 				weston_surface_set_position(surface, output->x, output->y);
 				break;
 			}
@@ -1498,8 +1498,8 @@ shell_stack_fullscreen(struct shell_surface *shsurf)
 			create_black_surface(surface->compositor,
 					     surface,
 					     output->x, output->y,
-					     output->current->width,
-					     output->current->height);
+					     output->width,
+					     output->height);
 
 	wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
 	wl_list_insert(&surface->layer_link,
@@ -1537,8 +1537,8 @@ shell_surface_set_fullscreen(struct wl_client *client,
 	shsurf->next_type = SHELL_SURFACE_FULLSCREEN;
 
 	shsurf->client->send_configure(shsurf->surface, 0,
-				       shsurf->output->current->width,
-				       shsurf->output->current->height);
+				       shsurf->output->width,
+				       shsurf->output->height);
 }
 
 static void
@@ -1915,8 +1915,8 @@ desktop_shell_set_background(struct wl_client *client,
 	surface->output = output_resource->data;
 	desktop_shell_send_configure(resource, 0,
 				     surface_resource,
-				     surface->output->current->width,
-				     surface->output->current->height);
+				     surface->output->width,
+				     surface->output->height);
 }
 
 static void
@@ -1948,8 +1948,8 @@ desktop_shell_set_panel(struct wl_client *client,
 	surface->output = output_resource->data;
 	desktop_shell_send_configure(resource, 0,
 				     surface_resource,
-				     surface->output->current->width,
-				     surface->output->current->height);
+				     surface->output->width,
+				     surface->output->height);
 }
 
 static void
@@ -2567,9 +2567,8 @@ hide_input_panels(struct wl_listener *listener, void *data)
 static void
 center_on_output(struct weston_surface *surface, struct weston_output *output)
 {
-	struct weston_mode *mode = output->current;
-	GLfloat x = (mode->width - surface->buffer->width) / 2;
-	GLfloat y = (mode->height - surface->buffer->height) / 2;
+	GLfloat x = (output->width - surface->buffer->width) / 2;
+	GLfloat y = (output->height - surface->buffer->height) / 2;
 
 	weston_surface_configure(surface, output->x + x, output->y + y,
 				 surface->buffer->width,
@@ -2618,8 +2617,8 @@ weston_surface_set_initial_position (struct weston_surface *surface,
 	 * output.
 	 */
 	panel_height = get_output_panel_height(shell, target_output);
-	range_x = target_output->current->width - surface->geometry.width;
-	range_y = (target_output->current->height - panel_height) -
+	range_x = target_output->width - surface->geometry.width;
+	range_y = (target_output->height - panel_height) -
 		  surface->geometry.height;
 
 	if (range_x > 0)
diff --git a/src/zoom.c b/src/zoom.c
index 56a9ead..674a80e 100644
--- a/src/zoom.c
+++ b/src/zoom.c
@@ -187,14 +187,58 @@ zoom_area_center_from_pointer(struct weston_output *output,
 	float level = output->zoom.spring_z.current;
 	wl_fixed_t offset_x = wl_fixed_from_int(output->x);
 	wl_fixed_t offset_y = wl_fixed_from_int(output->y);
-	wl_fixed_t w = wl_fixed_from_int(output->current->width);
-	wl_fixed_t h = wl_fixed_from_int(output->current->height);
+	wl_fixed_t w = wl_fixed_from_int(output->width);
+	wl_fixed_t h = wl_fixed_from_int(output->height);
 
 	*x -= ((((*x - offset_x) / (float) w) - 0.5) * (w * (1.0 - level)));
 	*y -= ((((*y - offset_y) / (float) h) - 0.5) * (h * (1.0 - level)));
 }
 
 static void
+weston_zoom_apply_output_transform(struct weston_output *output,
+						float *x, float *y)
+{
+	float tx, ty;
+
+	switch(output->transform) {
+	case WL_OUTPUT_TRANSFORM_NORMAL:
+	default:
+		return;
+	case WL_OUTPUT_TRANSFORM_90:
+		tx = -*y;
+		ty = *x;
+		break;
+	case WL_OUTPUT_TRANSFORM_180:
+		tx = -*x;
+		ty = -*y;
+		break;
+	case WL_OUTPUT_TRANSFORM_270:
+		tx = *y;
+		ty = -*x;
+		break;
+	case WL_OUTPUT_TRANSFORM_FLIPPED:
+		tx = -*x;
+		ty = *y;
+		break;
+	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+		tx = -*y;
+		ty = -*x;
+		break;
+	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+		tx = *x;
+		ty = -*y;
+		break;
+	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+		tx = *y;
+		ty = *x;
+		break;
+	}
+
+	*x = tx;
+	*y = ty;
+}
+
+static void
 weston_output_update_zoom_transform(struct weston_output *output)
 {
 	uint32_t type = output->zoom.type;
@@ -218,12 +262,15 @@ weston_output_update_zoom_transform(struct weston_output *output)
 	global_y = wl_fixed_to_double(y);
 
 	output->zoom.trans_x =
-		((((global_x - output->x) / output->current->width) *
+		((((global_x - output->x) / output->width) *
 		(level * 2)) - level) * ratio;
 	output->zoom.trans_y =
-		((((global_y - output->y) / output->current->height) *
+		((((global_y - output->y) / output->height) *
 		(level * 2)) - level) * ratio;
 
+	weston_zoom_apply_output_transform(output, &output->zoom.trans_x,
+						   &output->zoom.trans_y);
+
 	trans_max = level * 2 - level;
 	trans_min = -trans_max;
 
diff --git a/weston.ini b/weston.ini
index 3fda31b..99d24dd 100644
--- a/weston.ini
+++ b/weston.ini
@@ -37,11 +37,14 @@ duration=600
 #[output]
 #name=LVDS1
 #mode=1680x1050
+#transform=90
 
 #[output]
 #name=VGA1
 #mode=173.00  1920 2048 2248 2576  1080 1083 1088 1120 -hsync +vsync
+#transform=flipped
 
 #[output]
 #name=X1
 #mode=1024x768
+#transform=flipped-270
-- 
1.7.11.2



More information about the wayland-devel mailing list