[weston,2/2] compositor-x11: Implement mode switching

Submitted by Armin Krezović on Oct. 28, 2016, 10:26 p.m.

Details

Message ID 20161028222646.28868-2-krezovic.armin@gmail.com
State Accepted
Headers show
Series "compositor-x11: Implement mode switching" ( rev: 1 ) in Wayland

Not browsing as part of any series.

Commit Message

Armin Krezović Oct. 28, 2016, 10:26 p.m.
Signed-off-by: Armin Krezović <krezovic.armin@gmail.com>
---
 libweston/compositor-x11.c | 140 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 132 insertions(+), 8 deletions(-)

Patch hide | download patch | download mbox

diff --git a/libweston/compositor-x11.c b/libweston/compositor-x11.c
index 7709d8f..a32ef8d 100644
--- a/libweston/compositor-x11.c
+++ b/libweston/compositor-x11.c
@@ -64,6 +64,12 @@ 
 
 #define DEFAULT_AXIS_STEP_DISTANCE 10
 
+#define WINDOW_MIN_WIDTH 128
+#define WINDOW_MIN_HEIGHT 128
+
+#define WINDOW_MAX_WIDTH 8192
+#define WINDOW_MAX_HEIGHT 8192
+
 struct x11_backend {
 	struct weston_backend	 base;
 	struct weston_compositor *compositor;
@@ -113,6 +119,7 @@  struct x11_output {
 
 	xcb_window_t		window;
 	struct weston_mode	mode;
+	struct weston_mode	native;
 	struct wl_event_source *finish_frame_timer;
 
 	xcb_gc_t		gc;
@@ -122,6 +129,8 @@  struct x11_output {
 	void		       *buf;
 	uint8_t			depth;
 	int32_t                 scale;
+	bool			resize_pending;
+	bool			window_resized;
 };
 
 struct window_delete_data {
@@ -770,6 +779,89 @@  x11_output_init_shm(struct x11_backend *b, struct x11_output *output,
 }
 
 static int
+x11_output_switch_mode(struct weston_output *base, struct weston_mode *mode)
+{
+	struct x11_backend *b;
+	struct x11_output *output;
+	static uint32_t values[2];
+	int ret;
+
+	if (base == NULL) {
+		weston_log("output is NULL.\n");
+		return -1;
+	}
+
+	if (mode == NULL) {
+		weston_log("mode is NULL.\n");
+		return -1;
+	}
+
+        b = to_x11_backend(base->compositor);
+        output = to_x11_output(base);
+
+        if (mode->width == output->mode.width &&
+	    mode->height == output->mode.height)
+	        return 0;
+
+        if (mode->width < WINDOW_MIN_WIDTH || mode->width > WINDOW_MAX_WIDTH)
+		return -1;
+
+	if (mode->height < WINDOW_MIN_HEIGHT || mode->height > WINDOW_MAX_HEIGHT)
+		return -1;
+
+	/* xcb_configure_window will create an event, and we could end up
+	   being called twice */
+	output->resize_pending = true;
+
+	/* window could've been resized by the user, so don't do it twice */
+	if (!output->window_resized) {
+		values[0] = mode->width;
+		values[1] = mode->height;
+		xcb_configure_window(b->conn, output->window, XCB_CONFIG_WINDOW_WIDTH |
+				     XCB_CONFIG_WINDOW_HEIGHT, values);
+	}
+
+	output->mode.width = mode->width;
+	output->mode.height = mode->height;
+
+	if (b->use_pixman) {
+		pixman_renderer_output_destroy(&output->base);
+		x11_output_deinit_shm(b, output);
+
+		if (x11_output_init_shm(b, output,
+		                        output->base.current_mode->width,
+		                        output->base.current_mode->height) < 0) {
+			weston_log("Failed to initialize SHM for the X11 output\n");
+			return -1;
+		}
+
+		if (pixman_renderer_output_create(&output->base) < 0) {
+			weston_log("Failed to create pixman renderer for output\n");
+			x11_output_deinit_shm(b, output);
+			return -1;
+		}
+	} else {
+		Window xid = (Window) output->window;
+
+		gl_renderer->output_destroy(&output->base);
+
+		ret = gl_renderer->output_create(&output->base,
+						 (EGLNativeWindowType) output->window,
+						 &xid,
+						 gl_renderer->opaque_attribs,
+						 NULL,
+						 0);
+		if (ret < 0)
+			return -1;
+	}
+
+	output->resize_pending = false;
+	output->window_resized = false;
+
+	return 0;
+}
+
+static int
 x11_output_disable(struct weston_output *base)
 {
 	struct x11_output *output = to_x11_output(base);
@@ -861,14 +953,13 @@  x11_output_enable(struct weston_output *base)
 				    XCB_ATOM_ATOM, 32,
 				    ARRAY_LENGTH(atom_list), atom_list);
 	} else {
-		/* Don't resize me. */
 		memset(&normal_hints, 0, sizeof normal_hints);
 		normal_hints.flags =
 			WM_NORMAL_HINTS_MAX_SIZE | WM_NORMAL_HINTS_MIN_SIZE;
-		normal_hints.min_width = output->base.current_mode->width;
-		normal_hints.min_height = output->base.current_mode->height;
-		normal_hints.max_width = output->base.current_mode->width;
-		normal_hints.max_height = output->base.current_mode->height;
+		normal_hints.min_width = WINDOW_MIN_WIDTH;
+		normal_hints.min_height = WINDOW_MIN_HEIGHT;
+		normal_hints.max_width = WINDOW_MAX_WIDTH;
+		normal_hints.max_height = WINDOW_MAX_HEIGHT;
 		xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window,
 				    b->atom.wm_normal_hints,
 				    b->atom.wm_size_hints, 32,
@@ -940,7 +1031,7 @@  x11_output_enable(struct weston_output *base)
 	output->base.assign_planes = NULL;
 	output->base.set_backlight = NULL;
 	output->base.set_dpms = NULL;
-	output->base.switch_mode = NULL;
+	output->base.switch_mode = x11_output_switch_mode;
 
 	loop = wl_display_get_event_loop(b->compositor->wl_display);
 	output->finish_frame_timer =
@@ -973,13 +1064,13 @@  x11_output_set_size(struct weston_output *base, int width, int height)
 	/* Make sure we have scale set. */
 	assert(output->base.scale);
 
-	if (width < 1) {
+	if (width < WINDOW_MIN_WIDTH) {
 		weston_log("Invalid width \"%d\" for output %s\n",
 			   width, output->base.name);
 		return -1;
 	}
 
-	if (height < 1) {
+	if (height < WINDOW_MIN_HEIGHT) {
 		weston_log("Invalid height \"%d\" for output %s\n",
 			   height, output->base.name);
 		return -1;
@@ -994,6 +1085,7 @@  x11_output_set_size(struct weston_output *base, int width, int height)
 	output->mode.width = output_width;
 	output->mode.height = output_height;
 	output->mode.refresh = 60000;
+	output->native = output->mode;
 	output->scale = output->base.scale;
 	wl_list_init(&output->base.mode_list);
 	wl_list_insert(&output->base.mode_list, &output->mode.link);
@@ -1002,6 +1094,9 @@  x11_output_set_size(struct weston_output *base, int width, int height)
 	output->base.make = "weston-X11";
 	output->base.model = "none";
 
+	output->base.native_mode = &output->native;
+	output->base.native_scale = output->base.scale;
+
 	output->base.mm_width = width * b->screen->width_in_millimeters /
 		b->screen->width_in_pixels;
 	output->base.mm_height = height * b->screen->height_in_millimeters /
@@ -1025,6 +1120,9 @@  x11_output_create(struct weston_compositor *compositor,
 		return -1;
 	}
 
+	output->resize_pending = false;
+	output->window_resized = false;
+
 	output->base.name = strdup(name);
 	output->base.destroy = x11_output_destroy;
 	output->base.disable = x11_output_disable;
@@ -1321,6 +1419,7 @@  x11_backend_handle_event(int fd, uint32_t mask, void *data)
 	xcb_keymap_notify_event_t *keymap_notify;
 	xcb_focus_in_event_t *focus_in;
 	xcb_expose_event_t *expose;
+	xcb_configure_notify_event_t *configure;
 	xcb_atom_t atom;
 	xcb_window_t window;
 	uint32_t *k;
@@ -1472,6 +1571,31 @@  x11_backend_handle_event(int fd, uint32_t mask, void *data)
 			}
 			break;
 
+		case XCB_CONFIGURE_NOTIFY:
+			configure = (struct xcb_configure_notify_event_t *) event;
+			struct x11_output *output =
+				x11_backend_find_output(b, configure->window);
+
+			if (!output || output->resize_pending)
+				break;
+
+			struct weston_mode mode = output->mode;
+
+			if (mode.width == configure->width &&
+			    mode.height == configure->height)
+				break;
+
+			output->window_resized = true;
+
+			mode.width = configure->width;
+			mode.height = configure->height;
+
+			if (weston_output_mode_set_native(&output->base,
+							  &mode, output->scale) < 0)
+				weston_log("Mode switch failed\n");
+
+			break;
+
 		case XCB_FOCUS_IN:
 			focus_in = (xcb_focus_in_event_t *) event;
 			if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED)

Comments

Hi Armin,

On 28 October 2016 at 23:26, Armin Krezović <krezovic.armin@gmail.com> wrote:
> Signed-off-by: Armin Krezović <krezovic.armin@gmail.com>

I couldn't find anything wrong with this one, so have reviewed and
pushed it now. Was probably about time.

Cheers,
Daniel