[PATCH 3/3] screenshooter: Scale damage by output scale in screen recorder
From: Alexander Larsson The damage region is in compositor coords, we need to scale it by the output scale when using the damage to read output buffer data. --- src/screenshooter.c | 5 + 1 file changed, 5 insertions(+) diff --git a/src/screenshooter.c b/src/screenshooter.c index d088cf7..83ad192 100644 --- a/src/screenshooter.c +++ b/src/screenshooter.c @@ -330,6 +330,11 @@ transform_rect(struct weston_output *output, pixman_box32_t *r) default: break; } + + r->x1 *= output->scale; + r->y1 *= output->scale; + r->x2 *= output->scale; + r->y2 *= output->scale; } static void -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 2/3] pixman-renderer: Fix read_pixels for screen recorder
From: Alexander Larsson The old code had an off-by-one error on the y coordinate where it says height - (cur_y - y). And it does the vflipping of the *destination* buffer, whereas what is really needed is to vflip the whole source buffer. This only affects when you read out part of the image, such as when using the screen recoder. Also, instead of doing the flipping manually we just let pixman handle it. --- src/pixman-renderer.c | 33 - 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c index ba7cb43..2c42390 100644 --- a/src/pixman-renderer.c +++ b/src/pixman-renderer.c @@ -72,8 +72,8 @@ pixman_renderer_read_pixels(struct weston_output *output, uint32_t width, uint32_t height) { struct pixman_output_state *po = get_output_state(output); + pixman_transform_t transform; pixman_image_t *out_buf; - uint32_t cur_y; if (!po->hw_buffer) { errno = ENODEV; @@ -86,18 +86,25 @@ pixman_renderer_read_pixels(struct weston_output *output, pixels, (PIXMAN_FORMAT_BPP(format) / 8) * width); - /* Caller expects vflipped image */ - for (cur_y = y; cur_y < y + height; cur_y++) { - pixman_image_composite32(PIXMAN_OP_SRC, - po->hw_buffer, /* src */ - NULL /* mask */, - out_buf, /* dest */ - x, cur_y, /* src_x, src_y */ - 0, 0, /* mask_x, mask_y */ - 0, height - (cur_y - y), /* dest_x, dest_y */ - width, /* width */ - 1 /* height */); - } + /* Caller expects vflipped source image */ + pixman_transform_init_translate(&transform, + pixman_int_to_fixed (x), + pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer))); + pixman_transform_scale(&transform, NULL, + pixman_fixed_1, + pixman_fixed_minus_1); + pixman_image_set_transform(po->hw_buffer, &transform); + + pixman_image_composite32(PIXMAN_OP_SRC, +po->hw_buffer, /* src */ +NULL /* mask */, +out_buf, /* dest */ +0, 0, /* src_x, src_y */ +0, 0, /* mask_x, mask_y */ +0, 0, /* dest_x, dest_y */ +pixman_image_get_width (po->hw_buffer), /* width */ +pixman_image_get_height (po->hw_buffer) /* height */); + pixman_image_set_transform(po->hw_buffer, NULL); pixman_image_unref(out_buf); -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 1/3] screenshoter: Make recorder handle PIXMAN_x8r8g8b8
From: Alexander Larsson This is what the pixman renderer reports for the read format. --- src/screenshooter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/screenshooter.c b/src/screenshooter.c index dde052f..d088cf7 100644 --- a/src/screenshooter.c +++ b/src/screenshooter.c @@ -465,6 +465,7 @@ weston_recorder_create(struct weston_output *output, const char *filename) header.magic = WCAP_HEADER_MAGIC; switch (compositor->read_format) { + case PIXMAN_x8r8g8b8: case PIXMAN_a8r8g8b8: header.format = WCAP_FORMAT_XRGB; break; -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 0/3] Fix screenshooter/recorder for scale
From: Alexander Larsson The actual fix for output scale is trivial, but I needed two fixes to get screenshooting to work with the pixman renderer. Alexander Larsson (3): screenshoter: Make recorder handle PIXMAN_x8r8g8b8 pixman-renderer: Fix read_pixels for screen recorder screenshooter: Scale damage by output scale in screen recorder src/pixman-renderer.c | 33 - src/screenshooter.c | 6 ++ 2 files changed, 26 insertions(+), 13 deletions(-) -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH] compositor-drm: Handle cursors on scaled screens
From: Alexander Larsson We fall back to not using the drm cursor any time the scale differs, or the scaled size is to large. --- src/compositor-drm.c | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 4222e57..a87cbc3 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -909,6 +909,8 @@ drm_output_prepare_cursor_surface(struct weston_output *output_base, return NULL; if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL) return NULL; + if (output->base.scale != es->buffer_scale) + return NULL; if (output->cursor_surface) return NULL; if (es->output_mask != (1u << output_base->id)) @@ -917,7 +919,7 @@ drm_output_prepare_cursor_surface(struct weston_output *output_base, return NULL; if (es->buffer_ref.buffer == NULL || !wl_buffer_is_shm(es->buffer_ref.buffer) || - es->geometry.width > 64 || es->geometry.height > 64) + es->geometry.width * es->buffer_scale > 64 || es->geometry.height * es->buffer_scale > 64) return NULL; output->cursor_surface = es; @@ -952,9 +954,9 @@ drm_output_set_cursor(struct drm_output *output) memset(buf, 0, sizeof buf); stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer); s = wl_shm_buffer_get_data(es->buffer_ref.buffer); - for (i = 0; i < es->geometry.height; i++) + for (i = 0; i < es->geometry.height * es->buffer_scale; i++) memcpy(buf + i * 64, s + i * stride, - es->geometry.width * 4); + es->geometry.width * es->buffer_scale * 4); if (gbm_bo_write(bo, buf, sizeof buf) < 0) weston_log("failed update cursor: %m\n"); -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 9/9] shell: Center window in fullscreen if needed
From: Alexander Larsson If modeset fails With DRIVER method, and always with FILL method we want to center the window. --- src/shell.c | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/shell.c b/src/shell.c index eac8471..ebeef55 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1832,11 +1832,14 @@ shell_configure_fullscreen(struct shell_surface *shsurf) output->width, output->height); break; - } else + } else { restore_output_mode(output); + center_on_output(surface, output); + } } break; case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL: + center_on_output(surface, output); break; default: break; -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 7/9] shell: Use buffer_scale as output scale on fullscreen DRIVER
From: Alexander Larsson It may happen that you e.g. fullscreen a 800x600 surface with buffer_scale 1 (e.g. a 800x600 buffer) on an output that is otherwise scale 2. In this case we want to temporarily set the output scale to 1, as we're really scanning out of a scale 1 buffer. This causes us to e.g. report the input positions in the right place, etc. When we restore the original mode we also restore the original scale. Note that the scale change is a purely compositor internal change, to clients it still looks like the output is scale 2. --- src/compositor.c | 4 +++- src/compositor.h | 2 +- src/shell.c | 12 +++- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index 8f82ba6..b5b5ab8 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -95,7 +95,7 @@ static void weston_output_transform_scale_init(struct weston_output *output, uint32_t transform, uint32_t scale); WL_EXPORT int -weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode) +weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode, int32_t scale) { struct weston_seat *seat; pixman_region32_t old_output_region; @@ -108,6 +108,8 @@ weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode if (ret < 0) return ret; +output->scale = scale; + pixman_region32_init(&old_output_region); pixman_region32_copy(&old_output_region, &output->region); diff --git a/src/compositor.h b/src/compositor.h index b17d832..86793f5 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -1141,7 +1141,7 @@ void weston_surface_destroy(struct weston_surface *surface); int -weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode); +weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode, int32_t scale); int noop_renderer_init(struct weston_compositor *ec); diff --git a/src/shell.c b/src/shell.c index 07be564..1f2ad60 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1503,7 +1503,8 @@ shell_unset_fullscreen(struct shell_surface *shsurf) if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER && shell_surface_is_top_fullscreen(shsurf)) { weston_output_switch_mode(shsurf->fullscreen_output, - shsurf->fullscreen_output->origin); + shsurf->fullscreen_output->origin, + shsurf->fullscreen_output->origin_scale); } shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT; shsurf->fullscreen.framerate = 0; @@ -1797,11 +1798,11 @@ shell_configure_fullscreen(struct shell_surface *shsurf) case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER: if (shell_surface_is_top_fullscreen(shsurf)) { struct weston_mode mode = {0, - surf_width, - surf_height, + surf_width * surface->buffer_scale, + surf_height * surface->buffer_scale, shsurf->fullscreen.framerate}; - if (weston_output_switch_mode(output, &mode) == 0) { + if (weston_output_switch_mode(output, &mode, surface->buffer_scale) == 0) { weston_surface_set_position(surface, output->x - surf_x, output->y - surf_y); @@ -2151,7 +2152,8 @@ destroy_shell_surface(struct shell_surface *shsurf) if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER && shell_surface_is_top_fullscreen(shsurf)) { weston_output_switch_mode(shsurf->fullscreen_output, - shsurf->fullscreen_output->origin); + shsurf->fullscreen_output->origin, + shsurf->fullscreen_output->origin_scale); } if (shsurf->fullscreen.black_surface) -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 8/9] shell: Always go to original mode when focused window not fullscreen
From: Alexander Larsson Right now we only switch mode on activating a fullscreened window. This has several problems: * Once you're in fullscreen its hard to switch to a non-fullscreened window with alt-tab as you stay in the small resolution. * If you switch from a fullscreened window to a non-fullscreened window and the fullscreened window is destroyed we will not restore the original mode (since the window is not shell_surface_is_top_fullscreen() * Its hard to reach a different output on the right with the mouse when the mode is smaller that the original, as there is a "gap" between the two outputs. So, if you alt-tab to another window you can not always reach it. This is somewhat of a sledge hammer, as it means you can't e.g. focus a non-fullscreen on one output and have a window fullscreened on another output. However, trying to restore only the outputs the new window is on is problematic: * It may later change output * We want to see all windows anyway during alt-tab * Can't reach the other windows with the mouse anyway So, this seems like an ok solution. --- src/shell.c | 38 +- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/shell.c b/src/shell.c index 1f2ad60..eac8471 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1496,15 +1496,32 @@ get_default_output(struct weston_compositor *compositor) } static void +restore_output_mode(struct weston_output *output) +{ + if (output->current != output->origin || + (int32_t)output->scale != output->origin_scale) + weston_output_switch_mode(output, + output->origin, + output->origin_scale); +} + +static void +restore_all_output_modes(struct weston_compositor *compositor) +{ + struct weston_output *output; + + wl_list_for_each(output, &compositor->output_list, link) + restore_output_mode(output); +} + +static void shell_unset_fullscreen(struct shell_surface *shsurf) { struct workspace *ws; /* undo all fullscreen things here */ if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER && shell_surface_is_top_fullscreen(shsurf)) { - weston_output_switch_mode(shsurf->fullscreen_output, - shsurf->fullscreen_output->origin, - shsurf->fullscreen_output->origin_scale); + restore_output_mode(shsurf->fullscreen_output); } shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT; shsurf->fullscreen.framerate = 0; @@ -1742,6 +1759,9 @@ shell_configure_fullscreen(struct shell_surface *shsurf) float scale, output_aspect, surface_aspect, x, y; int32_t surf_x, surf_y, surf_width, surf_height; + if (shsurf->fullscreen.type != WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER) + restore_output_mode(output); + if (!shsurf->fullscreen.black_surface) shsurf->fullscreen.black_surface = create_black_surface(surface->compositor, @@ -1812,7 +1832,8 @@ shell_configure_fullscreen(struct shell_surface *shsurf) output->width, output->height); break; - } + } else + restore_output_mode(output); } break; case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL: @@ -2150,11 +2171,8 @@ destroy_shell_surface(struct shell_surface *shsurf) } if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER && - shell_surface_is_top_fullscreen(shsurf)) { - weston_output_switch_mode(shsurf->fullscreen_output, - shsurf->fullscreen_output->origin, - shsurf->fullscreen_output->origin_scale); - } + shell_surface_is_top_fullscreen(shsurf)) + restore_output_mode (shsurf->fullscreen_output); if (shsurf->fullscreen.black_surface) weston_surface_destroy(shsurf->fullscreen.black_surface); @@ -2924,6 +2942,7 @@ activate(struct desktop_shell *shell, struct weston_surface *es, shell_configure_fullscreen(get_shell_surface(main_surface)); break; default: + restore_all_output_modes(shell->compositor); ws = get_current_workspace(shell); weston_surface_restack(main_surface, &ws->layer.surface_list); break; @@ -4014,6 +4033,7 @@ switcher_binding(struct weston_seat *seat, uint32_t time, uint32_t key, switcher->listener.notify = switcher_handle_surface_destroy; wl_list_init(&switcher->listener
[PATCH 5/9] compositor: Store modes in physical units
From: Alexander Larsson We changed the protocol to always list modes in physical pixel units (not scaled). And we removed the scaled mode flag. This just updates the DRM and X11 compositors and the gl and pixman renderers to handle this. --- src/compositor-drm.c | 37 + src/compositor-x11.c | 6 ++ src/compositor.c | 27 +++ src/compositor.h | 2 +- src/gl-renderer.c | 4 ++-- src/pixman-renderer.c | 4 ++-- 6 files changed, 31 insertions(+), 49 deletions(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 4435162..4222e57 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -449,7 +449,6 @@ drm_output_prepare_scanout_surface(struct weston_output *_output, buffer->width != output->base.current->width || buffer->height != output->base.current->height || output->base.transform != es->buffer_transform || - output->base.scale != es->buffer_scale || es->transform.enabled) return NULL; @@ -1249,7 +1248,7 @@ init_pixman(struct drm_compositor *ec) } static struct drm_mode * -drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info, int scale) +drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info) { struct drm_mode *mode; uint64_t refresh; @@ -1258,15 +1257,9 @@ drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info, int scale) if (mode == NULL) return NULL; - if (info->hdisplay % scale != 0 || - info->vdisplay % scale) { - weston_log("Mode %dx%d not multiple of scale %d\n", info->hdisplay, info->vdisplay, scale); - return NULL; - } - mode->base.flags = 0; - mode->base.width = info->hdisplay / scale; - mode->base.height = info->vdisplay / scale; + mode->base.width = info->hdisplay; + mode->base.height = info->vdisplay; /* Calculate higher precision (mHz) refresh rate */ refresh = (info->clock * 100LL / info->htotal + @@ -1282,9 +1275,6 @@ drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info, int scale) mode->base.refresh = refresh; mode->mode_info = *info; - if (scale != 1) - mode->base.flags |= WL_OUTPUT_MODE_SCALED; - if (info->type & DRM_MODE_TYPE_PREFERRED) mode->base.flags |= WL_OUTPUT_MODE_PREFERRED; @@ -1446,8 +1436,8 @@ drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec) int i, flags; output->surface = gbm_surface_create(ec->gbm, -output->base.current->width * output->base.scale, -output->base.current->height * output->base.scale, +output->base.current->width, +output->base.current->height, GBM_FORMAT_XRGB, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); @@ -1491,12 +1481,12 @@ drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c) /* FIXME error checking */ for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) { - output->dumb[i] = drm_fb_create_dumb(c, w * output->base.scale, h * output->base.scale); + output->dumb[i] = drm_fb_create_dumb(c, w, h); if (!output->dumb[i]) goto err; output->image[i] = - pixman_image_create_bits(PIXMAN_x8r8g8b8, w * output->base.scale, h * output->base.scale, + pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h, output->dumb[i]->map, output->dumb[i]->stride); if (!output->image[i]) @@ -1507,7 +1497,7 @@ drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c) goto err; pixman_region32_init_rect(&output->previous_damage, - output->base.x, output->base.y, w, h); + output->base.x, output->base.y, output->base.width, output->base.height); return 0; @@ -1839,8 +1829,7 @@ create_output_for_connector(struct drm_compositor *ec, } for (i = 0; i < connector->count_modes; i++) { - drm_mode = drm_output_add_mode(output, - &connector->modes[i], scale); + drm_mode = drm_output_add_mode(output, &connector->modes[i]); if (!drm_mode) goto err_free; } @@ -1858,8 +1847,8 @@ create_output_for_connector(struct drm_compositor *ec, wl_list_for_each(drm_m
[PATCH 6/9] compositor: Store original output scale
From: Alexander Larsson We want this so we can restore the original mode with the original size (after having been fullscreen). --- src/compositor.c | 1 + src/compositor.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/compositor.c b/src/compositor.c index 79acc76..8f82ba6 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -2697,6 +2697,7 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c, output->mm_width = mm_width; output->mm_height = mm_height; output->dirty = 1; + output->origin_scale = scale; weston_output_transform_scale_init(output, transform, scale); weston_output_init_zoom(output); diff --git a/src/compositor.h b/src/compositor.h index 3b428c5..b17d832 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -187,6 +187,7 @@ struct weston_output { struct weston_mode *current; struct weston_mode *origin; + int32_t origin_scale; struct wl_list mode_list; void (*start_repaint_loop)(struct weston_output *output); -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 4/9] compositor-x11: Set original mode after current
From: Alexander Larsson Otherwise we're pointing the original mode on some uninitialized value. --- src/compositor-x11.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compositor-x11.c b/src/compositor-x11.c index 279f1b3..ba6d053 100644 --- a/src/compositor-x11.c +++ b/src/compositor-x11.c @@ -887,7 +887,6 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y, if (fullscreen) x11_output_wait_for_map(c, output); - output->base.origin = output->base.current; output->base.start_repaint_loop = x11_output_start_repaint_loop; if (c->use_pixman) output->base.repaint = x11_output_repaint_shm; @@ -899,6 +898,7 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y, output->base.set_dpms = NULL; output->base.switch_mode = NULL; output->base.current = &output->mode; + output->base.origin = output->base.current; output->base.make = "xwayland"; output->base.model = "none"; weston_output_init(&output->base, &c->base, -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 3/9] fullscreen: Add fullscreen testing client
From: Alexander Larsson This lets you try fullscreen in different methods, sizes, scales, translations, etc. You can verify both output and input (via mouse over of the rectangles). --- clients/Makefile.am | 4 + clients/fullscreen.c | 356 +++ 2 files changed, 360 insertions(+) create mode 100644 clients/fullscreen.c diff --git a/clients/Makefile.am b/clients/Makefile.am index d360174..12a9938 100644 --- a/clients/Makefile.am +++ b/clients/Makefile.am @@ -63,6 +63,7 @@ clients_programs =\ eventdemo \ clickdot\ transformed \ + fullscreen \ calibrator \ $(subsurfaces) \ $(full_gl_client_programs) @@ -129,6 +130,9 @@ clickdot_LDADD = libtoytoolkit.la transformed_SOURCES = transformed.c transformed_LDADD = libtoytoolkit.la +fullscreen_SOURCES = fullscreen.c +fullscreen_LDADD = libtoytoolkit.la + calibrator_SOURCES = calibrator.c ../shared/matrix.c ../shared/matrix.h calibrator_LDADD = libtoytoolkit.la diff --git a/clients/fullscreen.c b/clients/fullscreen.c new file mode 100644 index 000..bea1a15 --- /dev/null +++ b/clients/fullscreen.c @@ -0,0 +1,356 @@ +/* + * Copyright © 2008 Kristian Høgsberg + * Copyright © 2012 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include "window.h" + +struct fullscreen { + struct display *display; + struct window *window; + struct widget *widget; + int width, height; + int fullscreen; + float pointer_x, pointer_y; + enum wl_shell_surface_fullscreen_method fullscreen_method; +}; + +static void +fullscreen_handler(struct window *window, void *data) +{ + struct fullscreen *fullscreen = data; + + fullscreen->fullscreen ^= 1; + window_set_fullscreen(window, fullscreen->fullscreen); +} + +static void +resize_handler(struct widget *widget, int width, int height, void *data) +{ + struct fullscreen *fullscreen = data; + + widget_set_size(widget, fullscreen->width, fullscreen->height); +} + +static void +draw_string(cairo_t *cr, + const char *fmt, ...) +{ + char buffer[4096]; + char *p, *end; + va_list argp; + cairo_text_extents_t text_extents; + cairo_font_extents_t font_extents; + + cairo_save(cr); + + cairo_select_font_face(cr, "sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size(cr, 14); + + cairo_font_extents (cr, &font_extents); + + va_start(argp, fmt); + + vsnprintf(buffer, sizeof(buffer), fmt, argp); + + p = buffer; + while (*p) { + end = strchr(p, '\n'); + if (end) + *end = 0; + + cairo_show_text(cr, p); + cairo_text_extents (cr, p, &text_extents); + cairo_rel_move_to (cr, -text_extents.x_advance, font_extents.height); + + if (end) + p = end + 1; + else + break; + } + + va_end(argp); + + cairo_restore(cr); + +} + +static void +redraw_handler(struct widget *widget, void *data) +{ + struct fullscreen *fullscreen = data; + struct rectangle allocation; + cairo_surface_t *surface; + cairo_t *cr; + int i; + double x, y, border; + const char *method_name[] = { "default", "scale", "driver", "fill" }; + + surface = window_get_surface(fullscreen->window); + if (surface
[PATCH 2/9] input: Fix possible crash in clip_pointer_motion
From: Alexander Larsson It was erronously using output->current->height in one place where it should use output->height. This may cause it to create an invalid clipped coordinate in case of output scaling or transform, because the next round "prev" would end up NULL. --- src/input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input.c b/src/input.c index 129593f..89f74f4 100644 --- a/src/input.c +++ b/src/input.c @@ -593,7 +593,7 @@ clip_pointer_motion(struct weston_seat *seat, wl_fixed_t *fx, wl_fixed_t *fy) prev->width - 1); if (y < prev->y) *fy = wl_fixed_from_int(prev->y); - else if (y >= prev->y + prev->current->height) + else if (y >= prev->y + prev->height) *fy = wl_fixed_from_int(prev->y + prev->height - 1); } -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 1/9] shell: Position DRIVER fullscreen surfaces at origin
From: Alexander Larsson When a window is fullscreened with DRIVER method and we succeeded in changing mode we need to actually move the surface to the origin of the output, or it won't be used for scanout. --- src/shell.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shell.c b/src/shell.c index 1443328..07be564 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1802,6 +1802,9 @@ shell_configure_fullscreen(struct shell_surface *shsurf) shsurf->fullscreen.framerate}; if (weston_output_switch_mode(output, &mode) == 0) { + weston_surface_set_position(surface, + output->x - surf_x, + output->y - surf_y); weston_surface_configure(shsurf->fullscreen.black_surface, output->x - surf_x, output->y - surf_y, -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 0/9] Update weston to the change in how modes work
From: Alexander Larsson This series updates weston wrt the protocol changes in: http://lists.freedesktop.org/archives/wayland-devel/2013-May/009498.html It also has a test client and some general fullscreen bugfixes. Alexander Larsson (9): shell: Position DRIVER fullscreen surfaces at origin input: Fix possible crash in clip_pointer_motion fullscreen: Add fullscreen testing client compositor-x11: Set original mode after current compositor: Store modes in physical units compositor: Store original output scale shell: Use buffer_scale as output scale on fullscreen DRIVER shell: Always go to original mode when focused window not fullscreen shell: Center window in fullscreen if needed clients/Makefile.am | 4 + clients/fullscreen.c | 356 ++ src/compositor-drm.c | 37 ++ src/compositor-x11.c | 8 +- src/compositor.c | 32 +++-- src/compositor.h | 5 +- src/gl-renderer.c | 4 +- src/input.c | 2 +- src/pixman-renderer.c | 4 +- src/shell.c | 46 +-- 10 files changed, 436 insertions(+), 62 deletions(-) create mode 100644 clients/fullscreen.c -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH] protocol: Modes are specified in HW pixels
From: Alexander Larsson Modes are mainly meant to be used in coordination with fullscreen in DRIVER mode, by e.g. games. For such games what they generally want is to match some hardware mode and resize their window for that. We don't really need to complicate this with the scaling. So, we keep the resolutions in HW pixels, and drop the SCALED flag (as it is now useless). This lets you just create e.g an 800x600 buffer of scale 1 and fullscreen that, ignoring the output scaling factor (although you can of course also respect it and create a 400x300 surface at scale 2). Conceptually the mode change is treated like a scaling which overrides the normal output scale. The only complexity is the FILL mode where it can happen that the user specifies a buffer of the same size as the screen, but the output has scale 2 and the buffer scale 1. Just scanning out this buffer will work, but effectively this is a downscaling operation, as the "real" size of the surface in pels is twice the size of the output. We solve this by allowing FILL to downscale (but still not upscale). --- protocol/wayland.xml | 30 +- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index acfb140..1ec704b 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -729,7 +729,7 @@ - + @@ -751,6 +751,19 @@ indicates that the app does not care about framerate. The framerate is specified in mHz, that is framerate of 6 is 60Hz. + A method of "scale" or "driver" implies a scaling operation of + the surface, either via a direct scaling operation or a change of + the output mode. This will override any kind of output scaling, so + that mapping a surface with a buffer size equal to the mode can + fill the screen independent of buffer_scale. + + A method of "fill" means we don't scale up the buffer, however + any output scale is applied. This means that you may run into + an edge case where the application maps a buffer with the same + size of the output mode but buffer_scale 1 (thus making a + surface larger than the output). In this case it is allowed to + downscale the results to fit the screen. + The compositor must reply to this request with a configure event with the dimensions for the output on which the surface will be made fullscreen. @@ -1596,8 +1609,6 @@ summary="indicates this is the current mode"/> - @@ -1610,14 +1621,15 @@ current. In other words, the current mode is always the last mode that was received with the current flag set. - The size of a mode is given relative to the global compositor - space. This is not necessarily the native size of the display, - as the output might be scaled, as described in wl_output.scale. - In this case the scaled flag will be set. + The size of a mode is given in physical hardware units of +the output device. This is not necessarily the same as +the output size in the global compositor space. For instance, +the output may be scaled, as described in wl_output.scale, +or transformed , as described in wl_output.transform. - - + + -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH] Convert all scales to int32_t
From: Alexander Larsson The type changed in the protocol, so update weston for this. --- clients/desktop-shell.c | 2 +- clients/window.c| 24 clients/window.h| 2 +- src/compositor-x11.c| 4 ++-- src/compositor.c| 12 ++-- src/compositor.h| 14 +++--- 6 files changed, 29 insertions(+), 29 deletions(-) diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c index 40dd1dd..51ce3ec 100644 --- a/clients/desktop-shell.c +++ b/clients/desktop-shell.c @@ -1115,7 +1115,7 @@ output_handle_done(void *data, static void output_handle_scale(void *data, struct wl_output *wl_output, -uint32_t scale) +int32_t scale) { struct output *output = data; diff --git a/clients/window.c b/clients/window.c index b2e1af7..3870898 100644 --- a/clients/window.c +++ b/clients/window.c @@ -159,7 +159,7 @@ struct toysurface { */ cairo_surface_t *(*prepare)(struct toysurface *base, int dx, int dy, int32_t width, int32_t height, uint32_t flags, - enum wl_output_transform buffer_transform, uint32_t buffer_scale); + enum wl_output_transform buffer_transform, int32_t buffer_scale); /* * Post the surface to the server, returning the server allocation @@ -167,7 +167,7 @@ struct toysurface { * after calling this. */ void (*swap)(struct toysurface *base, -enum wl_output_transform buffer_transform, uint32_t buffer_scale, +enum wl_output_transform buffer_transform, int32_t buffer_scale, struct rectangle *server_allocation); /* @@ -210,7 +210,7 @@ struct surface { enum window_buffer_type buffer_type; enum wl_output_transform buffer_transform; - uint32_t buffer_scale; + int32_t buffer_scale; cairo_surface_t *cairo_surface; @@ -468,7 +468,7 @@ debug_print(void *proxy, int line, const char *func, const char *fmt, ...) #endif static void -surface_to_buffer_size (enum wl_output_transform buffer_transform, uint32_t buffer_scale, int32_t *width, int32_t *height) +surface_to_buffer_size (enum wl_output_transform buffer_transform, int32_t buffer_scale, int32_t *width, int32_t *height) { int32_t tmp; @@ -490,7 +490,7 @@ surface_to_buffer_size (enum wl_output_transform buffer_transform, uint32_t buff } static void -buffer_to_surface_size (enum wl_output_transform buffer_transform, uint32_t buffer_scale, int32_t *width, int32_t *height) +buffer_to_surface_size (enum wl_output_transform buffer_transform, int32_t buffer_scale, int32_t *width, int32_t *height) { int32_t tmp; @@ -531,7 +531,7 @@ to_egl_window_surface(struct toysurface *base) static cairo_surface_t * egl_window_surface_prepare(struct toysurface *base, int dx, int dy, int32_t width, int32_t height, uint32_t flags, - enum wl_output_transform buffer_transform, uint32_t buffer_scale) + enum wl_output_transform buffer_transform, int32_t buffer_scale) { struct egl_window_surface *surface = to_egl_window_surface(base); @@ -545,7 +545,7 @@ egl_window_surface_prepare(struct toysurface *base, int dx, int dy, static void egl_window_surface_swap(struct toysurface *base, - enum wl_output_transform buffer_transform, uint32_t buffer_scale, + enum wl_output_transform buffer_transform, int32_t buffer_scale, struct rectangle *server_allocation) { struct egl_window_surface *surface = to_egl_window_surface(base); @@ -1017,7 +1017,7 @@ static const struct wl_buffer_listener shm_surface_buffer_listener = { static cairo_surface_t * shm_surface_prepare(struct toysurface *base, int dx, int dy, int32_t width, int32_t height, uint32_t flags, - enum wl_output_transform buffer_transform, uint32_t buffer_scale) + enum wl_output_transform buffer_transform, int32_t buffer_scale) { int resize_hint = !!(flags & SURFACE_HINT_RESIZE); struct shm_surface *surface = to_shm_surface(base); @@ -1095,7 +1095,7 @@ out: static void shm_surface_swap(struct toysurface *base, -enum wl_output_transform buffer_transform, uint32_t buffer_scale, +enum wl_output_transform buffer_transform, int32_t buffer_scale, struct rectangle *server_allocation) { struct shm_surface *surface = to_shm_surface(base); @@ -1457,7 +1457,7 @@ window_set_buffer_transform(struct window *window, void window_set_buffer_scale(struct window *window, - uint32_t scale) + int32_t scale) { window->main_surface->buffer_scale = scale;
[PATCH] protocol: Use signed int for scale values
From: Alexander Larsson We usually use signed ints for things like this, to avoid issues C sign coersion. --- protocol/wayland.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index acfb140..0c7c053 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1155,7 +1155,7 @@ a buffer that is larger (by a factor of scale in each dimension) than the desired surface size. - + @@ -1652,7 +1652,7 @@ avoid scaling the surface, and the client can supply a higher detail image. - + -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH] window: Bind to version 3 of compositor
From: Alexander Larsson We need version 3 of the compositor to get version 3 of wl_surface which has set_buffer_transform and set_buffer_scale. --- clients/window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/window.c b/clients/window.c index b2e1af7..8e49f22 100644 --- a/clients/window.c +++ b/clients/window.c @@ -4749,7 +4749,7 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, if (strcmp(interface, "wl_compositor") == 0) { d->compositor = wl_registry_bind(registry, id, -&wl_compositor_interface, 1); +&wl_compositor_interface, 3); } else if (strcmp(interface, "wl_output") == 0) { display_add_output(d, id); } else if (strcmp(interface, "wl_seat") == 0) { -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 2/2] wayland-server: Version check requests
From: Alexander Larsson If an interface has any messages and its version is larger than 1 then we emit a method counts array which lists the number of methods for each version of the interface. This can be used in addition to the normal method_count to reject requests that the server doesn't support. This allows the wayland server library to be upgraded and still safely run oler compositors that don't implement the new requests. Since there is no other space in the wm_interface we add the method count array at the end of the events array. We then add some warnings to the event sending code so that we never accidentally trigger these events. Then we add code in the server to reject messages that are not supported by the server version of the object they are sent to. --- src/scanner.c| 54 ++-- src/wayland-server.c | 34 +++-- 2 files changed, 80 insertions(+), 8 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 9c14ad3..38e7909 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1019,12 +1019,13 @@ emit_types(struct protocol *protocol, struct wl_list *message_list) static void emit_messages(struct wl_list *message_list, - struct interface *interface, const char *suffix) + struct interface *interface, const char *suffix, + int emit_method_counts) { struct message *m; struct arg *a; - if (wl_list_empty(message_list)) + if (wl_list_empty(message_list) && !emit_method_counts) return; printf("static const struct wl_message " @@ -1070,13 +1071,52 @@ emit_messages(struct wl_list *message_list, printf("\", types + %d },\n", m->type_index); } + if (emit_method_counts) { + printf("\t{ NULL, \"\", (void *)%s_method_counts },\n", interface->name); + } + + printf("};\n\n"); +} + +static int +emit_method_counts(struct wl_list *message_list, + struct interface *interface) +{ + struct message *m; + int version = 1; + int count; + + if (wl_list_empty(message_list) || interface->version == 1) + return 0; + + printf("static const uint32_t " + "%s_method_counts[] = { ", + interface->name); + + count = 0; + wl_list_for_each(m, message_list, link) { + while (m->since != version) { + printf("%d,", count); + version++; + } + count++; + } + + while (version <= interface->version) { + printf("%d, ", count); + version++; + } + printf("};\n\n"); + + return 1; } static void emit_code(struct protocol *protocol) { struct interface *i; + int has_method_counts; if (protocol->copyright) format_copyright(protocol->copyright); @@ -1101,8 +1141,10 @@ emit_code(struct protocol *protocol) wl_list_for_each(i, &protocol->interface_list, link) { - emit_messages(&i->request_list, i, "requests"); - emit_messages(&i->event_list, i, "events"); + + emit_messages(&i->request_list, i, "requests", 0); + has_method_counts = emit_method_counts(&i->request_list, i); + emit_messages(&i->event_list, i, "events", has_method_counts); printf("WL_EXPORT const struct wl_interface " "%s_interface = {\n" @@ -1115,9 +1157,9 @@ emit_code(struct protocol *protocol) else printf("\t0, NULL,\n"); - if (!wl_list_empty(&i->event_list)) + if (!wl_list_empty(&i->event_list) || has_method_counts) printf("\t%d, %s_events,\n", - wl_list_length(&i->event_list), i->name); + wl_list_length(&i->event_list) + has_method_counts, i->name); else printf("\t0, NULL,\n"); diff --git a/src/wayland-server.c b/src/wayland-server.c index 4604008..a82707a 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -124,6 +124,12 @@ wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...) struct wl_object *object = &resource->object; va_list ap; + if (opcode >= (uint32_t)object->interface->event_count || + object->interface->events[opcode].name == NULL) { + wl_log ("Trying to post unsupported event\n"); + return; + } + va_start(ap, opcode); closure = wl_closure_vmarshal(object, opcode, ap, &object->interface->events[opcode]); @@ -150,6 +156,12 @@ wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...) struct wl_object *object = &resource->object; va_list ap; +
[PATCH 1/2] wl_resource: Add version field and getter/setter
From: Alexander Larsson We create a private structure for extra data and store it in a destroy notifier. In this way we can store the version in a backwards compatible way. This lets us track the actual version of a resource which is generally the min of what the client requested and what the server supports. This will let us avoid sending messages the client doesn't support and to not handle requests the server doesn't support. --- src/wayland-server.c | 66 +++- src/wayland-server.h | 6 + 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index a3d3887..4604008 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -102,6 +102,11 @@ struct wl_global { struct wl_list link; }; +struct wl_resource_private { + struct wl_listener listener; + uint32_t version; +}; + static int wl_debug = 0; static void @@ -373,10 +378,28 @@ wl_client_get_credentials(struct wl_client *client, *gid = client->ucred.gid; } +static void +resource_private_notify(struct wl_listener *listener, void *data) +{ + struct wl_resource *resource = data; + struct wl_resource_private *priv = (struct wl_resource_private *)listener; + + if (priv != (struct wl_resource_private *)(resource + 1)) + free (priv); +} + WL_EXPORT uint32_t wl_client_add_resource(struct wl_client *client, struct wl_resource *resource) { + struct wl_resource_private *priv; + + priv = calloc(1, sizeof(struct wl_resource_private)); + if (!priv) { + wl_resource_post_no_memory(resource); + return 0; + } + if (resource->object.id == 0) { resource->object.id = wl_map_insert_new(&client->objects, @@ -387,12 +410,18 @@ wl_client_add_resource(struct wl_client *client, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid new id %d", resource->object.id); + free(priv); return 0; } resource->client = client; wl_signal_init(&resource->destroy_signal); + priv->listener.notify = resource_private_notify; + wl_signal_add(&resource->destroy_signal, &priv->listener); + + priv->version = 1; + return resource->object.id; } @@ -895,6 +924,33 @@ wl_display_get_destroy_listener(struct wl_display *display, return wl_signal_get(&display->destroy_signal, notify); } +static struct wl_resource_private * +wl_resource_get_priv (struct wl_resource *resource) +{ + return (struct wl_resource_private *) + wl_signal_get(&resource->destroy_signal, resource_private_notify); +} + +WL_EXPORT void +wl_resource_set_version(struct wl_resource *resource, + uint32_t version) +{ + struct wl_resource_private *priv = wl_resource_get_priv (resource); + + /* We don't want anything to set this to 0, as that will cause us + to look before the start of the method_counts array */ + if (version >= 1) + priv->version = version; +} + +WL_EXPORT uint32_t +wl_resource_get_version(struct wl_resource *resource) +{ + struct wl_resource_private *priv = wl_resource_get_priv (resource); + + return priv->version; +} + WL_EXPORT struct wl_resource * wl_client_add_object(struct wl_client *client, const struct wl_interface *interface, @@ -902,8 +958,9 @@ wl_client_add_object(struct wl_client *client, uint32_t id, void *data) { struct wl_resource *resource; + struct wl_resource_private *priv; - resource = malloc(sizeof *resource); + resource = malloc(sizeof *resource + sizeof (struct wl_resource_private)); if (resource == NULL) { wl_resource_post_no_memory(client->display_resource); return NULL; @@ -913,6 +970,13 @@ wl_client_add_object(struct wl_client *client, resource->client = client; resource->destroy = (void *) free; + priv = (struct wl_resource_private *)(resource + 1); + + priv->listener.notify = resource_private_notify; + wl_signal_add(&resource->destroy_signal, &priv->listener); + + priv->version = 1; + if (wl_map_insert_at(&client->objects, resource->object.id, resource) < 0) { wl_resource_post_error(client->display_resource, WL_DISPLAY_ERROR_INVALID_OBJECT, diff --git a/src/wayland-server.h b/src/wayland-server.h index a9cf544..6beb0dd 100644 --- a/src/wayland-server.h +++ b/src/wayland-server.h @@ -135,6 +135,12 @@ wl_client_new_object(struct wl_client *client, struct wl_resource * wl_client_get_object(struct wl_client *client, uint32_t id); +void +wl_resource_set_version(struct wl_resource *
[PATCH 0/2] resource versioning V3
From: Alexander Larsson New in this version: * We look up the private with wl_signal_get * Fixed off-by-one error in method_counts array lookup (version 1 is at offset 0) Alexander Larsson (2): wl_resource: Add version field and getter/setter wayland-server: Version check requests src/scanner.c| 54 src/wayland-server.c | 100 +-- src/wayland-server.h | 6 3 files changed, 151 insertions(+), 9 deletions(-) -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH] wayland-server: Version check requests
From: Alexander Larsson If an interface has any messages and its version is larger than 1 then we emit a method counts array which lists the number of methods for each version of the interface. This can be used in addition to the normal method_count to reject requests that the server doesn't support. This allows the wayland server library to be upgraded and still safely run oler compositors that don't implement the new requests. Since there is no other space in the wm_interface we add the method count array at the end of the events array. We then add some warnings to the event sending code so that we never accidentally trigger these events. Then we add code in the server to reject messages that are not supported by the server version of the object they are sent to. --- src/scanner.c| 54 ++-- src/wayland-server.c | 34 +++-- 2 files changed, 80 insertions(+), 8 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 9c14ad3..38e7909 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1019,12 +1019,13 @@ emit_types(struct protocol *protocol, struct wl_list *message_list) static void emit_messages(struct wl_list *message_list, - struct interface *interface, const char *suffix) + struct interface *interface, const char *suffix, + int emit_method_counts) { struct message *m; struct arg *a; - if (wl_list_empty(message_list)) + if (wl_list_empty(message_list) && !emit_method_counts) return; printf("static const struct wl_message " @@ -1070,13 +1071,52 @@ emit_messages(struct wl_list *message_list, printf("\", types + %d },\n", m->type_index); } + if (emit_method_counts) { + printf("\t{ NULL, \"\", (void *)%s_method_counts },\n", interface->name); + } + + printf("};\n\n"); +} + +static int +emit_method_counts(struct wl_list *message_list, + struct interface *interface) +{ + struct message *m; + int version = 1; + int count; + + if (wl_list_empty(message_list) || interface->version == 1) + return 0; + + printf("static const uint32_t " + "%s_method_counts[] = { ", + interface->name); + + count = 0; + wl_list_for_each(m, message_list, link) { + while (m->since != version) { + printf("%d,", count); + version++; + } + count++; + } + + while (version <= interface->version) { + printf("%d, ", count); + version++; + } + printf("};\n\n"); + + return 1; } static void emit_code(struct protocol *protocol) { struct interface *i; + int has_method_counts; if (protocol->copyright) format_copyright(protocol->copyright); @@ -1101,8 +1141,10 @@ emit_code(struct protocol *protocol) wl_list_for_each(i, &protocol->interface_list, link) { - emit_messages(&i->request_list, i, "requests"); - emit_messages(&i->event_list, i, "events"); + + emit_messages(&i->request_list, i, "requests", 0); + has_method_counts = emit_method_counts(&i->request_list, i); + emit_messages(&i->event_list, i, "events", has_method_counts); printf("WL_EXPORT const struct wl_interface " "%s_interface = {\n" @@ -1115,9 +1157,9 @@ emit_code(struct protocol *protocol) else printf("\t0, NULL,\n"); - if (!wl_list_empty(&i->event_list)) + if (!wl_list_empty(&i->event_list) || has_method_counts) printf("\t%d, %s_events,\n", - wl_list_length(&i->event_list), i->name); + wl_list_length(&i->event_list) + has_method_counts, i->name); else printf("\t0, NULL,\n"); diff --git a/src/wayland-server.c b/src/wayland-server.c index c808f6a..e94366b 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -124,6 +124,12 @@ wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...) struct wl_object *object = &resource->object; va_list ap; + if (opcode >= (uint32_t)object->interface->event_count || + object->interface->events[opcode].name == NULL) { + wl_log ("Trying to post unsupported event\n"); + return; + } + va_start(ap, opcode); closure = wl_closure_vmarshal(object, opcode, ap, &object->interface->events[opcode]); @@ -150,6 +156,12 @@ wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...) struct wl_object *object = &resource->object; va_list ap; +
[PATCH 2/2] compositor/shell: Set version on all wl_resources
From: Alexander Larsson A few wl_resources have version != 1, we need to set this based on the supported version and the client requested version. --- src/compositor.c | 22 -- src/shell.c | 1 + 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index 02e79e6..9df4014 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -1671,6 +1671,21 @@ compositor_create_surface(struct wl_client *client, surface->resource.data = surface; wl_client_add_resource(client, &surface->resource); + + /* The surface version depends on the requested compositor version, as + that is the only way to negotiate surface versions */ + switch (wl_resource_get_version (resource)) { + case 1: + wl_resource_set_version (&surface->resource, 1); + break; + case 2: + wl_resource_set_version (&surface->resource, 2); + break; + case 3: + default: + wl_resource_set_version (&surface->resource, 3); + break; + } } static void @@ -2508,6 +2523,7 @@ bind_output(struct wl_client *client, resource = wl_client_add_object(client, &wl_output_interface, NULL, id, data); + wl_resource_set_version (resource, MIN(version, 2)); wl_list_insert(&output->resource_list, &resource->link); resource->destroy = unbind_resource; @@ -2728,9 +2744,11 @@ compositor_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { struct weston_compositor *compositor = data; + struct wl_resource *resource; - wl_client_add_object(client, &wl_compositor_interface, -&compositor_interface, id, compositor); + resource = wl_client_add_object(client, &wl_compositor_interface, + &compositor_interface, id, compositor); + wl_resource_set_version (resource, MIN(version, 3)); } static void diff --git a/src/shell.c b/src/shell.c index eb8d802..12f6b5e 100644 --- a/src/shell.c +++ b/src/shell.c @@ -3580,6 +3580,7 @@ bind_desktop_shell(struct wl_client *client, resource = wl_client_add_object(client, &desktop_shell_interface, &desktop_shell_implementation, id, shell); + wl_resource_set_version (resource, MIN(version, 2)); if (client == shell->child.client) { resource->destroy = unbind_desktop_shell; -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 1/2] Add MIN() macro
From: Alexander Larsson This will be needed for the version negotiation --- src/compositor.h | 4 1 file changed, 4 insertions(+) diff --git a/src/compositor.h b/src/compositor.h index 06476cc..8f96016 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -36,6 +36,10 @@ extern "C" { #include "matrix.h" #include "config-parser.h" +#ifndef MIN +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#endif + #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) #define container_of(ptr, type, member) ({ \ -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 0/2] Do proper version negotiation V2
From: Alexander Larsson This initializes the new version field of wl_resource to the negotiated value (i.e. the min of the requested version and the version supported by weston). Alexander Larsson (2): Add MIN() macro compositor/shell: Set version on all wl_resources src/compositor.c | 22 -- src/compositor.h | 4 src/shell.c | 1 + 3 files changed, 25 insertions(+), 2 deletions(-) -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH] wl_resource: Add version field and getter/setter
From: Alexander Larsson We create a private structure for extra data and store it in a destroy notifier. In this way we can store the version in a backwards compatible way. This lets us track the actual version of a resource which is generally the min of what the client requested and what the server supports. This will let us avoid sending messages the client doesn't support and to not handle requests the server doesn't support. --- src/wayland-server.c | 58 +++- src/wayland-server.h | 6 ++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index a3d3887..c808f6a 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -102,6 +102,11 @@ struct wl_global { struct wl_list link; }; +struct wl_resource_private { + struct wl_listener listener; + uint32_t version; +}; + static int wl_debug = 0; static void @@ -377,6 +382,14 @@ WL_EXPORT uint32_t wl_client_add_resource(struct wl_client *client, struct wl_resource *resource) { + struct wl_resource_private *priv; + + priv = calloc(1, sizeof(struct wl_resource_private)); + if (!priv) { + wl_resource_post_no_memory(resource); + return 0; + } + if (resource->object.id == 0) { resource->object.id = wl_map_insert_new(&client->objects, @@ -387,12 +400,18 @@ wl_client_add_resource(struct wl_client *client, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid new id %d", resource->object.id); + free(priv); return 0; } resource->client = client; wl_signal_init(&resource->destroy_signal); + priv->listener.notify = (wl_notify_func_t)free; + wl_signal_add(&resource->destroy_signal, &priv->listener); + + priv->version = 1; + return resource->object.id; } @@ -895,6 +914,35 @@ wl_display_get_destroy_listener(struct wl_display *display, return wl_signal_get(&display->destroy_signal, notify); } +static struct wl_resource_private * +wl_resource_get_priv (struct wl_resource *resource) +{ + /* The priv pointer is always the notify handler */ + return (struct wl_resource_private *)resource->destroy_signal.listener_list.next; +} + +WL_EXPORT void +wl_resource_set_version(struct wl_resource *resource, + uint32_t version) +{ + struct wl_resource_private *priv = wl_resource_get_priv (resource); + + priv->version = version; +} + +WL_EXPORT uint32_t +wl_resource_get_version(struct wl_resource *resource) +{ + struct wl_resource_private *priv = wl_resource_get_priv (resource); + + return priv->version; +} + +static void +dummy_notify(struct wl_listener *listener, void *data) +{ +} + WL_EXPORT struct wl_resource * wl_client_add_object(struct wl_client *client, const struct wl_interface *interface, @@ -902,8 +950,9 @@ wl_client_add_object(struct wl_client *client, uint32_t id, void *data) { struct wl_resource *resource; + struct wl_resource_private *priv; - resource = malloc(sizeof *resource); + resource = malloc(sizeof *resource + sizeof (struct wl_resource_private)); if (resource == NULL) { wl_resource_post_no_memory(client->display_resource); return NULL; @@ -913,6 +962,13 @@ wl_client_add_object(struct wl_client *client, resource->client = client; resource->destroy = (void *) free; + priv = (struct wl_resource_private *)(resource + 1); + + priv->listener.notify = dummy_notify; + wl_signal_add(&resource->destroy_signal, &priv->listener); + + priv->version = 1; + if (wl_map_insert_at(&client->objects, resource->object.id, resource) < 0) { wl_resource_post_error(client->display_resource, WL_DISPLAY_ERROR_INVALID_OBJECT, diff --git a/src/wayland-server.h b/src/wayland-server.h index a9cf544..6beb0dd 100644 --- a/src/wayland-server.h +++ b/src/wayland-server.h @@ -135,6 +135,12 @@ wl_client_new_object(struct wl_client *client, struct wl_resource * wl_client_get_object(struct wl_client *client, uint32_t id); +void +wl_resource_set_version(struct wl_resource *resource, + uint32_t version); +uint32_t +wl_resource_get_version(struct wl_resource *resource); + struct wl_listener { struct wl_list link; wl_notify_func_t notify; -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH] Add version support to wl_resource
From: Alexander Larsson New simpler version that uses a destroy notify to stash away the private pointer. Alexander Larsson (1): wl_resource: Add version field and getter/setter src/wayland-server.c | 58 +++- src/wayland-server.h | 6 ++ 2 files changed, 63 insertions(+), 1 deletion(-) -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 3/3] compositor/shell: Set version on all wl_resources
From: Alexander Larsson A few wl_resources have version != 1, we need to set this based on the supported version and the client requested version. --- src/compositor.c | 22 -- src/shell.c | 1 + 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index 13a6f47..1e27d51 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -1671,6 +1671,21 @@ compositor_create_surface(struct wl_client *client, surface->resource.data = surface; wl_client_add_resource(client, &surface->resource); + + /* The surface version depends on the requested compositor version, as + that is the only way to negotiate surface versions */ + switch (wl_resource_get_version (resource)) { + case 1: + wl_resource_set_version (&surface->resource, 1); + break; + case 2: + wl_resource_set_version (&surface->resource, 2); + break; + case 3: + default: + wl_resource_set_version (&surface->resource, 3); + break; + } } static void @@ -2510,6 +2525,7 @@ bind_output(struct wl_client *client, resource = wl_client_add_object(client, &wl_output_interface, NULL, id, data); + wl_resource_set_version (resource, MIN(version, 2)); wl_slist_insert(&output->resource_list, &resource->link); resource->destroy = unbind_resource; @@ -2730,9 +2746,11 @@ compositor_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { struct weston_compositor *compositor = data; + struct wl_resource *resource; - wl_client_add_object(client, &wl_compositor_interface, -&compositor_interface, id, compositor); + resource = wl_client_add_object(client, &wl_compositor_interface, + &compositor_interface, id, compositor); + wl_resource_set_version (resource, MIN(version, 3)); } static void diff --git a/src/shell.c b/src/shell.c index dc7cd05..1e42d6b 100644 --- a/src/shell.c +++ b/src/shell.c @@ -3582,6 +3582,7 @@ bind_desktop_shell(struct wl_client *client, resource = wl_client_add_object(client, &desktop_shell_interface, &desktop_shell_implementation, id, shell); + wl_resouce_set_version (resource, MIN(version, 2)); if (client == shell->child.client) { resource->destroy = unbind_desktop_shell; -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 2/3] Add MIN() macro
From: Alexander Larsson This will be needed for the version negotiation --- src/compositor.h | 4 1 file changed, 4 insertions(+) diff --git a/src/compositor.h b/src/compositor.h index 176b501..5ddbc95 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -36,6 +36,10 @@ extern "C" { #include "matrix.h" #include "config-parser.h" +#ifndef MIN +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#endif + #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) #define container_of(ptr, type, member) ({ \ -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 1/3] Update wl_resource.link to wl_slist due to wayland change
From: Alexander Larsson --- src/compositor.c | 12 ++- src/compositor.h | 12 +-- src/data-device.c | 10 + src/input.c | 62 +++ src/shell.c | 10 + 5 files changed, 69 insertions(+), 37 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index 02e79e6..13a6f47 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -505,11 +505,11 @@ weston_surface_damage_below(struct weston_surface *surface) } static struct wl_resource * -find_resource_for_client(struct wl_list *list, struct wl_client *client) +find_resource_for_client(struct wl_slist *list, struct wl_client *client) { struct wl_resource *r; -wl_list_for_each(r, list, link) { +wl_slist_for_each(r, list, link) { if (r->client == client) return r; } @@ -2494,7 +2494,9 @@ weston_compositor_stack_plane(struct weston_compositor *ec, static void unbind_resource(struct wl_resource *resource) { - wl_list_remove(&resource->link); + struct weston_output *output = resource->data; + + wl_slist_remove(&output->resource_list, &resource->link); free(resource); } @@ -2509,7 +2511,7 @@ bind_output(struct wl_client *client, resource = wl_client_add_object(client, &wl_output_interface, NULL, id, data); - wl_list_insert(&output->resource_list, &resource->link); + wl_slist_insert(&output->resource_list, &resource->link); resource->destroy = unbind_resource; wl_output_send_geometry(resource, @@ -2712,7 +2714,7 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c, wl_signal_init(&output->frame_signal); wl_signal_init(&output->destroy_signal); wl_list_init(&output->animation_list); - wl_list_init(&output->resource_list); + wl_slist_init(&output->resource_list); output->id = ffs(~output->compositor->output_id_pool) - 1; output->compositor->output_id_pool |= 1 << output->id; diff --git a/src/compositor.h b/src/compositor.h index 06476cc..176b501 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -161,7 +161,7 @@ struct weston_output { void *renderer_state; struct wl_list link; - struct wl_list resource_list; + struct wl_slist resource_list; struct wl_global *global; struct weston_compositor *compositor; struct weston_matrix matrix; @@ -279,7 +279,7 @@ struct wl_data_source { struct weston_pointer { struct weston_seat *seat; - struct wl_list resource_list; + struct wl_slist resource_list; struct weston_surface *focus; struct wl_resource *focus_resource; struct wl_listener focus_listener; @@ -305,7 +305,7 @@ struct weston_pointer { struct weston_touch { struct weston_seat *seat; - struct wl_list resource_list; + struct wl_slist resource_list; struct weston_surface *focus; struct wl_resource *focus_resource; struct wl_listener focus_listener; @@ -388,7 +388,7 @@ struct weston_xkb_info { struct weston_keyboard { struct weston_seat *seat; - struct wl_list resource_list; + struct wl_slist resource_list; struct weston_surface *focus; struct wl_resource *focus_resource; struct wl_listener focus_listener; @@ -415,7 +415,7 @@ struct weston_keyboard { }; struct weston_seat { - struct wl_list base_resource_list; + struct wl_slist base_resource_list; struct weston_pointer *pointer; struct weston_keyboard *keyboard; @@ -428,7 +428,7 @@ struct weston_seat { enum weston_keyboard_modifier modifier_state; struct weston_surface *saved_kbd_focus; struct wl_listener saved_kbd_focus_listener; - struct wl_list drag_resource_list; + struct wl_slist drag_resource_list; uint32_t selection_serial; struct wl_data_source *selection_data_source; diff --git a/src/data-device.c b/src/data-device.c index 0decbb9..9dc988f 100644 --- a/src/data-device.c +++ b/src/data-device.c @@ -163,11 +163,11 @@ static struct wl_data_source_interface data_source_interface = { }; static struct wl_resource * -find_resource(struct wl_list *list, struct wl_client *client) +find_resource(struct wl_slist *list, struct wl_client *client) { struct wl_resource *r; - wl_list_for_each(r, list, link) { + wl_slist_for_each(r, list, link) { if (r->client == client) return r; } @@ -563,7 +563,9 @@ create_data_source(struct wl_client *client, static void unbind_data_device(struct wl_resource *resource) { - wl_list_remove(&resource->link); + struct weston_seat *seat = resource->data; + + wl_slist_remove(&seat->drag_resource_list, &resource->link); free(resource); } @@ -
[PATCH 0/3] Do proper version negotiation
From: Alexander Larsson This initializes the new version field of wl_resource to the negotiated value (i.e. the min of the requested version and the version supported by weston). Alexander Larsson (3): Update wl_resource.link to wl_slist due to wayland change Add MIN() macro compositor/shell: Set version on all wl_resources src/compositor.c | 34 +++--- src/compositor.h | 16 -- src/data-device.c | 10 + src/input.c | 62 +++ src/shell.c | 11 ++ 5 files changed, 94 insertions(+), 39 deletions(-) -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 4/4] wl_resource: Add version field and getter/setter
From: Alexander Larsson This lets us track the actual version of a resource which is generally the min of what the client requested and what the server supports. This will let us avoid sending messages the client doesn't support and to not handle requests the server doesn't support. --- src/wayland-private.h | 2 +- src/wayland-server.c | 16 src/wayland-server.h | 6 ++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/wayland-private.h b/src/wayland-private.h index 105f9b9..b184309 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -48,7 +48,7 @@ struct wl_map { }; struct wl_resource_private { - uint32_t dummy; + uint32_t version; }; typedef void (*wl_iterator_func_t)(void *element, void *data); diff --git a/src/wayland-server.c b/src/wayland-server.c index e3a0376..c7a5e1d 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -401,6 +401,7 @@ wl_client_add_resource(struct wl_client *client, resource->priv = priv; resource->client = client; + resource->priv->version = 1; wl_signal_init(&resource->destroy_signal); return resource->object.id; @@ -912,6 +913,20 @@ wl_display_get_destroy_listener(struct wl_display *display, return wl_signal_get(&display->destroy_signal, notify); } +WL_EXPORT void +wl_resource_set_version(struct wl_resource *resource, + uint32_t version) +{ + resource->priv->version = version; +} + +WL_EXPORT uint32_t +wl_resource_get_version(struct wl_resource *resource) +{ + return resource->priv->version; +} + + WL_EXPORT struct wl_resource * wl_client_add_object(struct wl_client *client, const struct wl_interface *interface, @@ -930,6 +945,7 @@ wl_client_add_object(struct wl_client *client, resource->priv = (struct wl_resource_private *)(resource + 1); resource->client = client; resource->destroy = (void *) free; + resource->priv->version = 1; if (wl_map_insert_at(&client->objects, resource->object.id, resource) < 0) { wl_resource_post_error(client->display_resource, diff --git a/src/wayland-server.h b/src/wayland-server.h index 3ac0351..22b845c 100644 --- a/src/wayland-server.h +++ b/src/wayland-server.h @@ -135,6 +135,12 @@ wl_client_new_object(struct wl_client *client, struct wl_resource * wl_client_get_object(struct wl_client *client, uint32_t id); +void +wl_resource_set_version(struct wl_resource *resource, + uint32_t version); +uint32_t +wl_resource_get_version(struct wl_resource *resource); + struct wl_listener { struct wl_list link; wl_notify_func_t notify; -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 3/4] wl_resource: Add a private field to wl_resource
From: Alexander Larsson This takes the place of the second pointer in the old wl_list and lets us add more fields to wl_resource in a backwards compat fashion. --- src/wayland-private.h | 4 src/wayland-server.c | 17 - src/wayland-server.h | 4 +++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/wayland-private.h b/src/wayland-private.h index c4ce6b0..105f9b9 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -47,6 +47,10 @@ struct wl_map { uint32_t free_list; }; +struct wl_resource_private { + uint32_t dummy; +}; + typedef void (*wl_iterator_func_t)(void *element, void *data); void wl_map_init(struct wl_map *map); diff --git a/src/wayland-server.c b/src/wayland-server.c index f1a6aac..e3a0376 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -377,6 +377,14 @@ WL_EXPORT uint32_t wl_client_add_resource(struct wl_client *client, struct wl_resource *resource) { + struct wl_resource_private *priv; + + priv = calloc(1, sizeof(struct wl_resource_private)); + if (!priv) { + wl_resource_post_no_memory(resource); + return 0; + } + if (resource->object.id == 0) { resource->object.id = wl_map_insert_new(&client->objects, @@ -387,9 +395,11 @@ wl_client_add_resource(struct wl_client *client, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid new id %d", resource->object.id); + free(priv); return 0; } + resource->priv = priv; resource->client = client; wl_signal_init(&resource->destroy_signal); @@ -413,11 +423,15 @@ static void destroy_resource(void *element, void *data) { struct wl_resource *resource = element; + struct wl_resource_private *resource_priv = resource->priv; wl_signal_emit(&resource->destroy_signal, resource); if (resource->destroy) resource->destroy(resource); + + if (resource_priv != (struct wl_resource_private *)(resource + 1)) + free (resource_priv); } WL_EXPORT void @@ -906,13 +920,14 @@ wl_client_add_object(struct wl_client *client, { struct wl_resource *resource; - resource = malloc(sizeof *resource); + resource = malloc(sizeof *resource + sizeof (struct wl_resource_private)); if (resource == NULL) { wl_resource_post_no_memory(client->display_resource); return NULL; } wl_resource_init(resource, interface, implementation, id, data); + resource->priv = (struct wl_resource_private *)(resource + 1); resource->client = client; resource->destroy = (void *) free; diff --git a/src/wayland-server.h b/src/wayland-server.h index 4867652..3ac0351 100644 --- a/src/wayland-server.h +++ b/src/wayland-server.h @@ -177,11 +177,13 @@ wl_signal_emit(struct wl_signal *signal, void *data) l->notify(l, data); } +struct wl_resource_private; + struct wl_resource { struct wl_object object; void (*destroy)(struct wl_resource *resource); struct wl_slist link; - void *reserved; + struct wl_resource_private *priv; struct wl_signal destroy_signal; struct wl_client *client; void *data; -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 2/4] Convert wl_resource.link to a wl_slink
From: Alexander Larsson This lets us free up an extra pointer in wl_resource for other use. --- src/wayland-server.c | 17 ++--- src/wayland-server.h | 3 ++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index a3d3887..f1a6aac 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -86,7 +86,7 @@ struct wl_display { uint32_t id; uint32_t serial; - struct wl_list registry_resource_list; + struct wl_slist registry_resource_list; struct wl_list global_list; struct wl_list socket_list; struct wl_list client_list; @@ -513,7 +513,10 @@ display_sync(struct wl_client *client, static void unbind_resource(struct wl_resource *resource) { - wl_list_remove(&resource->link); + struct wl_display *display = resource->data; + + wl_slist_remove(&display->registry_resource_list, + &resource->link); free(resource); } @@ -530,8 +533,8 @@ display_get_registry(struct wl_client *client, ®istry_interface, id, display); registry_resource->destroy = unbind_resource; - wl_list_insert(&display->registry_resource_list, - ®istry_resource->link); + wl_slist_insert(&display->registry_resource_list, + ®istry_resource->link); wl_list_for_each(global, &display->global_list, link) wl_resource_post_event(registry_resource, @@ -590,7 +593,7 @@ wl_display_create(void) wl_list_init(&display->global_list); wl_list_init(&display->socket_list); wl_list_init(&display->client_list); - wl_list_init(&display->registry_resource_list); + wl_slist_init(&display->registry_resource_list); wl_signal_init(&display->destroy_signal); @@ -649,7 +652,7 @@ wl_display_add_global(struct wl_display *display, global->bind = bind; wl_list_insert(display->global_list.prev, &global->link); - wl_list_for_each(resource, &display->registry_resource_list, link) + wl_slist_for_each(resource, &display->registry_resource_list, link) wl_resource_post_event(resource, WL_REGISTRY_GLOBAL, global->name, @@ -664,7 +667,7 @@ wl_display_remove_global(struct wl_display *display, struct wl_global *global) { struct wl_resource *resource; - wl_list_for_each(resource, &display->registry_resource_list, link) + wl_slist_for_each(resource, &display->registry_resource_list, link) wl_resource_post_event(resource, WL_REGISTRY_GLOBAL_REMOVE, global->name); wl_list_remove(&global->link); diff --git a/src/wayland-server.h b/src/wayland-server.h index a9cf544..4867652 100644 --- a/src/wayland-server.h +++ b/src/wayland-server.h @@ -180,7 +180,8 @@ wl_signal_emit(struct wl_signal *signal, void *data) struct wl_resource { struct wl_object object; void (*destroy)(struct wl_resource *resource); - struct wl_list link; + struct wl_slist link; + void *reserved; struct wl_signal destroy_signal; struct wl_client *client; void *data; -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 1/4] Add single linked lists wl_slist similar to wl_list
From: Alexander Larsson --- src/wayland-util.c | 66 ++ src/wayland-util.h | 24 2 files changed, 90 insertions(+) diff --git a/src/wayland-util.c b/src/wayland-util.c index 598ab42..c774a7e 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -89,6 +89,72 @@ wl_list_insert_list(struct wl_list *list, struct wl_list *other) } WL_EXPORT void +wl_slist_init(struct wl_slist *list) +{ + list->next = list; +} + +WL_EXPORT void +wl_slist_insert(struct wl_slist *list, struct wl_slist *elm) +{ + elm->next = list->next; + list->next = elm; +} + +WL_EXPORT void +wl_slist_remove(struct wl_slist *list, struct wl_slist *elm) +{ + struct wl_slist *prev; + + prev = list; + while (prev->next != elm && prev->next != list) + prev = prev->next; + + if (prev->next == elm) { + prev->next = elm->next; + elm->next = NULL; + } +} + +WL_EXPORT int +wl_slist_length(const struct wl_slist *list) +{ + struct wl_slist *e; + int count; + + count = 0; + e = list->next; + while (e != list) { + e = e->next; + count++; + } + + return count; +} + +WL_EXPORT int +wl_slist_empty(const struct wl_slist *list) +{ + return list->next == list; +} + +WL_EXPORT void +wl_slist_insert_list(struct wl_slist *list, struct wl_slist *other) +{ + struct wl_slist *end; + + if (wl_slist_empty(other)) + return; + + end = other; + while (end->next != other) + end = end->next; + + end->next = list->next; + list->next = other->next; +} + +WL_EXPORT void wl_array_init(struct wl_array *array) { memset(array, 0, sizeof *array); diff --git a/src/wayland-util.h b/src/wayland-util.h index dbe05a5..40f2509 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -145,6 +145,30 @@ void wl_list_insert_list(struct wl_list *list, struct wl_list *other); pos = tmp, \ tmp = wl_container_of(pos->member.prev, tmp, member)) +struct wl_slist { + struct wl_slist *next; +}; + +void wl_slist_init(struct wl_slist *list); +void wl_slist_insert(struct wl_slist *list, struct wl_slist *elm); +void wl_slist_remove(struct wl_slist *list, struct wl_slist *elm); +int wl_slist_length(const struct wl_slist *list); +int wl_slist_empty(const struct wl_slist *list); +void wl_slist_insert_list(struct wl_slist *list, struct wl_slist *other); + +#define wl_slist_for_each(pos, head, member) \ + for (pos = 0, pos = wl_container_of((head)->next, pos, member); \ +&pos->member != (head);\ +pos = wl_container_of(pos->member.next, pos, member)) + +#define wl_slist_for_each_safe(pos, tmp, head, member) \ + for (pos = 0, tmp = 0, \ +pos = wl_container_of((head)->next, pos, member), \ +tmp = wl_container_of((pos)->member.next, tmp, member);\ +&pos->member != (head);\ +pos = tmp, \ +tmp = wl_container_of(pos->member.next, tmp, member)) + struct wl_array { size_t size; size_t alloc; -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 0/4] Add version support to wl_resource
From: Alexander Larsson Unfortunately there seems to be no easy way to add a version field to wl_resource in a compatible way, even if we are willing to break the server library API for compositors, as the wl_resource struct is embedded in a struct in the EGL code in mesa. Here is a version that uses one of the two pointers in wl_resource.link as a privat pointer allowing us to put extra info in the wl_resource. This is an incompatible ABI/API change in the server libraries, as anything using the wl_resource.link field need to be updated. There is also a slight cost to this as removal from a singly linked list is O(n) whereas it is O(1) on doubly linked list, but I don't expect the wayland lists to become very long, so this is probably ok. Alexander Larsson (4): Add single linked lists wl_slist similar to wl_list Convert wl_resource.link to a wl_slink wl_resource: Add a private field to wl_resource wl_resource: Add version field and getter/setter src/wayland-private.h | 4 src/wayland-server.c | 50 +++--- src/wayland-server.h | 11 - src/wayland-util.c| 66 +++ src/wayland-util.h| 24 +++ 5 files changed, 146 insertions(+), 9 deletions(-) -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 15/15] compositor-drm: Support output scaling
From: Alexander Larsson If you specify e.g. scale=2 in an output section in weston.ini we scale all modes by that factor. We also correctly scale cursor positioning, but ATM there is no scaling of the cursor sprite itself. --- src/compositor-drm.c | 87 +++- 1 file changed, 59 insertions(+), 28 deletions(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 8b33256..1485c6c 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -61,6 +61,7 @@ static int option_current_mode = 0; static char *output_name; static char *output_mode; static char *output_transform; +static char *output_scale; static struct wl_list configured_output_list; enum output_config { @@ -76,6 +77,7 @@ struct drm_configured_output { char *name; char *mode; uint32_t transform; + int32_t scale; int32_t width, height; drmModeModeInfo crtc_mode; enum output_config config; @@ -463,6 +465,7 @@ drm_output_prepare_scanout_surface(struct weston_output *_output, buffer->width != output->base.current->width || buffer->height != output->base.current->height || output->base.transform != es->buffer_transform || + output->base.scale != es->buffer_scale || es->transform.enabled) return NULL; @@ -791,6 +794,9 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base, if (es->buffer_transform != output_base->transform) return NULL; + if (es->buffer_scale != output_base->scale) + return NULL; + if (c->sprites_are_broken) return NULL; @@ -859,7 +865,8 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base, tbox = weston_transformed_rect(output_base->width, output_base->height, output_base->transform, - 1, *box); + output_base->scale, + *box); s->dest_x = tbox.x1; s->dest_y = tbox.y1; s->dest_w = tbox.x2 - tbox.x1; @@ -896,7 +903,7 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base, tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width), wl_fixed_from_int(es->geometry.height), - es->buffer_transform, 1, tbox); + es->buffer_transform, es->buffer_scale, tbox); s->src_x = tbox.x1 << 8; s->src_y = tbox.y1 << 8; @@ -977,8 +984,8 @@ drm_output_set_cursor(struct drm_output *output) } } - x = es->geometry.x - output->base.x; - y = es->geometry.y - output->base.y; + x = (es->geometry.x - output->base.x) * output->base.scale; + y = (es->geometry.y - output->base.y) * output->base.scale; if (output->cursor_plane.x != x || output->cursor_plane.y != y) { if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) { weston_log("failed to move cursor: %m\n"); @@ -1258,18 +1265,29 @@ init_pixman(struct drm_compositor *ec) } static struct drm_mode * -drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info) +drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info, struct drm_configured_output *config) { struct drm_mode *mode; uint64_t refresh; +int scale; mode = malloc(sizeof *mode); if (mode == NULL) return NULL; +scale = 1; +if (config) + scale = config->scale; + + if (info->hdisplay % scale != 0 || + info->vdisplay % scale) { + weston_log("Mode %dx%d not multiple of scale %d\n", info->hdisplay, info->vdisplay, scale); + return NULL; + } + mode->base.flags = 0; - mode->base.width = info->hdisplay; - mode->base.height = info->vdisplay; + mode->base.width = info->hdisplay / scale; + mode->base.height = info->vdisplay / scale; /* Calculate higher precision (mHz) refresh rate */ refresh = (info->clock * 100LL / info->htotal + @@ -1285,6 +1303,9 @@ drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info) mode->base.refresh = refresh; mode->mode_info = *info; + if (scale != 1) + mode->base.flags |= WL_OUTPUT_MODE_SCALED; + if (info->type & DRM_MODE_TYPE_PREFERRED) mode->base.flags |= WL_OUTPUT_MODE_PREFERRED; @@ -1446,8 +1467,8 @@ drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec) int i, flags; output->surface = gbm_surface_create(ec->gbm, -output->base.current->width, -
[PATCH 14/15] compositor-x11: Only repaint the damaged region
From: Alexander Larsson Set a clip on the GC when painting the damaged region so that we don't copy the entire shadow buffer each time. --- src/compositor-x11.c | 106 +++ 1 file changed, 106 insertions(+) diff --git a/src/compositor-x11.c b/src/compositor-x11.c index 58ccc16..9d6b6e7 100644 --- a/src/compositor-x11.c +++ b/src/compositor-x11.c @@ -355,6 +355,111 @@ x11_output_repaint_gl(struct weston_output *output_base, } static void +set_clip_for_output(struct weston_output *output_base, pixman_region32_t *region) +{ + struct x11_output *output = (struct x11_output *)output_base; + struct weston_compositor *ec = output->base.compositor; + struct x11_compositor *c = (struct x11_compositor *)ec; + pixman_box32_t *rects; + xcb_rectangle_t *output_rects; + pixman_box32_t rect, transformed_rect; + xcb_void_cookie_t cookie; + int width, height, nrects, i; + xcb_generic_error_t *err; + + rects = pixman_region32_rectangles(region, &nrects); + output_rects = calloc(nrects, sizeof(xcb_rectangle_t)); + + if (output_rects == NULL) + return; + + width = output_base->width; + height = output_base->height; + + for (i = 0; i < nrects; i++) { + rect = rects[i]; + rect.x1 -= output_base->x; + rect.y1 -= output_base->y; + rect.x2 -= output_base->x; + rect.y2 -= output_base->y; + + switch (output_base->transform) { + default: + case WL_OUTPUT_TRANSFORM_NORMAL: + transformed_rect.x1 = rect.x1; + transformed_rect.y1 = rect.y1; + transformed_rect.x2 = rect.x2; + transformed_rect.y2 = rect.y2; + break; + case WL_OUTPUT_TRANSFORM_90: + transformed_rect.x1 = height - rect.y2; + transformed_rect.y1 = rect.x1; + transformed_rect.x2 = height - rect.y1; + transformed_rect.y2 = rect.x2; + break; + case WL_OUTPUT_TRANSFORM_180: + transformed_rect.x1 = width - rect.x2; + transformed_rect.y1 = height - rect.y2; + transformed_rect.x2 = width - rect.x1; + transformed_rect.y2 = height - rect.y1; + break; + case WL_OUTPUT_TRANSFORM_270: + transformed_rect.x1 = rect.y1; + transformed_rect.y1 = width - rect.x2; + transformed_rect.x2 = rect.y2; + transformed_rect.y2 = width - rect.x1; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED: + transformed_rect.x1 = width - rect.x2; + transformed_rect.y1 = rect.y1; + transformed_rect.x2 = width - rect.x1; + transformed_rect.y2 = rect.y2; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + transformed_rect.x1 = height - rect.y2; + transformed_rect.y1 = width - rect.x2; + transformed_rect.x2 = height - rect.y1; + transformed_rect.y2 = width - rect.x1; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + transformed_rect.x1 = rect.x1; + transformed_rect.y1 = height - rect.y2; + transformed_rect.x2 = rect.x2; + transformed_rect.y2 = height - rect.y1; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + transformed_rect.x1 = rect.y1; + transformed_rect.y1 = rect.x1; + transformed_rect.x2 = rect.y2; + transformed_rect.y2 = rect.x2; + break; + } + + transformed_rect.x1 *= output_base->scale; + transformed_rect.y1 *= output_base->scale; + transformed_rect.x2 *= output_base->scale; + transformed_rect.y2 *= output_base->scale; + + output_rects[i].x = transformed_rect.x1; + output_rects[i].y = transformed_rect.y1; + output_rects[i].width = transformed_rect.x2 - transformed_rect.x1; + output_rects[i].height = transformed_rect.y2 - transformed_rect.y1; + } + + cookie = xcb_set_clip_rectangles_checked(c->conn, XCB_CLIP_ORDERING_UNSORTED, + output->gc, + 0, 0, nrects, + output_rects); + err = xcb_request_check(c->conn, cookie); + if (err !
[PATCH 13/15] compositor: Support output/buffer scaling
From: Alexander Larsson If you specify e.g. scale=2 in weston.ini an output section for the X11 backend we automatically upscale all normal surfaces by this amount. Additionally we respect a buffer_scale set on the buffer to mean that the buffer is already in a scaled form. This works with both the gl and the pixman renderer. The non-X backends compile and work, but don't support changing the output scale (they do downscale as needed due to buffer_scale though). This also sends the new "scale" and "done" events on wl_output, making clients aware of the scale. --- src/compositor-drm.c | 7 +-- src/compositor-fbdev.c| 3 +- src/compositor-headless.c | 2 +- src/compositor-rpi.c | 3 +- src/compositor-wayland.c | 2 +- src/compositor-x11.c | 60 ++--- src/compositor.c | 110 +- src/compositor.h | 18 +++- src/gl-renderer.c | 21 +++-- src/pixman-renderer.c | 48 +--- 10 files changed, 210 insertions(+), 64 deletions(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 35019e0..8b33256 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -858,7 +858,8 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base, box = pixman_region32_extents(&dest_rect); tbox = weston_transformed_rect(output_base->width, output_base->height, - output_base->transform, *box); + output_base->transform, + 1, *box); s->dest_x = tbox.x1; s->dest_y = tbox.y1; s->dest_w = tbox.x2 - tbox.x1; @@ -895,7 +896,7 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base, tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width), wl_fixed_from_int(es->geometry.height), - es->buffer_transform, tbox); + es->buffer_transform, 1, tbox); s->src_x = tbox.x1 << 8; s->src_y = tbox.y1 << 8; @@ -1813,7 +1814,7 @@ create_output_for_connector(struct drm_compositor *ec, weston_output_init(&output->base, &ec->base, x, y, connector->mmWidth, connector->mmHeight, - o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL); + o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL, 1); if (ec->use_pixman) { if (drm_output_init_pixman(output, ec) < 0) { diff --git a/src/compositor-fbdev.c b/src/compositor-fbdev.c index 21028a5..c643c23 100644 --- a/src/compositor-fbdev.c +++ b/src/compositor-fbdev.c @@ -537,7 +537,8 @@ fbdev_output_create(struct fbdev_compositor *compositor, weston_output_init(&output->base, &compositor->base, 0, 0, output->fb_info.width_mm, output->fb_info.height_mm, - WL_OUTPUT_TRANSFORM_NORMAL); + WL_OUTPUT_TRANSFORM_NORMAL, + 1); width = output->fb_info.x_resolution; height = output->fb_info.y_resolution; diff --git a/src/compositor-headless.c b/src/compositor-headless.c index 0df0f7d..e4bd1be 100644 --- a/src/compositor-headless.c +++ b/src/compositor-headless.c @@ -112,7 +112,7 @@ headless_compositor_create_output(struct headless_compositor *c, output->base.current = &output->mode; weston_output_init(&output->base, &c->base, 0, 0, width, height, - WL_OUTPUT_TRANSFORM_NORMAL); + WL_OUTPUT_TRANSFORM_NORMAL, 1); output->base.make = "weston"; output->base.model = "headless"; diff --git a/src/compositor-rpi.c b/src/compositor-rpi.c index 3cb2b56..226c5ce 100644 --- a/src/compositor-rpi.c +++ b/src/compositor-rpi.c @@ -1080,7 +1080,8 @@ rpi_output_create(struct rpi_compositor *compositor) weston_output_init(&output->base, &compositor->base, 0, 0, round(mm_width), round(mm_height), - WL_OUTPUT_TRANSFORM_NORMAL); + WL_OUTPUT_TRANSFORM_NORMAL, + 1); if (gl_renderer_output_create(&output->base, (EGLNativeWindowType)&output->egl_window) < 0) diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c index 4112401..511a12d 100644 --- a/src/compositor-wayland.c +++ b/src/compositor-wayland.c @@ -267,7 +267,7 @@ wayland_compositor_create_output(struct wayland_compositor *c, output->base.current = &output->mode; weston_output_init(&output->base, &c->base, 0, 0, width, height, - WL_OUTPUT_TRANSFORM_NORMAL); + WL_OUTPUT_TRANSFORM_NORMAL, 1);
[PATCH 12/15] pixman-renderer: Fix up transform handling
From: Alexander Larsson Rather than storing the shadow_image in the untransformed space and rotating on copy to hw_buffer we store both on the transformed space. This means a copy between them is a straight copy, and that apps supplying correctly transformed surface buffers need not change them. We also correctly handle all output transform including the previously unhandled flipped ones, as well as client supplied buffer_transforms (which were previously ignored). We also simplify the actual rendering by just converting any damage region to output coordinates and set it on a clip and composite the whole buffer, letting pixman do the rectangle handling. This means we always do all the transforms, including the surface positioning as a pixman_image transform. This simplifies the code and sets us up for handling scaling at a later stage. The transform looks complicated, but in practice it ends up being an integer translation almost always, so it will hit the pixman fastpaths. --- src/pixman-renderer.c | 408 ++ 1 file changed, 248 insertions(+), 160 deletions(-) diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c index 60800bc..92c6bb3 100644 --- a/src/pixman-renderer.c +++ b/src/pixman-renderer.c @@ -105,92 +105,98 @@ pixman_renderer_read_pixels(struct weston_output *output, } static void -box_translate(pixman_box32_t *dst, const pixman_box32_t *src, int x, int y) +transform_region (pixman_region32_t *region, int width, int height, enum wl_output_transform transform) { - dst->x1 = src->x1 + x; - dst->x2 = src->x2 + x; - dst->y1 = src->y1 + y; - dst->y2 = src->y2 + y; -} - -#define D2F(v) pixman_double_to_fixed((double)v) - -static void -repaint_region_complex(struct weston_surface *es, struct weston_output *output, - pixman_region32_t *region) -{ - struct pixman_renderer *pr = - (struct pixman_renderer *) output->compositor->renderer; - struct pixman_surface_state *ps = get_surface_state(es); - struct pixman_output_state *po = get_output_state(output); + pixman_box32_t *rects, *transformed_rects; int nrects, i; - pixman_box32_t *rects, rect; - /* Pixman supports only 2D transform matrix, but Weston uses 3D, -* so we're omitting Z coordinate here -*/ - pixman_transform_t transform = {{ - { D2F(es->transform.matrix.d[0]), - D2F(es->transform.matrix.d[4]), - D2F(es->transform.matrix.d[12]), - }, - { D2F(es->transform.matrix.d[1]), - D2F(es->transform.matrix.d[5]), - D2F(es->transform.matrix.d[13]), - }, - { D2F(es->transform.matrix.d[3]), - D2F(es->transform.matrix.d[7]), - D2F(es->transform.matrix.d[15]), - } - }}; - - pixman_transform_invert(&transform, &transform); - - pixman_image_set_transform(ps->image, &transform); - pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0); + if (transform == WL_OUTPUT_TRANSFORM_NORMAL) + return; rects = pixman_region32_rectangles(region, &nrects); + transformed_rects = calloc(nrects, sizeof(pixman_box32_t)); + for (i = 0; i < nrects; i++) { - box_translate(&rect, &rects[i], -output->x, -output->y); - pixman_image_composite32(PIXMAN_OP_OVER, - ps->image, /* src */ - NULL /* mask */, - po->shadow_image, /* dest */ - rects[i].x1, rects[i].y1, /* src_x, src_y */ - 0, 0, /* mask_x, mask_y */ - rect.x1, rect.y1, /* dst_x, dst_y */ - rect.x2 - rect.x1, /* width */ - rect.y2 - rect.y1 /* height */ - ); + switch (transform) { + default: + case WL_OUTPUT_TRANSFORM_NORMAL: + transformed_rects[i].x1 = rects[i].x1; + transformed_rects[i].y1 = rects[i].y1; + transformed_rects[i].x2 = rects[i].x2; + transformed_rects[i].y2 = rects[i].y2; + break; + case WL_OUTPUT_TRANSFORM_90: + transformed_rects[i].x1 = height - rects[i].y2; + transformed_rects[i].y1 = rects[i].x1; + transformed_rects[i].x2 = height - rects[i].y1; + transformed_rects[i].y2 = rects[i].x2; + break; + case WL_OUTPUT_TRANSFORM_180: + transformed_rects[i].x1 = width - rects[i].x2; + transformed_rects[i].y1 = height - rects[i].y2; + transformed_rects[i].x2 = width - rects[i].x1; + transforme
[PATCH 11/15] transformed: Add keyboard shortcuts to change transform
From: Alexander Larsson This makes it easy to test buffer_transform and buffer_scale handling. left-right: rotate space: toggle inverse z: toggle scale between 1 and 2 --- clients/transformed.c | 54 +++ 1 file changed, 54 insertions(+) diff --git a/clients/transformed.c b/clients/transformed.c index d685330..e8d817d 100644 --- a/clients/transformed.c +++ b/clients/transformed.c @@ -145,6 +145,59 @@ output_handler(struct window *window, struct output *output, int enter, } static void +key_handler(struct window *window, struct input *input, uint32_t time, + uint32_t key, uint32_t sym, enum wl_keyboard_key_state state, + void *data) +{ + int transform, scale; + + if (state == WL_KEYBOARD_KEY_STATE_RELEASED) + return; + + transform = window_get_buffer_transform (window); + scale = window_get_buffer_scale (window); + switch (sym) { + case XKB_KEY_Left: + if (transform == 0) + transform = 3; + else if (transform == 4) + transform = 7; + else + transform--; + break; + + case XKB_KEY_Right: + if (transform == 3) + transform = 0; + else if (transform == 7) + transform = 4; + else + transform++; + break; + + case XKB_KEY_space: + if (transform >= 4) + transform -= 4; + else + transform += 4; + break; + + case XKB_KEY_z: + if (scale == 1) + scale = 2; + else + scale = 1; + break; + } + + printf ("setting buffer transform to %d\n", transform); + printf ("setting buffer scale to %d\n", scale); + window_set_buffer_transform(window, transform); + window_set_buffer_scale(window, scale); + window_schedule_redraw(window); +} + +static void button_handler(struct widget *widget, struct input *input, uint32_t time, uint32_t button, enum wl_pointer_button_state state, void *data) @@ -234,6 +287,7 @@ int main(int argc, char *argv[]) widget_set_redraw_handler(transformed.widget, redraw_handler); widget_set_button_handler(transformed.widget, button_handler); + window_set_key_handler(transformed.window, key_handler); window_set_fullscreen_handler(transformed.window, fullscreen_handler); window_set_output_handler(transformed.window, output_handler); -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 10/15] terminal: Handle output transform
From: Alexander Larsson We pick the highest scale of any output the terminal is on, and the transform from the last one it entered. --- clients/terminal.c | 13 - 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/clients/terminal.c b/clients/terminal.c index f11a6cc..2985726 100644 --- a/clients/terminal.c +++ b/clients/terminal.c @@ -933,7 +933,7 @@ redraw_handler(struct widget *widget, void *data) surface = window_get_surface(terminal->window); widget_get_allocation(terminal->widget, &allocation); - cr = cairo_create(surface); + cr = widget_cairo_create(terminal->widget); cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height); cairo_clip(cr); @@ -2517,6 +2517,16 @@ motion_handler(struct widget *widget, return CURSOR_IBEAM; } +static void +output_handler(struct window *window, struct output *output, int enter, + void *data) +{ + if (enter) + window_set_buffer_transform(window, output_get_transform(output)); + window_set_buffer_scale(window, window_get_output_scale(window)); + window_schedule_redraw(window); +} + static struct terminal * terminal_create(struct display *display) { @@ -2549,6 +2559,7 @@ terminal_create(struct display *display) window_set_keyboard_focus_handler(terminal->window, keyboard_focus_handler); window_set_fullscreen_handler(terminal->window, fullscreen_handler); + window_set_output_handler(terminal->window, output_handler); window_set_close_handler(terminal->window, close_handler); widget_set_redraw_handler(terminal->widget, redraw_handler); -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 09/15] window: Add window_get_output_scale()
From: Alexander Larsson This lets you find the maximal scale for all the outputs a window is on, which is useful for picking a buffer_scale. --- clients/window.c | 18 ++ clients/window.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/clients/window.c b/clients/window.c index 6dd6533..09573f6 100644 --- a/clients/window.c +++ b/clients/window.c @@ -1454,6 +1454,22 @@ window_get_buffer_scale(struct window *window) return window->main_surface->buffer_scale; } +uint32_t +window_get_output_scale(struct window *window) +{ + struct window_output *window_output; + struct window_output *window_output_tmp; + int scale = 1; + + wl_list_for_each_safe(window_output, window_output_tmp, + &window->window_output_list, link) { + if (window_output->output->scale > scale) + scale = window_output->output->scale; + } + + return scale; +} + static void frame_destroy(struct frame *frame); static void @@ -4370,6 +4386,8 @@ window_show_menu(struct display *display, menu->window = window; menu->widget = window_add_widget(menu->window, menu); + window_set_buffer_scale (menu->window, window_get_buffer_scale (parent)); + window_set_buffer_transform (menu->window, window_get_buffer_transform (parent)); menu->entries = entries; menu->count = count; menu->release_count = 0; diff --git a/clients/window.h b/clients/window.h index fec601f..f7b3f28 100644 --- a/clients/window.h +++ b/clients/window.h @@ -260,6 +260,9 @@ void window_set_buffer_scale(struct window *window, uint32_t scale); +uint32_t +window_get_output_scale(struct window *window); + void window_destroy(struct window *window); -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 08/15] desktop-shell: Respect output scale and translate
From: Alexander Larsson We pick the window scale/tranform based on what the output uses, which means we can avoid rotations in the compositor, and get sharper rendering in scaled outputs. --- clients/desktop-shell.c | 75 - 1 file changed, 62 insertions(+), 13 deletions(-) diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c index 3949975..497e4ff 100644 --- a/clients/desktop-shell.c +++ b/clients/desktop-shell.c @@ -201,12 +201,10 @@ static void panel_launcher_redraw_handler(struct widget *widget, void *data) { struct panel_launcher *launcher = data; - cairo_surface_t *surface; struct rectangle allocation; cairo_t *cr; - surface = window_get_surface(launcher->panel->window); - cr = cairo_create(surface); + cr = widget_cairo_create(launcher->panel->widget); widget_get_allocation(widget, &allocation); if (launcher->pressed) { @@ -255,13 +253,13 @@ panel_redraw_handler(struct widget *widget, void *data) cairo_t *cr; struct panel *panel = data; - surface = window_get_surface(panel->window); - cr = cairo_create(surface); + cr = widget_cairo_create(panel->widget); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); set_hex_color(cr, key_panel_color); cairo_paint(cr); cairo_destroy(cr); + surface = window_get_surface(panel->window); cairo_surface_destroy(surface); } @@ -317,7 +315,6 @@ clock_func(struct task *task, uint32_t events) static void panel_clock_redraw_handler(struct widget *widget, void *data) { - cairo_surface_t *surface; struct panel_clock *clock = data; cairo_t *cr; struct rectangle allocation; @@ -335,8 +332,7 @@ panel_clock_redraw_handler(struct widget *widget, void *data) if (allocation.width == 0) return; - surface = window_get_surface(clock->panel->window); - cr = cairo_create(surface); + cr = widget_cairo_create(clock->panel->widget); cairo_select_font_face(cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); @@ -644,7 +640,7 @@ background_draw(struct widget *widget, void *data) surface = window_get_surface(background->window); - cr = cairo_create(surface); + cr = widget_cairo_create(background->widget); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0); cairo_paint(cr); @@ -713,13 +709,12 @@ unlock_dialog_redraw_handler(struct widget *widget, void *data) { struct unlock_dialog *dialog = data; struct rectangle allocation; - cairo_t *cr; cairo_surface_t *surface; + cairo_t *cr; cairo_pattern_t *pat; double cx, cy, r, f; - surface = window_get_surface(dialog->window); - cr = cairo_create(surface); + cr = widget_cairo_create(widget); widget_get_allocation(dialog->widget, &allocation); cairo_rectangle(cr, allocation.x, allocation.y, @@ -752,6 +747,7 @@ unlock_dialog_redraw_handler(struct widget *widget, void *data) cairo_destroy(cr); + surface = window_get_surface(dialog->window); cairo_surface_destroy(surface); } @@ -1025,6 +1021,57 @@ desktop_destroy_outputs(struct desktop *desktop) } static void +output_handle_geometry(void *data, + struct wl_output *wl_output, + int x, int y, + int physical_width, + int physical_height, + int subpixel, + const char *make, + const char *model, + int transform) +{ + struct output *output = data; + + window_set_buffer_transform(output->panel->window, transform); + window_set_buffer_transform(output->background->window, transform); +} + +static void +output_handle_mode(void *data, + struct wl_output *wl_output, + uint32_t flags, + int width, + int height, + int refresh) +{ +} + +static void +output_handle_done(void *data, + struct wl_output *wl_output) +{ +} + +static void +output_handle_scale(void *data, +struct wl_output *wl_output, +uint32_t scale) +{ + struct output *output = data; + + window_set_buffer_scale(output->panel->window, scale); + window_set_buffer_scale(output->background->window, scale); +} + +static const struct wl_output_listener output_listener = { + output_handle_geometry, + output_handle_mode, + output_handle_done, + output_handle_scale +}; + +static void create_output(struct desktop *desktop, uint32_t id) { struct output *output; @@ -1034,7 +1081,9 @@ create_output(struct desktop
[PATCH 07/15] window: Store server_allocation in surface size
From: Alexander Larsson We used to just store the buffer size here which is not right if the surface has a buffer_transform or a buffer_scale. To fix this we pass the transform and scale into the toysurface prepare and swap calls and move both the surface to buffer and the buffer to surface size conversion there. Without this interactive resize on the top or left sides of a transformed or scaled surface will not work correctly. --- clients/window.c | 92 1 file changed, 72 insertions(+), 20 deletions(-) diff --git a/clients/window.c b/clients/window.c index 00ffd27..6dd6533 100644 --- a/clients/window.c +++ b/clients/window.c @@ -158,7 +158,8 @@ struct toysurface { * Returns the Cairo surface to draw to. */ cairo_surface_t *(*prepare)(struct toysurface *base, int dx, int dy, - int width, int height, uint32_t flags); + int32_t width, int32_t height, uint32_t flags, + enum wl_output_transform buffer_transform, uint32_t buffer_scale); /* * Post the surface to the server, returning the server allocation @@ -166,6 +167,7 @@ struct toysurface { * after calling this. */ void (*swap)(struct toysurface *base, +enum wl_output_transform buffer_transform, uint32_t buffer_scale, struct rectangle *server_allocation); /* @@ -463,6 +465,50 @@ debug_print(void *proxy, int line, const char *func, const char *fmt, ...) #endif +static void +surface_to_buffer_size (enum wl_output_transform buffer_transform, uint32_t buffer_scale, int32_t *width, int32_t *height) +{ + int32_t tmp; + + switch (buffer_transform) { + case WL_OUTPUT_TRANSFORM_90: + case WL_OUTPUT_TRANSFORM_270: + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + tmp = *width; + *width = *height; + *height = tmp; + break; + default: + break; + } + + *width *= buffer_scale; + *height *= buffer_scale; +} + +static void +buffer_to_surface_size (enum wl_output_transform buffer_transform, uint32_t buffer_scale, int32_t *width, int32_t *height) +{ + int32_t tmp; + + switch (buffer_transform) { + case WL_OUTPUT_TRANSFORM_90: + case WL_OUTPUT_TRANSFORM_270: + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + tmp = *width; + *width = *height; + *height = tmp; + break; + default: + break; + } + + *width /= buffer_scale; + *height /= buffer_scale; +} + #ifdef HAVE_CAIRO_EGL struct egl_window_surface { @@ -482,10 +528,13 @@ to_egl_window_surface(struct toysurface *base) static cairo_surface_t * egl_window_surface_prepare(struct toysurface *base, int dx, int dy, - int width, int height, uint32_t flags) + int32_t width, int32_t height, uint32_t flags, + enum wl_output_transform buffer_transform, uint32_t buffer_scale) { struct egl_window_surface *surface = to_egl_window_surface(base); + surface_to_buffer_size (buffer_transform, buffer_scale, &width, &height); + wl_egl_window_resize(surface->egl_window, width, height, dx, dy); cairo_gl_surface_set_size(surface->cairo_surface, width, height); @@ -494,6 +543,7 @@ egl_window_surface_prepare(struct toysurface *base, int dx, int dy, static void egl_window_surface_swap(struct toysurface *base, + enum wl_output_transform buffer_transform, uint32_t buffer_scale, struct rectangle *server_allocation) { struct egl_window_surface *surface = to_egl_window_surface(base); @@ -502,6 +552,10 @@ egl_window_surface_swap(struct toysurface *base, wl_egl_window_get_attached_size(surface->egl_window, &server_allocation->width, &server_allocation->height); + + buffer_to_surface_size (buffer_transform, buffer_scale, + &server_allocation->width, + &server_allocation->height); } static int @@ -948,11 +1002,12 @@ static const struct wl_buffer_listener shm_surface_buffer_listener = { static cairo_surface_t * shm_surface_prepare(struct toysurface *base, int dx, int dy, - int width, int height, uint32_t flags) + int32_t width, int32_t height, uint32_t flags, + enum wl_output_transform buffer_transform, uint32_t buffer_scale) { int resize_hint = !!(flags & SURFACE_HINT_RESIZE); struct shm_surface *surface = to_shm_surface(base); - struct rectang
[PATCH 06/15] transformed: Use the scale factor from the output
From: Alexander Larsson --- clients/transformed.c | 1 + 1 file changed, 1 insertion(+) diff --git a/clients/transformed.c b/clients/transformed.c index 560ddf3..d685330 100644 --- a/clients/transformed.c +++ b/clients/transformed.c @@ -140,6 +140,7 @@ output_handler(struct window *window, struct output *output, int enter, return; window_set_buffer_transform(window, output_get_transform(output)); + window_set_buffer_scale(window, output_get_scale(output)); window_schedule_redraw(window); } -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 05/15] window: Apply buffer_scale automatically in widget_cairo_create
From: Alexander Larsson --- clients/window.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clients/window.c b/clients/window.c index 378cc75..00ffd27 100644 --- a/clients/window.c +++ b/clients/window.c @@ -1636,11 +1636,13 @@ widget_cairo_update_transform(struct widget *widget, cairo_t *cr) enum wl_output_transform transform; int surface_width, surface_height; int translate_x, translate_y; + uint32_t scale; surface_width = surface->allocation.width; surface_height = surface->allocation.height; transform = surface->buffer_transform; + scale = surface->buffer_scale; switch (transform) { case WL_OUTPUT_TRANSFORM_FLIPPED: @@ -1698,6 +1700,7 @@ widget_cairo_update_transform(struct widget *widget, cairo_t *cr) break; } + cairo_scale(cr, scale, scale); cairo_translate(cr, translate_x, translate_y); cairo_rotate(cr, angle); cairo_transform(cr, &m); -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 04/15] window: allow setting a buffer scale on a window
From: Alexander Larsson --- clients/window.c | 25 +++-- clients/window.h | 7 +++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/clients/window.c b/clients/window.c index 36fda25..378cc75 100644 --- a/clients/window.c +++ b/clients/window.c @@ -152,7 +152,7 @@ struct toysurface { * Prepare the surface for drawing. Makes sure there is a surface * of the right size available for rendering, and returns it. * dx,dy are the x,y of wl_surface.attach. -* width,height are the new surface size. +* width,height are the new buffer size. * If flags has SURFACE_HINT_RESIZE set, the user is * doing continuous resizing. * Returns the Cairo surface to draw to. @@ -208,6 +208,7 @@ struct surface { enum window_buffer_type buffer_type; enum wl_output_transform buffer_transform; + uint32_t buffer_scale; cairo_surface_t *cairo_surface; @@ -1325,6 +1326,9 @@ surface_create_surface(struct surface *surface, int dx, int dy, uint32_t flags) break; } + allocation.width *= surface->buffer_scale; + allocation.height *= surface->buffer_scale; + if (!surface->toysurface && display->dpy && surface->buffer_type == WINDOW_BUFFER_TYPE_EGL_WINDOW) { surface->toysurface = @@ -1383,6 +1387,21 @@ window_set_buffer_transform(struct window *window, transform); } +void +window_set_buffer_scale(struct window *window, + uint32_t scale) +{ + window->main_surface->buffer_scale = scale; + wl_surface_set_buffer_scale(window->main_surface->surface, + scale); +} + +uint32_t +window_get_buffer_scale(struct window *window) +{ + return window->main_surface->buffer_scale; +} + static void frame_destroy(struct frame *frame); static void @@ -1621,7 +1640,8 @@ widget_cairo_update_transform(struct widget *widget, cairo_t *cr) surface_width = surface->allocation.width; surface_height = surface->allocation.height; - transform = window_get_buffer_transform(widget->window); + transform = surface->buffer_transform; + switch (transform) { case WL_OUTPUT_TRANSFORM_FLIPPED: case WL_OUTPUT_TRANSFORM_FLIPPED_90: @@ -4057,6 +4077,7 @@ surface_create(struct window *window) surface->window = window; surface->surface = wl_compositor_create_surface(display->compositor); + surface->buffer_scale = 1; wl_surface_add_listener(surface->surface, &surface_listener, window); wl_list_insert(&window->subsurface_list, &surface->link); diff --git a/clients/window.h b/clients/window.h index c0a7cb6..fec601f 100644 --- a/clients/window.h +++ b/clients/window.h @@ -253,6 +253,13 @@ void window_set_buffer_transform(struct window *window, enum wl_output_transform transform); +uint32_t +window_get_buffer_scale(struct window *window); + +void +window_set_buffer_scale(struct window *window, +uint32_t scale); + void window_destroy(struct window *window); -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 03/15] window: Track output scales
From: Alexander Larsson --- clients/window.c | 30 -- clients/window.h | 3 +++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/clients/window.c b/clients/window.c index 48b784d..36fda25 100644 --- a/clients/window.c +++ b/clients/window.c @@ -322,6 +322,7 @@ struct output { struct rectangle allocation; struct wl_list link; int transform; + int scale; display_output_handler_t destroy_handler; void *user_data; @@ -4382,6 +4383,22 @@ display_handle_geometry(void *data, } static void +display_handle_done(void *data, +struct wl_output *wl_output) +{ +} + +static void +display_handle_scale(void *data, +struct wl_output *wl_output, +uint32_t scale) +{ + struct output *output = data; + + output->scale = scale; +} + +static void display_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags, @@ -4403,7 +4420,9 @@ display_handle_mode(void *data, static const struct wl_output_listener output_listener = { display_handle_geometry, - display_handle_mode + display_handle_mode, + display_handle_done, + display_handle_scale }; static void @@ -4417,8 +4436,9 @@ display_add_output(struct display *d, uint32_t id) memset(output, 0, sizeof *output); output->display = d; + output->scale = 1; output->output = - wl_registry_bind(d->registry, id, &wl_output_interface, 1); + wl_registry_bind(d->registry, id, &wl_output_interface, 2); wl_list_insert(d->output_list.prev, &output->link); wl_output_add_listener(output->output, &output_listener, output); @@ -4522,6 +4542,12 @@ output_get_transform(struct output *output) return output->transform; } +uint32_t +output_get_scale(struct output *output) +{ + return output->scale; +} + static void fini_xkb(struct input *input) { diff --git a/clients/window.h b/clients/window.h index 7db9c63..c0a7cb6 100644 --- a/clients/window.h +++ b/clients/window.h @@ -504,6 +504,9 @@ output_get_wl_output(struct output *output); enum wl_output_transform output_get_transform(struct output *output); +uint32_t +output_get_scale(struct output *output); + void keysym_modifiers_add(struct wl_array *modifiers_map, const char *name); -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 02/15] transformed: Rely on transformation in widget_cairo_create
From: Alexander Larsson Rather than doing our own transformation handling when drawing we just rely on the generic code in widget_cairo_create --- clients/transformed.c | 69 ++- 1 file changed, 8 insertions(+), 61 deletions(-) diff --git a/clients/transformed.c b/clients/transformed.c index 8983bb5..560ddf3 100644 --- a/clients/transformed.c +++ b/clients/transformed.c @@ -42,67 +42,14 @@ struct transformed { }; static void -update_transform(cairo_t *cr, enum wl_output_transform transform) +draw_stuff(cairo_t *cr, int width, int height) { - double angle; - cairo_matrix_t m; + cairo_get_matrix (cr, &m); - switch(transform) { - case WL_OUTPUT_TRANSFORM_FLIPPED: - case WL_OUTPUT_TRANSFORM_FLIPPED_90: - case WL_OUTPUT_TRANSFORM_FLIPPED_180: - case WL_OUTPUT_TRANSFORM_FLIPPED_270: - cairo_matrix_init(&m, -1, 0, 0, 1, 0, 0); - break; - default: - cairo_matrix_init_identity(&m); - break; - } - switch (transform) { - case WL_OUTPUT_TRANSFORM_NORMAL: - case WL_OUTPUT_TRANSFORM_FLIPPED: - default: - angle = 0; - break; - case WL_OUTPUT_TRANSFORM_90: - case WL_OUTPUT_TRANSFORM_FLIPPED_90: - angle = M_PI_2; - break; - case WL_OUTPUT_TRANSFORM_180: - case WL_OUTPUT_TRANSFORM_FLIPPED_180: - angle = M_PI; - break; - case WL_OUTPUT_TRANSFORM_270: - case WL_OUTPUT_TRANSFORM_FLIPPED_270: - angle = M_PI + M_PI_2; - break; - } - - cairo_rotate(cr, angle); - cairo_transform(cr, &m); -} - -static void -draw_stuff(cairo_surface_t *surface, int width, int height, int transform) -{ - cairo_t *cr; - int tmp; - - if (transform & 1) { - tmp = width; - width = height; - height = tmp; - } - - cr = cairo_create(surface); - - cairo_identity_matrix(cr); cairo_translate(cr, width / 2, height / 2); cairo_scale(cr, width / 2, height / 2); - update_transform(cr, transform); - cairo_set_source_rgba(cr, 0, 0, 0.3, 1.0); cairo_set_source_rgba(cr, 0, 0, 0, 1.0); cairo_rectangle(cr, -1, -1, 2, 2); @@ -113,7 +60,7 @@ draw_stuff(cairo_surface_t *surface, int width, int height, int transform) cairo_line_to(cr, 0, -1); cairo_save(cr); - cairo_identity_matrix(cr); + cairo_set_matrix(cr, &m); cairo_set_line_width(cr, 2.0); cairo_stroke(cr); cairo_restore(cr); @@ -123,7 +70,7 @@ draw_stuff(cairo_surface_t *surface, int width, int height, int transform) cairo_line_to(cr, 1, 0); cairo_save(cr); - cairo_identity_matrix(cr); + cairo_set_matrix(cr, &m); cairo_set_line_width(cr, 2.0); cairo_stroke(cr); cairo_restore(cr); @@ -135,7 +82,7 @@ draw_stuff(cairo_surface_t *surface, int width, int height, int transform) cairo_line_to(cr, -1, 0); cairo_save(cr); - cairo_identity_matrix(cr); + cairo_set_matrix(cr, &m); cairo_set_line_width(cr, 2.0); cairo_stroke(cr); cairo_restore(cr); @@ -168,7 +115,7 @@ redraw_handler(struct widget *widget, void *data) struct transformed *transformed = data; struct rectangle allocation; cairo_surface_t *surface; - int transform; + cairo_t *cr; surface = window_get_surface(transformed->window); if (surface == NULL || @@ -178,9 +125,9 @@ redraw_handler(struct widget *widget, void *data) } widget_get_allocation(transformed->widget, &allocation); - transform = window_get_buffer_transform(transformed->window); - draw_stuff(surface, allocation.width, allocation.height, transform); + cr = widget_cairo_create(widget); + draw_stuff(cr, allocation.width, allocation.height); cairo_surface_destroy(surface); } -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 01/15] window: Support transform in widget_cairo_create()
From: Alexander Larsson If a buffer_transform it specified in the window we automatically compensate for it in the cairo_t --- clients/window.c | 77 1 file changed, 77 insertions(+) diff --git a/clients/window.c b/clients/window.c index 40c0ef4..48b784d 100644 --- a/clients/window.c +++ b/clients/window.c @@ -1607,6 +1607,81 @@ widget_get_cairo_surface(struct widget *widget) return surface->cairo_surface; } +static void +widget_cairo_update_transform(struct widget *widget, cairo_t *cr) +{ + struct surface *surface = widget->surface; + double angle; + cairo_matrix_t m; + enum wl_output_transform transform; + int surface_width, surface_height; + int translate_x, translate_y; + + surface_width = surface->allocation.width; + surface_height = surface->allocation.height; + + transform = window_get_buffer_transform(widget->window); + switch (transform) { + case WL_OUTPUT_TRANSFORM_FLIPPED: + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + cairo_matrix_init(&m, -1, 0, 0, 1, 0, 0); + break; + default: + cairo_matrix_init_identity(&m); + break; + } + + switch (transform) { + case WL_OUTPUT_TRANSFORM_NORMAL: + default: + angle = 0; + translate_x = 0; + translate_y = 0; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED: + angle = 0; + translate_x = surface_width; + translate_y = 0; + break; + case WL_OUTPUT_TRANSFORM_90: + angle = M_PI_2; + translate_x = surface_height; + translate_y = 0; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + angle = M_PI_2; + translate_x = surface_height; + translate_y = surface_width; + break; + case WL_OUTPUT_TRANSFORM_180: + angle = M_PI; + translate_x = surface_width; + translate_y = surface_height; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + angle = M_PI; + translate_x = 0; + translate_y = surface_height; + break; + case WL_OUTPUT_TRANSFORM_270: + angle = M_PI + M_PI_2; + translate_x = 0; + translate_y = surface_width; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + angle = M_PI + M_PI_2; + translate_x = 0; + translate_y = 0; + break; + } + + cairo_translate(cr, translate_x, translate_y); + cairo_rotate(cr, angle); + cairo_transform(cr, &m); +} + cairo_t * widget_cairo_create(struct widget *widget) { @@ -1617,6 +1692,8 @@ widget_cairo_create(struct widget *widget) cairo_surface = widget_get_cairo_surface(widget); cr = cairo_create(cairo_surface); + widget_cairo_update_transform(widget, cr); + cairo_translate(cr, -surface->allocation.x, -surface->allocation.y); return cr; -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 00/15] weston scaling support
From: Alexander Larsson This adds support to weston (X11 and DRM backends) for output scale and buffer_scale. It also contains some work on the example clients to make them support buffer scaling. I think the support is fairly comprehensive, although I'm aware of a few outstanding issues: * The drm backend doesn't upscale pointers on the DRM backend * There is no support in the desktop shell for setting up a higher resolution cursor image on scaled outputs * I did not yet look at the screenshoter/read_pixels APIs Overall I think the approach is working out well, but an obvious issue is how we handle scaling wrt modes. I'll bring this up in another mail. The series is also availible in the scale branch here: (eventually) http://cgit.freedesktop.org/~alexl/weston/ Alexander Larsson (15): window: Support transform in widget_cairo_create() transformed: Rely on transformation in widget_cairo_create window: Track output scales window: allow setting a buffer scale on a window window: Apply buffer_scale automatically in widget_cairo_create transformed: Use the scale factor from the output window: Store server_allocation in surface size desktop-shell: Respect output scale and translate window: Add window_get_output_scale() terminal: Handle output transform transformed: Add keyboard shortcuts to change transform pixman-renderer: Fix up transform handling compositor: Support output/buffer scaling compositor-x11: Only repaint the damaged region compositor-drm: Support output scaling clients/desktop-shell.c | 75 ++-- clients/terminal.c| 13 +- clients/transformed.c | 124 ++--- clients/window.c | 237 ++--- clients/window.h | 13 ++ src/compositor-drm.c | 88 +++--- src/compositor-fbdev.c| 3 +- src/compositor-headless.c | 2 +- src/compositor-rpi.c | 3 +- src/compositor-wayland.c | 2 +- src/compositor-x11.c | 166 -- src/compositor.c | 110 +--- src/compositor.h | 18 +- src/gl-renderer.c | 21 +-- src/pixman-renderer.c | 436 ++ 15 files changed, 977 insertions(+), 334 deletions(-) -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 2/2] protocol: Support scaled outputs and surfaces
From: Alexander Larsson This adds the wl_surface.set_buffer_scale request, and a wl_output.scale event. These together lets us support automatic upscaling of "old" clients on very high resolution monitors, while allowing "new" clients to take advantage of this to render at the higher resolution when the surface is displayed on the scaled output. It is similar to set_buffer_transform in that the buffer is stored in a transformed pixels (in this case scaled). This means that if an output is scaled we can directly use the pre-scaled buffer with additional data, rather than having to scale it. Additionally this adds a "scaled" flag to the wl_output.mode flags so that clients know which resolutions are native and which are scaled. Also, in places where the documentation was previously not clear as to what coordinate system was used this was fleshed out. It also adds a scaling_factor event to wl_output that specifies the scaling of an output. This is meant to be used for outputs with a very high DPI to tell the client that this particular output has subpixel precision. Coordinates in other parts of the protocol, like input events, relative window positioning and output positioning are still in the compositor space rather than the scaled space. However, input has subpixel precision so you can still get input at full resolution. This setup means global properties like mouse acceleration/speed, pointer size, monitor geometry, etc can be specified in a "mostly similar" resolution even on a multimonitor setup where some monitors are low dpi and some are e.g. retina-class outputs. --- protocol/wayland.xml | 107 --- 1 file changed, 93 insertions(+), 14 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index d3ae149..acfb140 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -173,7 +173,7 @@ - + A compositor. This object is a singleton global. The compositor is in charge of combining the contents of multiple @@ -709,7 +709,7 @@ The x and y arguments specify the locations of the upper left corner of the surface relative to the upper left corner of the - parent surface. + parent surface, in surface local coordinates. The flags argument controls details of the transient behaviour. @@ -777,6 +777,10 @@ in any of the clients surfaces is reported as normal, however, clicks in other clients surfaces will be discarded and trigger the callback. + + The x and y arguments specify the locations of the upper left + corner of the surface relative to the upper left corner of the + parent surface, in surface local coordinates. @@ -860,6 +864,9 @@ The client is free to dismiss all but the last configure event it received. + + The width and height arguments specify the size of the window + in surface local coordinates. @@ -876,11 +883,16 @@ - + A surface is a rectangular area that is displayed on the screen. It has a location, size and pixel contents. + The size of a surface (and relative positions on it) is described + in surface local coordinates, which may differ from the buffer + local coordinates of the pixel content, in case a buffer_transform + or a buffer_scale is used. + Surfaces are also used for some special purposes, e.g. as cursor images for pointers, drag icons, etc. @@ -895,20 +907,25 @@ Set a buffer as the content of this surface. + The new size of the surface is calculated based on the buffer + size transformed by the inverse buffer_transform and the + inverse buffer_scale. This means that the supplied buffer + must be an integer multiple of the buffer_scale. + The x and y arguments specify the location of the new pending - buffer's upper left corner, relative to the current buffer's - upper left corner. In other words, the x and y, and the width - and height of the wl_buffer together define in which directions - the surface's size changes. + buffer's upper left corner, relative to the current buffer's upper + left corner, in surface local coordinates. In other words, the + x and y, combined with the new surface size define in which + directions the surface's size changes. Surface contents are double-buffered state, see wl_surface.commit. The initial surface contents are void; there is no content. wl_surface.attach assigns the given wl_buffer as the pending wl_buffer. wl_surface.commit makes the pending wl_buffer the new - surface contents, and the size of the surface becomes the size of - the wl_buffer, as described above. After commit, there is no - pending buffer until the next attach. + surface contents,
[PATCH 1/2] protocol: Allow output changes to be treated atomically
From: Alexander Larsson This add a wl_output.done event which is send after every group of events caused by some property change. This allows clients to treat changes touching multiple events in an atomic fashion. --- protocol/wayland.xml | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 3bce022..d3ae149 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1467,7 +1467,7 @@ - + An output describes part of the compositor geometry. The compositor works in the 'compositor coordinate system' and an @@ -1565,6 +1565,16 @@ + + + +This event is sent after all other properties has been +sent after binding to the output object and after any +other property changes done after that. This allows +changes to the output properties to be seen as +atomic, even if they happen via multiple events. + + -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 0/2] Updated scaling patch
From: Alexander Larsson Here is a new version of the scaling work, based on the feedback from Pekka. Changes in this version are: * Better documentation in general, and about coordinate spaces in particular. * Scaling is an integer * Updated wl_compository version as needed * Added a flag to wl_output.mode to mark resolutions that are scaled * Support grouping of property changes to wl_output using a wl_output.done event Alexander Larsson (2): protocol: Allow output changes to be treated atomically protocol: Support scaled outputs and surfaces protocol/wayland.xml | 119 --- 1 file changed, 104 insertions(+), 15 deletions(-) -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH] protocol: Add buffer_scale to wl_surface and wl_output
From: Alexander Larsson This adds wl_surface_set_buffer_scale() to set the buffer scale of a surface. It is similar to set_buffer_transform that the buffer is stored in a way that has been transformed (in this case scaled). This means that if an output is scaled we can directly use the pre-scaled buffer with additional data, rather than having to scale it. It also adds a geometry2 event with a scale member to wl_output that specifies the scaling of an output. This is meant to be used for outputs with a very high DPI to tell the client that this particular output has subpixel precision. Coordinates in other parts of the protocol, like input events, relative window positioning and output positioning are still in the compositor space rather than the scaled space. However, input has subpixel precision so you can still get input at full resolution. This setup means global properties like mouse acceleration/speed, pointer size, monitor geometry, etc can be specified in a "mostly similar" resolution even on a multimonitor setup where some monitors are low dpi and some are e.g. retina-class outputs. --- protocol/wayland.xml | 41 +++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 3bce022..e5744c7 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -876,7 +876,7 @@ - + A surface is a rectangular area that is displayed on the screen. It has a location, size and pixel contents. @@ -1110,6 +1110,30 @@ + + + + + + This request sets an optional scaling factor on how the compositor + interprets the contents of the buffer attached to the surface. A + value larger than 1, like e.g. 2 means that the buffer is 2 times the + size of the surface. + + Buffer scale is double-buffered state, see wl_surface.commit. + + A newly created surface has its buffer scale set to 1. + + The purpose of this request is to allow clients to supply higher resolution + buffer data for use on high-resolution outputs where the output itself + has a scaling factor set. For instance, a laptop with a high DPI + internal screen and an low DPI external screen would have two outputs + with different scaling, and a wl_surface rendered on the scaled output + would normally be scaled up. To avoid this upscaling the app can supply + a pre-scaled version with more detail by using set_buffer_scale. + + + @@ -1467,7 +1491,7 @@ - + An output describes part of the compositor geometry. The compositor works in the 'compositor coordinate system' and an @@ -1520,6 +1544,8 @@ The geometry event describes geometric properties of the output. The event is sent when binding to the output object and whenever any of the properties change. + +Some additional properties were later added, see wl_output.geometry2. @@ -1565,6 +1591,17 @@ + + + + This event contains additional geometric information +that are not in the geometry event. Whenever it is sent +it will be followed by a geometry event. This way you can +tell by the time the geometry event is recieved whether a +geometry2 event will be seen or not. + + + -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 2/2] protocol: Add buffer_scale to wl_surface and wl_output
From: Alexander Larsson This adds wl_surface_set_buffer_scale() to set the buffer scale of a surface. It is similar to set_buffer_transform in that it says that the buffer is stored in a way that has been transformed (in this case scaled). This means that if an output is naturally scaled (i.e. has sub-pixel precision) we can directly use the pre-scaled buffer with additional data, rather than having to scale it. It also adds a scale member to the wl_output geometry event that specifies the natural scaling of an output. This is meant to be used for outputs with a very high DPI to tell the client that this particular output has subpixel precision. The coordinates for e.g. input and the positioning in the compositor wrt other outputs (which may be non-subpixel-precision) are in "logical" pixel coordinates, and need to be multiplied by the scaling factor to convert to the physical pixels of the output. This setup means global properties like mouse acceleration/speed, pointer size, monitor geometry, etc can be specified in a "mostly similar" resolution even on a multimonitor setup where some monitors are low dpi and some are e.g. retina-class outputs. It also adds a scale_priority to the geometry event. This can be used by clients to know what scale factor to use for buffers on mirrored displays. If a window surface is equally much on two outputs, such as the case of a mirrored output, the app doesn't know what scale factor to pick to match the native output. In this case it can pick the one with the highest priority, giving the compositor (and thus the user) the possibility of selecting which output should look "best". --- protocol/wayland.xml | 35 --- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 3bce022..941952a 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -876,7 +876,7 @@ - + A surface is a rectangular area that is displayed on the screen. It has a location, size and pixel contents. @@ -1110,7 +1110,32 @@ - + + + + + + This request sets an optional scaling factor on how the compositor + interprets the contents of the buffer attached to the surface. A + value larger than 1, like e.g. 2 means that the buffer is 2 times the + size of the surface. + + Buffer scale is double-buffered state, see wl_surface.commit. + + A newly created surface has its buffer scale set to 1. + + The purpose of this request is to allow clients to supply higher resolution + buffer data for use on high-resolution outputs where the output itself + has a scaling factor set. For instance, a laptop with a high DPI + internal screen and an low DPI external screen would have two outputs + with different scaling, and a wl_surface rendered on the scaled output + would normally be scaled up. To avoid this upscaling the app can supply + a pre-scaled version with more detail by using set_buffer_scale. + + + + + @@ -1467,7 +1492,7 @@ - + An output describes part of the compositor geometry. The compositor works in the 'compositor coordinate system' and an @@ -1537,6 +1562,10 @@ summary="textual description of the model"/> + + -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 1/2] protocol: Allow versioned message arguments
From: Alexander Larsson This allows an event to be extended in a backwards compatible way (on the client side) by marking an argument with a since attribute. Any arguments with a since value later than then value of the message itself will be marked optional and the demarshaller will supply default values for these arguments. Versioned arguments must be added at the end of the message in strictly increasing version order. We don't allow optional arguments of fd type as we can't make useful "default" fds. Optional arguments have a default value of 0 or 0 length, but messages of int/unsigned/fixed can have a different default specified. The changes in the generated client code are ABI compatible, in two senses: * For old servers not passing the optional arguments a new client will get the default value for the argument * A client compiled against the old client headers will not see the new arguments, but c calling conventions makes the call work as before. However, this is not strictly API compatible. Building a client that uses the old version of the interface against a new client header will get a warning about the callback types mismatching (due to the new arguments). We could possibly solve this by adding some #ifdefs that you then need to define to get the new arguments. --- src/connection.c | 81 +++ src/scanner.c | 38 src/wayland-private.h | 2 ++ 3 files changed, 109 insertions(+), 12 deletions(-) diff --git a/src/connection.c b/src/connection.c index dca134b..f74f261 100644 --- a/src/connection.c +++ b/src/connection.c @@ -399,9 +399,33 @@ wl_connection_put_fd(struct wl_connection *connection, int32_t fd) return 0; } +static int +char_is_digit (char c) +{ + return c >= '0' && c <= '9'; +} + +static int +digit_value (char c) +{ + return c - '0'; +} + const char * get_next_argument(const char *signature, struct argument_details *details) { + if (*signature == '#') { + details->optional = 1; + details->default_value = 0; + signature++; + + while (char_is_digit (*signature)) { + details->default_value = 10*details->default_value + digit_value (*signature); + signature++; + } + } else + details->optional = 0; + if (*signature == '?') { details->nullable = 1; signature++; @@ -417,8 +441,15 @@ arg_count_for_signature(const char *signature) { int count = 0; while (*signature) { - if (*signature != '?') - count++; + if (*signature == '#') { + signature++; + while (char_is_digit (*signature)) + signature++; + } + if (*signature == '?') { + signature++; + } + count++; signature++; } return count; @@ -572,10 +603,10 @@ wl_connection_demarshal(struct wl_connection *connection, struct wl_map *objects, const struct wl_message *message) { - uint32_t *p, *next, *end, length, id; + uint32_t *p, *next, *end, length, id, first; int fd; char *s; - unsigned int i, count, num_arrays; + unsigned int i, count, num_arrays, is_optional;; const char *signature; struct argument_details arg; struct wl_closure *closure; @@ -609,7 +640,7 @@ wl_connection_demarshal(struct wl_connection *connection, for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); - if (arg.type != 'h' && p + 1 > end) { + if (!arg.optional && arg.type != 'h' && p + 1 > end) { printf("message too short, " "object (%d), message %s(%s)\n", *p, message->name, message->signature); @@ -617,24 +648,41 @@ wl_connection_demarshal(struct wl_connection *connection, goto err; } + is_optional = p + 1 > end && arg.type != 'h'; + if (is_optional) + first = arg.default_value; + else if (arg.type != 'h') + first = *p++; + else + first = 0; + switch (arg.type) { case 'u': - closure->args[i].u = *p++; + closure->args[i].u = first; break; case 'i': - closure->args[i].i = *p++; + closure->args[i].i = first; break; case 'f': - closure->args[i].f = *p++; + closure->a
[PATCH 0/2] Support for high DPI outputs via scaling
From: Alexander Larsson I'm working on trying to make high DPI (i.e. retina-class) outputs work well on Linux. I've written a proposal here: https://docs.google.com/document/d/1rvtiZb_Sm9C9718IoYQgnpzkirdl-wJZBBu_qLgaYyY/edit?usp=sharing This adds the initial protocol support needed for this. I will then then start adding support for this to weston. Alexander Larsson (2): protocol: Allow versioned message arguments protocol: Add buffer_scale to wl_surface and wl_output protocol/wayland.xml | 35 -- src/connection.c | 81 +++ src/scanner.c | 38 src/wayland-private.h | 2 ++ 4 files changed, 141 insertions(+), 15 deletions(-) -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel