Discussion:
[PATCH weston 00/18] Raspberry Pi: a new renderer and demos
(too old to reply)
ppaalanen
2013-05-22 15:03:03 UTC
Permalink
From: Pekka Paalanen <pekka.paalanen at collabora.co.uk>

Hi all,

this patch series consists of several independent features, which all come
together in demonstrating the capabilities of Raspberry Pi for running a
desktop.

We add a new rpi-renderer, that replaces the gl-renderer + weston_planes
on RPi. Since it is not as flexible as the gl-renderer, we add some
capability bits to disable incompatible features in Weston.

Weston-desktop-shell gets new features. The major new feature is
"exposay", a window overview mode with animated transitions. Another new
feature is optional keyboard-focus animation, which dims unfocused
surfaces. Smaller enhancements include a new wallpaper scaling mode, and
ensuring weston-desktop-shell has finished starting up before the
compositor fades in.

Then there are various smaller fixes and enhancements.

This work is joint effort of the Raspberry Pi foundation and Collabora. I
will later (tomorrow) reply with an email with links to all the related
announcements and blog posts. More details behind those links, and the
individual commits.

Beware of the rough edges, there are some bugs we didn't have time to fix
yet. Most of them need a little effort to discover, though, that's why we
didn't see them earlier. ;-)

This series is also available as a branch:

git://git.collabora.co.uk/git/user/pq/weston.git raspberrypi-dispmanx
http://cgit.collabora.com/git/user/pq/weston.git/log/?h=raspberrypi-dispmanx

There is also a patch for the RPi building guide on the Wayland website.


Daniel Stone (4):
Add modifier-only binding
Add move/scale animation
Shell: Add Exposay
configure.ac: Enable AC_USE_SYSTEM_EXTENSIONS

Louis-Francis Ratte?-Boulianne (3):
animation: Make zoom animation renders better and smoother
compositor, shell: Add animation to measure desktop fps
xwayland: Fix the race condition when mapping a surface

Louis-Francis Ratt?-Boulianne (3):
toytoolkit: Make the window resizing optimization optional
animation, shell: add kbd focus change animation
shell: Fix calculation of center point in surface rotation

Pekka Paalanen (8):
compositor: add capability flag for arbitrary surface rotation
compositor: add capability CAPTURE_YFLIP
rpi: add a Dispmanx renderer
rpi: switch to rpi-renderer
rpi: remove weston_plane support
shell: wait for desktop-shell init before fade in
desktop-shell: new wallpaper mode scale-crop
screenshooter: print info to log

clients/desktop-shell.c | 73 ++-
clients/window.c | 6 +-
configure.ac | 13 +-
man/weston.ini.man | 9 +-
protocol/desktop-shell.xml | 13 +-
shared/cairo-util.c | 2 +-
shared/config-parser.c | 3 +-
shared/image-loader.c | 2 +-
shared/matrix.c | 2 +
shared/option-parser.c | 2 +
shared/os-compatibility.c | 2 +-
src/Makefile.am | 2 +
src/animation.c | 128 +++-
src/bindings.c | 60 ++
src/clipboard.c | 2 +-
src/cms-helper.c | 4 +-
src/cms-static.c | 5 +-
src/compositor-drm.c | 6 +-
src/compositor-fbdev.c | 2 +-
src/compositor-headless.c | 4 +-
src/compositor-rdp.c | 4 +-
src/compositor-rpi.c | 898 +++------------------------
src/compositor-wayland.c | 5 +-
src/compositor-x11.c | 4 +-
src/compositor.c | 71 ++-
src/compositor.h | 48 ++
src/evdev-touchpad.c | 2 +
src/evdev.c | 2 +
src/filter.c | 2 +
src/gl-renderer.c | 4 +-
src/gl-renderer.h | 7 +-
src/input.c | 38 ++
src/launcher-util.c | 2 +
src/libbacklight.c | 2 +-
src/log.c | 2 +
src/noop-renderer.c | 2 +-
src/pixman-renderer.c | 4 +-
src/rpi-bcm-stubs.h | 39 ++
src/rpi-renderer.c | 1370 +++++++++++++++++++++++++++++++++++++++++
src/rpi-renderer.h | 48 ++
src/screenshooter.c | 103 +++-
src/shell.c | 1078 ++++++++++++++++++++++++++++++--
src/tablet-shell.c | 2 +
src/text-backend.c | 2 +
src/tty.c | 2 +
src/udev-seat.c | 2 +
src/weston-launch.c | 2 -
src/xwayland/launcher.c | 2 +-
src/xwayland/selection.c | 2 +-
src/xwayland/window-manager.c | 20 +-
src/zoom.c | 2 +
51 files changed, 3166 insertions(+), 945 deletions(-)
create mode 100644 src/rpi-renderer.c
create mode 100644 src/rpi-renderer.h
--
1.8.1.5


Thanks,
pq
ppaalanen
2013-05-22 15:03:04 UTC
Permalink
From: Pekka Paalanen <ppaalanen at gmail.com>

The upcoming rpi-renderer cannot handle arbitrary rotations. Introduce
Weston capability bits, and add a bit for arbitrary rotation. GL and
Pixman renderers support it.

Shell or any other module must not produce surface transformations with
rotation, if the capability bit is not set. Do not register the surface
rotation binding in desktop shell, if arbitary rotation is not
supported.

Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
src/compositor.c | 24 ++++++++++++++++++++++++
src/compositor.h | 6 ++++++
src/gl-renderer.c | 1 +
src/pixman-renderer.c | 1 +
src/shell.c | 7 +++++--
5 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/src/compositor.c b/src/compositor.c
index f67028e..657e134 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -2820,6 +2820,28 @@ weston_version(int *major, int *minor, int *micro)
*micro = WESTON_VERSION_MICRO;
}

+static const struct {
+ uint32_t bit;
+ const char *desc;
+} capability_strings[] = {
+ { WESTON_CAP_ROTATION_ANY, "arbitrary surface rotation:" },
+};
+
+static void
+weston_compositor_log_capabilities(struct weston_compositor *compositor)
+{
+ unsigned i;
+ int yes;
+
+ weston_log("Compositor capabilities:\n");
+ for (i = 0; i < ARRAY_LENGTH(capability_strings); i++) {
+ yes = compositor->capabilities & capability_strings[i].bit;
+ weston_log_continue(STAMP_SPACE "%s %s\n",
+ capability_strings[i].desc,
+ yes ? "yes" : "no");
+ }
+}
+
static int on_term_signal(int signal_number, void *data)
{
struct wl_display *display = data;
@@ -3214,6 +3236,8 @@ int main(int argc, char *argv[])
goto out;
}

+ weston_compositor_log_capabilities(ec);
+
if (wl_display_add_socket(display, socket_name)) {
weston_log("fatal: failed to add socket: %m\n");
ret = EXIT_FAILURE;
diff --git a/src/compositor.h b/src/compositor.h
index 318fc0d..e7d19b0 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -484,6 +484,11 @@ struct weston_renderer {
void (*destroy)(struct weston_compositor *ec);
};

+enum weston_capability {
+ /* backend/renderer supports arbitrary rotation */
+ WESTON_CAP_ROTATION_ANY = 0x0001,
+};
+
struct weston_compositor {
struct wl_signal destroy_signal;

@@ -525,6 +530,7 @@ struct weston_compositor {

/* Repaint state. */
struct weston_plane primary_plane;
+ uint32_t capabilities; /* combination of enum weston_capability */

uint32_t focus;

diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index be74eba..87b3be0 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -1837,6 +1837,7 @@ gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
}

ec->renderer = &gr->base;
+ ec->capabilities |= WESTON_CAP_ROTATION_ANY;

return 0;

diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c
index 60800bc..ad79c95 100644
--- a/src/pixman-renderer.c
+++ b/src/pixman-renderer.c
@@ -496,6 +496,7 @@ pixman_renderer_init(struct weston_compositor *ec)
renderer->base.destroy_surface = pixman_renderer_destroy_surface;
renderer->base.destroy = pixman_renderer_destroy;
ec->renderer = &renderer->base;
+ ec->capabilities |= WESTON_CAP_ROTATION_ANY;

weston_compositor_add_debug_binding(ec, KEY_R,
debug_binding, ec);
diff --git a/src/shell.c b/src/shell.c
index 7261570..e23c09b 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -4247,8 +4247,11 @@ shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
shell);
weston_compositor_add_button_binding(ec, BTN_MIDDLE, mod,
resize_binding, shell);
- weston_compositor_add_button_binding(ec, BTN_RIGHT, mod,
- rotate_binding, NULL);
+
+ if (ec->capabilities & WESTON_CAP_ROTATION_ANY)
+ weston_compositor_add_button_binding(ec, BTN_RIGHT, mod,
+ rotate_binding, NULL);
+
weston_compositor_add_key_binding(ec, KEY_TAB, mod, switcher_binding,
shell);
weston_compositor_add_key_binding(ec, KEY_F9, mod, backlight_binding,
--
1.8.1.5
ppaalanen
2013-05-22 15:03:05 UTC
Permalink
From: Pekka Paalanen <ppaalanen at gmail.com>

Both GL and pixman renderer (pixman probably only because GL did?)
return the screen capture image as y-flipped, therefore Weston y-flips
it again. However, the future rpi-renderer can produce only right-way-up
(non-flipped) screen captures, and does not need an y-flip.

Add a capability flag for y-flip, which the rpi-renderer will not set,
to get screen captures the right way up.

The wcap recording code needs yet another temporary buffer for the
non-flipped case, since the WCAP format is flipped, and the code
normally overwrites the input image as it compresses it. This becomes
difficult, if the compressor is supposed to flip while processing.

Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
src/compositor.c | 3 +-
src/compositor.h | 3 ++
src/gl-renderer.c | 1 +
src/pixman-renderer.c | 1 +
src/screenshooter.c | 96 ++++++++++++++++++++++++++++++++++++++++-----------
5 files changed, 83 insertions(+), 21 deletions(-)

diff --git a/src/compositor.c b/src/compositor.c
index 657e134..33010dd 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -2821,10 +2821,11 @@ weston_version(int *major, int *minor, int *micro)
}

static const struct {
- uint32_t bit;
+ uint32_t bit; /* enum weston_capability */
const char *desc;
} capability_strings[] = {
{ WESTON_CAP_ROTATION_ANY, "arbitrary surface rotation:" },
+ { WESTON_CAP_CAPTURE_YFLIP, "screen capture uses y-flip:" },
};

static void
diff --git a/src/compositor.h b/src/compositor.h
index e7d19b0..efc4102 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -487,6 +487,9 @@ struct weston_renderer {
enum weston_capability {
/* backend/renderer supports arbitrary rotation */
WESTON_CAP_ROTATION_ANY = 0x0001,
+
+ /* screencaptures need to be y-flipped */
+ WESTON_CAP_CAPTURE_YFLIP = 0x0002,
};

struct weston_compositor {
diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index 87b3be0..4915b90 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -1838,6 +1838,7 @@ gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,

ec->renderer = &gr->base;
ec->capabilities |= WESTON_CAP_ROTATION_ANY;
+ ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;

return 0;

diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c
index ad79c95..36563c6 100644
--- a/src/pixman-renderer.c
+++ b/src/pixman-renderer.c
@@ -497,6 +497,7 @@ pixman_renderer_init(struct weston_compositor *ec)
renderer->base.destroy = pixman_renderer_destroy;
ec->renderer = &renderer->base;
ec->capabilities |= WESTON_CAP_ROTATION_ANY;
+ ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;

weston_compositor_add_debug_binding(ec, KEY_R,
debug_binding, ec);
diff --git a/src/screenshooter.c b/src/screenshooter.c
index ae97b4e..6f53fad 100644
--- a/src/screenshooter.c
+++ b/src/screenshooter.c
@@ -62,6 +62,13 @@ copy_bgra_yflip(uint8_t *dst, uint8_t *src, int height, int stride)
}

static void
+copy_bgra(uint8_t *dst, uint8_t *src, int height, int stride)
+{
+ /* TODO: optimize this out */
+ memcpy(dst, src, height * stride);
+}
+
+static void
copy_row_swap_RB(void *vdst, void *vsrc, int bytes)
{
uint32_t *dst = vdst;
@@ -92,18 +99,32 @@ copy_rgba_yflip(uint8_t *dst, uint8_t *src, int height, int stride)
}

static void
+copy_rgba(uint8_t *dst, uint8_t *src, int height, int stride)
+{
+ uint8_t *end;
+
+ end = dst + height * stride;
+ while (dst < end) {
+ copy_row_swap_RB(dst, src, stride);
+ dst += stride;
+ src += stride;
+ }
+}
+
+static void
screenshooter_frame_notify(struct wl_listener *listener, void *data)
{
struct screenshooter_frame_listener *l =
container_of(listener,
struct screenshooter_frame_listener, listener);
struct weston_output *output = data;
+ struct weston_compositor *compositor = output->compositor;
int32_t stride;
uint8_t *pixels, *d, *s;

output->disable_planes--;
wl_list_remove(&listener->link);
- stride = l->buffer->width * (PIXMAN_FORMAT_BPP(output->compositor->read_format) / 8);
+ stride = l->buffer->width * (PIXMAN_FORMAT_BPP(compositor->read_format) / 8);
pixels = malloc(stride * l->buffer->height);

if (pixels == NULL) {
@@ -112,8 +133,8 @@ screenshooter_frame_notify(struct wl_listener *listener, void *data)
return;
}

- output->compositor->renderer->read_pixels(output,
- output->compositor->read_format, pixels,
+ compositor->renderer->read_pixels(output,
+ compositor->read_format, pixels,
0, 0, output->current->width,
output->current->height);

@@ -122,14 +143,20 @@ screenshooter_frame_notify(struct wl_listener *listener, void *data)
d = wl_shm_buffer_get_data(l->buffer);
s = pixels + stride * (l->buffer->height - 1);

- switch (output->compositor->read_format) {
+ switch (compositor->read_format) {
case PIXMAN_a8r8g8b8:
case PIXMAN_x8r8g8b8:
- copy_bgra_yflip(d, s, output->current->height, stride);
+ if (compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP)
+ copy_bgra_yflip(d, s, output->current->height, stride);
+ else
+ copy_bgra(d, pixels, output->current->height, stride);
break;
case PIXMAN_x8b8g8r8:
case PIXMAN_a8b8g8r8:
- copy_rgba_yflip(d, s, output->current->height, stride);
+ if (compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP)
+ copy_rgba_yflip(d, s, output->current->height, stride);
+ else
+ copy_rgba(d, pixels, output->current->height, stride);
break;
default:
break;
@@ -218,6 +245,7 @@ screenshooter_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
struct weston_recorder {
struct weston_output *output;
uint32_t *frame, *rect;
+ uint32_t *tmpbuf;
uint32_t total;
int fd;
struct wl_listener frame_listener;
@@ -260,7 +288,7 @@ transform_rect(struct weston_output *output, pixman_box32_t *r)
{
pixman_box32_t s = *r;

- switch(output->transform) {
+ switch (output->transform) {
case WL_OUTPUT_TRANSFORM_FLIPPED:
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
@@ -272,7 +300,7 @@ transform_rect(struct weston_output *output, pixman_box32_t *r)
break;
}

- switch(output->transform) {
+ switch (output->transform) {
case WL_OUTPUT_TRANSFORM_NORMAL:
case WL_OUTPUT_TRANSFORM_FLIPPED:
r->x1 = s.x1;
@@ -310,6 +338,7 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data)
struct weston_recorder *recorder =
container_of(listener, struct weston_recorder, frame_listener);
struct weston_output *output = data;
+ struct weston_compositor *compositor = output->compositor;
uint32_t msecs = output->frame_time;
pixman_box32_t *r;
pixman_region32_t damage;
@@ -320,6 +349,15 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data)
uint32_t nrects;
} header;
struct iovec v[2];
+ int do_yflip;
+ int y_orig;
+ uint32_t *outbuf;
+
+ do_yflip = !!(compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP);
+ if (do_yflip)
+ outbuf = recorder->rect;
+ else
+ outbuf = recorder->tmpbuf;

pixman_region32_init(&damage);
pixman_region32_intersect(&damage, &output->region,
@@ -344,17 +382,26 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data)
for (i = 0; i < n; i++) {
width = r[i].x2 - r[i].x1;
height = r[i].y2 - r[i].y1;
- output->compositor->renderer->read_pixels(output,
- output->compositor->read_format, recorder->rect,
- r[i].x1, output->current->height - r[i].y2,
- width, height);
+
+ if (do_yflip)
+ y_orig = output->current->height - r[i].y2;
+ else
+ y_orig = r[i].y1;
+
+ compositor->renderer->read_pixels(output,
+ compositor->read_format, recorder->rect,
+ r[i].x1, y_orig, width, height);

s = recorder->rect;
- p = recorder->rect;
+ p = outbuf;
run = prev = 0; /* quiet gcc */
for (j = 0; j < height; j++) {
- d = recorder->frame +
- stride * (r[i].y2 - j - 1) + r[i].x1;
+ if (do_yflip)
+ y_orig = r[i].y2 - j - 1;
+ else
+ y_orig = r[i].y1 + j;
+ d = recorder->frame + stride * y_orig + r[i].x1;
+
for (k = 0; k < width; k++) {
next = *s++;
delta = component_delta(next, *d);
@@ -372,15 +419,14 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data)
p = output_run(p, prev, run);

recorder->total += write(recorder->fd,
- recorder->rect,
- (p - recorder->rect) * 4);
+ outbuf, (p - outbuf) * 4);

#if 0
fprintf(stderr,
"%dx%d at %d,%d rle from %d to %d bytes (%f) total %dM\n",
width, height, r[i].x1, r[i].y1,
- width * height * 4, (int) (p - recorder->rect) * 4,
- (float) (p - recorder->rect) / (width * height),
+ width * height * 4, (int) (p - outbuf) * 4,
+ (float) (p - outbuf) / (width * height),
recorder->total / 1024 / 1024);
#endif
}
@@ -391,9 +437,13 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data)
static void
weston_recorder_create(struct weston_output *output, const char *filename)
{
+ struct weston_compositor *compositor = output->compositor;
struct weston_recorder *recorder;
int stride, size;
struct { uint32_t magic, format, width, height; } header;
+ int do_yflip;
+
+ do_yflip = !!(compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP);

recorder = malloc(sizeof *recorder);

@@ -406,9 +456,14 @@ weston_recorder_create(struct weston_output *output, const char *filename)
recorder->output = output;
memset(recorder->frame, 0, size);

+ if (do_yflip)
+ recorder->tmpbuf = NULL;
+ else
+ recorder->tmpbuf = malloc(size);
+
header.magic = WCAP_HEADER_MAGIC;

- switch (output->compositor->read_format) {
+ switch (compositor->read_format) {
case PIXMAN_a8r8g8b8:
header.format = WCAP_FORMAT_XRGB8888;
break;
@@ -445,6 +500,7 @@ weston_recorder_destroy(struct weston_recorder *recorder)
{
wl_list_remove(&recorder->frame_listener.link);
close(recorder->fd);
+ free(recorder->tmpbuf);
free(recorder->frame);
free(recorder->rect);
recorder->output->disable_planes--;
--
1.8.1.5
ppaalanen
2013-05-22 15:03:06 UTC
Permalink
From: Pekka Paalanen <ppaalanen at gmail.com>

Dispmanx is the prorietary display API on the Raspberry Pi, which
provides hardware compositing. Every visible surface is assigned a
Dispmanx element, and the hardware or firmware will do all compositing
onto screen. The API supports translation, scaling, flips, discrete
rotations in 90-degree steps, alpha channel on the surfaces, and
full-surface alpha on top.

Previously, Dispmanx capabilities were used via the weston_plane
mechanism, where surfaces were assigned to planes when possible, and
otherwise transparently falling back to GLESv2 compositing. Because we
have no way to use the same memory buffer as a GL texture and a Dispmanx
resource, we had to prepare for both. In the worst case, that means one GL
texture, and two (double-buffered case) Dispmanx resources, all the size
of a whole surface, for all surfaces. This was eating memory fast. To
make things worse (and less slow), the wl_shm buffer was kept around,
since it was copied to either a texture or a resource as needed. This
caused all clients to need two buffers. In a Dispmanx-only renderer, we
can drop the GL texture, and we can release wl_shm buffer immediately
after the first copy, so clients become effectively single-buffered. So
from the worst case of 5 buffers per surface, we go down to 3 or just
2 (single-buffered Dispmanx element, one wl_shm buffer in the client)
buffers per surface.

As this will replace the GL renderer on rpi, we cannot fall back to the
GLESv2 compositing anymore. We lose arbitrary surface rotation, but we
lose also the GL fallback, which caused glitches.

This patch depends on new RaspberryPi firmware. Older firmware may not
render ARGB surfaces correctly, solid color surfaces maybe cause a
performance hit, and the output may completely fail in case the firmware
does not fall back internal off-line compositing properly as needed.

This new rpi-renderer support surface translation and scaling, but not
rotation or transpose (not even in 90-deg steps). In theory, 90-deg step
surface rotation is possible to support. Output transformations are
supported, but flipped variants do not seem to work right.

As a detail, menus and other surfaces that are simply translated with
respect to another surface caused falling back to the GL renderer. The
rpi-renderer handles them directly.

This patch only adds the new renderer, but does not hook it up into use.

Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
src/Makefile.am | 2 +
src/rpi-bcm-stubs.h | 39 ++
src/rpi-renderer.c | 1370 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/rpi-renderer.h | 48 ++
4 files changed, 1459 insertions(+)
create mode 100644 src/rpi-renderer.c
create mode 100644 src/rpi-renderer.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 859f583..106ccba 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -180,6 +180,8 @@ rpi_backend_la_CFLAGS = \
$(RPI_BCM_HOST_CFLAGS)
rpi_backend_la_SOURCES = \
compositor-rpi.c \
+ rpi-renderer.c \
+ rpi-renderer.h \
rpi-bcm-stubs.h \
tty.c \
evdev.c \
diff --git a/src/rpi-bcm-stubs.h b/src/rpi-bcm-stubs.h
index 989c99c..4b89319 100644
--- a/src/rpi-bcm-stubs.h
+++ b/src/rpi-bcm-stubs.h
@@ -43,6 +43,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
static inline void bcm_host_init(void) {}
static inline void bcm_host_deinit(void) {}

+
+/* from /opt/vc/include/interface/vmcs_host/vc_dispservice_defs.h */
+
+#define TRANSFORM_HFLIP (1<<0)
+#define TRANSFORM_VFLIP (1<<1)
+#define TRANSFORM_TRANSPOSE (1<<2)
+
+
/* from /opt/vc/include/interface/vctypes/vc_display_types.h */

typedef enum
@@ -61,6 +69,14 @@ typedef struct tag_VC_RECT_T {

typedef enum {
VC_IMAGE_ROT0,
+ /* these are not the right values: */
+ VC_IMAGE_ROT90,
+ VC_IMAGE_ROT180,
+ VC_IMAGE_ROT270,
+ VC_IMAGE_MIRROR_ROT0,
+ VC_IMAGE_MIRROR_ROT90,
+ VC_IMAGE_MIRROR_ROT180,
+ VC_IMAGE_MIRROR_ROT270,
} VC_IMAGE_TRANSFORM_T;

typedef enum
@@ -109,6 +125,12 @@ typedef struct {

typedef enum {
DISPMANX_NO_ROTATE = 0,
+ DISPMANX_ROTATE_90 = 1,
+ DISPMANX_ROTATE_180 = 2,
+ DISPMANX_ROTATE_270 = 3,
+
+ DISPMANX_FLIP_HRIZ = 1 << 16,
+ DISPMANX_FLIP_VERT = 1 << 17
} DISPMANX_TRANSFORM_T;

typedef struct {
@@ -161,6 +183,15 @@ vc_dispmanx_resource_write_data_rect(DISPMANX_RESOURCE_HANDLE_T handle,
}

static inline int
+vc_dispmanx_resource_read_data(DISPMANX_RESOURCE_HANDLE_T handle,
+ const VC_RECT_T *p_rect,
+ void *dst_address,
+ uint32_t dst_pitch)
+{
+ return -1;
+}
+
+static inline int
vc_dispmanx_resource_delete(DISPMANX_RESOURCE_HANDLE_T res)
{
return -1;
@@ -256,6 +287,14 @@ vc_dispmanx_element_change_attributes(DISPMANX_UPDATE_HANDLE_T update,
return -1;
}

+static inline int
+vc_dispmanx_snapshot(DISPMANX_DISPLAY_HANDLE_T display,
+ DISPMANX_RESOURCE_HANDLE_T snapshot_resource,
+ VC_IMAGE_TRANSFORM_T transform)
+{
+ return -1;
+}
+
/* from /opt/vc/include/EGL/eglplatform.h */

typedef struct {
diff --git a/src/rpi-renderer.c b/src/rpi-renderer.c
new file mode 100644
index 0000000..e429d2e
--- /dev/null
+++ b/src/rpi-renderer.c
@@ -0,0 +1,1370 @@
+/*
+ * Copyright ? 2012-2013 Raspberry Pi Foundation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include "config.h"
+
+#ifdef HAVE_BCM_HOST
+# include <bcm_host.h>
+#else
+# include "rpi-bcm-stubs.h"
+#endif
+
+#include "compositor.h"
+#include "rpi-renderer.h"
+
+/*
+ * Dispmanx API offers alpha-blended overlays for hardware compositing.
+ * The final composite consists of dispmanx elements, and their contents:
+ * the dispmanx resource assigned to the element. The elements may be
+ * scanned out directly, or composited to a temporary surface, depending on
+ * how the firmware decides to handle the scene. Updates to multiple elements
+ * may be queued in a single dispmanx update object, resulting in atomic and
+ * vblank synchronized display updates.
+ *
+ * To avoid tearing and display artifacts, the current dispmanx resource in a
+ * dispmanx element must not be touched. Therefore each element must be
+ * double-buffered, using two resources, the front and the back. While a
+ * dispmanx update is running, the both resources must be considered in use.
+ *
+ * A resource may be destroyed only, when the update removing the element has
+ * completed. Otherwise you risk showing an incomplete composition.
+ */
+
+#ifndef ELEMENT_CHANGE_LAYER
+/* copied from interface/vmcs_host/vc_vchi_dispmanx.h of userland.git */
+#define ELEMENT_CHANGE_LAYER (1<<0)
+#define ELEMENT_CHANGE_OPACITY (1<<1)
+#define ELEMENT_CHANGE_DEST_RECT (1<<2)
+#define ELEMENT_CHANGE_SRC_RECT (1<<3)
+#define ELEMENT_CHANGE_MASK_RESOURCE (1<<4)
+#define ELEMENT_CHANGE_TRANSFORM (1<<5)
+#endif
+
+#if 0
+#define DBG(...) \
+ weston_log(__VA_ARGS__)
+#else
+#define DBG(...) do {} while (0)
+#endif
+
+/* If we had a fully featured vc_dispmanx_resource_write_data()... */
+/*#define HAVE_RESOURCE_WRITE_DATA_RECT 1*/
+
+struct rpi_resource {
+ DISPMANX_RESOURCE_HANDLE_T handle;
+ int width;
+ int height; /* height of the image (valid pixel data) */
+ int stride; /* bytes */
+ int buffer_height; /* height of the buffer */
+ VC_IMAGE_TYPE_T ifmt;
+};
+
+struct rpir_output;
+
+struct rpir_surface {
+ struct weston_surface *surface;
+
+ /* If link is empty, the surface is guaranteed to not be on screen,
+ * i.e. updates removing Elements have completed.
+ */
+ struct wl_list link;
+
+ DISPMANX_ELEMENT_HANDLE_T handle;
+ int layer;
+ int need_swap;
+ int single_buffer;
+
+ struct rpi_resource resources[2];
+ struct rpi_resource *front;
+ struct rpi_resource *back;
+ pixman_region32_t prev_damage;
+
+ struct weston_buffer_reference buffer_ref;
+};
+
+struct rpir_output {
+ DISPMANX_DISPLAY_HANDLE_T display;
+
+ DISPMANX_UPDATE_HANDLE_T update;
+ struct weston_matrix matrix;
+
+ /* all Elements currently on screen */
+ struct wl_list surface_list; /* struct rpir_surface::link */
+
+ /* Elements just removed, waiting for update completion */
+ struct wl_list surface_cleanup_list; /* struct rpir_surface::link */
+
+ struct rpi_resource capture_buffer;
+ uint8_t *capture_data;
+};
+
+struct rpi_renderer {
+ struct weston_renderer base;
+
+ int single_buffer;
+};
+
+static inline struct rpir_surface *
+to_rpir_surface(struct weston_surface *surface)
+{
+ return surface->renderer_state;
+}
+
+static inline struct rpir_output *
+to_rpir_output(struct weston_output *output)
+{
+ return output->renderer_state;
+}
+
+static inline struct rpi_renderer *
+to_rpi_renderer(struct weston_compositor *compositor)
+{
+ return container_of(compositor->renderer, struct rpi_renderer, base);
+}
+
+static inline int
+int_max(int a, int b)
+{
+ return a > b ? a : b;
+}
+
+static inline void
+int_swap(int *a, int *b)
+{
+ int tmp = *a;
+ *a = *b;
+ *b = tmp;
+}
+
+static uint8_t
+float2uint8(float f)
+{
+ int v = roundf(f * 255.0f);
+
+ return v < 0 ? 0 : (v > 255 ? 255 : v);
+}
+
+static void
+rpi_resource_init(struct rpi_resource *resource)
+{
+ resource->handle = DISPMANX_NO_HANDLE;
+}
+
+static void
+rpi_resource_release(struct rpi_resource *resource)
+{
+ if (resource->handle == DISPMANX_NO_HANDLE)
+ return;
+
+ vc_dispmanx_resource_delete(resource->handle);
+ DBG("resource %p release\n", resource);
+ resource->handle = DISPMANX_NO_HANDLE;
+}
+
+static int
+rpi_resource_realloc(struct rpi_resource *resource, VC_IMAGE_TYPE_T ifmt,
+ int width, int height, int stride, int buffer_height)
+{
+ uint32_t dummy;
+
+ if (resource->handle != DISPMANX_NO_HANDLE &&
+ resource->width == width &&
+ resource->height == height &&
+ resource->stride == stride &&
+ resource->buffer_height == buffer_height &&
+ resource->ifmt == ifmt)
+ return 0;
+
+ rpi_resource_release(resource);
+
+ /* NOTE: if stride is not a multiple of 16 pixels in bytes,
+ * the vc_image_* functions may break. Dispmanx elements
+ * should be fine, though. Buffer_height probably has similar
+ * constraints, too.
+ */
+ resource->handle =
+ vc_dispmanx_resource_create(ifmt,
+ width | (stride << 16),
+ height | (buffer_height << 16),
+ &dummy);
+ if (resource->handle == DISPMANX_NO_HANDLE)
+ return -1;
+
+ resource->width = width;
+ resource->height = height;
+ resource->stride = stride;
+ resource->buffer_height = buffer_height;
+ resource->ifmt = ifmt;
+ DBG("resource %p alloc\n", resource);
+ return 1;
+}
+
+/* A firmware workaround for broken ALPHA_PREMULT + ALPHA_MIX hardware. */
+#define PREMULT_ALPHA_FLAG (1 << 31)
+
+static VC_IMAGE_TYPE_T
+shm_buffer_get_vc_format(struct wl_buffer *buffer)
+{
+ switch (wl_shm_buffer_get_format(buffer)) {
+ case WL_SHM_FORMAT_XRGB8888:
+ return VC_IMAGE_XRGB8888;
+ case WL_SHM_FORMAT_ARGB8888:
+ return VC_IMAGE_ARGB8888 | PREMULT_ALPHA_FLAG;
+ default:
+ /* invalid format */
+ return VC_IMAGE_MIN;
+ }
+}
+
+static int
+rpi_resource_update(struct rpi_resource *resource, struct wl_buffer *buffer,
+ pixman_region32_t *region)
+{
+ pixman_region32_t write_region;
+ pixman_box32_t *r;
+ VC_RECT_T rect;
+ VC_IMAGE_TYPE_T ifmt;
+ uint32_t *pixels;
+ int width;
+ int height;
+ int stride;
+ int ret;
+#ifdef HAVE_RESOURCE_WRITE_DATA_RECT
+ int n;
+#endif
+
+ if (!buffer)
+ return -1;
+
+ ifmt = shm_buffer_get_vc_format(buffer);
+ width = wl_shm_buffer_get_width(buffer);
+ height = wl_shm_buffer_get_height(buffer);
+ stride = wl_shm_buffer_get_stride(buffer);
+ pixels = wl_shm_buffer_get_data(buffer);
+
+ ret = rpi_resource_realloc(resource, ifmt & ~PREMULT_ALPHA_FLAG,
+ width, height, stride, height);
+ if (ret < 0)
+ return -1;
+
+ pixman_region32_init_rect(&write_region, 0, 0, width, height);
+ if (ret == 0)
+ pixman_region32_intersect(&write_region,
+ &write_region, region);
+
+#ifdef HAVE_RESOURCE_WRITE_DATA_RECT
+ /* XXX: Can this do a format conversion, so that scanout does not have to? */
+ r = pixman_region32_rectangles(&write_region, &n);
+ while (n--) {
+ vc_dispmanx_rect_set(&rect, r[n].x1, r[n].y1,
+ r[n].x2 - r[n].x1, r[n].y2 - r[n].y1);
+
+ ret = vc_dispmanx_resource_write_data_rect(resource->handle,
+ ifmt, stride,
+ pixels, &rect,
+ rect.x, rect.y);
+ DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
+ rect.width, rect.height, rect.x, rect.y, ret);
+ if (ret)
+ break;
+ }
+#else
+ /* vc_dispmanx_resource_write_data() ignores ifmt,
+ * rect.x, rect.width, and uses stride only for computing
+ * the size of the transfer as rect.height * stride.
+ * Therefore we can only write rows starting at x=0.
+ * To be able to write more than one scanline at a time,
+ * the resource must have been created with the same stride
+ * as used here, and we must write full scanlines.
+ */
+
+ r = pixman_region32_extents(&write_region);
+ vc_dispmanx_rect_set(&rect, 0, r->y1, width, r->y2 - r->y1);
+ ret = vc_dispmanx_resource_write_data(resource->handle,
+ ifmt, stride, pixels, &rect);
+ DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
+ width, r->y2 - r->y1, 0, r->y1, ret);
+#endif
+
+ pixman_region32_fini(&write_region);
+
+ return ret ? -1 : 0;
+}
+
+static struct rpir_surface *
+rpir_surface_create(struct rpi_renderer *renderer)
+{
+ struct rpir_surface *surface;
+
+ surface = calloc(1, sizeof *surface);
+ if (!surface)
+ return NULL;
+
+ wl_list_init(&surface->link);
+ surface->single_buffer = renderer->single_buffer;
+ surface->handle = DISPMANX_NO_HANDLE;
+ rpi_resource_init(&surface->resources[0]);
+ rpi_resource_init(&surface->resources[1]);
+ surface->front = &surface->resources[0];
+ if (surface->single_buffer)
+ surface->back = &surface->resources[0];
+ else
+ surface->back = &surface->resources[1];
+
+ pixman_region32_init(&surface->prev_damage);
+
+ return surface;
+}
+
+static void
+rpir_surface_destroy(struct rpir_surface *surface)
+{
+ wl_list_remove(&surface->link);
+
+ if (surface->handle != DISPMANX_NO_HANDLE)
+ weston_log("ERROR rpi: destroying on-screen element\n");
+
+ pixman_region32_fini(&surface->prev_damage);
+ rpi_resource_release(&surface->resources[0]);
+ rpi_resource_release(&surface->resources[1]);
+ DBG("rpir_surface %p destroyed (%u)\n", surface, surface->handle);
+
+ free(surface);
+}
+
+static int
+rpir_surface_damage(struct rpir_surface *surface, struct wl_buffer *buffer,
+ pixman_region32_t *damage)
+{
+ pixman_region32_t upload;
+ int ret;
+
+ if (!pixman_region32_not_empty(damage))
+ return 0;
+
+ DBG("rpir_surface %p update resource %p\n", surface, surface->back);
+
+ /* XXX: todo: if no surface->handle, update front buffer directly
+ * to avoid creating a new back buffer */
+ if (surface->single_buffer) {
+ ret = rpi_resource_update(surface->front, buffer, damage);
+ } else {
+ pixman_region32_init(&upload);
+ pixman_region32_union(&upload, &surface->prev_damage, damage);
+ ret = rpi_resource_update(surface->back, buffer, &upload);
+ pixman_region32_fini(&upload);
+ }
+
+ pixman_region32_copy(&surface->prev_damage, damage);
+ surface->need_swap = 1;
+
+ return ret;
+}
+
+static void
+matrix_type_str(struct weston_matrix *matrix, char *buf, int len)
+{
+ static const char types[33] = "TSRO";
+ unsigned mask = matrix->type;
+ int i = 0;
+
+ while (mask && i < len - 1) {
+ if (mask & (1u << i))
+ *buf++ = types[i];
+ mask &= ~(1u << i);
+ i++;
+ }
+ *buf = '\0';
+}
+
+static void
+log_print_matrix(struct weston_matrix *matrix)
+{
+ char typestr[6];
+ float *d = matrix->d;
+
+ matrix_type_str(matrix, typestr, sizeof typestr);
+ weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
+ d[0], d[4], d[8], d[12]);
+ weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
+ d[1], d[5], d[9], d[13]);
+ weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
+ d[2], d[6], d[10], d[14]);
+ weston_log_continue("%14.6e %14.6e %14.6e %14.6e type: %s\n",
+ d[3], d[7], d[11], d[15], typestr);
+}
+
+static void
+warn_bad_matrix(struct weston_matrix *total, struct weston_matrix *output,
+ struct weston_matrix *surface)
+{
+ static int n_warn;
+ char typestr[6];
+
+ if (n_warn++ == 10)
+ weston_log("%s: not showing more warnings\n", __func__);
+
+ if (n_warn > 10)
+ return;
+
+ weston_log("%s: warning: total transformation is not renderable:\n",
+ __func__);
+ log_print_matrix(total);
+
+ matrix_type_str(surface, typestr, sizeof typestr);
+ weston_log_continue("surface matrix type: %s\n", typestr);
+ matrix_type_str(output, typestr, sizeof typestr);
+ weston_log_continue("output matrix type: %s\n", typestr);
+}
+
+/*#define SURFACE_TRANSFORM */
+
+static int
+rpir_surface_compute_rects(struct rpir_surface *surface,
+ VC_RECT_T *src_rect, VC_RECT_T *dst_rect,
+ VC_IMAGE_TRANSFORM_T *flipmask)
+{
+ struct weston_output *output_base = surface->surface->output;
+ struct rpir_output *output = to_rpir_output(output_base);
+ struct weston_matrix matrix = surface->surface->transform.matrix;
+ VC_IMAGE_TRANSFORM_T flipt = 0;
+ int src_x, src_y;
+ int dst_x, dst_y;
+ int src_width, src_height;
+ int dst_width, dst_height;
+ struct weston_vector p1 = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
+ struct weston_vector p2 = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
+ int t;
+ int over;
+
+ /* XXX: take buffer transform into account */
+
+ /* src is in 16.16, dst is in 32.0 fixed point.
+ * Negative values are not allowed in VC_RECT_T.
+ * Clip size to output boundaries, firmware ignores
+ * huge elements like 8192x8192.
+ */
+
+ src_x = 0 << 16;
+ src_y = 0 << 16;
+ src_width = surface->front->width << 16;
+ src_height = surface->front->height << 16;
+
+ weston_matrix_multiply(&matrix, &output->matrix);
+
+#ifdef SURFACE_TRANSFORM
+ if (matrix.type >= WESTON_MATRIX_TRANSFORM_OTHER) {
+#else
+ if (matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE) {
+#endif
+ warn_bad_matrix(&matrix, &output->matrix,
+ &surface->surface->transform.matrix);
+ } else {
+ if (matrix.type & WESTON_MATRIX_TRANSFORM_ROTATE) {
+ if (fabsf(matrix.d[0]) < 1e-4f &&
+ fabsf(matrix.d[5]) < 1e-4f) {
+ flipt |= TRANSFORM_TRANSPOSE;
+ } else if (fabsf(matrix.d[1]) < 1e-4 &&
+ fabsf(matrix.d[4]) < 1e-4) {
+ /* no transpose */
+ } else {
+ warn_bad_matrix(&matrix, &output->matrix,
+ &surface->surface->transform.matrix);
+ }
+ }
+ }
+
+ p2.f[0] = surface->surface->geometry.width;
+ p2.f[1] = surface->surface->geometry.height;
+
+ /* transform top-left and bot-right corner into screen coordinates */
+ weston_matrix_transform(&matrix, &p1);
+ weston_matrix_transform(&matrix, &p2);
+
+ /* Compute the destination rectangle on screen, converting
+ * negative dimensions to flips.
+ */
+
+ dst_width = round(p2.f[0] - p1.f[0]);
+ if (dst_width < 0) {
+ dst_x = round(p2.f[0]);
+ dst_width = -dst_width;
+
+ if (!(flipt & TRANSFORM_TRANSPOSE))
+ flipt |= TRANSFORM_HFLIP;
+ else
+ flipt |= TRANSFORM_VFLIP;
+ } else {
+ dst_x = round(p1.f[0]);
+ }
+
+ dst_height = round(p2.f[1] - p1.f[1]);
+ if (dst_height < 0) {
+ dst_y = round(p2.f[1]);
+ dst_height = -dst_height;
+
+ if (!(flipt & TRANSFORM_TRANSPOSE))
+ flipt |= TRANSFORM_VFLIP;
+ else
+ flipt |= TRANSFORM_HFLIP;
+ } else {
+ dst_y = round(p1.f[1]);
+ }
+
+ if (dst_width == 0 || dst_height == 0) {
+ DBG("ignored, zero surface area before clipping\n");
+ return -1;
+ }
+
+#ifdef SURFACE_TRANSFORM
+ /* Dispmanx works as if you flipped the whole screen, when
+ * you flip an element. But, we want to flip an element in place.
+ * XXX: fixme
+ */
+ if (flipt & TRANSFORM_HFLIP)
+ dst_x = output_base->width - dst_x;
+ if (flipt & TRANSFORM_VFLIP)
+ dst_y = output_base->height - dst_y;
+ if (flipt & TRANSFORM_TRANSPOSE) {
+ int_swap(&dst_x, &dst_y);
+ int_swap(&dst_width, &dst_height);
+ }
+#else
+ switch (output_base->transform) {
+ case WL_OUTPUT_TRANSFORM_FLIPPED:
+ flipt = TRANSFORM_HFLIP;
+ break;
+ case WL_OUTPUT_TRANSFORM_NORMAL:
+ flipt = 0;
+ break;
+
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE;
+ break;
+ case WL_OUTPUT_TRANSFORM_90:
+ flipt = TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+ flipt = TRANSFORM_VFLIP;
+ break;
+ case WL_OUTPUT_TRANSFORM_180:
+ flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP;
+ break;
+
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ flipt = TRANSFORM_TRANSPOSE;
+ break;
+ case WL_OUTPUT_TRANSFORM_270:
+ flipt = TRANSFORM_HFLIP | TRANSFORM_TRANSPOSE;
+ break;
+ default:
+ break;
+ }
+#endif
+
+ /* clip destination rectangle to screen dimensions */
+
+ if (dst_x < 0) {
+ t = (int64_t)dst_x * src_width / dst_width;
+ src_width += t;
+ dst_width += dst_x;
+ src_x -= t;
+ dst_x = 0;
+ }
+
+ if (dst_y < 0) {
+ t = (int64_t)dst_y * src_height / dst_height;
+ src_height += t;
+ dst_height += dst_y;
+ src_y -= t;
+ dst_y = 0;
+ }
+
+ over = dst_x + dst_width - output_base->width;
+ if (over > 0) {
+ t = (int64_t)over * src_width / dst_width;
+ src_width -= t;
+ dst_width -= over;
+ }
+
+ over = dst_y + dst_height - output_base->height;
+ if (over > 0) {
+ t = (int64_t)over * src_height / dst_height;
+ src_height -= t;
+ dst_height -= over;
+ }
+
+ src_width = int_max(src_width, 0);
+ src_height = int_max(src_height, 0);
+
+ DBG("rpir_surface %p %dx%d: p1 %f, %f; p2 %f, %f\n", surface,
+ surface->surface->geometry.width,
+ surface->surface->geometry.height,
+ p1.f[0], p1.f[1], p2.f[0], p2.f[1]);
+ DBG("src rect %d;%d, %d;%d, %d;%dx%d;%d\n",
+ src_x >> 16, src_x & 0xffff,
+ src_y >> 16, src_y & 0xffff,
+ src_width >> 16, src_width & 0xffff,
+ src_height >> 16, src_height & 0xffff);
+ DBG("dest rect %d, %d, %dx%d%s%s%s\n",
+ dst_x, dst_y, dst_width, dst_height,
+ (flipt & TRANSFORM_HFLIP) ? " hflip" : "",
+ (flipt & TRANSFORM_VFLIP) ? " vflip" : "",
+ (flipt & TRANSFORM_TRANSPOSE) ? " transp" : "");
+
+ assert(src_x >= 0);
+ assert(src_y >= 0);
+ assert(dst_x >= 0);
+ assert(dst_y >= 0);
+
+ if (dst_width < 1 || dst_height < 1) {
+ DBG("ignored, zero surface area after clipping\n");
+ return -1;
+ }
+
+ vc_dispmanx_rect_set(src_rect, src_x, src_y, src_width, src_height);
+ vc_dispmanx_rect_set(dst_rect, dst_x, dst_y, dst_width, dst_height);
+ *flipmask = flipt;
+
+ return 0;
+}
+
+static DISPMANX_TRANSFORM_T
+vc_image2dispmanx_transform(VC_IMAGE_TRANSFORM_T t)
+{
+ /* XXX: uhh, are these right? */
+ switch (t) {
+ case VC_IMAGE_ROT0:
+ return DISPMANX_NO_ROTATE;
+ case VC_IMAGE_MIRROR_ROT0:
+ return DISPMANX_FLIP_HRIZ;
+ case VC_IMAGE_MIRROR_ROT180:
+ return DISPMANX_FLIP_VERT;
+ case VC_IMAGE_ROT180:
+ return DISPMANX_ROTATE_180;
+ case VC_IMAGE_MIRROR_ROT90:
+ return DISPMANX_ROTATE_90 | DISPMANX_FLIP_HRIZ;
+ case VC_IMAGE_ROT270:
+ return DISPMANX_ROTATE_270;
+ case VC_IMAGE_ROT90:
+ return DISPMANX_ROTATE_90;
+ case VC_IMAGE_MIRROR_ROT270:
+ return DISPMANX_ROTATE_270 | DISPMANX_FLIP_VERT;
+ default:
+ assert(0 && "bad VC_IMAGE_TRANSFORM_T");
+ return DISPMANX_NO_ROTATE;
+ }
+}
+
+static int
+rpir_surface_dmx_add(struct rpir_surface *surface, struct rpir_output *output,
+ DISPMANX_UPDATE_HANDLE_T update, int layer)
+{
+ /* Do not use DISPMANX_FLAGS_ALPHA_PREMULT here.
+ * If you define PREMULT and ALPHA_MIX, the hardware will not
+ * multiply the source color with the element alpha, leading to
+ * bad colors. Instead, we define PREMULT during pixel data upload.
+ */
+ VC_DISPMANX_ALPHA_T alphasetup = {
+ DISPMANX_FLAGS_ALPHA_FROM_SOURCE |
+ DISPMANX_FLAGS_ALPHA_MIX,
+ float2uint8(surface->surface->alpha), /* opacity 0-255 */
+ 0 /* mask resource handle */
+ };
+ VC_RECT_T dst_rect;
+ VC_RECT_T src_rect;
+ VC_IMAGE_TRANSFORM_T flipmask;
+ int ret;
+
+ ret = rpir_surface_compute_rects(surface, &src_rect, &dst_rect,
+ &flipmask);
+ if (ret < 0)
+ return 0;
+
+ surface->handle = vc_dispmanx_element_add(
+ update,
+ output->display,
+ layer,
+ &dst_rect,
+ surface->front->handle,
+ &src_rect,
+ DISPMANX_PROTECTION_NONE,
+ &alphasetup,
+ NULL /* clamp */,
+ vc_image2dispmanx_transform(flipmask));
+ DBG("rpir_surface %p add %u, alpha %f\n", surface, surface->handle,
+ surface->surface->alpha);
+
+ if (surface->handle == DISPMANX_NO_HANDLE)
+ return -1;
+
+ return 1;
+}
+
+static void
+rpir_surface_dmx_swap(struct rpir_surface *surface,
+ DISPMANX_UPDATE_HANDLE_T update)
+{
+ VC_RECT_T rect;
+ pixman_box32_t *r;
+
+ /* XXX: skip, iff resource was not reallocated, and single-buffering */
+ vc_dispmanx_element_change_source(update, surface->handle,
+ surface->front->handle);
+
+ /* This is current damage now, after rpir_surface_damage() */
+ r = pixman_region32_extents(&surface->prev_damage);
+
+ vc_dispmanx_rect_set(&rect, r->x1, r->y1,
+ r->x2 - r->x1, r->y2 - r->y1);
+ vc_dispmanx_element_modified(update, surface->handle, &rect);
+ DBG("rpir_surface %p swap\n", surface);
+}
+
+static int
+rpir_surface_dmx_move(struct rpir_surface *surface,
+ DISPMANX_UPDATE_HANDLE_T update, int layer)
+{
+ uint8_t alpha = float2uint8(surface->surface->alpha);
+ VC_RECT_T dst_rect;
+ VC_RECT_T src_rect;
+ VC_IMAGE_TRANSFORM_T flipmask;
+ int ret;
+
+ /* XXX: return early, if all attributes stay the same */
+
+ ret = rpir_surface_compute_rects(surface, &src_rect, &dst_rect,
+ &flipmask);
+ if (ret < 0)
+ return 0;
+
+ ret = vc_dispmanx_element_change_attributes(
+ update,
+ surface->handle,
+ ELEMENT_CHANGE_LAYER |
+ ELEMENT_CHANGE_OPACITY |
+ ELEMENT_CHANGE_TRANSFORM |
+ ELEMENT_CHANGE_DEST_RECT |
+ ELEMENT_CHANGE_SRC_RECT,
+ layer,
+ alpha,
+ &dst_rect,
+ &src_rect,
+ DISPMANX_NO_HANDLE,
+ /* This really is DISPMANX_TRANSFORM_T, no matter
+ * what the header says. */
+ vc_image2dispmanx_transform(flipmask));
+ DBG("rpir_surface %p move\n", surface);
+
+ if (ret)
+ return -1;
+
+ return 1;
+}
+
+static void
+rpir_surface_dmx_remove(struct rpir_surface *surface,
+ DISPMANX_UPDATE_HANDLE_T update)
+{
+ if (surface->handle == DISPMANX_NO_HANDLE)
+ return;
+
+ vc_dispmanx_element_remove(update, surface->handle);
+ DBG("rpir_surface %p remove %u\n", surface, surface->handle);
+ surface->handle = DISPMANX_NO_HANDLE;
+}
+
+static void
+rpir_surface_swap_pointers(struct rpir_surface *surface)
+{
+ struct rpi_resource *tmp;
+
+ tmp = surface->front;
+ surface->front = surface->back;
+ surface->back = tmp;
+ surface->need_swap = 0;
+ DBG("new back %p, new front %p\n", surface->back, surface->front);
+}
+
+static int
+is_surface_not_visible(struct weston_surface *surface)
+{
+ /* Return true, if surface is guaranteed to be totally obscured. */
+ int ret;
+ pixman_region32_t unocc;
+
+ pixman_region32_init(&unocc);
+ pixman_region32_subtract(&unocc, &surface->transform.boundingbox,
+ &surface->clip);
+ ret = !pixman_region32_not_empty(&unocc);
+ pixman_region32_fini(&unocc);
+
+ return ret;
+}
+
+static void
+rpir_surface_update(struct rpir_surface *surface, struct rpir_output *output,
+ DISPMANX_UPDATE_HANDLE_T update, int layer)
+{
+ int need_swap = surface->need_swap;
+ int ret;
+ int obscured;
+
+ if (need_swap)
+ rpir_surface_swap_pointers(surface);
+
+ obscured = is_surface_not_visible(surface->surface);
+ if (obscured) {
+ DBG("rpir_surface %p totally obscured.\n", surface);
+
+ wl_list_remove(&surface->link);
+ if (surface->handle == DISPMANX_NO_HANDLE) {
+ wl_list_init(&surface->link);
+ } else {
+ rpir_surface_dmx_remove(surface, update);
+ wl_list_insert(&output->surface_cleanup_list,
+ &surface->link);
+ }
+
+ goto out;
+ }
+
+ if (surface->handle == DISPMANX_NO_HANDLE) {
+ ret = rpir_surface_dmx_add(surface, output, update, layer);
+ if (ret == 0) {
+ wl_list_remove(&surface->link);
+ wl_list_init(&surface->link);
+ } else if (ret < 0) {
+ weston_log("ERROR rpir_surface_dmx_add() failed.\n");
+ }
+ } else {
+ if (need_swap)
+ rpir_surface_dmx_swap(surface, update);
+
+ ret = rpir_surface_dmx_move(surface, update, layer);
+ if (ret == 0) {
+ rpir_surface_dmx_remove(surface, update);
+
+ wl_list_remove(&surface->link);
+ wl_list_insert(&output->surface_cleanup_list,
+ &surface->link);
+ } else if (ret < 0) {
+ weston_log("ERROR rpir_surface_dmx_move() failed.\n");
+ }
+ }
+
+out:
+ surface->layer = layer;
+}
+
+static int
+rpi_renderer_read_pixels(struct weston_output *base,
+ pixman_format_code_t format, void *pixels,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct rpir_output *output = to_rpir_output(base);
+ struct rpi_resource *buffer = &output->capture_buffer;
+ VC_RECT_T rect;
+ uint32_t fb_width, fb_height;
+ uint32_t dst_pitch;
+ uint32_t i;
+ int ret;
+
+ fb_width = base->current->width;
+ fb_height = base->current->height;
+
+ DBG("%s(%u, %u, %u, %u), resource %p\n", __func__,
+ x, y, width, height, buffer);
+
+ if (format != PIXMAN_a8r8g8b8) {
+ weston_log("rpi-renderer error: bad read_format\n");
+ return -1;
+ }
+
+ dst_pitch = fb_width * 4;
+
+ if (buffer->handle == DISPMANX_NO_HANDLE) {
+ free(output->capture_data);
+ output->capture_data = NULL;
+
+ ret = rpi_resource_realloc(buffer, VC_IMAGE_ARGB8888,
+ fb_width, fb_height,
+ dst_pitch, fb_height);
+ if (ret < 0) {
+ weston_log("rpi-renderer error: "
+ "allocating read buffer failed\n");
+ return -1;
+ }
+
+ ret = vc_dispmanx_snapshot(output->display, buffer->handle,
+ VC_IMAGE_ROT0);
+ if (ret) {
+ weston_log("rpi-renderer error: "
+ "vc_dispmanx_snapshot returned %d\n", ret);
+ return -1;
+ }
+ DBG("%s: snapshot done.\n", __func__);
+ }
+
+ /*
+ * If vc_dispmanx_resource_read_data was able to read sub-rectangles,
+ * we could read directly into 'pixels'. But it cannot, it does not
+ * use rect.x or rect.width, and does this:
+ * host_start = (uint8_t *)dst_address + (dst_pitch * p_rect->y);
+ * In other words, it is only good for reading the full buffer in
+ * one go.
+ */
+ vc_dispmanx_rect_set(&rect, 0, 0, fb_width, fb_height);
+
+ if (x == 0 && y == 0 && width == fb_width && height == fb_height) {
+ ret = vc_dispmanx_resource_read_data(buffer->handle, &rect,
+ pixels, dst_pitch);
+ if (ret) {
+ weston_log("rpi-renderer error: "
+ "resource_read_data returned %d\n", ret);
+ return -1;
+ }
+ DBG("%s: full frame done.\n", __func__);
+ return 0;
+ }
+
+ if (!output->capture_data) {
+ output->capture_data = malloc(fb_height * dst_pitch);
+ if (!output->capture_data) {
+ weston_log("rpi-renderer error: "
+ "out of memory\n");
+ return -1;
+ }
+
+ ret = vc_dispmanx_resource_read_data(buffer->handle, &rect,
+ output->capture_data,
+ dst_pitch);
+ if (ret) {
+ weston_log("rpi-renderer error: "
+ "resource_read_data returned %d\n", ret);
+ return -1;
+ }
+ }
+
+ for (i = 0; i < height; i++) {
+ uint8_t *src = output->capture_data +
+ (y + i) * dst_pitch + x * 4;
+ uint8_t *dst = (uint8_t *)pixels + i * width * 4;
+ memcpy(dst, src, width * 4);
+ }
+
+ return 0;
+}
+
+static void
+rpir_output_dmx_remove_all(struct rpir_output *output,
+ DISPMANX_UPDATE_HANDLE_T update)
+{
+ struct rpir_surface *surface;
+
+ while (!wl_list_empty(&output->surface_list)) {
+ surface = container_of(output->surface_list.next,
+ struct rpir_surface, link);
+ rpir_surface_dmx_remove(surface, update);
+
+ wl_list_remove(&surface->link);
+ wl_list_insert(&output->surface_cleanup_list, &surface->link);
+ }
+}
+
+static void
+output_compute_matrix(struct weston_output *base)
+{
+ struct rpir_output *output = to_rpir_output(base);
+ struct weston_matrix *matrix = &output->matrix;
+ const float half_w = 0.5f * base->width;
+ const float half_h = 0.5f * base->height;
+ float mag;
+ float dx, dy;
+
+ weston_matrix_init(matrix);
+ weston_matrix_translate(matrix, -base->x, -base->y, 0.0f);
+
+#ifdef SURFACE_TRANSFORM
+ weston_matrix_translate(matrix, -half_w, -half_h, 0.0f);
+ switch (base->transform) {
+ case WL_OUTPUT_TRANSFORM_FLIPPED:
+ weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
+ case WL_OUTPUT_TRANSFORM_NORMAL:
+ /* weston_matrix_rotate_xy(matrix, 1.0f, 0.0f); no-op */
+ weston_matrix_translate(matrix, half_w, half_h, 0.0f);
+ break;
+
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
+ case WL_OUTPUT_TRANSFORM_90:
+ weston_matrix_rotate_xy(matrix, 0.0f, 1.0f);
+ weston_matrix_translate(matrix, half_h, half_w, 0.0f);
+ break;
+
+ case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+ weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
+ case WL_OUTPUT_TRANSFORM_180:
+ weston_matrix_rotate_xy(matrix, -1.0f, 0.0f);
+ weston_matrix_translate(matrix, half_w, half_h, 0.0f);
+ break;
+
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
+ case WL_OUTPUT_TRANSFORM_270:
+ weston_matrix_rotate_xy(matrix, 0.0f, -1.0f);
+ weston_matrix_translate(matrix, half_h, half_w, 0.0f);
+ break;
+
+ default:
+ break;
+ }
+#endif
+
+ if (base->zoom.active) {
+ /* The base->zoom stuff is in GL coordinate system */
+ mag = 1.0f / (1.0f - base->zoom.spring_z.current);
+ dx = -(base->zoom.trans_x + 1.0f) * half_w;
+ dy = -(base->zoom.trans_y + 1.0f) * half_h;
+ weston_matrix_translate(matrix, dx, dy, 0.0f);
+ weston_matrix_scale(matrix, mag, mag, 1.0f);
+ weston_matrix_translate(matrix, half_w, half_h, 0.0f);
+ }
+}
+
+/* Note: this won't work right for multiple outputs. A DispmanX Element
+ * is tied to one DispmanX Display, i.e. output.
+ */
+static void
+rpi_renderer_repaint_output(struct weston_output *base,
+ pixman_region32_t *output_damage)
+{
+ struct weston_compositor *compositor = base->compositor;
+ struct rpir_output *output = to_rpir_output(base);
+ struct weston_surface *ws;
+ struct rpir_surface *surface;
+ struct wl_list done_list;
+ int layer = 1;
+
+ assert(output->update != DISPMANX_NO_HANDLE);
+
+ output_compute_matrix(base);
+
+ rpi_resource_release(&output->capture_buffer);
+ free(output->capture_data);
+ output->capture_data = NULL;
+
+ /* update all renderable surfaces */
+ wl_list_init(&done_list);
+ wl_list_for_each_reverse(ws, &compositor->surface_list, link) {
+ if (ws->plane != &compositor->primary_plane)
+ continue;
+
+ surface = to_rpir_surface(ws);
+ assert(!wl_list_empty(&surface->link) ||
+ surface->handle == DISPMANX_NO_HANDLE);
+
+ wl_list_remove(&surface->link);
+ wl_list_insert(&done_list, &surface->link);
+ rpir_surface_update(surface, output, output->update, layer++);
+ }
+
+ /* Remove all surfaces that are still on screen, but were
+ * not rendered this time.
+ */
+ rpir_output_dmx_remove_all(output, output->update);
+
+ wl_list_insert_list(&output->surface_list, &done_list);
+ output->update = DISPMANX_NO_HANDLE;
+
+ /* The frame_signal is emitted in rpi_renderer_finish_frame(),
+ * so that the firmware can capture the up-to-date contents.
+ */
+}
+
+static void
+rpi_renderer_flush_damage(struct weston_surface *base)
+{
+ /* Called for every surface just before repainting it, if
+ * having an shm buffer.
+ */
+ struct rpir_surface *surface = to_rpir_surface(base);
+ struct wl_buffer *buffer = surface->buffer_ref.buffer;
+ int ret;
+
+ assert(buffer);
+ assert(wl_buffer_is_shm(buffer));
+
+ ret = rpir_surface_damage(surface, buffer, &base->damage);
+ if (ret)
+ weston_log("%s error: updating Dispmanx resource failed.\n",
+ __func__);
+
+ weston_buffer_reference(&surface->buffer_ref, NULL);
+}
+
+static void
+rpi_renderer_attach(struct weston_surface *base, struct wl_buffer *buffer)
+{
+ /* Called every time a client commits an attach. */
+ static int warned;
+ struct rpir_surface *surface = to_rpir_surface(base);
+
+ assert(surface);
+ if (!surface)
+ return;
+
+ if (buffer && !wl_buffer_is_shm(buffer) && !warned) {
+ weston_log("Error: non-wl_shm buffers not supported.\n");
+ warned = 1;
+ return;
+ }
+
+ weston_buffer_reference(&surface->buffer_ref, buffer);
+
+ /* XXX: need to check if in middle of update
+ if (!buffer && !surface->single_buffer)
+ rpi_resource_release(surface->back); */
+
+ /* XXX: cannot do this, if middle of an update
+ if (surface->handle == DISPMANX_NO_HANDLE)
+ rpi_resource_release(surface->front); */
+
+ /* If buffer is NULL, Weston core unmaps the surface, the surface
+ * will not appear in repaint list, and so rpi_renderer_repaint_output
+ * will remove the DispmanX element. Later, also the front buffer
+ * will be released in the cleanup_list processing.
+ */
+}
+
+static int
+rpi_renderer_create_surface(struct weston_surface *base)
+{
+ struct rpi_renderer *renderer = to_rpi_renderer(base->compositor);
+ struct rpir_surface *surface;
+
+ assert(base->renderer_state == NULL);
+
+ surface = rpir_surface_create(renderer);
+ if (!surface)
+ return -1;
+
+ surface->surface = base;
+ base->renderer_state = surface;
+ return 0;
+}
+
+static void
+rpi_renderer_surface_set_color(struct weston_surface *base,
+ float red, float green, float blue, float alpha)
+{
+ struct rpir_surface *surface = to_rpir_surface(base);
+ uint8_t color[4];
+ VC_RECT_T rect;
+ int ret;
+
+ assert(surface);
+
+ ret = rpi_resource_realloc(surface->back, VC_IMAGE_ARGB8888,
+ 1, 1, 4, 1);
+ if (ret < 0) {
+ weston_log("Error: %s: rpi_resource_realloc failed.\n",
+ __func__);
+ return;
+ }
+
+ color[0] = float2uint8(blue);
+ color[1] = float2uint8(green);
+ color[2] = float2uint8(red);
+ color[3] = float2uint8(alpha);
+
+ vc_dispmanx_rect_set(&rect, 0, 0, 1, 1);
+ ret = vc_dispmanx_resource_write_data(surface->back->handle,
+ VC_IMAGE_ARGB8888,
+ 4, color, &rect);
+ if (ret) {
+ weston_log("Error: %s: resource_write_data failed.\n",
+ __func__);
+ return;
+ }
+
+ DBG("%s: resource %p solid color BGRA %u,%u,%u,%u\n", __func__,
+ surface->back, color[0], color[1], color[2], color[3]);
+
+ /*pixman_region32_copy(&surface->prev_damage, damage);*/
+ surface->need_swap = 1;
+}
+
+static void
+rpi_renderer_destroy_surface(struct weston_surface *base)
+{
+ struct rpir_surface *surface = to_rpir_surface(base);
+
+ assert(surface);
+ assert(surface->surface == base);
+ if (!surface)
+ return;
+
+ surface->surface = NULL;
+ base->renderer_state = NULL;
+
+ /* If guaranteed to not be on screen, just detroy it. */
+ if (wl_list_empty(&surface->link))
+ rpir_surface_destroy(surface);
+
+ /* Otherwise, the surface is either on screen and needs
+ * to be removed by a repaint update, or it is in the
+ * surface_cleanup_list, and will be destroyed by
+ * rpi_renderer_finish_frame().
+ */
+}
+
+static void
+rpi_renderer_destroy(struct weston_compositor *compositor)
+{
+ struct rpi_renderer *renderer = to_rpi_renderer(compositor);
+
+ free(renderer);
+ compositor->renderer = NULL;
+}
+
+WL_EXPORT int
+rpi_renderer_create(struct weston_compositor *compositor,
+ const struct rpi_renderer_parameters *params)
+{
+ struct rpi_renderer *renderer;
+
+ weston_log("Initializing the DispmanX compositing renderer\n");
+
+ renderer = calloc(1, sizeof *renderer);
+ if (renderer == NULL)
+ return -1;
+
+ renderer->single_buffer = params->single_buffer;
+
+ renderer->base.read_pixels = rpi_renderer_read_pixels;
+ renderer->base.repaint_output = rpi_renderer_repaint_output;
+ renderer->base.flush_damage = rpi_renderer_flush_damage;
+ renderer->base.attach = rpi_renderer_attach;
+ renderer->base.create_surface = rpi_renderer_create_surface;
+ renderer->base.surface_set_color = rpi_renderer_surface_set_color;
+ renderer->base.destroy_surface = rpi_renderer_destroy_surface;
+ renderer->base.destroy = rpi_renderer_destroy;
+
+ compositor->renderer = &renderer->base;
+ compositor->read_format = PIXMAN_a8r8g8b8;
+ /* WESTON_CAP_ROTATION_ANY not supported */
+
+ return 0;
+}
+
+WL_EXPORT int
+rpi_renderer_output_create(struct weston_output *base,
+ DISPMANX_DISPLAY_HANDLE_T display)
+{
+ struct rpir_output *output;
+
+ assert(base->renderer_state == NULL);
+
+ output = calloc(1, sizeof *output);
+ if (!output)
+ return -1;
+
+ output->display = display;
+ output->update = DISPMANX_NO_HANDLE;
+ wl_list_init(&output->surface_list);
+ wl_list_init(&output->surface_cleanup_list);
+ rpi_resource_init(&output->capture_buffer);
+ base->renderer_state = output;
+
+ return 0;
+}
+
+WL_EXPORT void
+rpi_renderer_output_destroy(struct weston_output *base)
+{
+ struct rpir_output *output = to_rpir_output(base);
+ struct rpir_surface *surface;
+ DISPMANX_UPDATE_HANDLE_T update;
+
+ rpi_resource_release(&output->capture_buffer);
+ free(output->capture_data);
+ output->capture_data = NULL;
+
+ update = vc_dispmanx_update_start(0);
+ rpir_output_dmx_remove_all(output, update);
+ vc_dispmanx_update_submit_sync(update);
+
+ while (!wl_list_empty(&output->surface_cleanup_list)) {
+ surface = container_of(output->surface_cleanup_list.next,
+ struct rpir_surface, link);
+ if (surface->surface)
+ surface->surface->renderer_state = NULL;
+ rpir_surface_destroy(surface);
+ }
+
+ free(output);
+ base->renderer_state = NULL;
+}
+
+WL_EXPORT void
+rpi_renderer_set_update_handle(struct weston_output *base,
+ DISPMANX_UPDATE_HANDLE_T handle)
+{
+ struct rpir_output *output = to_rpir_output(base);
+
+ output->update = handle;
+}
+
+WL_EXPORT void
+rpi_renderer_finish_frame(struct weston_output *base)
+{
+ struct rpir_output *output = to_rpir_output(base);
+ struct rpir_surface *surface;
+
+ while (!wl_list_empty(&output->surface_cleanup_list)) {
+ surface = container_of(output->surface_cleanup_list.next,
+ struct rpir_surface, link);
+
+ if (surface->surface) {
+ /* The weston_surface still exists, but is
+ * temporarily not visible, and hence its Element
+ * was removed. The current front buffer contents
+ * must be preserved.
+ */
+ if (!surface->single_buffer)
+ rpi_resource_release(surface->back);
+
+ wl_list_remove(&surface->link);
+ wl_list_init(&surface->link);
+ } else {
+ rpir_surface_destroy(surface);
+ }
+ }
+
+ wl_signal_emit(&base->frame_signal, base);
+}
diff --git a/src/rpi-renderer.h b/src/rpi-renderer.h
new file mode 100644
index 0000000..28ae303
--- /dev/null
+++ b/src/rpi-renderer.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright ? 2013 Raspberry Pi Foundation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef RPI_RENDERER_H
+#define RPI_RENDERER_H
+
+struct rpi_renderer_parameters {
+ int single_buffer;
+};
+
+int
+rpi_renderer_create(struct weston_compositor *compositor,
+ const struct rpi_renderer_parameters *params);
+
+int
+rpi_renderer_output_create(struct weston_output *base,
+ DISPMANX_DISPLAY_HANDLE_T display);
+
+void
+rpi_renderer_output_destroy(struct weston_output *base);
+
+void
+rpi_renderer_set_update_handle(struct weston_output *base,
+ DISPMANX_UPDATE_HANDLE_T handle);
+
+void
+rpi_renderer_finish_frame(struct weston_output *base);
+
+#endif /* RPI_RENDERER_H */
--
1.8.1.5
ppaalanen
2013-05-22 15:03:07 UTC
Permalink
From: Pekka Paalanen <ppaalanen at gmail.com>

Replace the GL renderer with the new rpi-renderer on the Raspberry Pi
backend. This makes Weston on rpi not use EGL or GL anymore, at all.

The weston_plane feature is disabled, since the rpi-renderer does the
same, but better.

Add a command line option to select the output transform. It is not a
weston.ini option for now, since the rpi backend does not read the
configuration file yet. Hopefully that will be done later with some
shared code.

Add the rpi options to 'weston --help' output.

Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
configure.ac | 4 +-
src/compositor-rpi.c | 171 +++++++++++++++++++++++++--------------------------
src/compositor.c | 10 +++
3 files changed, 97 insertions(+), 88 deletions(-)

diff --git a/configure.ac b/configure.ac
index 93a6720..2aec1bb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -146,9 +146,9 @@ AC_ARG_ENABLE(rpi-compositor,
AS_HELP_STRING([--disable-rpi-compositor],
[do not build the Raspberry Pi backend]),,
enable_rpi_compositor=yes)
-AM_CONDITIONAL(ENABLE_RPI_COMPOSITOR, test "x$enable_rpi_compositor" = "xyes" -a "x$enable_egl" = "xyes")
+AM_CONDITIONAL(ENABLE_RPI_COMPOSITOR, test "x$enable_rpi_compositor" = "xyes")
have_bcm_host="no"
-if test x$enable_rpi_compositor = xyes -a x$enable_egl = xyes; then
+if test "x$enable_rpi_compositor" = "xyes"; then
AC_DEFINE([BUILD_RPI_COMPOSITOR], [1], [Build the compositor for Raspberry Pi])
PKG_CHECK_MODULES(RPI_COMPOSITOR, [libudev >= 136 mtdev >= 1.1.0])
PKG_CHECK_MODULES(RPI_BCM_HOST, [bcm_host],
diff --git a/src/compositor-rpi.c b/src/compositor-rpi.c
index 3cb2b56..f83e55c 100644
--- a/src/compositor-rpi.c
+++ b/src/compositor-rpi.c
@@ -1,7 +1,7 @@
/*
* Copyright ? 2008-2011 Kristian H?gsberg
* Copyright ? 2011 Intel Corporation
- * Copyright ? 2012 Raspberry Pi Foundation
+ * Copyright ? 2012-2013 Raspberry Pi Foundation
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
@@ -44,7 +44,7 @@
#endif

#include "compositor.h"
-#include "gl-renderer.h"
+#include "rpi-renderer.h"
#include "evdev.h"

/*
@@ -148,8 +148,6 @@ struct rpi_output {
struct rpi_flippipe flippipe;

DISPMANX_DISPLAY_HANDLE_T display;
- EGL_DISPMANX_WINDOW_T egl_window;
- DISPMANX_ELEMENT_HANDLE_T egl_element;

struct wl_list element_list; /* struct rpi_element */
struct wl_list old_element_list; /* struct rpi_element */
@@ -910,9 +908,12 @@ rpi_output_repaint(struct weston_output *base, pixman_region32_t *damage)
DISPMANX_UPDATE_HANDLE_T update;
int layer = 10000;

- DBG("%s\n", __func__);
+ DBG("frame update start\n");

- update = vc_dispmanx_update_start(0);
+ /* Update priority higher than in rpi-renderer's
+ * output destroy function, see rpi_output_destroy().
+ */
+ update = vc_dispmanx_update_start(1);

/* update all live elements */
wl_list_for_each(element, &output->element_list, link) {
@@ -923,20 +924,16 @@ rpi_output_repaint(struct weston_output *base, pixman_region32_t *damage)
/* remove all unused elements */
rpi_remove_elements(&output->old_element_list, update);

- /* schedule callback to rpi_output_update_complete() */
- rpi_dispmanx_update_submit(update, output);
-
- /* XXX: if there is anything to composite in GL,
- * framerate seems to suffer */
- /* XXX: optimise the renderer for the case of nothing to render */
- /* XXX: if nothing to render, remove the element...
- * but how, is destroying the EGLSurface a bad performance hit?
- */
+ rpi_renderer_set_update_handle(&output->base, update);
compositor->base.renderer->repaint_output(&output->base, damage);

pixman_region32_subtract(&primary_plane->damage,
&primary_plane->damage, damage);

+ /* schedule callback to rpi_output_update_complete() */
+ rpi_dispmanx_update_submit(update, output);
+ DBG("frame update submitted\n");
+
/* Move the list of elements into the old_element_list. */
wl_list_insert_list(&output->old_element_list, &output->element_list);
wl_list_init(&output->element_list);
@@ -945,7 +942,9 @@ rpi_output_repaint(struct weston_output *base, pixman_region32_t *damage)
static void
rpi_output_update_complete(struct rpi_output *output, uint64_t time)
{
+ DBG("frame update complete(%" PRIu64 ")\n", time);
rpi_output_destroy_old_elements(output);
+ rpi_renderer_finish_frame(&output->base);
weston_output_finish_frame(&output->base, time);
}

@@ -958,15 +957,12 @@ rpi_output_destroy(struct weston_output *base)

DBG("%s\n", __func__);

- rpi_flippipe_release(&output->flippipe);
-
update = vc_dispmanx_update_start(0);
rpi_remove_elements(&output->element_list, update);
rpi_remove_elements(&output->old_element_list, update);
- vc_dispmanx_element_remove(update, output->egl_element);
vc_dispmanx_update_submit_sync(update);

- gl_renderer_output_destroy(base);
+ rpi_renderer_output_destroy(base);

wl_list_for_each_safe(element, tmp, &output->element_list, link)
rpi_element_destroy(element);
@@ -974,6 +970,15 @@ rpi_output_destroy(struct weston_output *base)
wl_list_for_each_safe(element, tmp, &output->old_element_list, link)
rpi_element_destroy(element);

+ /* rpi_renderer_output_destroy() will schedule a removal of
+ * all Dispmanx Elements, and wait for the update to complete.
+ * Assuming updates are sequential, the wait should guarantee,
+ * that any pending rpi_flippipe_update_complete() callbacks
+ * have happened already. Therefore we can destroy the flippipe
+ * now.
+ */
+ rpi_flippipe_release(&output->flippipe);
+
wl_list_remove(&output->base.link);
weston_output_destroy(&output->base);

@@ -982,21 +987,45 @@ rpi_output_destroy(struct weston_output *base)
free(output);
}

+static const char *transform_names[] = {
+ [WL_OUTPUT_TRANSFORM_NORMAL] = "normal",
+ [WL_OUTPUT_TRANSFORM_90] = "90",
+ [WL_OUTPUT_TRANSFORM_180] = "180",
+ [WL_OUTPUT_TRANSFORM_270] = "270",
+ [WL_OUTPUT_TRANSFORM_FLIPPED] = "flipped",
+ [WL_OUTPUT_TRANSFORM_FLIPPED_90] = "flipped-90",
+ [WL_OUTPUT_TRANSFORM_FLIPPED_180] = "flipped-180",
+ [WL_OUTPUT_TRANSFORM_FLIPPED_270] = "flipped-270",
+};
+
+static int
+str2transform(const char *name)
+{
+ unsigned i;
+
+ for (i = 0; i < ARRAY_LENGTH(transform_names); i++)
+ if (strcmp(name, transform_names[i]) == 0)
+ return i;
+
+ return -1;
+}
+
+static const char *
+transform2str(uint32_t output_transform)
+{
+ if (output_transform >= ARRAY_LENGTH(transform_names))
+ return "<illegal value>";
+
+ return transform_names[output_transform];
+}
+
static int
-rpi_output_create(struct rpi_compositor *compositor)
+rpi_output_create(struct rpi_compositor *compositor, uint32_t transform)
{
struct rpi_output *output;
DISPMANX_MODEINFO_T modeinfo;
- DISPMANX_UPDATE_HANDLE_T update;
- VC_RECT_T dst_rect;
- VC_RECT_T src_rect;
int ret;
float mm_width, mm_height;
- VC_DISPMANX_ALPHA_T alphasetup = {
- DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS,
- 255, /* opacity 0-255 */
- 0 /* mask resource handle */
- };

output = calloc(1, sizeof *output);
if (!output)
@@ -1024,32 +1053,10 @@ rpi_output_create(struct rpi_compositor *compositor)
goto out_dmx_close;
}

- vc_dispmanx_rect_set(&dst_rect, 0, 0, modeinfo.width, modeinfo.height);
- vc_dispmanx_rect_set(&src_rect, 0, 0,
- modeinfo.width << 16, modeinfo.height << 16);
-
- update = vc_dispmanx_update_start(0);
- output->egl_element = vc_dispmanx_element_add(update,
- output->display,
- 0 /* layer */,
- &dst_rect,
- 0 /* src resource */,
- &src_rect,
- DISPMANX_PROTECTION_NONE,
- &alphasetup,
- NULL /* clamp */,
- DISPMANX_NO_ROTATE);
- vc_dispmanx_update_submit_sync(update);
-
- output->egl_window.element = output->egl_element;
- output->egl_window.width = modeinfo.width;
- output->egl_window.height = modeinfo.height;
-
output->base.start_repaint_loop = rpi_output_start_repaint_loop;
output->base.repaint = rpi_output_repaint;
output->base.destroy = rpi_output_destroy;
- if (compositor->max_planes > 0)
- output->base.assign_planes = rpi_output_assign_planes;
+ output->base.assign_planes = NULL;
output->base.set_backlight = NULL;
output->base.set_dpms = NULL;
output->base.switch_mode = NULL;
@@ -1080,36 +1087,27 @@ 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);
+ transform);

- if (gl_renderer_output_create(&output->base,
- (EGLNativeWindowType)&output->egl_window) < 0)
+ if (rpi_renderer_output_create(&output->base, output->display) < 0)
goto out_output;

- if (!eglSurfaceAttrib(gl_renderer_display(&compositor->base),
- gl_renderer_output_surface(&output->base),
- EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED)) {
- weston_log("Failed to set swap behaviour to preserved.\n");
- gl_renderer_print_egl_error_state();
- goto out_gl;
- }
-
wl_list_insert(compositor->base.output_list.prev, &output->base.link);

weston_log("Raspberry Pi HDMI output %dx%d px\n",
output->mode.width, output->mode.height);
weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
output->mode.refresh / 1000);
+ weston_log_continue(STAMP_SPACE "orientation: %s\n",
+ transform2str(output->base.transform));
+
+ if (!strncmp(transform2str(output->base.transform), "flipped", 7))
+ weston_log("warning: flipped output transforms may not work\n");

return 0;

-out_gl:
- gl_renderer_output_destroy(&output->base);
out_output:
weston_output_destroy(&output->base);
- update = vc_dispmanx_update_start(0);
- vc_dispmanx_element_remove(update, output->egl_element);
- vc_dispmanx_update_submit_sync(update);

out_dmx_close:
vc_dispmanx_display_close(output->display);
@@ -1436,7 +1434,8 @@ switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *d
struct rpi_parameters {
int tty;
int max_planes;
- int single_buffer;
+ struct rpi_renderer_parameters renderer;
+ uint32_t output_transform;
};

static struct weston_compositor *
@@ -1446,16 +1445,6 @@ rpi_compositor_create(struct wl_display *display, int *argc, char *argv[],
struct rpi_compositor *compositor;
const char *seat = default_seat;
uint32_t key;
- static const EGLint config_attrs[] = {
- EGL_SURFACE_TYPE, EGL_WINDOW_BIT |
- EGL_SWAP_BEHAVIOR_PRESERVED_BIT,
- EGL_RED_SIZE, 1,
- EGL_GREEN_SIZE, 1,
- EGL_BLUE_SIZE, 1,
- EGL_ALPHA_SIZE, 0,
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL_NONE
- };

weston_log("initializing Raspberry Pi backend\n");

@@ -1485,7 +1474,7 @@ rpi_compositor_create(struct wl_display *display, int *argc, char *argv[],
compositor->base.focus = 1;
compositor->prev_state = WESTON_COMPOSITOR_ACTIVE;
compositor->max_planes = int_max(param->max_planes, 0);
- compositor->single_buffer = param->single_buffer;
+ compositor->single_buffer = param->renderer.single_buffer;

weston_log("Maximum number of additional Dispmanx planes: %d\n",
compositor->max_planes);
@@ -1506,18 +1495,17 @@ rpi_compositor_create(struct wl_display *display, int *argc, char *argv[],
*/
bcm_host_init();

- if (gl_renderer_create(&compositor->base, EGL_DEFAULT_DISPLAY,
- config_attrs, NULL) < 0)
+ if (rpi_renderer_create(&compositor->base, &param->renderer) < 0)
goto out_tty;

- if (rpi_output_create(compositor) < 0)
- goto out_gl;
+ if (rpi_output_create(compositor, param->output_transform) < 0)
+ goto out_renderer;

evdev_input_create(&compositor->base, compositor->udev, seat);

return &compositor->base;

-out_gl:
+out_renderer:
compositor->base.renderer->destroy(&compositor->base);

out_tty:
@@ -1556,20 +1544,31 @@ WL_EXPORT struct weston_compositor *
backend_init(struct wl_display *display, int *argc, char *argv[],
int config_fd)
{
+ const char *transform = "normal";
+ int ret;
+
struct rpi_parameters param = {
.tty = 0, /* default to current tty */
.max_planes = DEFAULT_MAX_PLANES,
- .single_buffer = 0,
+ .renderer.single_buffer = 0,
+ .output_transform = WL_OUTPUT_TRANSFORM_NORMAL,
};

const struct weston_option rpi_options[] = {
{ WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
{ WESTON_OPTION_INTEGER, "max-planes", 0, &param.max_planes },
{ WESTON_OPTION_BOOLEAN, "single-buffer", 0,
- &param.single_buffer },
+ &param.renderer.single_buffer },
+ { WESTON_OPTION_STRING, "transform", 0, &transform },
};

parse_options(rpi_options, ARRAY_LENGTH(rpi_options), argc, argv);

+ ret = str2transform(transform);
+ if (ret < 0)
+ weston_log("invalid transform \"%s\"\n", transform);
+ else
+ param.output_transform = ret;
+
return rpi_compositor_create(display, argc, argv, config_fd, &param);
}
diff --git a/src/compositor.c b/src/compositor.c
index 33010dd..65da583 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -3107,6 +3107,16 @@ usage(int error_code)
" --height=HEIGHT\tHeight of Wayland surface\n"
" --display=DISPLAY\tWayland display to connect to\n\n");

+#if defined(BUILD_RPI_COMPOSITOR) && defined(HAVE_BCM_HOST)
+ fprintf(stderr,
+ "Options for rpi-backend.so:\n\n"
+ " --tty=TTY\t\tThe tty to use\n"
+ " --single-buffer\tUse single-buffered Dispmanx elements.\n"
+ " --transform=TR\tThe output transformation, TR is one of:\n"
+ "\tnormal 90 180 270 flipped flipped-90 flipped-180 flipped-270\n"
+ "\n");
+#endif
+
exit(error_code);
}
--
1.8.1.5
ppaalanen
2013-05-22 15:03:08 UTC
Permalink
From: Pekka Paalanen <ppaalanen at gmail.com>

There is no need to support weston_plane anymore.
The max-planes option is removed as unused.

Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
src/compositor-rpi.c | 727 ---------------------------------------------------
1 file changed, 727 deletions(-)

diff --git a/src/compositor-rpi.c b/src/compositor-rpi.c
index f83e55c..64ef0ff 100644
--- a/src/compositor-rpi.c
+++ b/src/compositor-rpi.c
@@ -47,51 +47,6 @@
#include "rpi-renderer.h"
#include "evdev.h"

-/*
- * Dispmanx API offers alpha-blended overlays for hardware compositing.
- * The final composite consists of dispmanx elements, and their contents:
- * the dispmanx resource assigned to the element. The elements may be
- * scanned out directly, or composited to a temporary surface, depending on
- * how the firmware decides to handle the scene. Updates to multiple elements
- * may be queued in a single dispmanx update object, resulting in atomic and
- * vblank synchronized display updates.
- *
- * To avoid tearing and display artifacts, the current dispmanx resource in a
- * dispmanx element must not be touched. Therefore each element must be
- * double-buffered, using two resources, the front and the back. The update
- * sequence is:
- * 0. the front resource is already in-use, the back resource is unused
- * 1. write data into the back resource
- * 2. submit an element update, back becomes in-use
- * 3. swap back and front pointers (both are in-use now)
- * 4. wait for update_submit completion, the new back resource becomes unused
- *
- * A resource may be destroyed only, when the update removing the element has
- * completed. Otherwise you risk showing an incomplete composition.
- *
- * The dispmanx element used as the native window for EGL does not need
- * manually allocated resources, EGL does double-buffering internally.
- * Unfortunately it also means, that we cannot alternate between two
- * buffers like the DRM backend does, since we have no control over what
- * resources EGL uses. We are forced to use EGL_BUFFER_PRESERVED as the
- * EGL_SWAP_BEHAVIOR to avoid repainting the whole output every frame.
- *
- * We also cannot bundle eglSwapBuffers into our own display update, which
- * means that Weston's primary plane updates and the overlay updates may
- * happen unsynchronized.
- */
-
-#ifndef ELEMENT_CHANGE_LAYER
-/* copied from interface/vmcs_host/vc_vchi_dispmanx.h of userland.git */
-#define ELEMENT_CHANGE_LAYER (1<<0)
-#define ELEMENT_CHANGE_OPACITY (1<<1)
-#define ELEMENT_CHANGE_DEST_RECT (1<<2)
-#define ELEMENT_CHANGE_SRC_RECT (1<<3)
-#define ELEMENT_CHANGE_MASK_RESOURCE (1<<4)
-#define ELEMENT_CHANGE_TRANSFORM (1<<5)
-#endif
-
-/* Enabling this debugging incurs a significant performance hit */
#if 0
#define DBG(...) \
weston_log(__VA_ARGS__)
@@ -99,40 +54,9 @@
#define DBG(...) do {} while (0)
#endif

-/* If we had a fully featured vc_dispmanx_resource_write_data()... */
-/*#define HAVE_RESOURCE_WRITE_DATA_RECT 1*/
-
struct rpi_compositor;
struct rpi_output;

-struct rpi_resource {
- DISPMANX_RESOURCE_HANDLE_T handle;
- int width;
- int height; /* height of the image (valid pixel data) */
- int stride; /* bytes */
- int buffer_height; /* height of the buffer */
- VC_IMAGE_TYPE_T ifmt;
-};
-
-struct rpi_element {
- struct wl_list link;
- struct weston_plane plane;
- struct rpi_output *output;
-
- DISPMANX_ELEMENT_HANDLE_T handle;
- int layer;
- int need_swap;
- int single_buffer;
-
- struct rpi_resource resources[2];
- struct rpi_resource *front;
- struct rpi_resource *back;
- pixman_region32_t prev_damage;
-
- struct weston_surface *surface;
- struct wl_listener surface_destroy_listener;
-};
-
struct rpi_flippipe {
int readfd;
int writefd;
@@ -148,9 +72,6 @@ struct rpi_output {
struct rpi_flippipe flippipe;

DISPMANX_DISPLAY_HANDLE_T display;
-
- struct wl_list element_list; /* struct rpi_element */
- struct wl_list old_element_list; /* struct rpi_element */
};

struct rpi_seat {
@@ -169,7 +90,6 @@ struct rpi_compositor {
struct udev *udev;
struct tty *tty;

- int max_planes; /* per output, really */
int single_buffer;
};

@@ -191,425 +111,6 @@ to_rpi_compositor(struct weston_compositor *base)
return container_of(base, struct rpi_compositor, base);
}

-static inline int
-int_max(int a, int b)
-{
- return a > b ? a : b;
-}
-
-static void
-rpi_resource_init(struct rpi_resource *resource)
-{
- resource->handle = DISPMANX_NO_HANDLE;
-}
-
-static void
-rpi_resource_release(struct rpi_resource *resource)
-{
- if (resource->handle == DISPMANX_NO_HANDLE)
- return;
-
- vc_dispmanx_resource_delete(resource->handle);
- DBG("resource %p release\n", resource);
- resource->handle = DISPMANX_NO_HANDLE;
-}
-
-static int
-rpi_resource_realloc(struct rpi_resource *resource, VC_IMAGE_TYPE_T ifmt,
- int width, int height, int stride, int buffer_height)
-{
- uint32_t dummy;
-
- if (resource->handle != DISPMANX_NO_HANDLE &&
- resource->width == width &&
- resource->height == height &&
- resource->stride == stride &&
- resource->buffer_height == buffer_height &&
- resource->ifmt == ifmt)
- return 0;
-
- rpi_resource_release(resource);
-
- /* NOTE: if stride is not a multiple of 16 pixels in bytes,
- * the vc_image_* functions may break. Dispmanx elements
- * should be fine, though. Buffer_height probably has similar
- * constraints, too.
- */
- resource->handle =
- vc_dispmanx_resource_create(ifmt,
- width | (stride << 16),
- height | (buffer_height << 16),
- &dummy);
- if (resource->handle == DISPMANX_NO_HANDLE)
- return -1;
-
- resource->width = width;
- resource->height = height;
- resource->stride = stride;
- resource->buffer_height = buffer_height;
- resource->ifmt = ifmt;
- DBG("resource %p alloc\n", resource);
- return 0;
-}
-
-static VC_IMAGE_TYPE_T
-shm_buffer_get_vc_format(struct wl_buffer *buffer)
-{
- switch (wl_shm_buffer_get_format(buffer)) {
- case WL_SHM_FORMAT_XRGB8888:
- return VC_IMAGE_XRGB8888;
- case WL_SHM_FORMAT_ARGB8888:
- return VC_IMAGE_ARGB8888;
- default:
- /* invalid format */
- return VC_IMAGE_MIN;
- }
-}
-
-static int
-rpi_resource_update(struct rpi_resource *resource, struct wl_buffer *buffer,
- pixman_region32_t *region)
-{
- pixman_region32_t write_region;
- pixman_box32_t *r;
- VC_RECT_T rect;
- VC_IMAGE_TYPE_T ifmt;
- uint32_t *pixels;
- int width;
- int height;
- int stride;
- int ret;
-#ifdef HAVE_RESOURCE_WRITE_DATA_RECT
- int n;
-#endif
-
- if (!buffer)
- return -1;
-
- ifmt = shm_buffer_get_vc_format(buffer);
- width = wl_shm_buffer_get_width(buffer);
- height = wl_shm_buffer_get_height(buffer);
- stride = wl_shm_buffer_get_stride(buffer);
- pixels = wl_shm_buffer_get_data(buffer);
-
- if (rpi_resource_realloc(resource, ifmt, width, height,
- stride, height) < 0)
- return -1;
-
- pixman_region32_init(&write_region);
- pixman_region32_intersect_rect(&write_region, region,
- 0, 0, width, height);
-
-#ifdef HAVE_RESOURCE_WRITE_DATA_RECT
- /* XXX: Can this do a format conversion, so that scanout does not have to? */
- r = pixman_region32_rectangles(&write_region, &n);
- while (n--) {
- vc_dispmanx_rect_set(&rect, r[n].x1, r[n].y1,
- r[n].x2 - r[n].x1, r[n].y2 - r[n].y1);
-
- ret = vc_dispmanx_resource_write_data_rect(resource->handle,
- ifmt, stride,
- pixels, &rect,
- rect.x, rect.y);
- DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
- rect.width, rect.height, rect.x, rect.y, ret);
- if (ret)
- break;
- }
-#else
- /* vc_dispmanx_resource_write_data() ignores ifmt,
- * rect.x, rect.width, and uses stride only for computing
- * the size of the transfer as rect.height * stride.
- * Therefore we can only write rows starting at x=0.
- * To be able to write more than one scanline at a time,
- * the resource must have been created with the same stride
- * as used here, and we must write full scanlines.
- */
-
- r = pixman_region32_extents(&write_region);
- vc_dispmanx_rect_set(&rect, 0, r->y1, width, r->y2 - r->y1);
- ret = vc_dispmanx_resource_write_data(resource->handle, ifmt,
- stride, pixels, &rect);
- DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
- width, r->y2 - r->y1, 0, r->y1, ret);
-#endif
-
- pixman_region32_fini(&write_region);
-
- return ret ? -1 : 0;
-}
-
-static void
-rpi_element_handle_surface_destroy(struct wl_listener *listener, void *data)
-{
- struct rpi_element *element =
- container_of(listener, struct rpi_element,
- surface_destroy_listener);
-
- element->surface = NULL;
-}
-
-static struct rpi_element *
-rpi_element_create(struct rpi_output *output, struct weston_surface *surface)
-{
- struct rpi_element *element;
-
- element = calloc(1, sizeof *element);
- if (!element)
- return NULL;
-
- element->output = output;
- element->single_buffer = output->single_buffer;
- element->handle = DISPMANX_NO_HANDLE;
- rpi_resource_init(&element->resources[0]);
- rpi_resource_init(&element->resources[1]);
- element->front = &element->resources[0];
-
- if (element->single_buffer) {
- element->back = element->front;
- } else {
- element->back = &element->resources[1];
- }
-
- pixman_region32_init(&element->prev_damage);
-
- weston_plane_init(&element->plane, floor(surface->geometry.x),
- floor(surface->geometry.y));
-
- element->surface = surface;
- element->surface_destroy_listener.notify =
- rpi_element_handle_surface_destroy;
- wl_signal_add(&surface->resource.destroy_signal,
- &element->surface_destroy_listener);
-
- wl_list_insert(output->element_list.prev, &element->link);
-
- return element;
-}
-
-static void
-rpi_element_destroy(struct rpi_element *element)
-{
- struct weston_surface *surface = element->surface;
-
- if (surface) {
- if (surface->plane == &element->plane) {
- /* If a surface, that was on a plane, gets hidden,
- * it will not appear in the repaint surface list,
- * is never considered in rpi_output_assign_planes(),
- * and hence can stay assigned to this element's plane.
- * We need to reassign it here.
- */
- DBG("surface %p (%dx%d@%.1f,%.1f) to primary plane*\n",
- surface,
- surface->geometry.width, surface->geometry.height,
- surface->geometry.x, surface->geometry.y);
- weston_surface_move_to_plane(surface,
- &surface->compositor->primary_plane);
- }
- wl_list_remove(&element->surface_destroy_listener.link);
- }
-
- wl_list_remove(&element->link);
- weston_plane_release(&element->plane);
-
- if (element->handle != DISPMANX_NO_HANDLE)
- weston_log("ERROR rpi: destroying on-screen element\n");
-
- pixman_region32_fini(&element->prev_damage);
- rpi_resource_release(&element->resources[0]);
- rpi_resource_release(&element->resources[1]);
- DBG("element %p destroyed (%u)\n", element, element->handle);
-
- free(element);
-}
-
-static void
-rpi_element_reuse(struct rpi_element *element)
-{
- wl_list_remove(&element->link);
- wl_list_insert(element->output->element_list.prev, &element->link);
-}
-
-static void
-rpi_element_schedule_destroy(struct rpi_element *element)
-{
- wl_list_remove(&element->link);
- wl_list_insert(element->output->old_element_list.prev,
- &element->link);
-}
-
-static int
-rpi_element_damage(struct rpi_element *element, struct wl_buffer *buffer,
- pixman_region32_t *damage)
-{
- pixman_region32_t upload;
- int ret;
-
- if (!pixman_region32_not_empty(damage))
- return 0;
-
- DBG("element %p update resource %p\n", element, element->back);
-
- if (element->single_buffer) {
- ret = rpi_resource_update(element->back, buffer, damage);
- } else {
- pixman_region32_init(&upload);
- pixman_region32_union(&upload, &element->prev_damage, damage);
- ret = rpi_resource_update(element->back, buffer, &upload);
- pixman_region32_fini(&upload);
- }
-
- pixman_region32_copy(&element->prev_damage, damage);
- element->need_swap = 1;
-
- return ret;
-}
-
-static void
-rpi_element_compute_rects(struct rpi_element *element,
- VC_RECT_T *src_rect, VC_RECT_T *dst_rect)
-{
- struct weston_output *output = &element->output->base;
- int src_x, src_y;
- int dst_x, dst_y;
- int width, height;
-
- /* assume element->plane.{x,y} == element->surface->geometry.{x,y} */
- src_x = 0;
- src_y = 0;
- width = element->surface->geometry.width;
- height = element->surface->geometry.height;
-
- dst_x = element->plane.x - output->x;
- dst_y = element->plane.y - output->y;
-
- if (dst_x < 0) {
- width += dst_x;
- src_x -= dst_x;
- dst_x = 0;
- }
-
- if (dst_y < 0) {
- height += dst_y;
- src_y -= dst_y;
- dst_y = 0;
- }
-
- width = int_max(width, 0);
- height = int_max(height, 0);
-
- /* src_rect is in 16.16, dst_rect is in 32.0 unsigned fixed point */
- vc_dispmanx_rect_set(src_rect, src_x << 16, src_y << 16,
- width << 16, height << 16);
- vc_dispmanx_rect_set(dst_rect, dst_x, dst_y, width, height);
-}
-
-static void
-rpi_element_dmx_add(struct rpi_element *element,
- DISPMANX_UPDATE_HANDLE_T update, int layer)
-{
- VC_DISPMANX_ALPHA_T alphasetup = {
- DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_PREMULT,
- 255, /* opacity 0-255 */
- 0 /* mask resource handle */
- };
- VC_RECT_T dst_rect;
- VC_RECT_T src_rect;
-
- rpi_element_compute_rects(element, &src_rect, &dst_rect);
-
- element->handle = vc_dispmanx_element_add(
- update,
- element->output->display,
- layer,
- &dst_rect,
- element->back->handle,
- &src_rect,
- DISPMANX_PROTECTION_NONE,
- &alphasetup,
- NULL /* clamp */,
- DISPMANX_NO_ROTATE);
- DBG("element %p add %u\n", element, element->handle);
-}
-
-static void
-rpi_element_dmx_swap(struct rpi_element *element,
- DISPMANX_UPDATE_HANDLE_T update)
-{
- VC_RECT_T rect;
- pixman_box32_t *r;
-
- /* XXX: skip, iff resource was not reallocated, and single-buffering */
- vc_dispmanx_element_change_source(update, element->handle,
- element->back->handle);
-
- /* This is current damage now, after rpi_assign_plane() */
- r = pixman_region32_extents(&element->prev_damage);
-
- vc_dispmanx_rect_set(&rect, r->x1, r->y1,
- r->x2 - r->x1, r->y2 - r->y1);
- vc_dispmanx_element_modified(update, element->handle, &rect);
- DBG("element %p swap\n", element);
-}
-
-static void
-rpi_element_dmx_move(struct rpi_element *element,
- DISPMANX_UPDATE_HANDLE_T update, int layer)
-{
- VC_RECT_T dst_rect;
- VC_RECT_T src_rect;
-
- /* XXX: return early, if all attributes stay the same */
-
- rpi_element_compute_rects(element, &src_rect, &dst_rect);
-
- vc_dispmanx_element_change_attributes(
- update,
- element->handle,
- ELEMENT_CHANGE_LAYER |
- ELEMENT_CHANGE_DEST_RECT |
- ELEMENT_CHANGE_SRC_RECT,
- layer,
- 255,
- &dst_rect,
- &src_rect,
- DISPMANX_NO_HANDLE,
- VC_IMAGE_ROT0);
- DBG("element %p move\n", element);
-}
-
-static int
-rpi_element_update(struct rpi_element *element,
- DISPMANX_UPDATE_HANDLE_T update, int layer)
-{
- struct rpi_resource *tmp;
-
- if (element->handle == DISPMANX_NO_HANDLE) {
- /* need_swap is already true, see rpi_assign_plane() */
-
- rpi_element_dmx_add(element, update, layer);
- if (element->handle == DISPMANX_NO_HANDLE)
- weston_log("ERROR rpi: element_add() failed.\n");
- } else {
- if (element->need_swap)
- rpi_element_dmx_swap(element, update);
- rpi_element_dmx_move(element, update, layer);
- }
- element->layer = layer;
-
- if (element->need_swap) {
- tmp = element->front;
- element->front = element->back;
- element->back = tmp;
- element->need_swap = 0;
- DBG("new back %p, new front %p\n",
- element->back, element->front);
- }
-
- return 0;
-}
-
static uint64_t
rpi_get_current_time(void)
{
@@ -714,181 +215,6 @@ rpi_flippipe_release(struct rpi_flippipe *flippipe)
close(flippipe->writefd);
}

-static struct rpi_element *
-find_rpi_element_from_surface(struct weston_surface *surface)
-{
- struct wl_listener *listener;
- struct rpi_element *element;
-
- listener = wl_signal_get(&surface->resource.destroy_signal,
- rpi_element_handle_surface_destroy);
- if (!listener)
- return NULL;
-
- element = container_of(listener, struct rpi_element,
- surface_destroy_listener);
-
- if (element->surface != surface)
- weston_log("ERROR rpi: sanity check failure in %s.\n",
- __func__);
-
- return element;
-}
-
-static struct rpi_element *
-rpi_assign_plane(struct weston_surface *surface, struct rpi_output *output)
-{
- struct rpi_element *element;
-
- /* dispmanx elements cannot transform */
- if (surface->transform.enabled) {
- /* XXX: inspect the transformation matrix, we might still
- * be able to put it into an element; scaling, additional
- * translation (window titlebar context menus?)
- */
- DBG("surface %p rejected: transform\n", surface);
- return NULL;
- }
-
- /* only shm surfaces supported */
- if (surface->buffer_ref.buffer &&
- !wl_buffer_is_shm(surface->buffer_ref.buffer)) {
- DBG("surface %p rejected: not shm\n", surface);
- return NULL;
- }
-
- if (surface->buffer_transform != WL_OUTPUT_TRANSFORM_NORMAL) {
- DBG("surface %p rejected: unsupported buffer transform\n",
- surface);
- return NULL;
- }
-
- /* check if this surface previously belonged to an element */
- element = find_rpi_element_from_surface(surface);
-
- if (element) {
- rpi_element_reuse(element);
- element->plane.x = floor(surface->geometry.x);
- element->plane.y = floor(surface->geometry.y);
- DBG("surface %p reuse element %p\n", surface, element);
- } else {
- if (!surface->buffer_ref.buffer) {
- DBG("surface %p rejected: no buffer\n", surface);
- return NULL;
- }
-
- element = rpi_element_create(output, surface);
- DBG("element %p created\n", element);
- }
-
- if (!element) {
- DBG("surface %p rejected: no element\n", surface);
- return NULL;
- }
-
- return element;
-}
-
-static void
-rpi_output_assign_planes(struct weston_output *base)
-{
- struct rpi_output *output = to_rpi_output(base);
- struct rpi_compositor *compositor = output->compositor;
- struct weston_surface *surface;
- pixman_region32_t overlap;
- pixman_region32_t surface_overlap;
- struct rpi_element *element;
- int n = 0;
-
- /* Construct the list of rpi_elements to be used into
- * output->element_list, which is empty right now.
- * Re-used elements are moved from old_element_list to
- * element_list. */
-
- DBG("%s\n", __func__);
-
- pixman_region32_init(&overlap);
- wl_list_for_each(surface, &compositor->base.surface_list, link) {
- /* always, since all buffers are shm on rpi */
- surface->keep_buffer = 1;
-
- pixman_region32_init(&surface_overlap);
- pixman_region32_intersect(&surface_overlap, &overlap,
- &surface->transform.boundingbox);
-
- element = NULL;
- if (!pixman_region32_not_empty(&surface_overlap) &&
- n < compositor->max_planes)
- element = rpi_assign_plane(surface, output);
-
- if (element) {
- weston_surface_move_to_plane(surface, &element->plane);
- DBG("surface %p (%dx%d@%.1f,%.1f) to element %p\n",
- surface,
- surface->geometry.width, surface->geometry.height,
- surface->geometry.x, surface->geometry.y, element);
-
- /* weston_surface_move_to_plane() does full-surface
- * damage, if the plane is new, so no need to force
- * initial resource update.
- */
- if (rpi_element_damage(element,
- surface->buffer_ref.buffer,
- &surface->damage) < 0) {
- rpi_element_schedule_destroy(element);
- DBG("surface %p rejected: resource update failed\n",
- surface);
- element = NULL;
- } else {
- n++;
- }
- }
-
- if (!element) {
- weston_surface_move_to_plane(surface,
- &compositor->base.primary_plane);
- DBG("surface %p (%dx%d@%.1f,%.1f) to primary plane\n",
- surface,
- surface->geometry.width, surface->geometry.height,
- surface->geometry.x, surface->geometry.y);
- pixman_region32_union(&overlap, &overlap,
- &surface->transform.boundingbox);
- }
-
- pixman_region32_fini(&surface_overlap);
- }
- pixman_region32_fini(&overlap);
-}
-
-static void
-rpi_remove_elements(struct wl_list *element_list,
- DISPMANX_UPDATE_HANDLE_T update)
-{
- struct rpi_element *element;
-
- wl_list_for_each(element, element_list, link) {
- if (element->handle == DISPMANX_NO_HANDLE)
- continue;
-
- vc_dispmanx_element_remove(update, element->handle);
- DBG("element %p remove %u\n", element, element->handle);
- element->handle = DISPMANX_NO_HANDLE;
- }
-}
-
-static void
-rpi_output_destroy_old_elements(struct rpi_output *output)
-{
- struct rpi_element *element, *tmp;
-
- wl_list_for_each_safe(element, tmp, &output->old_element_list, link) {
- if (element->handle != DISPMANX_NO_HANDLE)
- continue;
-
- rpi_element_destroy(element);
- }
-}
-
static void
rpi_output_start_repaint_loop(struct weston_output *output)
{
@@ -904,9 +230,7 @@ rpi_output_repaint(struct weston_output *base, pixman_region32_t *damage)
struct rpi_output *output = to_rpi_output(base);
struct rpi_compositor *compositor = output->compositor;
struct weston_plane *primary_plane = &compositor->base.primary_plane;
- struct rpi_element *element;
DISPMANX_UPDATE_HANDLE_T update;
- int layer = 10000;

DBG("frame update start\n");

@@ -915,15 +239,6 @@ rpi_output_repaint(struct weston_output *base, pixman_region32_t *damage)
*/
update = vc_dispmanx_update_start(1);

- /* update all live elements */
- wl_list_for_each(element, &output->element_list, link) {
- if (rpi_element_update(element, update, layer--) < 0)
- weston_log("ERROR rpi: element update failed.\n");
- }
-
- /* remove all unused elements */
- rpi_remove_elements(&output->old_element_list, update);
-
rpi_renderer_set_update_handle(&output->base, update);
compositor->base.renderer->repaint_output(&output->base, damage);

@@ -933,17 +248,12 @@ rpi_output_repaint(struct weston_output *base, pixman_region32_t *damage)
/* schedule callback to rpi_output_update_complete() */
rpi_dispmanx_update_submit(update, output);
DBG("frame update submitted\n");
-
- /* Move the list of elements into the old_element_list. */
- wl_list_insert_list(&output->old_element_list, &output->element_list);
- wl_list_init(&output->element_list);
}

static void
rpi_output_update_complete(struct rpi_output *output, uint64_t time)
{
DBG("frame update complete(%" PRIu64 ")\n", time);
- rpi_output_destroy_old_elements(output);
rpi_renderer_finish_frame(&output->base);
weston_output_finish_frame(&output->base, time);
}
@@ -952,24 +262,11 @@ static void
rpi_output_destroy(struct weston_output *base)
{
struct rpi_output *output = to_rpi_output(base);
- DISPMANX_UPDATE_HANDLE_T update;
- struct rpi_element *element, *tmp;

DBG("%s\n", __func__);

- update = vc_dispmanx_update_start(0);
- rpi_remove_elements(&output->element_list, update);
- rpi_remove_elements(&output->old_element_list, update);
- vc_dispmanx_update_submit_sync(update);
-
rpi_renderer_output_destroy(base);

- wl_list_for_each_safe(element, tmp, &output->element_list, link)
- rpi_element_destroy(element);
-
- wl_list_for_each_safe(element, tmp, &output->old_element_list, link)
- rpi_element_destroy(element);
-
/* rpi_renderer_output_destroy() will schedule a removal of
* all Dispmanx Elements, and wait for the update to complete.
* Assuming updates are sequential, the wait should guarantee,
@@ -1033,8 +330,6 @@ rpi_output_create(struct rpi_compositor *compositor, uint32_t transform)

output->compositor = compositor;
output->single_buffer = compositor->single_buffer;
- wl_list_init(&output->element_list);
- wl_list_init(&output->old_element_list);

if (rpi_flippipe_init(&output->flippipe, output) < 0) {
weston_log("Creating message pipe failed.\n");
@@ -1433,7 +728,6 @@ switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *d

struct rpi_parameters {
int tty;
- int max_planes;
struct rpi_renderer_parameters renderer;
uint32_t output_transform;
};
@@ -1473,11 +767,8 @@ rpi_compositor_create(struct wl_display *display, int *argc, char *argv[],

compositor->base.focus = 1;
compositor->prev_state = WESTON_COMPOSITOR_ACTIVE;
- compositor->max_planes = int_max(param->max_planes, 0);
compositor->single_buffer = param->renderer.single_buffer;

- weston_log("Maximum number of additional Dispmanx planes: %d\n",
- compositor->max_planes);
weston_log("Dispmanx planes are %s buffered.\n",
compositor->single_buffer ? "single" : "double");

@@ -1524,22 +815,6 @@ out_free:
return NULL;
}

-/*
- * If you have a recent enough firmware in Raspberry Pi, that
- * supports falling back to off-line hardware compositing, and
- * you have enabled it with dispmanx_offline=1 in /boot/config.txt,
- * then VideoCore should be able to handle almost 100 Dispmanx
- * elements. Therefore use 80 as the default limit.
- *
- * If you don't have off-line compositing support, this would be
- * better as something like 10. Failing on-line compositing may
- * show up as visible glitches, HDMI blanking, or invisible surfaces.
- *
- * When the max-planes number is reached, rpi-backend will start
- * to fall back to GLESv2 compositing.
- */
-#define DEFAULT_MAX_PLANES 80
-
WL_EXPORT struct weston_compositor *
backend_init(struct wl_display *display, int *argc, char *argv[],
int config_fd)
@@ -1549,14 +824,12 @@ backend_init(struct wl_display *display, int *argc, char *argv[],

struct rpi_parameters param = {
.tty = 0, /* default to current tty */
- .max_planes = DEFAULT_MAX_PLANES,
.renderer.single_buffer = 0,
.output_transform = WL_OUTPUT_TRANSFORM_NORMAL,
};

const struct weston_option rpi_options[] = {
{ WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
- { WESTON_OPTION_INTEGER, "max-planes", 0, &param.max_planes },
{ WESTON_OPTION_BOOLEAN, "single-buffer", 0,
&param.renderer.single_buffer },
{ WESTON_OPTION_STRING, "transform", 0, &transform },
--
1.8.1.5
ppaalanen
2013-05-22 15:03:09 UTC
Permalink
From: Pekka Paalanen <ppaalanen at gmail.com>

On Raspberry Pi, weston-desktop-shell is so slow to start, that the
compositor has time to run the fade-in before the wallpaper is up. The
user launching Weston sees the screen flipping to black, the fbcon
fading in, and then the desktop popping up.

To fix this, wait for the weston-desktop-shell to draw
everything before starting the initial fade-in. A new request is
added to the private desktop-shell protocol to signal it. If a
desktop-shell client does not support the new request, the fade-in
happens already at bind time.

If weston-desktop-shell crashes, or does not send the 'desktop_ready'
request in 15 seconds, the compositor will fade in anyway. This should
avoid a blocked screen in case weston-desktop-shell malfunction.

shell_fade_startup() does not directly start the fade-in but schedules
an idle callback, so that the compositor can process all pending events
before starting the fade clock. Otherwise (on RPi) we risk skipping part
of the animation. Yes, it is a hack, that should have been done in
window.c and weston-desktop-shell instead.

Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
clients/desktop-shell.c | 46 +++++++++++++++++-
protocol/desktop-shell.xml | 13 ++++-
src/shell.c | 119 +++++++++++++++++++++++++++++++++++++++------
3 files changed, 162 insertions(+), 16 deletions(-)

diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
index 3949975..4a39653 100644
--- a/clients/desktop-shell.c
+++ b/clients/desktop-shell.c
@@ -49,6 +49,7 @@ extern char **environ; /* defined by libc */
struct desktop {
struct display *display;
struct desktop_shell *shell;
+ uint32_t interface_version;
struct unlock_dialog *unlock_dialog;
struct task unlock_task;
struct wl_list outputs;
@@ -57,6 +58,8 @@ struct desktop {
struct widget *grab_widget;

enum cursor_type grab_cursor;
+
+ int painted;
};

struct surface {
@@ -72,12 +75,14 @@ struct panel {
struct widget *widget;
struct wl_list launcher_list;
struct panel_clock *clock;
+ int painted;
};

struct background {
struct surface base;
struct window *window;
struct widget *widget;
+ int painted;
};

struct output {
@@ -175,6 +180,38 @@ show_menu(struct panel *panel, struct input *input, uint32_t time)
x - 10, y - 10, menu_func, entries, 4);
}

+static int
+is_desktop_painted(struct desktop *desktop)
+{
+ struct output *output;
+
+ wl_list_for_each(output, &desktop->outputs, link) {
+ if (output->panel && !output->panel->painted)
+ return 0;
+ if (output->background && !output->background->painted)
+ return 0;
+ }
+
+ return 1;
+}
+
+static void
+check_desktop_ready(struct window *window)
+{
+ struct display *display;
+ struct desktop *desktop;
+
+ display = window_get_display(window);
+ desktop = display_get_user_data(display);
+
+ if (!desktop->painted && is_desktop_painted(desktop)) {
+ desktop->painted = 1;
+
+ if (desktop->interface_version >= 2)
+ desktop_shell_desktop_ready(desktop->shell);
+ }
+}
+
static void
panel_launcher_activate(struct panel_launcher *widget)
{
@@ -263,6 +300,8 @@ panel_redraw_handler(struct widget *widget, void *data)

cairo_destroy(cr);
cairo_surface_destroy(surface);
+ panel->painted = 1;
+ check_desktop_ready(panel->window);
}

static int
@@ -694,6 +733,9 @@ background_draw(struct widget *widget, void *data)
allocation.width, allocation.height);
wl_surface_set_opaque_region(window_get_wl_surface(background->window), opaque);
wl_region_destroy(opaque);
+
+ background->painted = 1;
+ check_desktop_ready(background->window);
}

static void
@@ -1046,8 +1088,10 @@ global_handler(struct display *display, uint32_t id,
struct desktop *desktop = data;

if (!strcmp(interface, "desktop_shell")) {
+ desktop->interface_version = (version < 2) ? version : 2;
desktop->shell = display_bind(desktop->display,
- id, &desktop_shell_interface, 1);
+ id, &desktop_shell_interface,
+ desktop->interface_version);
desktop_shell_add_listener(desktop->shell, &listener, desktop);
} else if (!strcmp(interface, "wl_output")) {
create_output(desktop, id);
diff --git a/protocol/desktop-shell.xml b/protocol/desktop-shell.xml
index d48c3dd..65e44a7 100644
--- a/protocol/desktop-shell.xml
+++ b/protocol/desktop-shell.xml
@@ -1,6 +1,6 @@
<protocol name="desktop">

- <interface name="desktop_shell" version="1">
+ <interface name="desktop_shell" version="2">
<description summary="create desktop widgets and helpers">
Traditional user interfaces can rely on this interface to define the
foundations of typical desktops. Currently it's possible to set up
@@ -33,6 +33,17 @@
<arg name="surface" type="object" interface="wl_surface"/>
</request>

+ <request name="desktop_ready" since="2">
+ <description summary="desktop is ready to be shown">
+ Tell the server, that enough desktop elements have been drawn
+ to make the desktop look ready for use. During start-up, the
+ server can wait for this request with a black screen before
+ starting to fade in the desktop, for instance. If the client
+ parts of a desktop take a long time to initialize, we avoid
+ showing temporary garbage.
+ </description>
+ </request>
+
<!-- We'll fold most of wl_shell into this interface and then
they'll share the configure event. -->
<event name="configure">
diff --git a/src/shell.c b/src/shell.c
index e23c09b..eb8d802 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -156,6 +156,7 @@ struct desktop_shell {
struct weston_surface *surface;
struct weston_surface_animation *animation;
enum fade_type type;
+ struct wl_event_source *startup_timer;
} fade;

uint32_t binding_modifier;
@@ -275,6 +276,9 @@ shell_surface_get_shell(struct shell_surface *shsurf);
static void
surface_rotate(struct shell_surface *surface, struct weston_seat *seat);

+static void
+shell_fade_startup(struct desktop_shell *shell);
+
static bool
shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
{
@@ -2548,12 +2552,22 @@ desktop_shell_set_grab_surface(struct wl_client *client,
shell->grab_surface = surface_resource->data;
}

+static void
+desktop_shell_desktop_ready(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct desktop_shell *shell = resource->data;
+
+ shell_fade_startup(shell);
+}
+
static const struct desktop_shell_interface desktop_shell_implementation = {
desktop_shell_set_background,
desktop_shell_set_panel,
desktop_shell_set_lock_surface,
desktop_shell_unlock,
- desktop_shell_set_grab_surface
+ desktop_shell_set_grab_surface,
+ desktop_shell_desktop_ready
};

static enum shell_surface_type
@@ -3031,11 +3045,28 @@ shell_fade_done(struct weston_surface_animation *animation, void *data)
}
}

-static void
-shell_fade(struct desktop_shell *shell, enum fade_type type)
+static struct weston_surface *
+shell_fade_create_surface(struct desktop_shell *shell)
{
struct weston_compositor *compositor = shell->compositor;
struct weston_surface *surface;
+
+ surface = weston_surface_create(compositor);
+ if (!surface)
+ return NULL;
+
+ weston_surface_configure(surface, 0, 0, 8192, 8192);
+ weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
+ wl_list_insert(&compositor->fade_layer.surface_list,
+ &surface->layer_link);
+ pixman_region32_init(&surface->input);
+
+ return surface;
+}
+
+static void
+shell_fade(struct desktop_shell *shell, enum fade_type type)
+{
float tint;

switch (type) {
@@ -3053,18 +3084,12 @@ shell_fade(struct desktop_shell *shell, enum fade_type type)
shell->fade.type = type;

if (shell->fade.surface == NULL) {
- surface = weston_surface_create(compositor);
- if (!surface)
+ shell->fade.surface = shell_fade_create_surface(shell);
+ if (!shell->fade.surface)
return;

- weston_surface_configure(surface, 0, 0, 8192, 8192);
- weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
- surface->alpha = 1.0 - tint;
- wl_list_insert(&compositor->fade_layer.surface_list,
- &surface->layer_link);
- weston_surface_update_transform(surface);
- shell->fade.surface = surface;
- pixman_region32_init(&surface->input);
+ shell->fade.surface->alpha = 1.0 - tint;
+ weston_surface_update_transform(shell->fade.surface);
}

if (shell->fade.animation)
@@ -3078,6 +3103,67 @@ shell_fade(struct desktop_shell *shell, enum fade_type type)
}

static void
+do_shell_fade_startup(void *data)
+{
+ struct desktop_shell *shell = data;
+
+ shell_fade(shell, FADE_IN);
+}
+
+static void
+shell_fade_startup(struct desktop_shell *shell)
+{
+ struct wl_event_loop *loop;
+
+ if (!shell->fade.startup_timer)
+ return;
+
+ wl_event_source_remove(shell->fade.startup_timer);
+ shell->fade.startup_timer = NULL;
+
+ loop = wl_display_get_event_loop(shell->compositor->wl_display);
+ wl_event_loop_add_idle(loop, do_shell_fade_startup, shell);
+}
+
+static int
+fade_startup_timeout(void *data)
+{
+ struct desktop_shell *shell = data;
+
+ shell_fade_startup(shell);
+ return 0;
+}
+
+static void
+shell_fade_init(struct desktop_shell *shell)
+{
+ /* Make compositor output all black, and wait for the desktop-shell
+ * client to signal it is ready, then fade in. The timer triggers a
+ * fade-in, in case the desktop-shell client takes too long.
+ */
+
+ struct wl_event_loop *loop;
+
+ if (shell->fade.surface != NULL) {
+ weston_log("%s: warning: fade surface already exists\n",
+ __func__);
+ return;
+ }
+
+ shell->fade.surface = shell_fade_create_surface(shell);
+ if (!shell->fade.surface)
+ return;
+
+ weston_surface_update_transform(shell->fade.surface);
+ weston_surface_damage(shell->fade.surface);
+
+ loop = wl_display_get_event_loop(shell->compositor->wl_display);
+ shell->fade.startup_timer =
+ wl_event_loop_add_timer(loop, fade_startup_timeout, shell);
+ wl_event_source_timer_update(shell->fade.startup_timer, 15000);
+}
+
+static void
idle_handler(struct wl_listener *listener, void *data)
{
struct desktop_shell *shell =
@@ -3444,6 +3530,7 @@ desktop_shell_sigchld(struct weston_process *process, int status)

weston_log("weston-desktop-shell died, respawning...\n");
launch_desktop_shell_process(shell);
+ shell_fade_startup(shell);
}

static void
@@ -3497,6 +3584,10 @@ bind_desktop_shell(struct wl_client *client,
if (client == shell->child.client) {
resource->destroy = unbind_desktop_shell;
shell->child.desktop_shell = resource;
+
+ if (version < 2)
+ shell_fade_startup(shell);
+
return;
}

@@ -4391,7 +4482,7 @@ module_init(struct weston_compositor *ec,

shell_add_bindings(ec, shell);

- shell_fade(shell, FADE_IN);
+ shell_fade_init(shell);

return 0;
}
--
1.8.1.5
ppaalanen
2013-05-22 15:03:10 UTC
Permalink
From: Pekka Paalanen <ppaalanen at gmail.com>

Scale-crop mode scales the wallpaper to tightly fill the whole output,
but preserving wallpaper aspect ratio. If aspect ratio differs from the
output's, the wallpaper is centered cutting it from top/bottom or
left/right.

Add this to the weston.ini man page, and explain all three modes.

Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
clients/desktop-shell.c | 27 ++++++++++++++++++++++-----
man/weston.ini.man | 9 +++++++--
2 files changed, 29 insertions(+), 7 deletions(-)

diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
index 4a39653..1fc8753 100644
--- a/clients/desktop-shell.c
+++ b/clients/desktop-shell.c
@@ -664,6 +664,7 @@ panel_add_launcher(struct panel *panel, const char *icon, const char *path)

enum {
BACKGROUND_SCALE,
+ BACKGROUND_SCALE_CROP,
BACKGROUND_TILE
};

@@ -675,7 +676,9 @@ background_draw(struct widget *widget, void *data)
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
cairo_t *cr;
- double sx, sy;
+ double im_w, im_h;
+ double sx, sy, s;
+ double tx, ty;
struct rectangle allocation;
int type = -1;
struct display *display;
@@ -695,6 +698,8 @@ background_draw(struct widget *widget, void *data)

if (strcmp(key_background_type, "scale") == 0)
type = BACKGROUND_SCALE;
+ else if (strcmp(key_background_type, "scale-crop") == 0)
+ type = BACKGROUND_SCALE_CROP;
else if (strcmp(key_background_type, "tile") == 0)
type = BACKGROUND_TILE;
else
@@ -702,20 +707,32 @@ background_draw(struct widget *widget, void *data)
key_background_type);

if (image && type != -1) {
+ im_w = cairo_image_surface_get_width(image);
+ im_h = cairo_image_surface_get_height(image);
+ sx = im_w / allocation.width;
+ sy = im_h / allocation.height;
+
pattern = cairo_pattern_create_for_surface(image);
+
switch (type) {
case BACKGROUND_SCALE:
- sx = (double) cairo_image_surface_get_width(image) /
- allocation.width;
- sy = (double) cairo_image_surface_get_height(image) /
- allocation.height;
cairo_matrix_init_scale(&matrix, sx, sy);
cairo_pattern_set_matrix(pattern, &matrix);
break;
+ case BACKGROUND_SCALE_CROP:
+ s = (sx < sy) ? sx : sy;
+ /* align center */
+ tx = (im_w - s * allocation.width) * 0.5;
+ ty = (im_h - s * allocation.height) * 0.5;
+ cairo_matrix_init_translate(&matrix, tx, ty);
+ cairo_matrix_scale(&matrix, s, s);
+ cairo_pattern_set_matrix(pattern, &matrix);
+ break;
case BACKGROUND_TILE:
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
break;
}
+
cairo_set_source(cr, pattern);
cairo_pattern_destroy (pattern);
cairo_surface_destroy(image);
diff --git a/man/weston.ini.man b/man/weston.ini.man
index d37654a..c3e5747 100644
--- a/man/weston.ini.man
+++ b/man/weston.ini.man
@@ -118,8 +118,13 @@ The entries that can appear in this section are:
sets the path for the background image file (string).
.TP 7
.BI "background-type=" tile
-determines how the background image is drawn (string). Can be scale or
-tile (default).
+determines how the background image is drawn (string). Can be
+.BR scale ", " scale-crop " or " tile " (default)."
+Scale means scaled to fit the output precisely, not preserving aspect ratio.
+Scale-crop preserves aspect ratio, scales the background image just big
+enough to cover the output, and centers it. The image ends up cropped from
+left and right, or top and bottom, if the aspect ratio does not match the
+output. Tile repeats the background image to fill the output.
.TP 7
.BI "background-color=" 0xAARRGGBB
sets the color of the background (unsigned integer). The hexadecimal
--
1.8.1.5
ppaalanen
2013-05-22 15:03:11 UTC
Permalink
From: Louis-Francis Ratt?-Boulianne <lfrb at collabora.com>

Whether or not a shm pool is used for resizing is now configurable at
build time (--disable-resize-optimization).

[pq: removed an unnecessary hunk from the patch]
---
clients/window.c | 2 ++
configure.ac | 7 +++++++
2 files changed, 9 insertions(+)

diff --git a/clients/window.c b/clients/window.c
index 627f1e8..3f54111 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -1004,6 +1004,7 @@ shm_surface_prepare(struct toysurface *base, int dx, int dy,
if (leaf->cairo_surface)
cairo_surface_destroy(leaf->cairo_surface);

+#ifdef USE_RESIZE_POOL
if (resize_hint && !leaf->resize_pool) {
/* Create a big pool to allocate from, while continuously
* resizing. Mmapping a new pool in the server
@@ -1014,6 +1015,7 @@ shm_surface_prepare(struct toysurface *base, int dx, int dy,
leaf->resize_pool = shm_pool_create(surface->display,
6 * 1024 * 1024);
}
+#endif

leaf->cairo_surface =
display_create_shm_surface(surface->display, &rect,
diff --git a/configure.ac b/configure.ac
index 2aec1bb..323bd87 100644
--- a/configure.ac
+++ b/configure.ac
@@ -239,6 +239,13 @@ if test x$enable_clients = xyes; then
PKG_CHECK_MODULES(PANGO, [pangocairo], [have_pango=yes], [have_pango=no])
fi

+AC_ARG_ENABLE(resize-optimization,
+ AS_HELP_STRING([--disable-resize-optimization],
+ [disable resize optimization allocating a big buffer in toytoolkit]),,
+ enable_resize_optimization=yes)
+AS_IF([test "x$enable_resize_optimization" = "xyes"],
+ [AC_DEFINE([USE_RESIZE_POOL], [1], [Use resize memory pool as a performance optimization])])
+
AC_ARG_ENABLE(weston-launch, [ --enable-weston-launch],, enable_weston_launch=yes)
AM_CONDITIONAL(BUILD_WESTON_LAUNCH, test x$enable_weston_launch == xyes)
if test x$enable_weston_launch == xyes; then
--
1.8.1.5
ppaalanen
2013-05-22 15:03:12 UTC
Permalink
From: Pekka Paalanen <pekka.paalanen at collabora.co.uk>

Print the recording info to Weston log, not stderr.

Also fix the frame counter.

Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
src/screenshooter.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/screenshooter.c b/src/screenshooter.c
index 6f53fad..dde052f 100644
--- a/src/screenshooter.c
+++ b/src/screenshooter.c
@@ -432,6 +432,7 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data)
}

pixman_region32_fini(&damage);
+ recorder->count++;
}

static void
@@ -525,13 +526,13 @@ recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *da
recorder = container_of(listener, struct weston_recorder,
frame_listener);

- fprintf(stderr,
+ weston_log(
"stopping recorder, total file size %dM, %d frames\n",
recorder->total / (1024 * 1024), recorder->count);

weston_recorder_destroy(recorder);
} else {
- fprintf(stderr, "starting recorder, file %s\n", filename);
+ weston_log("starting recorder, file %s\n", filename);
weston_recorder_create(output, filename);
}
}
--
1.8.1.5
ppaalanen
2013-05-22 15:03:13 UTC
Permalink
From: Louis-Francis Ratt?-Boulianne <lfrb at collabora.com>

When enabled, this will make all but the keyboard-focused window dim.
Also the background gets dimmed, if there are any windows open. The
panel is not dimmed.

When the keyboard focus changes, the change in dimming is animated.

The dimming is implemented with transparent solid-color surfaces, two at
most. The net effect of two overlapping dim surfaces is kept constant
during animations (stable fade animation).

There is a new weston.ini option "focus-animation", that defaults to
none, and can be set to "dim-layer" to enable the focus change
animation.

[pq: Sliced, squashed, and rebased the patch series. Fixed surface alpha
interaction with the switcher. Wrote the commit message.]
---
src/animation.c | 52 ++++++++++--
src/compositor.h | 8 ++
src/shell.c | 251 +++++++++++++++++++++++++++++++++++++++++++++++++------
3 files changed, 282 insertions(+), 29 deletions(-)

diff --git a/src/animation.c b/src/animation.c
index e947d72..6f20179 100644
--- a/src/animation.c
+++ b/src/animation.c
@@ -108,9 +108,10 @@ struct weston_surface_animation {
weston_surface_animation_frame_func_t frame;
weston_surface_animation_done_func_t done;
void *data;
+ void *private;
};

-static void
+WL_EXPORT void
weston_surface_animation_destroy(struct weston_surface_animation *animation)
{
wl_list_remove(&animation->animation.link);
@@ -162,7 +163,8 @@ weston_surface_animation_run(struct weston_surface *surface,
float start, float stop,
weston_surface_animation_frame_func_t frame,
weston_surface_animation_done_func_t done,
- void *data)
+ void *data,
+ void *private)
{
struct weston_surface_animation *animation;

@@ -176,6 +178,7 @@ weston_surface_animation_run(struct weston_surface *surface,
animation->data = data;
animation->start = start;
animation->stop = stop;
+ animation->private = private;
weston_matrix_init(&animation->transform.matrix);
wl_list_insert(&surface->geometry.transformation_list,
&animation->transform.link);
@@ -222,7 +225,7 @@ weston_zoom_run(struct weston_surface *surface, float start, float stop,
weston_surface_animation_done_func_t done, void *data)
{
return weston_surface_animation_run(surface, start, stop,
- zoom_frame, done, data);
+ zoom_frame, done, data, NULL);
}

static void
@@ -244,7 +247,7 @@ weston_fade_run(struct weston_surface *surface,
struct weston_surface_animation *fade;

fade = weston_surface_animation_run(surface, 0, 0,
- fade_frame, done, data);
+ fade_frame, done, data, NULL);

weston_spring_init(&fade->spring, k, start, end);
surface->alpha = start;
@@ -260,6 +263,45 @@ weston_fade_update(struct weston_surface_animation *fade,
}

static void
+stable_fade_frame(struct weston_surface_animation *animation)
+{
+ struct weston_surface *back_surface;
+
+ if (animation->spring.current > 0.999)
+ animation->surface->alpha = 1;
+ else if (animation->spring.current < 0.001 )
+ animation->surface->alpha = 0;
+ else
+ animation->surface->alpha = animation->spring.current;
+
+ back_surface = (struct weston_surface *) animation->private;
+ back_surface->alpha =
+ (animation->spring.target - animation->surface->alpha) /
+ (1.0 - animation->surface->alpha);
+ weston_surface_geometry_dirty(back_surface);
+}
+
+WL_EXPORT struct weston_surface_animation *
+weston_stable_fade_run(struct weston_surface *front_surface, float start,
+ struct weston_surface *back_surface, float end,
+ weston_surface_animation_done_func_t done, void *data)
+{
+ struct weston_surface_animation *fade;
+
+ fade = weston_surface_animation_run(front_surface, 0, 0,
+ stable_fade_frame, done, data, back_surface);
+
+
+ weston_spring_init(&fade->spring, 400, start, end);
+ fade->spring.friction = 1150;
+
+ front_surface->alpha = start;
+ back_surface->alpha = end;
+
+ return fade;
+}
+
+static void
slide_frame(struct weston_surface_animation *animation)
{
float scale;
@@ -278,7 +320,7 @@ weston_slide_run(struct weston_surface *surface, float start, float stop,
struct weston_surface_animation *animation;

animation = weston_surface_animation_run(surface, start, stop,
- slide_frame, done, data);
+ slide_frame, done, data, NULL);
if (!animation)
return NULL;

diff --git a/src/compositor.h b/src/compositor.h
index efc4102..61aeb9f 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -1105,6 +1105,9 @@ weston_watch_process(struct weston_process *process);
struct weston_surface_animation;
typedef void (*weston_surface_animation_done_func_t)(struct weston_surface_animation *animation, void *data);

+void
+weston_surface_animation_destroy(struct weston_surface_animation *animation);
+
struct weston_surface_animation *
weston_zoom_run(struct weston_surface *surface, float start, float stop,
weston_surface_animation_done_func_t done, void *data);
@@ -1118,6 +1121,11 @@ weston_fade_update(struct weston_surface_animation *fade,
float start, float end, float k);

struct weston_surface_animation *
+weston_stable_fade_run(struct weston_surface *front_surface, float start,
+ struct weston_surface *back_surface, float end,
+ weston_surface_animation_done_func_t done, void *data);
+
+struct weston_surface_animation *
weston_slide_run(struct weston_surface *surface, float start, float stop,
weston_surface_animation_done_func_t done, void *data);

diff --git a/src/shell.c b/src/shell.c
index eb8d802..b7c372e 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -46,7 +46,8 @@ enum animation_type {
ANIMATION_NONE,

ANIMATION_ZOOM,
- ANIMATION_FADE
+ ANIMATION_FADE,
+ ANIMATION_DIM_LAYER,
};

enum fade_type {
@@ -63,11 +64,20 @@ struct focus_state {
struct wl_listener surface_destroy_listener;
};

+struct focus_surface {
+ struct weston_surface *surface;
+ struct weston_transform workspace_transform;
+};
+
struct workspace {
struct weston_layer layer;

struct wl_list focus_list;
struct wl_listener seat_destroyed_listener;
+
+ struct focus_surface *fsurf_front;
+ struct focus_surface *fsurf_back;
+ struct weston_surface_animation *focus_animation;
};

struct input_panel_surface {
@@ -161,6 +171,7 @@ struct desktop_shell {

uint32_t binding_modifier;
enum animation_type win_animation_type;
+ enum animation_type focus_animation_type;
};

enum shell_surface_type {
@@ -374,6 +385,8 @@ get_animation_type(char *animation)
return ANIMATION_ZOOM;
else if (!strcmp("fade", animation))
return ANIMATION_FADE;
+ else if (!strcmp("dim-layer", animation))
+ return ANIMATION_DIM_LAYER;
else
return ANIMATION_NONE;
}
@@ -386,10 +399,12 @@ shell_configuration(struct desktop_shell *shell, int config_fd)
unsigned int num_workspaces = DEFAULT_NUM_WORKSPACES;
char *modifier = NULL;
char *win_animation = NULL;
+ char *focus_animation = NULL;

struct config_key shell_keys[] = {
{ "binding-modifier", CONFIG_KEY_STRING, &modifier },
{ "animation", CONFIG_KEY_STRING, &win_animation},
+ { "focus-animation", CONFIG_KEY_STRING, &focus_animation},
{ "num-workspaces",
CONFIG_KEY_UNSIGNED_INTEGER, &num_workspaces },
};
@@ -410,9 +425,90 @@ shell_configuration(struct desktop_shell *shell, int config_fd)
shell->screensaver.duration = duration * 1000;
shell->binding_modifier = get_modifier(modifier);
shell->win_animation_type = get_animation_type(win_animation);
+ shell->focus_animation_type = get_animation_type(focus_animation);
shell->workspaces.num = num_workspaces > 0 ? num_workspaces : 1;
}

+static struct weston_output *
+get_default_output(struct weston_compositor *compositor)
+{
+ return container_of(compositor->output_list.next,
+ struct weston_output, link);
+}
+
+
+/* no-op func for checking focus surface */
+static void
+focus_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy,
+ int32_t width, int32_t height)
+{
+}
+
+static struct focus_surface *
+get_focus_surface(struct weston_surface *surface)
+{
+ if (surface->configure == focus_surface_configure)
+ return surface->configure_private;
+ else
+ return NULL;
+}
+
+static bool
+is_focus_surface (struct weston_surface *es)
+{
+ return (es->configure == focus_surface_configure);
+}
+
+static struct focus_surface *
+create_focus_surface(struct weston_compositor *ec,
+ struct weston_output *output)
+{
+ struct focus_surface *fsurf = NULL;
+ struct weston_surface *surface = NULL;
+
+ fsurf = malloc(sizeof *fsurf);
+ if (!fsurf)
+ return NULL;
+
+ fsurf->surface = weston_surface_create(ec);
+ surface = fsurf->surface;
+ if (surface == NULL) {
+ free(fsurf);
+ return NULL;
+ }
+
+ surface->configure = focus_surface_configure;
+ surface->output = output;
+ surface->configure_private = fsurf;
+ weston_surface_configure(surface, output->x, output->y,
+ output->width, output->height);
+ weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
+ pixman_region32_fini(&surface->opaque);
+ pixman_region32_init_rect(&surface->opaque, output->x, output->y,
+ output->width, output->height);
+ pixman_region32_fini(&surface->input);
+ pixman_region32_init(&surface->input);
+
+ wl_list_init(&fsurf->workspace_transform.link);
+
+ return fsurf;
+}
+
+static void
+focus_surface_destroy(struct focus_surface *fsurf)
+{
+ weston_surface_destroy(fsurf->surface);
+ free(fsurf);
+}
+
+static void
+focus_animation_done(struct weston_surface_animation *animation, void *data)
+{
+ struct workspace *ws = data;
+
+ ws->focus_animation = NULL;
+}
+
static void
focus_state_destroy(struct focus_state *state)
{
@@ -448,6 +544,8 @@ focus_state_surface_destroy(struct wl_listener *listener, void *data)
wl_list_for_each(surface, &state->ws->layer.surface_list, layer_link) {
if (surface == main_surface)
continue;
+ if (is_focus_surface(surface))
+ continue;

next = surface;
break;
@@ -457,10 +555,21 @@ focus_state_surface_destroy(struct wl_listener *listener, void *data)
if (main_surface != state->keyboard_focus)
next = main_surface;

+ shell = state->seat->compositor->shell_interface.shell;
if (next) {
- shell = state->seat->compositor->shell_interface.shell;
+ state->keyboard_focus = NULL;
activate(shell, next, state->seat);
} else {
+ if (shell->focus_animation_type == ANIMATION_DIM_LAYER) {
+ if (state ->ws->focus_animation)
+ weston_surface_animation_destroy(state->ws->focus_animation);
+
+ state->ws->focus_animation = weston_fade_run(
+ state->ws->fsurf_front->surface,
+ state->ws->fsurf_front->surface->alpha, 0.0, 300,
+ focus_animation_done, state->ws);
+ }
+
wl_list_remove(&state->link);
focus_state_destroy(state);
}
@@ -475,6 +584,7 @@ focus_state_create(struct weston_seat *seat, struct workspace *ws)
if (state == NULL)
return NULL;

+ state->keyboard_focus = NULL;
state->ws = ws;
state->seat = seat;
wl_list_insert(&ws->focus_list, &state->link);
@@ -546,6 +656,63 @@ drop_focus_state(struct desktop_shell *shell, struct workspace *ws,
}

static void
+animate_focus_change(struct desktop_shell *shell, struct workspace *ws,
+ struct weston_surface *from, struct weston_surface *to)
+{
+ struct weston_output *output;
+ bool focus_surface_created = false;
+
+ /* FIXME: Only support dim animation using two layers */
+ if (from == to || shell->focus_animation_type != ANIMATION_DIM_LAYER)
+ return;
+
+ output = get_default_output(shell->compositor);
+ if (ws->fsurf_front == NULL && (from || to)) {
+ ws->fsurf_front = create_focus_surface(shell->compositor, output);
+ ws->fsurf_back = create_focus_surface(shell->compositor, output);
+ ws->fsurf_front->surface->alpha = 0.0;
+ ws->fsurf_back->surface->alpha = 0.0;
+ focus_surface_created = true;
+ } else {
+ wl_list_remove(&ws->fsurf_front->surface->layer_link);
+ wl_list_remove(&ws->fsurf_back->surface->layer_link);
+ }
+
+ if (ws->focus_animation) {
+ weston_surface_animation_destroy(ws->focus_animation);
+ ws->focus_animation = NULL;
+ }
+
+ if (to)
+ wl_list_insert(&to->layer_link,
+ &ws->fsurf_front->surface->layer_link);
+ else if (from)
+ wl_list_insert(&ws->layer.surface_list,
+ &ws->fsurf_front->surface->layer_link);
+
+ if (focus_surface_created) {
+ ws->focus_animation = weston_fade_run(
+ ws->fsurf_front->surface,
+ ws->fsurf_front->surface->alpha, 0.6, 300,
+ focus_animation_done, ws);
+ } else if (from) {
+ wl_list_insert(&from->layer_link,
+ &ws->fsurf_back->surface->layer_link);
+ ws->focus_animation = weston_stable_fade_run(
+ ws->fsurf_front->surface, 0.0,
+ ws->fsurf_back->surface, 0.6,
+ focus_animation_done, ws);
+ } else if (to) {
+ wl_list_insert(&ws->layer.surface_list,
+ &ws->fsurf_back->surface->layer_link);
+ ws->focus_animation = weston_stable_fade_run(
+ ws->fsurf_front->surface, 0.0,
+ ws->fsurf_back->surface, 0.6,
+ focus_animation_done, ws);
+ }
+}
+
+static void
workspace_destroy(struct workspace *ws)
{
struct focus_state *state, *next;
@@ -553,6 +720,11 @@ workspace_destroy(struct workspace *ws)
wl_list_for_each_safe(state, next, &ws->focus_list, link)
focus_state_destroy(state);

+ if (ws->fsurf_front)
+ focus_surface_destroy(ws->fsurf_front);
+ if (ws->fsurf_back)
+ focus_surface_destroy(ws->fsurf_back);
+
free(ws);
}

@@ -582,6 +754,9 @@ workspace_create(void)
wl_list_init(&ws->focus_list);
wl_list_init(&ws->seat_destroyed_listener.link);
ws->seat_destroyed_listener.notify = seat_destroyed;
+ ws->fsurf_front = NULL;
+ ws->fsurf_back = NULL;
+ ws->focus_animation = NULL;

return ws;
}
@@ -625,18 +800,24 @@ get_output_height(struct weston_output *output)
}

static void
-surface_translate(struct weston_surface *surface, double d)
+surface_translate(struct workspace *ws, struct weston_surface *surface, double d)
{
- struct shell_surface *shsurf = get_shell_surface(surface);
struct weston_transform *transform;

- transform = &shsurf->workspace_transform;
+ if (is_focus_surface(surface)) {
+ struct focus_surface *fsurf = get_focus_surface(surface);
+ transform = &fsurf->workspace_transform;
+ } else {
+ struct shell_surface *shsurf = get_shell_surface(surface);
+ transform = &shsurf->workspace_transform;
+ }
+
if (wl_list_empty(&transform->link))
wl_list_insert(surface->geometry.transformation_list.prev,
- &shsurf->workspace_transform.link);
+ &transform->link);

- weston_matrix_init(&shsurf->workspace_transform.matrix);
- weston_matrix_translate(&shsurf->workspace_transform.matrix,
+ weston_matrix_init(&transform->matrix);
+ weston_matrix_translate(&transform->matrix,
0.0, d, 0.0);
weston_surface_geometry_dirty(surface);
}
@@ -652,7 +833,7 @@ workspace_translate_out(struct workspace *ws, double fraction)
height = get_output_height(surface->output);
d = height * fraction;

- surface_translate(surface, d);
+ surface_translate(ws, surface, d);
}
}

@@ -671,7 +852,7 @@ workspace_translate_in(struct workspace *ws, double fraction)
else
d = height + height * fraction;

- surface_translate(surface, d);
+ surface_translate(ws, surface, d);
}
}

@@ -706,13 +887,20 @@ static void
workspace_deactivate_transforms(struct workspace *ws)
{
struct weston_surface *surface;
- struct shell_surface *shsurf;
+ struct weston_transform *transform;

wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
- shsurf = get_shell_surface(surface);
- if (!wl_list_empty(&shsurf->workspace_transform.link)) {
- wl_list_remove(&shsurf->workspace_transform.link);
- wl_list_init(&shsurf->workspace_transform.link);
+ if (is_focus_surface(surface)) {
+ struct focus_surface *fsurf = get_focus_surface(surface);
+ transform = &fsurf->workspace_transform;
+ } else {
+ struct shell_surface *shsurf = get_shell_surface(surface);
+ transform = &shsurf->workspace_transform;
+ }
+
+ if (!wl_list_empty(&transform->link)) {
+ wl_list_remove(&transform->link);
+ wl_list_init(&transform->link);
}
weston_surface_geometry_dirty(surface);
}
@@ -835,6 +1023,7 @@ change_workspace(struct desktop_shell *shell, unsigned int index)
{
struct workspace *from;
struct workspace *to;
+ struct focus_state *state;

if (index == shell->workspaces.current)
return;
@@ -861,6 +1050,18 @@ change_workspace(struct desktop_shell *shell, unsigned int index)

restore_focus_state(shell, to);

+ if (shell->focus_animation_type != ANIMATION_NONE) {
+ wl_list_for_each(state, &from->focus_list, link)
+ if (state->keyboard_focus)
+ animate_focus_change(shell, from,
+ state->keyboard_focus, NULL);
+
+ wl_list_for_each(state, &to->focus_list, link)
+ if (state->keyboard_focus)
+ animate_focus_change(shell, to,
+ NULL, state->keyboard_focus);
+ }
+
if (workspace_is_empty(to) && workspace_is_empty(from))
update_workspace(shell, index, from, to);
else
@@ -936,7 +1137,8 @@ take_surface_to_workspace_by_seat(struct desktop_shell *shell,

surface = weston_surface_get_main_surface(seat->keyboard->focus);
if (surface == NULL ||
- index == shell->workspaces.current)
+ index == shell->workspaces.current ||
+ is_focus_surface(surface))
return;

from = get_current_workspace(shell);
@@ -1497,13 +1699,6 @@ shell_surface_set_class(struct wl_client *client,
shsurf->class = strdup(class);
}

-static struct weston_output *
-get_default_output(struct weston_compositor *compositor)
-{
- return container_of(compositor->output_list.next,
- struct weston_output, link);
-}
-
static void
shell_unset_fullscreen(struct shell_surface *shsurf)
{
@@ -2907,6 +3102,7 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
struct weston_surface *main_surface;
struct focus_state *state;
struct workspace *ws;
+ struct weston_surface *old_es;

main_surface = weston_surface_get_main_surface(es);

@@ -2916,6 +3112,7 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
if (state == NULL)
return;

+ old_es = state->keyboard_focus;
state->keyboard_focus = es;
wl_list_remove(&state->surface_destroy_listener.link);
wl_signal_add(&es->resource.destroy_signal,
@@ -2926,12 +3123,15 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
/* should on top of panels */
shell_stack_fullscreen(get_shell_surface(main_surface));
shell_configure_fullscreen(get_shell_surface(main_surface));
- break;
+ return;
default:
ws = get_current_workspace(shell);
weston_surface_restack(main_surface, &ws->layer.surface_list);
break;
}
+
+ if (shell->focus_animation_type != ANIMATION_NONE)
+ animate_focus_change(shell, ws, old_es, es);
}

/* no-op func for checking black surface */
@@ -3967,6 +4167,9 @@ switcher_destroy(struct switcher *switcher)
struct workspace *ws = get_current_workspace(switcher->shell);

wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
+ if (is_focus_surface(surface))
+ continue;
+
surface->alpha = 1.0;
weston_surface_damage(surface);
}
--
1.8.1.5
ppaalanen
2013-05-22 15:03:14 UTC
Permalink
From: Louis-Francis Ratte?-Boulianne <lfrb at collabora.com>

Don't scale to a size smaller than 1/8 the surface size
Adjust spring parameters so we don't go over the target value
---
src/animation.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/src/animation.c b/src/animation.c
index 6f20179..835ed13 100644
--- a/src/animation.c
+++ b/src/animation.c
@@ -206,6 +206,9 @@ zoom_frame(struct weston_surface_animation *animation)
scale = animation->start +
(animation->stop - animation->start) *
animation->spring.current;
+ if (scale < 0.125)
+ scale = 0.125;
+
weston_matrix_init(&animation->transform.matrix);
weston_matrix_translate(&animation->transform.matrix,
-0.5f * es->geometry.width,
@@ -224,8 +227,15 @@ WL_EXPORT struct weston_surface_animation *
weston_zoom_run(struct weston_surface *surface, float start, float stop,
weston_surface_animation_done_func_t done, void *data)
{
- return weston_surface_animation_run(surface, start, stop,
+ struct weston_surface_animation *zoom;
+
+ zoom = weston_surface_animation_run(surface, start, stop,
zoom_frame, done, data, NULL);
+
+ zoom->spring.k = 400;
+ zoom->spring.friction = 1150;
+
+ return zoom;
}

static void
--
1.8.1.5
ppaalanen
2013-05-22 15:03:15 UTC
Permalink
From: Louis-Francis Ratte?-Boulianne <lfrb at collabora.com>

On the first output, count the number of frames rendered for each
second, and report the fps in the Weston log.

To ensure a busy rendering loop, the debug key binding starting the
measurement also creates a bouncing box animation on screen. The box is
simply a solid color surface that moves around randomly.

This crude benchmark mode is useful for seeing whether the compositor
can consistently hit the screen refresh rate.

[pq: wrote the commit message, ported over the great input rework]
---
src/compositor.c | 33 +++++++++++++++
src/compositor.h | 10 +++++
src/shell.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 164 insertions(+)

diff --git a/src/compositor.c b/src/compositor.c
index 65da583..238c809 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -1293,6 +1293,22 @@ weston_output_finish_frame(struct weston_output *output, uint32_t msecs)
wl_display_get_event_loop(compositor->wl_display);
int fd;

+ if (output->benchmark.enabled) {
+ if (output->benchmark.update_time == 0) {
+ output->benchmark.update_time = msecs;
+ } else {
+ uint32_t d = msecs - output->benchmark.update_time;
+ float fps;
+ output->benchmark.frame_counter++;
+ if (d >= 1000) {
+ fps = output->benchmark.frame_counter * 1000.0f / d;
+ weston_log("FPS = %f\n", fps);
+ output->benchmark.update_time = msecs;
+ output->benchmark.frame_counter = 0;
+ }
+ }
+ }
+
output->frame_time = msecs;
if (output->repaint_needed) {
weston_output_repaint(output, msecs);
@@ -2634,6 +2650,9 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,
output->mm_width = width;
output->mm_height = height;
output->dirty = 1;
+ output->benchmark.enabled = 0;
+ output->benchmark.update_time = 0;
+ output->benchmark.frame_counter = 0;

weston_output_transform_init(output, transform);
weston_output_init_zoom(output);
@@ -2655,6 +2674,20 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,
wl_signal_emit(&c->output_created_signal, output);
}

+WL_EXPORT void
+weston_output_enable_benchmark(struct weston_output *output)
+{
+ output->benchmark.enabled = 1;
+ output->benchmark.update_time = 0;
+ output->benchmark.frame_counter = 0;
+}
+
+WL_EXPORT void
+weston_output_disable_benchmark(struct weston_output *output)
+{
+ output->benchmark.enabled = 0;
+}
+
static void
compositor_bind(struct wl_client *client,
void *data, uint32_t version, uint32_t id)
diff --git a/src/compositor.h b/src/compositor.h
index 61aeb9f..96cabeb 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -188,6 +188,12 @@ struct weston_output {
struct weston_mode *origin;
struct wl_list mode_list;

+ struct {
+ int enabled;
+ uint32_t update_time;
+ int frame_counter;
+ } benchmark;
+
void (*start_repaint_loop)(struct weston_output *output);
void (*repaint)(struct weston_output *output,
pixman_region32_t *damage);
@@ -864,6 +870,10 @@ weston_output_schedule_repaint(struct weston_output *output);
void
weston_output_damage(struct weston_output *output);
void
+weston_output_enable_benchmark(struct weston_output *output);
+void
+weston_output_disable_benchmark(struct weston_output *output);
+void
weston_compositor_schedule_repaint(struct weston_compositor *compositor);
void
weston_compositor_fade(struct weston_compositor *compositor, float tint);
diff --git a/src/shell.c b/src/shell.c
index b7c372e..812296a 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -158,6 +158,18 @@ struct desktop_shell {
} screensaver;

struct {
+ struct weston_layer layer;
+ struct weston_surface *surface;
+ struct weston_animation animation;
+ struct weston_transform transform;
+ uint32_t anim_timestamp;
+ double anim_current;
+ double anim_duration;
+ int32_t anim_dx;
+ int32_t anim_dy;
+ } benchmark;
+
+ struct {
struct wl_resource *binding;
struct wl_list surfaces;
} input_panel;
@@ -4265,6 +4277,111 @@ backlight_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
output->set_backlight(output, output->backlight_current);
}

+static void
+benchmark_animation_frame(struct weston_animation *animation,
+ struct weston_output *output, uint32_t msecs)
+{
+ struct desktop_shell *shell =
+ container_of(animation, struct desktop_shell,
+ benchmark.animation);
+ struct weston_surface *surface = shell->benchmark.surface;
+ uint32_t t;
+ uint32_t target_x, target_y;
+ double dx, dy;
+
+
+ if (shell->benchmark.anim_timestamp == 0)
+ shell->benchmark.anim_timestamp = msecs;
+ t = msecs - shell->benchmark.anim_timestamp;
+
+ if (t >= shell->benchmark.anim_duration) {
+ t = 0;
+ weston_surface_set_position(surface,
+ surface->geometry.x + shell->benchmark.anim_dx,
+ surface->geometry.y + shell->benchmark.anim_dy);
+ }
+
+ if (t == 0) {
+ target_x = 10 + random() % (output->width - 110);
+ target_y = 10 + random() % (output->height - 110);
+
+ shell->benchmark.anim_timestamp = msecs;
+ shell->benchmark.anim_duration = 2000;
+ shell->benchmark.anim_dx = target_x - surface->geometry.x;
+ shell->benchmark.anim_dy = target_y - surface->geometry.y;
+ }
+
+ dx = t / shell->benchmark.anim_duration * shell->benchmark.anim_dx;
+ dy = t / shell->benchmark.anim_duration * shell->benchmark.anim_dy;
+
+ weston_compositor_schedule_repaint(shell->compositor);
+
+ if (wl_list_empty(&shell->benchmark.transform.link))
+ wl_list_insert(surface->geometry.transformation_list.prev,
+ &shell->benchmark.transform.link);
+
+ weston_matrix_init(&shell->benchmark.transform.matrix);
+ weston_matrix_translate(&shell->benchmark.transform.matrix,
+ dx, dy, 0.0);
+ weston_surface_geometry_dirty(surface);
+
+ weston_compositor_schedule_repaint(shell->compositor);
+}
+
+static void
+benchmark_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
+ void *data)
+{
+ struct desktop_shell *shell = data;
+ struct weston_compositor *compositor = shell->compositor;
+ struct weston_output *output;
+ struct weston_surface *surface;
+
+ output = get_default_output(compositor);
+ if (!output)
+ return;
+
+ if (shell->benchmark.surface == NULL) {
+ weston_log("Benchmark mode started\n");
+ weston_output_enable_benchmark(output);
+ surface = weston_surface_create(compositor);
+ if (surface == NULL) {
+ return;
+ }
+
+ surface->output = output;
+ weston_surface_configure(surface, 0, 0, 100, 100);
+ weston_surface_set_color(surface, 0.6, 0.2, 0.2, 1.0);
+ pixman_region32_fini(&surface->opaque);
+ pixman_region32_init_rect(&surface->opaque, 0, 0, 100, 100);
+ pixman_region32_fini(&surface->input);
+ pixman_region32_init(&surface->input);
+
+ shell->benchmark.surface = surface;
+ shell->benchmark.anim_timestamp = 0;
+ shell->benchmark.animation.frame = benchmark_animation_frame;
+
+ wl_list_insert(&shell->panel_layer.link,
+ &shell->benchmark.layer.link);
+ wl_list_insert(&shell->benchmark.layer.surface_list,
+ &surface->layer_link);
+ wl_list_insert(&output->animation_list,
+ &shell->benchmark.animation.link);
+
+ weston_compositor_schedule_repaint(compositor);
+ } else {
+ weston_log("Benchmark mode stopped\n");
+ weston_output_disable_benchmark(output);
+ surface = shell->benchmark.surface;
+ wl_list_remove(&shell->benchmark.animation.link);
+ wl_list_remove(&shell->benchmark.layer.link);
+ wl_list_remove(&shell->benchmark.transform.link);
+ wl_list_init(&shell->benchmark.transform.link);
+ weston_surface_destroy(surface);
+ shell->benchmark.surface = NULL;
+ }
+}
+
struct debug_binding_grab {
struct weston_keyboard_grab grab;
struct weston_seat *seat;
@@ -4583,6 +4700,8 @@ shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
/* Debug bindings */
weston_compositor_add_key_binding(ec, KEY_SPACE, mod | MODIFIER_SHIFT,
debug_binding, shell);
+ weston_compositor_add_debug_binding(ec, KEY_B,
+ benchmark_binding, shell);
}

WL_EXPORT int
@@ -4630,6 +4749,7 @@ module_init(struct weston_compositor *ec,
weston_layer_init(&shell->background_layer, &shell->panel_layer.link);
weston_layer_init(&shell->lock_layer, NULL);
weston_layer_init(&shell->input_panel_layer, NULL);
+ weston_layer_init(&shell->benchmark.layer, NULL);

wl_array_init(&shell->workspaces.array);
wl_list_init(&shell->workspaces.client_list);
@@ -4647,6 +4767,7 @@ module_init(struct weston_compositor *ec,
}
activate_workspace(shell, 0);

+ wl_list_init(&shell->benchmark.transform.link);
wl_list_init(&shell->workspaces.anim_sticky_list);
wl_list_init(&shell->workspaces.animation.link);
shell->workspaces.animation.frame = animate_workspace_change_frame;
--
1.8.1.5
ppaalanen
2013-05-22 15:03:16 UTC
Permalink
From: Daniel Stone <daniel at fooishbar.org>

Add the ability to bind to modifiers; the binding is armed when a key
which sets the requested modifier is pressed, and triggered if the key
is released with no other keys having been pressed in the meantime, as
well as mouse buttons or scroll axes.

This only works for direct modifiers (e.g. Shift and Alt), not modifiers
which latch or lock.

Signed-off-by: Daniel Stone <daniel at fooishbar.org>
---
src/bindings.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/compositor.c | 1 +
src/compositor.h | 16 ++++++++++++++++
src/input.c | 38 +++++++++++++++++++++++++++++++++++++
4 files changed, 113 insertions(+)

diff --git a/src/bindings.c b/src/bindings.c
index e548ff1..e560b61 100644
--- a/src/bindings.c
+++ b/src/bindings.c
@@ -74,6 +74,24 @@ weston_compositor_add_key_binding(struct weston_compositor *compositor,
}

WL_EXPORT struct weston_binding *
+weston_compositor_add_modifier_binding(struct weston_compositor *compositor,
+ uint32_t modifier,
+ weston_modifier_binding_handler_t handler,
+ void *data)
+{
+ struct weston_binding *binding;
+
+ binding = weston_compositor_add_binding(compositor, 0, 0, 0,
+ modifier, handler, data);
+ if (binding == NULL)
+ return NULL;
+
+ wl_list_insert(compositor->modifier_binding_list.prev, &binding->link);
+
+ return binding;
+}
+
+WL_EXPORT struct weston_binding *
weston_compositor_add_button_binding(struct weston_compositor *compositor,
uint32_t button, uint32_t modifier,
weston_button_binding_handler_t handler,
@@ -215,6 +233,10 @@ weston_compositor_run_key_binding(struct weston_compositor *compositor,
if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
return;

+ /* Invalidate all active modifier bindings. */
+ wl_list_for_each(b, &compositor->modifier_binding_list, link)
+ b->key = key;
+
wl_list_for_each(b, &compositor->key_binding_list, link) {
if (b->key == key && b->modifier == seat->modifier_state) {
weston_key_binding_handler_t handler = b->handler;
@@ -231,6 +253,34 @@ weston_compositor_run_key_binding(struct weston_compositor *compositor,
}

WL_EXPORT void
+weston_compositor_run_modifier_binding(struct weston_compositor *compositor,
+ struct weston_seat *seat,
+ enum weston_keyboard_modifier modifier,
+ enum wl_keyboard_key_state state)
+{
+ struct weston_binding *b;
+
+ wl_list_for_each(b, &compositor->modifier_binding_list, link) {
+ weston_modifier_binding_handler_t handler = b->handler;
+
+ if (b->modifier != modifier)
+ continue;
+
+ /* Prime the modifier binding. */
+ if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+ b->key = 0;
+ continue;
+ }
+ /* Ignore the binding if a key was pressed in between. */
+ else if (b->key != 0) {
+ return;
+ }
+
+ handler(seat, modifier, b->data);
+ }
+}
+
+WL_EXPORT void
weston_compositor_run_button_binding(struct weston_compositor *compositor,
struct weston_seat *seat,
uint32_t time, uint32_t button,
@@ -241,6 +291,10 @@ weston_compositor_run_button_binding(struct weston_compositor *compositor,
if (state == WL_POINTER_BUTTON_STATE_RELEASED)
return;

+ /* Invalidate all active modifier bindings. */
+ wl_list_for_each(b, &compositor->modifier_binding_list, link)
+ b->key = button;
+
wl_list_for_each(b, &compositor->button_binding_list, link) {
if (b->button == button && b->modifier == seat->modifier_state) {
weston_button_binding_handler_t handler = b->handler;
@@ -257,6 +311,10 @@ weston_compositor_run_axis_binding(struct weston_compositor *compositor,
{
struct weston_binding *b;

+ /* Invalidate all active modifier bindings. */
+ wl_list_for_each(b, &compositor->modifier_binding_list, link)
+ b->key = axis;
+
wl_list_for_each(b, &compositor->axis_binding_list, link) {
if (b->axis == axis && b->modifier == seat->modifier_state) {
weston_axis_binding_handler_t handler = b->handler;
diff --git a/src/compositor.c b/src/compositor.c
index 238c809..aa5baaf 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -2786,6 +2786,7 @@ weston_compositor_init(struct weston_compositor *ec,
wl_list_init(&ec->seat_list);
wl_list_init(&ec->output_list);
wl_list_init(&ec->key_binding_list);
+ wl_list_init(&ec->modifier_binding_list);
wl_list_init(&ec->button_binding_list);
wl_list_init(&ec->axis_binding_list);
wl_list_init(&ec->debug_binding_list);
diff --git a/src/compositor.h b/src/compositor.h
index 96cabeb..4d70ba2 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -528,6 +528,7 @@ struct weston_compositor {
struct wl_list surface_list;
struct wl_list plane_list;
struct wl_list key_binding_list;
+ struct wl_list modifier_binding_list;
struct wl_list button_binding_list;
struct wl_list axis_binding_list;
struct wl_list debug_binding_list;
@@ -904,6 +905,15 @@ weston_compositor_add_key_binding(struct weston_compositor *compositor,
weston_key_binding_handler_t binding,
void *data);

+typedef void (*weston_modifier_binding_handler_t)(struct weston_seat *seat,
+ enum weston_keyboard_modifier modifier,
+ void *data);
+struct weston_binding *
+weston_compositor_add_modifier_binding(struct weston_compositor *compositor,
+ enum weston_keyboard_modifier modifier,
+ weston_modifier_binding_handler_t binding,
+ void *data);
+
typedef void (*weston_button_binding_handler_t)(struct weston_seat *seat,
uint32_t time, uint32_t button,
void *data);
@@ -939,6 +949,12 @@ weston_compositor_run_key_binding(struct weston_compositor *compositor,
struct weston_seat *seat, uint32_t time,
uint32_t key,
enum wl_keyboard_key_state state);
+
+void
+weston_compositor_run_modifier_binding(struct weston_compositor *compositor,
+ struct weston_seat *seat,
+ enum weston_keyboard_modifier modifier,
+ enum wl_keyboard_key_state state);
void
weston_compositor_run_button_binding(struct weston_compositor *compositor,
struct weston_seat *seat, uint32_t time,
diff --git a/src/input.c b/src/input.c
index 129593f..a49fafb 100644
--- a/src/input.c
+++ b/src/input.c
@@ -741,6 +741,41 @@ notify_axis(struct weston_seat *seat, uint32_t time, uint32_t axis,
value);
}

+static void
+run_modifier_bindings(struct weston_seat *seat, uint32_t old, uint32_t new)
+{
+ struct weston_compositor *compositor = seat->compositor;
+ uint32_t diff;
+ unsigned int i;
+ struct {
+ uint32_t xkb;
+ enum weston_keyboard_modifier weston;
+ } mods[] = {
+ { seat->xkb_info.ctrl_mod, MODIFIER_CTRL },
+ { seat->xkb_info.alt_mod, MODIFIER_ALT },
+ { seat->xkb_info.super_mod, MODIFIER_SUPER },
+ { seat->xkb_info.shift_mod, MODIFIER_SHIFT },
+ };
+
+ diff = new & ~old;
+ for (i = 0; i < ARRAY_LENGTH(mods); i++) {
+ if (diff & (1 << mods[i].xkb))
+ weston_compositor_run_modifier_binding(compositor,
+ seat,
+ mods[i].weston,
+ WL_KEYBOARD_KEY_STATE_PRESSED);
+ }
+
+ diff = old & ~new;
+ for (i = 0; i < ARRAY_LENGTH(mods); i++) {
+ if (diff & (1 << mods[i].xkb))
+ weston_compositor_run_modifier_binding(compositor,
+ seat,
+ mods[i].weston,
+ WL_KEYBOARD_KEY_STATE_RELEASED);
+ }
+}
+
WL_EXPORT void
notify_modifiers(struct weston_seat *seat, uint32_t serial)
{
@@ -768,6 +803,9 @@ notify_modifiers(struct weston_seat *seat, uint32_t serial)
group != seat->keyboard->modifiers.group)
changed = 1;

+ run_modifier_bindings(seat, seat->keyboard->modifiers.mods_depressed,
+ mods_depressed);
+
seat->keyboard->modifiers.mods_depressed = mods_depressed;
seat->keyboard->modifiers.mods_latched = mods_latched;
seat->keyboard->modifiers.mods_locked = mods_locked;
--
1.8.1.5
ppaalanen
2013-05-22 15:03:17 UTC
Permalink
From: Daniel Stone <daniel at fooishbar.org>

Add an animation which moves a surface to a new location, at the same
time as also rescaling it to a different size from the origin, rather
than the existing scale animation which resizes from the centre.

Signed-off-by: Daniel Stone <daniel at fooishbar.org>
---
src/animation.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/compositor.h | 5 +++++
2 files changed, 67 insertions(+)

diff --git a/src/animation.c b/src/animation.c
index 835ed13..7dd3683 100644
--- a/src/animation.c
+++ b/src/animation.c
@@ -339,3 +339,65 @@ weston_slide_run(struct weston_surface *surface, float start, float stop,

return animation;
}
+
+struct weston_move_animation {
+ int dx;
+ int dy;
+ int reverse;
+ weston_surface_animation_done_func_t done;
+};
+
+static void
+move_frame(struct weston_surface_animation *animation)
+{
+ struct weston_move_animation *move = animation->private;
+ float scale;
+ float progress = animation->spring.current;
+
+ if (move->reverse)
+ progress = 1.0 - progress;
+
+ scale = animation->start +
+ (animation->stop - animation->start) *
+ progress;
+ weston_matrix_init(&animation->transform.matrix);
+ weston_matrix_scale(&animation->transform.matrix, scale, scale, 1.0f);
+ weston_matrix_translate(&animation->transform.matrix,
+ move->dx * progress, move->dy * progress,
+ 0);
+}
+
+static void
+move_done(struct weston_surface_animation *animation, void *data)
+{
+ struct weston_move_animation *move = animation->private;
+
+ if (move->done)
+ move->done(animation, data);
+
+ free(move);
+}
+
+WL_EXPORT struct weston_surface_animation *
+weston_move_scale_run(struct weston_surface *surface, int dx, int dy,
+ float start, float end, int reverse,
+ weston_surface_animation_done_func_t done, void *data)
+{
+ struct weston_move_animation *move;
+ struct weston_surface_animation *animation;
+
+ move = malloc(sizeof(*move));
+ if (!move)
+ return NULL;
+ move->dx = dx;
+ move->dy = dy;
+ move->reverse = reverse;
+ move->done = done;
+
+ animation = weston_surface_animation_run(surface, start, end, move_frame,
+ move_done, data, move);
+ animation->spring.k = 400;
+ animation->spring.friction = 1150;
+
+ return animation;
+}
diff --git a/src/compositor.h b/src/compositor.h
index 4d70ba2..2de6eb4 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -1142,6 +1142,11 @@ struct weston_surface_animation *
weston_fade_run(struct weston_surface *surface,
float start, float end, float k,
weston_surface_animation_done_func_t done, void *data);
+
+struct weston_surface_animation *
+weston_move_scale_run(struct weston_surface *surface, int dx, int dy,
+ float start, float end, int reverse,
+ weston_surface_animation_done_func_t done, void *data);
void
weston_fade_update(struct weston_surface_animation *fade,
float start, float end, float k);
--
1.8.1.5
ppaalanen
2013-05-22 15:03:18 UTC
Permalink
From: Daniel Stone <daniel at fooishbar.org>

Exposay provides window overview functions which, when a key which
produces the binding modifier is pressed on its own, scales all
currently-open windows down to be shown overlaid on the desktop,
providing keyboard and mouse navigation to be able to switch window
focus.

Signed-off-by: Daniel Stone <daniel at fooishbar.org>
---
src/shell.c | 574 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 574 insertions(+)

diff --git a/src/shell.c b/src/shell.c
index 812296a..e0d579a 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -1,6 +1,7 @@
/*
* Copyright ? 2010-2012 Intel Corporation
* Copyright ? 2011-2012 Collabora, Ltd.
+ * Copyright ? 2013 Raspberry Pi Foundation
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
@@ -55,6 +56,19 @@ enum fade_type {
FADE_OUT
};

+enum exposay_target_state {
+ EXPOSAY_TARGET_OVERVIEW, /* show all windows */
+ EXPOSAY_TARGET_CANCEL, /* return to normal, same focus */
+ EXPOSAY_TARGET_SWITCH, /* return to normal, switch focus */
+};
+
+enum exposay_layout_state {
+ EXPOSAY_LAYOUT_INACTIVE = 0, /* normal desktop */
+ EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE, /* in transition to normal */
+ EXPOSAY_LAYOUT_OVERVIEW, /* show all windows */
+ EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW, /* in transition to all windows */
+};
+
struct focus_state {
struct weston_seat *seat;
struct workspace *ws;
@@ -181,6 +195,34 @@ struct desktop_shell {
struct wl_event_source *startup_timer;
} fade;

+ struct exposay {
+ /* XXX: Make these exposay_surfaces. */
+ struct weston_surface *focus_prev;
+ struct weston_surface *focus_current;
+ struct weston_surface *clicked;
+ struct workspace *workspace;
+ struct weston_seat *seat;
+ struct wl_list surface_list;
+
+ struct weston_keyboard_grab grab_kbd;
+ struct weston_pointer_grab grab_ptr;
+
+ enum exposay_target_state state_target;
+ enum exposay_layout_state state_cur;
+ int in_flight; /* number of animations still running */
+
+ int num_surfaces;
+ int grid_size;
+ int surface_size;
+
+ int hpadding_outer;
+ int vpadding_outer;
+ int padding_inner;
+
+ int row_current;
+ int column_current;
+ } exposay;
+
uint32_t binding_modifier;
enum animation_type win_animation_type;
enum animation_type focus_animation_type;
@@ -4244,6 +4286,533 @@ switcher_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
switcher_next(switcher);
}

+struct exposay_surface {
+ struct desktop_shell *shell;
+ struct weston_surface *surface;
+ struct wl_list link;
+
+ int x;
+ int y;
+ int width;
+ int height;
+ double scale;
+
+ int row;
+ int column;
+
+ /* The animations only apply a transformation for their own lifetime,
+ * and don't have an option to indefinitely maintain the
+ * transformation in a steady state - so, we apply our own once the
+ * animation has finished. */
+ struct weston_transform transform;
+};
+
+static void exposay_set_state(struct desktop_shell *shell,
+ enum exposay_target_state state,
+ struct weston_seat *seat);
+static void exposay_check_state(struct desktop_shell *shell);
+
+static void
+exposay_in_flight_inc(struct desktop_shell *shell)
+{
+ shell->exposay.in_flight++;
+}
+
+static void
+exposay_in_flight_dec(struct desktop_shell *shell)
+{
+ if (--shell->exposay.in_flight > 0)
+ return;
+
+ exposay_check_state(shell);
+}
+
+static void
+exposay_animate_in_done(struct weston_surface_animation *animation, void *data)
+{
+ struct exposay_surface *esurface = data;
+
+ wl_list_insert(&esurface->surface->geometry.transformation_list,
+ &esurface->transform.link);
+ weston_matrix_init(&esurface->transform.matrix);
+ weston_matrix_scale(&esurface->transform.matrix,
+ esurface->scale, esurface->scale, 1.0f);
+ weston_matrix_translate(&esurface->transform.matrix,
+ esurface->x - esurface->surface->geometry.x,
+ esurface->y - esurface->surface->geometry.y,
+ 0);
+
+ weston_surface_geometry_dirty(esurface->surface);
+ weston_compositor_schedule_repaint(esurface->surface->compositor);
+
+ exposay_in_flight_dec(esurface->shell);
+}
+
+static void
+exposay_animate_in(struct exposay_surface *esurface)
+{
+ exposay_in_flight_inc(esurface->shell);
+
+ weston_move_scale_run(esurface->surface,
+ esurface->x - esurface->surface->geometry.x,
+ esurface->y - esurface->surface->geometry.y,
+ 1.0, esurface->scale, 0,
+ exposay_animate_in_done, esurface);
+}
+
+static void
+exposay_animate_out_done(struct weston_surface_animation *animation, void *data)
+{
+ struct exposay_surface *esurface = data;
+ struct desktop_shell *shell = esurface->shell;
+
+ wl_list_remove(&esurface->link);
+ free(esurface);
+
+ exposay_in_flight_dec(shell);
+}
+
+static void
+exposay_animate_out(struct exposay_surface *esurface)
+{
+ exposay_in_flight_inc(esurface->shell);
+
+ /* Remove the static transformation set up by
+ * exposay_transform_in_done(). */
+ wl_list_remove(&esurface->transform.link);
+ weston_surface_geometry_dirty(esurface->surface);
+
+ weston_move_scale_run(esurface->surface,
+ esurface->x - esurface->surface->geometry.x,
+ esurface->y - esurface->surface->geometry.y,
+ 1.0, esurface->scale, 1,
+ exposay_animate_out_done, esurface);
+}
+
+static void
+exposay_highlight_surface(struct desktop_shell *shell,
+ struct exposay_surface *esurface)
+{
+ struct weston_surface *ws = NULL;
+
+ if (esurface) {
+ shell->exposay.row_current = esurface->row;
+ shell->exposay.column_current = esurface->column;
+ ws = esurface->surface;
+ }
+
+ animate_focus_change(shell, shell->exposay.workspace,
+ shell->exposay.focus_current, ws);
+ shell->exposay.focus_current = ws;
+}
+
+static int
+exposay_is_animating(struct desktop_shell *shell)
+{
+ if (shell->exposay.state_cur == EXPOSAY_LAYOUT_INACTIVE ||
+ shell->exposay.state_cur == EXPOSAY_LAYOUT_OVERVIEW)
+ return 0;
+
+ return (shell->exposay.in_flight > 0);
+}
+
+static void
+exposay_pick(struct desktop_shell *shell, int x, int y)
+{
+ struct exposay_surface *esurface;
+
+ if (exposay_is_animating(shell))
+ return;
+
+ wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
+ if (x < esurface->x || x > esurface->x + esurface->width)
+ continue;
+ if (y < esurface->y || y > esurface->y + esurface->height)
+ continue;
+
+ exposay_highlight_surface(shell, esurface);
+ return;
+ }
+}
+
+/* Pretty lame layout for now; just tries to make a square. Should take
+ * aspect ratio into account really. Also needs to be notified of surface
+ * addition and removal and adjust layout/animate accordingly. */
+static enum exposay_layout_state
+exposay_layout(struct desktop_shell *shell)
+{
+ struct workspace *workspace = shell->exposay.workspace;
+ struct weston_compositor *compositor = shell->compositor;
+ struct weston_output *output = get_default_output(compositor);
+ struct weston_surface *ws;
+ struct exposay_surface *esurface;
+ int w, h;
+ int i;
+ int last_row_removed = 0;
+
+ wl_list_init(&shell->exposay.surface_list);
+
+ shell->exposay.num_surfaces = 0;
+ wl_list_for_each(ws, &workspace->layer.surface_list, layer_link) {
+ if (!get_shell_surface(ws))
+ continue;
+ shell->exposay.num_surfaces++;
+ }
+
+ if (shell->exposay.num_surfaces == 0) {
+ shell->exposay.grid_size = 0;
+ shell->exposay.hpadding_outer = 0;
+ shell->exposay.vpadding_outer = 0;
+ shell->exposay.padding_inner = 0;
+ shell->exposay.surface_size = 0;
+ return EXPOSAY_LAYOUT_OVERVIEW;
+ }
+
+ /* Lay the grid out as square as possible, losing surfaces from the
+ * bottom row if required. Start with fixed padding of a 10% margin
+ * around the outside and 80px internal padding between surfaces, and
+ * maximise the area made available to surfaces after this, but only
+ * to a maximum of 1/3rd the total output size.
+ *
+ * If we can't make a square grid, add one extra row at the bottom
+ * which will have a smaller number of columns.
+ *
+ * XXX: Surely there has to be a better way to express this maths,
+ * right?!
+ */
+ shell->exposay.grid_size = floor(sqrtf(shell->exposay.num_surfaces));
+ if (pow(shell->exposay.grid_size, 2) != shell->exposay.num_surfaces)
+ shell->exposay.grid_size++;
+ last_row_removed = pow(shell->exposay.grid_size, 2) - shell->exposay.num_surfaces;
+
+ shell->exposay.hpadding_outer = (output->width / 10);
+ shell->exposay.vpadding_outer = (output->height / 10);
+ shell->exposay.padding_inner = 80;
+
+ w = output->width - (shell->exposay.hpadding_outer * 2);
+ w -= shell->exposay.padding_inner * (shell->exposay.grid_size - 1);
+ w /= shell->exposay.grid_size;
+
+ h = output->height - (shell->exposay.vpadding_outer * 2);
+ h -= shell->exposay.padding_inner * (shell->exposay.grid_size - 1);
+ h /= shell->exposay.grid_size;
+
+ shell->exposay.surface_size = (w < h) ? w : h;
+ if (shell->exposay.surface_size > (output->width / 2))
+ shell->exposay.surface_size = output->width / 2;
+ if (shell->exposay.surface_size > (output->height / 2))
+ shell->exposay.surface_size = output->height / 2;
+
+ i = 0;
+ wl_list_for_each(ws, &workspace->layer.surface_list, layer_link) {
+ int pad;
+
+ pad = shell->exposay.surface_size + shell->exposay.padding_inner;
+
+ if (!get_shell_surface(ws))
+ continue;
+
+ esurface = malloc(sizeof(*esurface));
+ if (!esurface) {
+ exposay_set_state(shell, EXPOSAY_TARGET_CANCEL,
+ shell->exposay.seat);
+ break;
+ }
+
+ wl_list_insert(&shell->exposay.surface_list, &esurface->link);
+ esurface->shell = shell;
+ esurface->surface = ws;
+
+ esurface->row = i / shell->exposay.grid_size;
+ esurface->column = i % shell->exposay.grid_size;
+
+ esurface->x = shell->exposay.hpadding_outer;
+ esurface->x += pad * esurface->column;
+ esurface->y = shell->exposay.vpadding_outer;
+ esurface->y += pad * esurface->row;
+
+ if (esurface->row == shell->exposay.grid_size - 1)
+ esurface->x += (shell->exposay.surface_size + shell->exposay.padding_inner) * last_row_removed / 2;
+
+ if (ws->geometry.width > ws->geometry.height)
+ esurface->scale = shell->exposay.surface_size / (float) ws->geometry.width;
+ else
+ esurface->scale = shell->exposay.surface_size / (float) ws->geometry.height;
+ esurface->width = ws->geometry.width * esurface->scale;
+ esurface->height = ws->geometry.height * esurface->scale;
+
+ if (shell->exposay.focus_current == esurface->surface)
+ exposay_highlight_surface(shell, esurface);
+
+ exposay_animate_in(esurface);
+
+ i++;
+ }
+
+ weston_compositor_schedule_repaint(shell->compositor);
+
+ return EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW;
+}
+
+static void
+exposay_motion(struct weston_pointer_grab *grab, uint32_t time)
+{
+ struct desktop_shell *shell =
+ container_of(grab, struct desktop_shell, exposay.grab_ptr);
+
+ exposay_pick(shell,
+ wl_fixed_to_int(grab->pointer->x),
+ wl_fixed_to_int(grab->pointer->y));
+}
+
+static void
+exposay_button(struct weston_pointer_grab *grab, uint32_t time, uint32_t button,
+ uint32_t state_w)
+{
+ struct desktop_shell *shell =
+ container_of(grab, struct desktop_shell, exposay.grab_ptr);
+ struct weston_seat *seat = grab->pointer->seat;
+ enum wl_pointer_button_state state = state_w;
+
+ if (button != BTN_LEFT)
+ return;
+
+ /* Store the surface we clicked on, and don't do anything if we end up
+ * releasing on a different surface. */
+ if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
+ shell->exposay.clicked = shell->exposay.focus_current;
+ return;
+ }
+
+ if (shell->exposay.focus_current == shell->exposay.clicked)
+ exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
+ else
+ shell->exposay.clicked = NULL;
+}
+
+static const struct weston_pointer_grab_interface exposay_ptr_grab = {
+ noop_grab_focus,
+ exposay_motion,
+ exposay_button,
+};
+
+static int
+exposay_maybe_move(struct desktop_shell *shell, int row, int column)
+{
+ struct exposay_surface *esurface;
+
+ wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
+ if (esurface->row != row || esurface->column != column)
+ continue;
+
+ exposay_highlight_surface(shell, esurface);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void
+exposay_key(struct weston_keyboard_grab *grab, uint32_t time, uint32_t key,
+ uint32_t state_w)
+{
+ struct weston_seat *seat = grab->keyboard->seat;
+ struct desktop_shell *shell =
+ container_of(grab, struct desktop_shell, exposay.grab_kbd);
+ enum wl_keyboard_key_state state = state_w;
+
+ if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
+ return;
+
+ switch (key) {
+ case KEY_ESC:
+ exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
+ break;
+ case KEY_ENTER:
+ exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
+ break;
+ case KEY_UP:
+ exposay_maybe_move(shell, shell->exposay.row_current - 1,
+ shell->exposay.column_current);
+ break;
+ case KEY_DOWN:
+ /* Special case for trying to move to the bottom row when it
+ * has fewer items than all the others. */
+ if (!exposay_maybe_move(shell, shell->exposay.row_current + 1,
+ shell->exposay.column_current) &&
+ shell->exposay.row_current < (shell->exposay.grid_size - 1)) {
+ exposay_maybe_move(shell, shell->exposay.row_current + 1,
+ (shell->exposay.num_surfaces %
+ shell->exposay.grid_size) - 1);
+ }
+ break;
+ case KEY_LEFT:
+ exposay_maybe_move(shell, shell->exposay.row_current,
+ shell->exposay.column_current - 1);
+ break;
+ case KEY_RIGHT:
+ exposay_maybe_move(shell, shell->exposay.row_current,
+ shell->exposay.column_current + 1);
+ break;
+ case KEY_TAB:
+ /* Try to move right, then down (and to the leftmost column),
+ * then if all else fails, to the top left. */
+ if (!exposay_maybe_move(shell, shell->exposay.row_current,
+ shell->exposay.column_current + 1) &&
+ !exposay_maybe_move(shell, shell->exposay.row_current + 1, 0))
+ exposay_maybe_move(shell, 0, 0);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+exposay_modifier(struct weston_keyboard_grab *grab, uint32_t serial,
+ uint32_t mods_depressed, uint32_t mods_latched,
+ uint32_t mods_locked, uint32_t group)
+{
+}
+
+static const struct weston_keyboard_grab_interface exposay_kbd_grab = {
+ exposay_key,
+ exposay_modifier,
+};
+
+/**
+ * Called when the transition from overview -> inactive has completed.
+ */
+static enum exposay_layout_state
+exposay_set_inactive(struct desktop_shell *shell)
+{
+ struct weston_seat *seat = shell->exposay.seat;
+
+ weston_keyboard_end_grab(seat->keyboard);
+ weston_pointer_end_grab(seat->pointer);
+ if (seat->keyboard->input_method_resource)
+ seat->keyboard->grab = &seat->keyboard->input_method_grab;
+
+ return EXPOSAY_LAYOUT_INACTIVE;
+}
+
+/**
+ * Begins the transition from overview to inactive. */
+static enum exposay_layout_state
+exposay_transition_inactive(struct desktop_shell *shell, int switch_focus)
+{
+ struct exposay_surface *esurface;
+
+ /* Call activate() before we start the animations to avoid
+ * animating back the old state and then immediately transitioning
+ * to the new. */
+ if (switch_focus && shell->exposay.focus_current)
+ activate(shell, shell->exposay.focus_current,
+ shell->exposay.seat);
+ else if (shell->exposay.focus_prev)
+ activate(shell, shell->exposay.focus_prev,
+ shell->exposay.seat);
+
+ wl_list_for_each(esurface, &shell->exposay.surface_list, link)
+ exposay_animate_out(esurface);
+ weston_compositor_schedule_repaint(shell->compositor);
+
+ return EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE;
+}
+
+static enum exposay_layout_state
+exposay_transition_active(struct desktop_shell *shell)
+{
+ struct weston_seat *seat = shell->exposay.seat;
+
+ shell->exposay.workspace = get_current_workspace(shell);
+ shell->exposay.focus_prev = seat->keyboard->focus;
+ shell->exposay.focus_current = seat->keyboard->focus;
+ shell->exposay.clicked = NULL;
+ wl_list_init(&shell->exposay.surface_list);
+
+ lower_fullscreen_layer(shell);
+ shell->exposay.grab_kbd.interface = &exposay_kbd_grab;
+ weston_keyboard_start_grab(seat->keyboard,
+ &shell->exposay.grab_kbd);
+ weston_keyboard_set_focus(seat->keyboard, NULL);
+
+ shell->exposay.grab_ptr.interface = &exposay_ptr_grab;
+ weston_pointer_start_grab(seat->pointer,
+ &shell->exposay.grab_ptr);
+ weston_pointer_set_focus(seat->pointer, NULL,
+ seat->pointer->x, seat->pointer->y);
+
+ return exposay_layout(shell);
+}
+
+static void
+exposay_check_state(struct desktop_shell *shell)
+{
+ enum exposay_layout_state state_new = shell->exposay.state_cur;
+ int do_switch = 0;
+
+ /* Don't do anything whilst animations are running, just store up
+ * target state changes and only act on them when the animations have
+ * completed. */
+ if (exposay_is_animating(shell))
+ return;
+
+ switch (shell->exposay.state_target) {
+ case EXPOSAY_TARGET_OVERVIEW:
+ switch (shell->exposay.state_cur) {
+ case EXPOSAY_LAYOUT_OVERVIEW:
+ goto out;
+ case EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW:
+ state_new = EXPOSAY_LAYOUT_OVERVIEW;
+ break;
+ default:
+ state_new = exposay_transition_active(shell);
+ break;
+ }
+ break;
+
+ case EXPOSAY_TARGET_SWITCH:
+ do_switch = 1; /* fallthrough */
+ case EXPOSAY_TARGET_CANCEL:
+ switch (shell->exposay.state_cur) {
+ case EXPOSAY_LAYOUT_INACTIVE:
+ goto out;
+ case EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE:
+ state_new = exposay_set_inactive(shell);
+ break;
+ default:
+ state_new = exposay_transition_inactive(shell, do_switch);
+ break;
+ }
+
+ break;
+ }
+
+out:
+ shell->exposay.state_cur = state_new;
+}
+
+static void
+exposay_set_state(struct desktop_shell *shell, enum exposay_target_state state,
+ struct weston_seat *seat)
+{
+ shell->exposay.state_target = state;
+ shell->exposay.seat = seat;
+ exposay_check_state(shell);
+}
+
+static void
+exposay_binding(struct weston_seat *seat, enum weston_keyboard_modifier modifier,
+ void *data)
+{
+ struct desktop_shell *shell = data;
+
+ if (shell->exposay.state_target == EXPOSAY_TARGET_OVERVIEW)
+ exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
+ else
+ exposay_set_state(shell, EXPOSAY_TARGET_OVERVIEW, seat);
+}
+
static void
backlight_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
void *data)
@@ -4686,6 +5255,8 @@ shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
workspace_move_surface_down_binding,
shell);

+ weston_compositor_add_modifier_binding(ec, mod, exposay_binding, shell);
+
/* Add bindings for mod+F[1-6] for workspace 1 to 6. */
if (shell->workspaces.num > 1) {
num_workspace_bindings = shell->workspaces.num;
@@ -4756,6 +5327,9 @@ module_init(struct weston_compositor *ec,

shell_configuration(shell, ec->config_fd);

+ shell->exposay.state_cur = EXPOSAY_LAYOUT_INACTIVE;
+ shell->exposay.state_target = EXPOSAY_TARGET_CANCEL;
+
for (i = 0; i < shell->workspaces.num; i++) {
pws = wl_array_add(&shell->workspaces.array, sizeof *pws);
if (pws == NULL)
--
1.8.1.5
ppaalanen
2013-05-22 15:03:19 UTC
Permalink
From: Daniel Stone <daniel at fooishbar.org>

AC_USE_SYSTEM_EXTENSIONS enables _XOPEN_SOURCE, _GNU_SOURCE and similar
macros to expose the largest extent of functionality supported by the
underlying system. This is required since these macros are often
limiting rather than merely additive, e.g. _XOPEN_SOURCE will actually
on some systems hide declarations which are not part of the X/Open spec.

Since this goes into config.h rather than the command line, ensure all
source is consistently including config.h before anything else,
including system libraries. This doesn't need to be guarded by a
HAVE_CONFIG_H ifdef, which was only ever a hangover from the X.Org
modular transition.

Signed-off-by: Daniel Stone <daniel at fooishbar.org>

[pq: rebased and converted more files]
---
clients/window.c | 4 +---
configure.ac | 2 ++
shared/cairo-util.c | 2 +-
shared/config-parser.c | 3 ++-
shared/image-loader.c | 2 +-
shared/matrix.c | 2 ++
shared/option-parser.c | 2 ++
shared/os-compatibility.c | 2 +-
src/animation.c | 2 ++
src/bindings.c | 2 ++
src/clipboard.c | 2 +-
src/cms-helper.c | 4 +---
src/cms-static.c | 5 +----
src/compositor-drm.c | 6 +-----
src/compositor-fbdev.c | 2 +-
src/compositor-headless.c | 4 +---
src/compositor-rdp.c | 4 +---
src/compositor-rpi.c | 4 +---
src/compositor-wayland.c | 5 +----
src/compositor-x11.c | 4 +---
src/compositor.c | 2 --
src/evdev-touchpad.c | 2 ++
src/evdev.c | 2 ++
src/filter.c | 2 ++
src/gl-renderer.c | 2 +-
src/gl-renderer.h | 7 +++----
src/launcher-util.c | 2 ++
src/libbacklight.c | 2 +-
src/log.c | 2 ++
src/noop-renderer.c | 2 +-
src/pixman-renderer.c | 2 +-
src/rpi-renderer.c | 4 ++--
src/screenshooter.c | 2 ++
src/shell.c | 2 ++
src/tablet-shell.c | 2 ++
src/text-backend.c | 2 ++
src/tty.c | 2 ++
src/udev-seat.c | 2 ++
src/weston-launch.c | 2 --
src/xwayland/launcher.c | 2 +-
src/xwayland/selection.c | 2 +-
src/xwayland/window-manager.c | 2 +-
src/zoom.c | 2 ++
43 files changed, 62 insertions(+), 54 deletions(-)

diff --git a/clients/window.c b/clients/window.c
index 3f54111..28df2ca 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -21,9 +21,7 @@
* OF THIS SOFTWARE.
*/

-#define _GNU_SOURCE
-
-#include "../config.h"
+#include "config.h"

#include <stdint.h>
#include <stdio.h>
diff --git a/configure.ac b/configure.ac
index 323bd87..68a54e7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -18,6 +18,8 @@ AC_SUBST([WESTON_VERSION], [weston_version])

AC_CONFIG_HEADERS([config.h])

+AC_USE_SYSTEM_EXTENSIONS
+
AM_INIT_AUTOMAKE([1.11 parallel-tests foreign no-dist-gzip dist-xz color-tests])

AM_SILENT_RULES([yes])
diff --git a/shared/cairo-util.c b/shared/cairo-util.c
index 8b41f41..c3a966a 100644
--- a/shared/cairo-util.c
+++ b/shared/cairo-util.c
@@ -21,7 +21,7 @@
* OF THIS SOFTWARE.
*/

-#include "../config.h"
+#include "config.h"

#include <stdint.h>
#include <stdlib.h>
diff --git a/shared/config-parser.c b/shared/config-parser.c
index 652da1f..a49e29e 100644
--- a/shared/config-parser.c
+++ b/shared/config-parser.c
@@ -20,7 +20,8 @@
* OF THIS SOFTWARE.
*/

-#define _GNU_SOURCE /* for stchrnul() */
+#include "config.h"
+
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/shared/image-loader.c b/shared/image-loader.c
index 9f65dea..35dadd3 100644
--- a/shared/image-loader.c
+++ b/shared/image-loader.c
@@ -21,7 +21,7 @@
* OF THIS SOFTWARE.
*/

-#include "../config.h"
+#include "config.h"

#include <stdlib.h>
#include <stdio.h>
diff --git a/shared/matrix.c b/shared/matrix.c
index 3ff4089..4f0b6b7 100644
--- a/shared/matrix.c
+++ b/shared/matrix.c
@@ -21,6 +21,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

+#include "config.h"
+
#include <float.h>
#include <string.h>
#include <stdlib.h>
diff --git a/shared/option-parser.c b/shared/option-parser.c
index a7e497f..c00349a 100644
--- a/shared/option-parser.c
+++ b/shared/option-parser.c
@@ -20,6 +20,8 @@
* OF THIS SOFTWARE.
*/

+#include "config.h"
+
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
diff --git a/shared/os-compatibility.c b/shared/os-compatibility.c
index 21d4d02..4f96dd4 100644
--- a/shared/os-compatibility.c
+++ b/shared/os-compatibility.c
@@ -20,7 +20,7 @@
* OF THIS SOFTWARE.
*/

-#define _GNU_SOURCE
+#include "config.h"

#include <sys/types.h>
#include <sys/socket.h>
diff --git a/src/animation.c b/src/animation.c
index 7dd3683..80b200e 100644
--- a/src/animation.c
+++ b/src/animation.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

+#include "config.h"
+
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
diff --git a/src/bindings.c b/src/bindings.c
index e560b61..8022f55 100644
--- a/src/bindings.c
+++ b/src/bindings.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

+#include "config.h"
+
#include <stdlib.h>

#include "compositor.h"
diff --git a/src/clipboard.c b/src/clipboard.c
index 11edc71..eb0b230 100644
--- a/src/clipboard.c
+++ b/src/clipboard.c
@@ -20,7 +20,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#define _GNU_SOURCE
+#include "config.h"

#include <stdlib.h>
#include <string.h>
diff --git a/src/cms-helper.c b/src/cms-helper.c
index 2c7b57f..c063c77 100644
--- a/src/cms-helper.c
+++ b/src/cms-helper.c
@@ -20,9 +20,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "config.h"

#include <stdlib.h>
#include <string.h>
diff --git a/src/cms-static.c b/src/cms-static.c
index 94fea99..be2004a 100644
--- a/src/cms-static.c
+++ b/src/cms-static.c
@@ -20,11 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "config.h"

-#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>

diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 35019e0..7340a1b 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -21,11 +21,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#define _GNU_SOURCE
+#include "config.h"

#include <errno.h>
#include <stdlib.h>
diff --git a/src/compositor-fbdev.c b/src/compositor-fbdev.c
index 21028a5..7b092d3 100644
--- a/src/compositor-fbdev.c
+++ b/src/compositor-fbdev.c
@@ -23,7 +23,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#define _GNU_SOURCE
+#include "config.h"

#include <errno.h>
#include <stdlib.h>
diff --git a/src/compositor-headless.c b/src/compositor-headless.c
index 0df0f7d..6115ecd 100644
--- a/src/compositor-headless.c
+++ b/src/compositor-headless.c
@@ -21,9 +21,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "config.h"

#include <stdlib.h>
#include <string.h>
diff --git a/src/compositor-rdp.c b/src/compositor-rdp.c
index 0dae963..0293486 100644
--- a/src/compositor-rdp.c
+++ b/src/compositor-rdp.c
@@ -20,9 +20,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "config.h"

#include <stdlib.h>
#include <string.h>
diff --git a/src/compositor-rpi.c b/src/compositor-rpi.c
index 64ef0ff..f1f920b 100644
--- a/src/compositor-rpi.c
+++ b/src/compositor-rpi.c
@@ -22,7 +22,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#define _GNU_SOURCE
+#include "config.h"

#include <errno.h>
#include <stdlib.h>
@@ -35,8 +35,6 @@

#include <libudev.h>

-#include "config.h"
-
#ifdef HAVE_BCM_HOST
# include <bcm_host.h>
#else
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index 4112401..3368ee1 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -20,12 +20,9 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "config.h"

#include <stddef.h>
-#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/src/compositor-x11.c b/src/compositor-x11.c
index ea0d4b9..07ca824 100644
--- a/src/compositor-x11.c
+++ b/src/compositor-x11.c
@@ -22,9 +22,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "config.h"

#include <assert.h>
#include <stddef.h>
diff --git a/src/compositor.c b/src/compositor.c
index aa5baaf..4654d83 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -22,8 +22,6 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#define _GNU_SOURCE
-
#include "config.h"

#include <fcntl.h>
diff --git a/src/evdev-touchpad.c b/src/evdev-touchpad.c
index 4f9bb03..a21ae0b 100644
--- a/src/evdev-touchpad.c
+++ b/src/evdev-touchpad.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

+#include "config.h"
+
#include <stdlib.h>
#include <math.h>
#include <string.h>
diff --git a/src/evdev.c b/src/evdev.c
index 9289b1c..122a2d9 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

+#include "config.h"
+
#include <stdlib.h>
#include <string.h>
#include <linux/input.h>
diff --git a/src/filter.c b/src/filter.c
index 91e588d..a55ebf2 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

+#include "config.h"
+
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index 4915b90..ff7920c 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -20,7 +20,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#define _GNU_SOURCE
+#include "config.h"

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
diff --git a/src/gl-renderer.h b/src/gl-renderer.h
index a2e8690..4919a1e 100644
--- a/src/gl-renderer.h
+++ b/src/gl-renderer.h
@@ -20,10 +20,9 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include "compositor.h"
+#include "config.h"
+
+#include "compositor.h"

#ifdef ENABLE_EGL

diff --git a/src/launcher-util.c b/src/launcher-util.c
index 9196e4f..6f6ee11 100644
--- a/src/launcher-util.c
+++ b/src/launcher-util.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

+#include "config.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/src/libbacklight.c b/src/libbacklight.c
index 98a20be..b3acc63 100644
--- a/src/libbacklight.c
+++ b/src/libbacklight.c
@@ -29,7 +29,7 @@
* Tiago Vignatti <vignatti at freedesktop.org>
*/

-#define _GNU_SOURCE
+#include "config.h"

#include "libbacklight.h"
#include <stdio.h>
diff --git a/src/log.c b/src/log.c
index e5430d6..1c05e25 100644
--- a/src/log.c
+++ b/src/log.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

+#include "config.h"
+
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
diff --git a/src/noop-renderer.c b/src/noop-renderer.c
index a0b1679..c0765f2 100644
--- a/src/noop-renderer.c
+++ b/src/noop-renderer.c
@@ -20,7 +20,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#define _GNU_SOURCE
+#include "config.h"

#include <stdlib.h>

diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c
index 36563c6..b036135 100644
--- a/src/pixman-renderer.c
+++ b/src/pixman-renderer.c
@@ -21,7 +21,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#define _GNU_SOURCE
+#include "config.h"

#include <errno.h>
#include <stdlib.h>
diff --git a/src/rpi-renderer.c b/src/rpi-renderer.c
index e429d2e..c361185 100644
--- a/src/rpi-renderer.c
+++ b/src/rpi-renderer.c
@@ -20,12 +20,12 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

+#include "config.h"
+
#include <stdlib.h>
#include <assert.h>
#include <string.h>

-#include "config.h"
-
#ifdef HAVE_BCM_HOST
# include <bcm_host.h>
#else
diff --git a/src/screenshooter.c b/src/screenshooter.c
index dde052f..ee2585b 100644
--- a/src/screenshooter.c
+++ b/src/screenshooter.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

+#include "config.h"
+
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
diff --git a/src/shell.c b/src/shell.c
index e0d579a..e46c30f 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -22,6 +22,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

+#include "config.h"
+
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
diff --git a/src/tablet-shell.c b/src/tablet-shell.c
index cae8acf..91fbaed 100644
--- a/src/tablet-shell.c
+++ b/src/tablet-shell.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

+#include "config.h"
+
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
diff --git a/src/text-backend.c b/src/text-backend.c
index 3d1670b..67cacf6 100644
--- a/src/text-backend.c
+++ b/src/text-backend.c
@@ -21,6 +21,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

+#include "config.h"
+
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
diff --git a/src/tty.c b/src/tty.c
index 05e5e20..2324f6c 100644
--- a/src/tty.c
+++ b/src/tty.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

+#include "config.h"
+
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/src/udev-seat.c b/src/udev-seat.c
index 7e62429..05b8163 100644
--- a/src/udev-seat.c
+++ b/src/udev-seat.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

+#include "config.h"
+
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
diff --git a/src/weston-launch.c b/src/weston-launch.c
index 42b2506..bd621a0 100644
--- a/src/weston-launch.c
+++ b/src/weston-launch.c
@@ -20,8 +20,6 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#define _GNU_SOURCE
-
#include "config.h"

#include <stdio.h>
diff --git a/src/xwayland/launcher.c b/src/xwayland/launcher.c
index 664cf6c..a8ad478 100644
--- a/src/xwayland/launcher.c
+++ b/src/xwayland/launcher.c
@@ -20,7 +20,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#define _GNU_SOURCE
+#include "config.h"

#include <stdlib.h>
#include <stdio.h>
diff --git a/src/xwayland/selection.c b/src/xwayland/selection.c
index 69665b7..66cb5fe 100644
--- a/src/xwayland/selection.c
+++ b/src/xwayland/selection.c
@@ -20,7 +20,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#define _GNU_SOURCE
+#include "config.h"

#include <stdlib.h>
#include <string.h>
diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c
index b4b0a83..366f2e0 100644
--- a/src/xwayland/window-manager.c
+++ b/src/xwayland/window-manager.c
@@ -20,7 +20,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

-#define _GNU_SOURCE
+#include "config.h"

#include <stdlib.h>
#include <stdio.h>
diff --git a/src/zoom.c b/src/zoom.c
index ccc5d49..292aed6 100644
--- a/src/zoom.c
+++ b/src/zoom.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

+#include "config.h"
+
#include <stdlib.h>

#include "compositor.h"
--
1.8.1.5
Kristian Høgsberg
2013-06-05 05:17:45 UTC
Permalink
Post by ppaalanen
From: Daniel Stone <daniel at fooishbar.org>
AC_USE_SYSTEM_EXTENSIONS enables _XOPEN_SOURCE, _GNU_SOURCE and similar
macros to expose the largest extent of functionality supported by the
underlying system. This is required since these macros are often
limiting rather than merely additive, e.g. _XOPEN_SOURCE will actually
on some systems hide declarations which are not part of the X/Open spec.
Since this goes into config.h rather than the command line, ensure all
source is consistently including config.h before anything else,
including system libraries. This doesn't need to be guarded by a
HAVE_CONFIG_H ifdef, which was only ever a hangover from the X.Org
modular transition.
Makes sense, applied.

Kristian
Post by ppaalanen
Signed-off-by: Daniel Stone <daniel at fooishbar.org>
[pq: rebased and converted more files]
---
clients/window.c | 4 +---
configure.ac | 2 ++
shared/cairo-util.c | 2 +-
shared/config-parser.c | 3 ++-
shared/image-loader.c | 2 +-
shared/matrix.c | 2 ++
shared/option-parser.c | 2 ++
shared/os-compatibility.c | 2 +-
src/animation.c | 2 ++
src/bindings.c | 2 ++
src/clipboard.c | 2 +-
src/cms-helper.c | 4 +---
src/cms-static.c | 5 +----
src/compositor-drm.c | 6 +-----
src/compositor-fbdev.c | 2 +-
src/compositor-headless.c | 4 +---
src/compositor-rdp.c | 4 +---
src/compositor-rpi.c | 4 +---
src/compositor-wayland.c | 5 +----
src/compositor-x11.c | 4 +---
src/compositor.c | 2 --
src/evdev-touchpad.c | 2 ++
src/evdev.c | 2 ++
src/filter.c | 2 ++
src/gl-renderer.c | 2 +-
src/gl-renderer.h | 7 +++----
src/launcher-util.c | 2 ++
src/libbacklight.c | 2 +-
src/log.c | 2 ++
src/noop-renderer.c | 2 +-
src/pixman-renderer.c | 2 +-
src/rpi-renderer.c | 4 ++--
src/screenshooter.c | 2 ++
src/shell.c | 2 ++
src/tablet-shell.c | 2 ++
src/text-backend.c | 2 ++
src/tty.c | 2 ++
src/udev-seat.c | 2 ++
src/weston-launch.c | 2 --
src/xwayland/launcher.c | 2 +-
src/xwayland/selection.c | 2 +-
src/xwayland/window-manager.c | 2 +-
src/zoom.c | 2 ++
43 files changed, 62 insertions(+), 54 deletions(-)
diff --git a/clients/window.c b/clients/window.c
index 3f54111..28df2ca 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -21,9 +21,7 @@
* OF THIS SOFTWARE.
*/
-#define _GNU_SOURCE
-
-#include "../config.h"
+#include "config.h"
#include <stdint.h>
#include <stdio.h>
diff --git a/configure.ac b/configure.ac
index 323bd87..68a54e7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -18,6 +18,8 @@ AC_SUBST([WESTON_VERSION], [weston_version])
AC_CONFIG_HEADERS([config.h])
+AC_USE_SYSTEM_EXTENSIONS
+
AM_INIT_AUTOMAKE([1.11 parallel-tests foreign no-dist-gzip dist-xz color-tests])
AM_SILENT_RULES([yes])
diff --git a/shared/cairo-util.c b/shared/cairo-util.c
index 8b41f41..c3a966a 100644
--- a/shared/cairo-util.c
+++ b/shared/cairo-util.c
@@ -21,7 +21,7 @@
* OF THIS SOFTWARE.
*/
-#include "../config.h"
+#include "config.h"
#include <stdint.h>
#include <stdlib.h>
diff --git a/shared/config-parser.c b/shared/config-parser.c
index 652da1f..a49e29e 100644
--- a/shared/config-parser.c
+++ b/shared/config-parser.c
@@ -20,7 +20,8 @@
* OF THIS SOFTWARE.
*/
-#define _GNU_SOURCE /* for stchrnul() */
+#include "config.h"
+
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/shared/image-loader.c b/shared/image-loader.c
index 9f65dea..35dadd3 100644
--- a/shared/image-loader.c
+++ b/shared/image-loader.c
@@ -21,7 +21,7 @@
* OF THIS SOFTWARE.
*/
-#include "../config.h"
+#include "config.h"
#include <stdlib.h>
#include <stdio.h>
diff --git a/shared/matrix.c b/shared/matrix.c
index 3ff4089..4f0b6b7 100644
--- a/shared/matrix.c
+++ b/shared/matrix.c
@@ -21,6 +21,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <float.h>
#include <string.h>
#include <stdlib.h>
diff --git a/shared/option-parser.c b/shared/option-parser.c
index a7e497f..c00349a 100644
--- a/shared/option-parser.c
+++ b/shared/option-parser.c
@@ -20,6 +20,8 @@
* OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
diff --git a/shared/os-compatibility.c b/shared/os-compatibility.c
index 21d4d02..4f96dd4 100644
--- a/shared/os-compatibility.c
+++ b/shared/os-compatibility.c
@@ -20,7 +20,7 @@
* OF THIS SOFTWARE.
*/
-#define _GNU_SOURCE
+#include "config.h"
#include <sys/types.h>
#include <sys/socket.h>
diff --git a/src/animation.c b/src/animation.c
index 7dd3683..80b200e 100644
--- a/src/animation.c
+++ b/src/animation.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
diff --git a/src/bindings.c b/src/bindings.c
index e560b61..8022f55 100644
--- a/src/bindings.c
+++ b/src/bindings.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdlib.h>
#include "compositor.h"
diff --git a/src/clipboard.c b/src/clipboard.c
index 11edc71..eb0b230 100644
--- a/src/clipboard.c
+++ b/src/clipboard.c
@@ -20,7 +20,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define _GNU_SOURCE
+#include "config.h"
#include <stdlib.h>
#include <string.h>
diff --git a/src/cms-helper.c b/src/cms-helper.c
index 2c7b57f..c063c77 100644
--- a/src/cms-helper.c
+++ b/src/cms-helper.c
@@ -20,9 +20,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "config.h"
#include <stdlib.h>
#include <string.h>
diff --git a/src/cms-static.c b/src/cms-static.c
index 94fea99..be2004a 100644
--- a/src/cms-static.c
+++ b/src/cms-static.c
@@ -20,11 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "config.h"
-#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 35019e0..7340a1b 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -21,11 +21,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#define _GNU_SOURCE
+#include "config.h"
#include <errno.h>
#include <stdlib.h>
diff --git a/src/compositor-fbdev.c b/src/compositor-fbdev.c
index 21028a5..7b092d3 100644
--- a/src/compositor-fbdev.c
+++ b/src/compositor-fbdev.c
@@ -23,7 +23,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define _GNU_SOURCE
+#include "config.h"
#include <errno.h>
#include <stdlib.h>
diff --git a/src/compositor-headless.c b/src/compositor-headless.c
index 0df0f7d..6115ecd 100644
--- a/src/compositor-headless.c
+++ b/src/compositor-headless.c
@@ -21,9 +21,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "config.h"
#include <stdlib.h>
#include <string.h>
diff --git a/src/compositor-rdp.c b/src/compositor-rdp.c
index 0dae963..0293486 100644
--- a/src/compositor-rdp.c
+++ b/src/compositor-rdp.c
@@ -20,9 +20,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "config.h"
#include <stdlib.h>
#include <string.h>
diff --git a/src/compositor-rpi.c b/src/compositor-rpi.c
index 64ef0ff..f1f920b 100644
--- a/src/compositor-rpi.c
+++ b/src/compositor-rpi.c
@@ -22,7 +22,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define _GNU_SOURCE
+#include "config.h"
#include <errno.h>
#include <stdlib.h>
@@ -35,8 +35,6 @@
#include <libudev.h>
-#include "config.h"
-
#ifdef HAVE_BCM_HOST
# include <bcm_host.h>
#else
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index 4112401..3368ee1 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -20,12 +20,9 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "config.h"
#include <stddef.h>
-#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/src/compositor-x11.c b/src/compositor-x11.c
index ea0d4b9..07ca824 100644
--- a/src/compositor-x11.c
+++ b/src/compositor-x11.c
@@ -22,9 +22,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "config.h"
#include <assert.h>
#include <stddef.h>
diff --git a/src/compositor.c b/src/compositor.c
index aa5baaf..4654d83 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -22,8 +22,6 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define _GNU_SOURCE
-
#include "config.h"
#include <fcntl.h>
diff --git a/src/evdev-touchpad.c b/src/evdev-touchpad.c
index 4f9bb03..a21ae0b 100644
--- a/src/evdev-touchpad.c
+++ b/src/evdev-touchpad.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdlib.h>
#include <math.h>
#include <string.h>
diff --git a/src/evdev.c b/src/evdev.c
index 9289b1c..122a2d9 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdlib.h>
#include <string.h>
#include <linux/input.h>
diff --git a/src/filter.c b/src/filter.c
index 91e588d..a55ebf2 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index 4915b90..ff7920c 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -20,7 +20,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define _GNU_SOURCE
+#include "config.h"
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
diff --git a/src/gl-renderer.h b/src/gl-renderer.h
index a2e8690..4919a1e 100644
--- a/src/gl-renderer.h
+++ b/src/gl-renderer.h
@@ -20,10 +20,9 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include "compositor.h"
+#include "config.h"
+
+#include "compositor.h"
#ifdef ENABLE_EGL
diff --git a/src/launcher-util.c b/src/launcher-util.c
index 9196e4f..6f6ee11 100644
--- a/src/launcher-util.c
+++ b/src/launcher-util.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/src/libbacklight.c b/src/libbacklight.c
index 98a20be..b3acc63 100644
--- a/src/libbacklight.c
+++ b/src/libbacklight.c
@@ -29,7 +29,7 @@
* Tiago Vignatti <vignatti at freedesktop.org>
*/
-#define _GNU_SOURCE
+#include "config.h"
#include "libbacklight.h"
#include <stdio.h>
diff --git a/src/log.c b/src/log.c
index e5430d6..1c05e25 100644
--- a/src/log.c
+++ b/src/log.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
diff --git a/src/noop-renderer.c b/src/noop-renderer.c
index a0b1679..c0765f2 100644
--- a/src/noop-renderer.c
+++ b/src/noop-renderer.c
@@ -20,7 +20,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define _GNU_SOURCE
+#include "config.h"
#include <stdlib.h>
diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c
index 36563c6..b036135 100644
--- a/src/pixman-renderer.c
+++ b/src/pixman-renderer.c
@@ -21,7 +21,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define _GNU_SOURCE
+#include "config.h"
#include <errno.h>
#include <stdlib.h>
diff --git a/src/rpi-renderer.c b/src/rpi-renderer.c
index e429d2e..c361185 100644
--- a/src/rpi-renderer.c
+++ b/src/rpi-renderer.c
@@ -20,12 +20,12 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdlib.h>
#include <assert.h>
#include <string.h>
-#include "config.h"
-
#ifdef HAVE_BCM_HOST
# include <bcm_host.h>
#else
diff --git a/src/screenshooter.c b/src/screenshooter.c
index dde052f..ee2585b 100644
--- a/src/screenshooter.c
+++ b/src/screenshooter.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
diff --git a/src/shell.c b/src/shell.c
index e0d579a..e46c30f 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -22,6 +22,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
diff --git a/src/tablet-shell.c b/src/tablet-shell.c
index cae8acf..91fbaed 100644
--- a/src/tablet-shell.c
+++ b/src/tablet-shell.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
diff --git a/src/text-backend.c b/src/text-backend.c
index 3d1670b..67cacf6 100644
--- a/src/text-backend.c
+++ b/src/text-backend.c
@@ -21,6 +21,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
diff --git a/src/tty.c b/src/tty.c
index 05e5e20..2324f6c 100644
--- a/src/tty.c
+++ b/src/tty.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/src/udev-seat.c b/src/udev-seat.c
index 7e62429..05b8163 100644
--- a/src/udev-seat.c
+++ b/src/udev-seat.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
diff --git a/src/weston-launch.c b/src/weston-launch.c
index 42b2506..bd621a0 100644
--- a/src/weston-launch.c
+++ b/src/weston-launch.c
@@ -20,8 +20,6 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define _GNU_SOURCE
-
#include "config.h"
#include <stdio.h>
diff --git a/src/xwayland/launcher.c b/src/xwayland/launcher.c
index 664cf6c..a8ad478 100644
--- a/src/xwayland/launcher.c
+++ b/src/xwayland/launcher.c
@@ -20,7 +20,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define _GNU_SOURCE
+#include "config.h"
#include <stdlib.h>
#include <stdio.h>
diff --git a/src/xwayland/selection.c b/src/xwayland/selection.c
index 69665b7..66cb5fe 100644
--- a/src/xwayland/selection.c
+++ b/src/xwayland/selection.c
@@ -20,7 +20,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define _GNU_SOURCE
+#include "config.h"
#include <stdlib.h>
#include <string.h>
diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c
index b4b0a83..366f2e0 100644
--- a/src/xwayland/window-manager.c
+++ b/src/xwayland/window-manager.c
@@ -20,7 +20,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define _GNU_SOURCE
+#include "config.h"
#include <stdlib.h>
#include <stdio.h>
diff --git a/src/zoom.c b/src/zoom.c
index ccc5d49..292aed6 100644
--- a/src/zoom.c
+++ b/src/zoom.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdlib.h>
#include "compositor.h"
--
1.8.1.5
ppaalanen
2013-05-22 15:03:20 UTC
Permalink
From: Louis-Francis Ratte?-Boulianne <lfrb at collabora.com>

Make sure XCB_MAP_NOTIFY has been received and the window id has been
set before mapping the shell surface. It fixes race condition making the
surface appears at wrong coordinates or with wrong size.
---
src/xwayland/window-manager.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c
index 366f2e0..c2e680b 100644
--- a/src/xwayland/window-manager.c
+++ b/src/xwayland/window-manager.c
@@ -113,6 +113,7 @@ struct weston_wm_window {
int decorate;
int override_redirect;
int fullscreen;
+ int mapped;
};

static struct weston_wm_window *
@@ -121,6 +122,9 @@ get_wm_window(struct weston_surface *surface);
static void
weston_wm_window_schedule_repaint(struct weston_wm_window *window);

+static void
+xserver_map_shell_surface(struct weston_wm *wm, struct weston_wm_window *window);
+
const char *
get_atom_name(xcb_connection_t *c, xcb_atom_t atom)
{
@@ -723,6 +727,14 @@ static void
weston_wm_handle_map_notify(struct weston_wm *wm, xcb_generic_event_t *event)
{
xcb_map_notify_event_t *map_notify = (xcb_map_notify_event_t *) event;
+ struct weston_wm_window *window;
+
+ window = hash_table_lookup(wm->window_hash, map_notify->window);
+
+ if (window->surface != NULL)
+ xserver_map_shell_surface(wm, window);
+ else
+ window->mapped = 1;

if (our_resource(wm, map_notify->window)) {
weston_log("XCB_MAP_NOTIFY (window %d, ours)\n",
@@ -915,6 +927,8 @@ weston_wm_window_create(struct weston_wm *wm,
window->override_redirect = override;
window->width = width;
window->height = height;
+ window->surface = NULL;
+ window->mapped = 0;

hash_table_insert(wm->window_hash, id, window);
}
@@ -1874,7 +1888,9 @@ xserver_set_window_id(struct wl_client *client, struct wl_resource *resource,
&window->surface_destroy_listener);

weston_wm_window_schedule_repaint(window);
- xserver_map_shell_surface(wm, window);
+
+ if (window->mapped)
+ xserver_map_shell_surface(wm, window);
}

const struct xserver_interface xserver_implementation = {
--
1.8.1.5
MoD
2013-06-10 18:11:41 UTC
Permalink
I've been poking at XWayland+Weston's XWM recently and wanted to find this
behavior and check that this patch is effective so I could vouch for it, but
I haven't seen something that looks like windows being mapped with the wrong
coordinates or size. Louis-Francis, could you explain how to reproduce this
behavior?

Thanks.
Post by ppaalanen
From: Louis-Francis Ratte?-Boulianne <lfrb at collabora.com>
Make sure XCB_MAP_NOTIFY has been received and the window id has been
set before mapping the shell surface. It fixes race condition
making the
surface appears at wrong coordinates or with wrong size.
---
src/xwayland/window-manager.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-
manager.c
index 366f2e0..c2e680b 100644
--- a/src/xwayland/window-manager.c
+++ b/src/xwayland/window-manager.c
@@ -113,6 +113,7 @@ struct weston_wm_window {
int decorate;
int override_redirect;
int fullscreen;
+ int mapped;
};
static struct weston_wm_window *
@@ -121,6 +122,9 @@ get_wm_window(struct weston_surface *surface);
static void
weston_wm_window_schedule_repaint(struct weston_wm_window
*window);
+static void
+xserver_map_shell_surface(struct weston_wm *wm, struct
weston_wm_window *window);
+
const char *
get_atom_name(xcb_connection_t *c, xcb_atom_t atom)
{
@@ -723,6 +727,14 @@ static void
weston_wm_handle_map_notify(struct weston_wm *wm,
xcb_generic_event_t *event)
{
xcb_map_notify_event_t *map_notify = (xcb_map_notify_event_t *) event;
+ struct weston_wm_window *window;
+
+ window = hash_table_lookup(wm->window_hash, map_notify->window);
+
+ if (window->surface != NULL)
+ xserver_map_shell_surface(wm, window);
+ else
+ window->mapped = 1;
if (our_resource(wm, map_notify->window)) {
weston_log("XCB_MAP_NOTIFY (window %d, ours)\n",
@@ -915,6 +927,8 @@ weston_wm_window_create(struct weston_wm *wm,
window->override_redirect = override;
window->width = width;
window->height = height;
+ window->surface = NULL;
+ window->mapped = 0;
hash_table_insert(wm->window_hash, id, window);
}
@@ -1874,7 +1888,9 @@ xserver_set_window_id(struct wl_client
*client, struct wl_resource *resource,
&window->surface_destroy_listener);
weston_wm_window_schedule_repaint(window);
- xserver_map_shell_surface(wm, window);
+
+ if (window->mapped)
+ xserver_map_shell_surface(wm, window);
}
const struct xserver_interface xserver_implementation = {
--
1.8.1.5
_______________________________________________
wayland-devel mailing list
wayland-devel at lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel
ppaalanen
2013-05-22 15:03:21 UTC
Permalink
From: Louis-Francis Ratt?-Boulianne <lfrb at collabora.com>

---
src/shell.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/shell.c b/src/shell.c
index e46c30f..757d98d 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -3092,8 +3092,8 @@ surface_rotate(struct shell_surface *surface, struct weston_seat *seat)
return;

weston_surface_to_global_float(surface->surface,
- surface->surface->geometry.width / 2,
- surface->surface->geometry.height / 2,
+ surface->surface->geometry.width * 0.5f,
+ surface->surface->geometry.height * 0.5f,
&rotate->center.x, &rotate->center.y);

dx = wl_fixed_to_double(seat->pointer->x) - rotate->center.x;
--
1.8.1.5
ppaalanen
2013-05-22 15:03:22 UTC
Permalink
From: Pekka Paalanen <pekka.paalanen at collabora.co.uk>

This depends on the rpi-renderer patch series for Weston.

Update the build instructions for the current state of Weston, remove
options that do not exist anymore, add some more troubleshooting issues.

Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
raspberrypi.html | 42 ++++++++++++++++++++++++++----------------
1 file changed, 26 insertions(+), 16 deletions(-)

diff --git a/raspberrypi.html b/raspberrypi.html
index 67b7829..d77a9e1 100644
--- a/raspberrypi.html
+++ b/raspberrypi.html
@@ -47,14 +47,6 @@ old firmware may cause rpi-backend to malfunction on Raspberry Pi.</p>
happen off-line into the buffer.</dd>
</dl>

-<p>By default, the rpi-backend is configured for the <tt>dispmanx_offline=1</tt>
-case. Without this setting, it would be better to run Weston with
-<tt>--max-planes=10</tt> command line option.</p>
-
-<p>If you want to use Weston with purely GLESv2 compositing, you can pass
-<tt>--max-planes=0</tt> to Weston. In that case it would be preferrable
-to not set <tt>dispmanx_offline=1</tt> to conserve VideoCore memory.</p>
-
<h2>Setting up the environment</h2>

<p>Here we will install to the home directory of the pi user.</p>
@@ -67,9 +59,11 @@ export PKG_CONFIG_PATH="$WLD/lib/pkgconfig/:$WLD/share/pkgconfig/"
export ACLOCAL="aclocal -I $WLD/share/aclocal"
export XDG_RUNTIME_DIR="/run/shm/wayland"
export XDG_CONFIG_HOME="$WLD/etc"
+export XORGCONFIG="$WLD/etc/xorg.conf"

mkdir -p "$WLD/share/aclocal"
mkdir -p "$XDG_RUNTIME_DIR"
+chmod 0700 "$XDG_RUNTIME_DIR"
</pre>
</blockquote>

@@ -97,11 +91,11 @@ contains similar files for Android, and will not work.</p>

<pre> $ git clone git://anongit.freedesktop.org/wayland/wayland
$ cd wayland
- $ ./autogen.sh --prefix=$WLD
+ $ ./autogen.sh --prefix=$WLD --disable-documentation
$ make
$ make install
</pre>
-
+<p>The <tt>--disable-documentation</tt> makes it not require Doxygen.</p>

<h2>libxkbcommon</h2>

@@ -124,9 +118,10 @@ contains similar files for Android, and will not work.</p>
$ ./autogen.sh --prefix=$WLD \
--disable-setuid-install --with-cairo-glesv2 \
--disable-x11-compositor --disable-drm-compositor \
- --disable-android-compositor --disable-wayland-compositor \
+ --disable-fbdev-compositor --disable-wayland-compositor \
--disable-weston-launch --disable-simple-egl-clients \
- --disable-fbdev-compositor \
+ --disable-egl --disable-libunwind --disable-colord \
+ --disable-resize-optimization --disable-xwayland-test \
WESTON_NATIVE_BACKEND="rpi-backend.so"

$ make
@@ -168,10 +163,25 @@ configure: WARNING: clients will use cairo image, cairo-egl not used</pre>

<h3>Some or all surfaces (graphics) are corrupted</h3>

-<p>Too old firmware might cause corrupted graphics. If you don't want to
-update the firmware, a workaround is to add <tt>--max-planes=0</tt> to the
-Weston command line. This forces everything to be composited with
-GLESv2.</p>
+<p>Too old firmware might cause corrupted graphics.
+Try upgrading the firmware, and try the <tt>/boot/config.txt</tt>
+options mentioned above.</p>
+
+<h3>Monitor or TV goes blank, loses signal, etc.</h3>
+
+<p>You probably do not have <tt>dispmanx_offline=1</tt> for the firmware.
+When there are too many things on screen for the on-line compositor to
+handle, the output dies or becomes corrupt without the off-line fallback.</p>
+
+<h3>Some windows or the whole image flickers</h3>
+
+<p>There may be so many things on screen, that even the off-line compositor
+in the firmware cannot keep up. Try to close some windows.</p>
+
+<h3>Programs are dying on SIGBUS</h3>
+
+<p>Most likely you are running out of space in <tt>$XDG_RUNTIME_DIR</tt>.
+This is where Wayland programs allocate their pixel buffers.</p>

</body>
</html>
--
1.8.1.5
darxus
2013-05-23 18:15:51 UTC
Permalink
Committed, html validated.
Post by ppaalanen
From: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
This depends on the rpi-renderer patch series for Weston.
Update the build instructions for the current state of Weston, remove
options that do not exist anymore, add some more troubleshooting issues.
Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
raspberrypi.html | 42 ++++++++++++++++++++++++++----------------
1 file changed, 26 insertions(+), 16 deletions(-)
diff --git a/raspberrypi.html b/raspberrypi.html
index 67b7829..d77a9e1 100644
--- a/raspberrypi.html
+++ b/raspberrypi.html
@@ -47,14 +47,6 @@ old firmware may cause rpi-backend to malfunction on Raspberry Pi.</p>
happen off-line into the buffer.</dd>
</dl>
-<p>By default, the rpi-backend is configured for the <tt>dispmanx_offline=1</tt>
-case. Without this setting, it would be better to run Weston with
-<tt>--max-planes=10</tt> command line option.</p>
-
-<p>If you want to use Weston with purely GLESv2 compositing, you can pass
-<tt>--max-planes=0</tt> to Weston. In that case it would be preferrable
-to not set <tt>dispmanx_offline=1</tt> to conserve VideoCore memory.</p>
-
<h2>Setting up the environment</h2>
<p>Here we will install to the home directory of the pi user.</p>
@@ -67,9 +59,11 @@ export PKG_CONFIG_PATH="$WLD/lib/pkgconfig/:$WLD/share/pkgconfig/"
export ACLOCAL="aclocal -I $WLD/share/aclocal"
export XDG_RUNTIME_DIR="/run/shm/wayland"
export XDG_CONFIG_HOME="$WLD/etc"
+export XORGCONFIG="$WLD/etc/xorg.conf"
mkdir -p "$WLD/share/aclocal"
mkdir -p "$XDG_RUNTIME_DIR"
+chmod 0700 "$XDG_RUNTIME_DIR"
</pre>
</blockquote>
@@ -97,11 +91,11 @@ contains similar files for Android, and will not work.</p>
<pre> $ git clone git://anongit.freedesktop.org/wayland/wayland
$ cd wayland
- $ ./autogen.sh --prefix=$WLD
+ $ ./autogen.sh --prefix=$WLD --disable-documentation
$ make
$ make install
</pre>
-
+<p>The <tt>--disable-documentation</tt> makes it not require Doxygen.</p>
<h2>libxkbcommon</h2>
@@ -124,9 +118,10 @@ contains similar files for Android, and will not work.</p>
$ ./autogen.sh --prefix=$WLD \
--disable-setuid-install --with-cairo-glesv2 \
--disable-x11-compositor --disable-drm-compositor \
- --disable-android-compositor --disable-wayland-compositor \
+ --disable-fbdev-compositor --disable-wayland-compositor \
--disable-weston-launch --disable-simple-egl-clients \
- --disable-fbdev-compositor \
+ --disable-egl --disable-libunwind --disable-colord \
+ --disable-resize-optimization --disable-xwayland-test \
WESTON_NATIVE_BACKEND="rpi-backend.so"
$ make
@@ -168,10 +163,25 @@ configure: WARNING: clients will use cairo image, cairo-egl not used</pre>
<h3>Some or all surfaces (graphics) are corrupted</h3>
-<p>Too old firmware might cause corrupted graphics. If you don't want to
-update the firmware, a workaround is to add <tt>--max-planes=0</tt> to the
-Weston command line. This forces everything to be composited with
-GLESv2.</p>
+<p>Too old firmware might cause corrupted graphics.
+Try upgrading the firmware, and try the <tt>/boot/config.txt</tt>
+options mentioned above.</p>
+
+<h3>Monitor or TV goes blank, loses signal, etc.</h3>
+
+<p>You probably do not have <tt>dispmanx_offline=1</tt> for the firmware.
+When there are too many things on screen for the on-line compositor to
+handle, the output dies or becomes corrupt without the off-line fallback.</p>
+
+<h3>Some windows or the whole image flickers</h3>
+
+<p>There may be so many things on screen, that even the off-line compositor
+in the firmware cannot keep up. Try to close some windows.</p>
+
+<h3>Programs are dying on SIGBUS</h3>
+
+<p>Most likely you are running out of space in <tt>$XDG_RUNTIME_DIR</tt>.
+This is where Wayland programs allocate their pixel buffers.</p>
</body>
</html>
--
1.8.1.5
_______________________________________________
wayland-devel mailing list
wayland-devel at lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel
--
"Every man, woman and child on the face of this earth is at the mercy
of chaos." - a maxwell smart movie
http://www.ChaosReigns.com
Kristian Høgsberg
2013-05-23 02:15:31 UTC
Permalink
Post by ppaalanen
From: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
Hi all,
this patch series consists of several independent features, which all come
together in demonstrating the capabilities of Raspberry Pi for running a
desktop.
Hi Pekka,

Thanks, happy to see this go out. The new renderer is a cool
demonstration of a fast, non-gl renderer. Patches 1-9 all looked good
and I've applied and pushed them (minor conflicts with Alexs scale
patches). From 10 and onwards I have some comments, but I'll try to
send those out tomorrow.

Kristian
Post by ppaalanen
We add a new rpi-renderer, that replaces the gl-renderer + weston_planes
on RPi. Since it is not as flexible as the gl-renderer, we add some
capability bits to disable incompatible features in Weston.
Weston-desktop-shell gets new features. The major new feature is
"exposay", a window overview mode with animated transitions. Another new
feature is optional keyboard-focus animation, which dims unfocused
surfaces. Smaller enhancements include a new wallpaper scaling mode, and
ensuring weston-desktop-shell has finished starting up before the
compositor fades in.
Then there are various smaller fixes and enhancements.
This work is joint effort of the Raspberry Pi foundation and Collabora. I
will later (tomorrow) reply with an email with links to all the related
announcements and blog posts. More details behind those links, and the
individual commits.
Beware of the rough edges, there are some bugs we didn't have time to fix
yet. Most of them need a little effort to discover, though, that's why we
didn't see them earlier. ;-)
git://git.collabora.co.uk/git/user/pq/weston.git raspberrypi-dispmanx
http://cgit.collabora.com/git/user/pq/weston.git/log/?h=raspberrypi-dispmanx
There is also a patch for the RPi building guide on the Wayland website.
Add modifier-only binding
Add move/scale animation
Shell: Add Exposay
configure.ac: Enable AC_USE_SYSTEM_EXTENSIONS
animation: Make zoom animation renders better and smoother
compositor, shell: Add animation to measure desktop fps
xwayland: Fix the race condition when mapping a surface
toytoolkit: Make the window resizing optimization optional
animation, shell: add kbd focus change animation
shell: Fix calculation of center point in surface rotation
compositor: add capability flag for arbitrary surface rotation
compositor: add capability CAPTURE_YFLIP
rpi: add a Dispmanx renderer
rpi: switch to rpi-renderer
rpi: remove weston_plane support
shell: wait for desktop-shell init before fade in
desktop-shell: new wallpaper mode scale-crop
screenshooter: print info to log
clients/desktop-shell.c | 73 ++-
clients/window.c | 6 +-
configure.ac | 13 +-
man/weston.ini.man | 9 +-
protocol/desktop-shell.xml | 13 +-
shared/cairo-util.c | 2 +-
shared/config-parser.c | 3 +-
shared/image-loader.c | 2 +-
shared/matrix.c | 2 +
shared/option-parser.c | 2 +
shared/os-compatibility.c | 2 +-
src/Makefile.am | 2 +
src/animation.c | 128 +++-
src/bindings.c | 60 ++
src/clipboard.c | 2 +-
src/cms-helper.c | 4 +-
src/cms-static.c | 5 +-
src/compositor-drm.c | 6 +-
src/compositor-fbdev.c | 2 +-
src/compositor-headless.c | 4 +-
src/compositor-rdp.c | 4 +-
src/compositor-rpi.c | 898 +++------------------------
src/compositor-wayland.c | 5 +-
src/compositor-x11.c | 4 +-
src/compositor.c | 71 ++-
src/compositor.h | 48 ++
src/evdev-touchpad.c | 2 +
src/evdev.c | 2 +
src/filter.c | 2 +
src/gl-renderer.c | 4 +-
src/gl-renderer.h | 7 +-
src/input.c | 38 ++
src/launcher-util.c | 2 +
src/libbacklight.c | 2 +-
src/log.c | 2 +
src/noop-renderer.c | 2 +-
src/pixman-renderer.c | 4 +-
src/rpi-bcm-stubs.h | 39 ++
src/rpi-renderer.c | 1370 +++++++++++++++++++++++++++++++++++++++++
src/rpi-renderer.h | 48 ++
src/screenshooter.c | 103 +++-
src/shell.c | 1078 ++++++++++++++++++++++++++++++--
src/tablet-shell.c | 2 +
src/text-backend.c | 2 +
src/tty.c | 2 +
src/udev-seat.c | 2 +
src/weston-launch.c | 2 -
src/xwayland/launcher.c | 2 +-
src/xwayland/selection.c | 2 +-
src/xwayland/window-manager.c | 20 +-
src/zoom.c | 2 +
51 files changed, 3166 insertions(+), 945 deletions(-)
create mode 100644 src/rpi-renderer.c
create mode 100644 src/rpi-renderer.h
--
1.8.1.5
Thanks,
pq
Pekka Paalanen
2013-05-24 06:47:41 UTC
Permalink
On Wed, 22 May 2013 18:03:03 +0300
Post by ppaalanen
From: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
Hi all,
this patch series consists of several independent features, which all come
together in demonstrating the capabilities of Raspberry Pi for running a
desktop.
We add a new rpi-renderer, that replaces the gl-renderer + weston_planes
on RPi. Since it is not as flexible as the gl-renderer, we add some
capability bits to disable incompatible features in Weston.
Weston-desktop-shell gets new features. The major new feature is
"exposay", a window overview mode with animated transitions. Another new
feature is optional keyboard-focus animation, which dims unfocused
surfaces. Smaller enhancements include a new wallpaper scaling mode, and
ensuring weston-desktop-shell has finished starting up before the
compositor fades in.
Then there are various smaller fixes and enhancements.
This work is joint effort of the Raspberry Pi foundation and Collabora. I
will later (tomorrow) reply with an email with links to all the related
announcements and blog posts. More details behind those links, and the
individual commits.
Beware of the rough edges, there are some bugs we didn't have time to fix
yet. Most of them need a little effort to discover, though, that's why we
didn't see them earlier. ;-)
git://git.collabora.co.uk/git/user/pq/weston.git raspberrypi-dispmanx
http://cgit.collabora.com/git/user/pq/weston.git/log/?h=raspberrypi-dispmanx
There is also a patch for the RPi building guide on the Wayland website.
Hi all,

the Raspberry Pi specific commits are merged upstream, and the demo
candy patches are still waiting for review. I have a WIP branch (i.e.
throw-away) with the pending patches at:
http://cgit.collabora.com/git/user/pq/weston.git/log/?h=raspberrypi-dispmanx-wip

Now that we finally got all the PR out, here's the collection of links
to announcements etc.

Raspberry Pi Foundation News, "Wayland preview"
http://www.raspberrypi.org/archives/4053

Daniel Stone's blog, "Weston on Raspberry Pi", answers "why?"
http://fooishbar.org/tell-me-about/wayland-on-raspberry-pi/

My blog, "Weston on Raspberry Pi Accelerated", answers "how?"
http://ppaalanen.blogspot.fi/2013/05/weston-on-raspberry-pi-accelerated.html

Collabora's press release
http://www.collabora.com/press/2013/05/collabora-brings-wayland-and-x11-graphics-performance-to-raspberry-pi.html

Collabora's Raspberry Pi case study, with the video
http://www.collabora.com/services/case-studies/raspberrypi

Collabora's Wayland promotion
http://www.collabora.com/projects/graphics/

Pre-built Raspbian packages
http://raspberrypi.collabora.com/


Thanks,
pq
Louis-Francis Ratté-Boulianne
2013-06-13 16:45:41 UTC
Permalink
Hi,
Post by MoD
I've been poking at XWayland+Weston's XWM recently and wanted to find this
behavior and check that this patch is effective so I could vouch for it, but
I haven't seen something that looks like windows being mapped with the wrong
coordinates or size. Louis-Francis, could you explain how to reproduce this
behavior?
I reproduced it by running LibreOffice on a RaspberryPi. A race condition made the menus (sometimes) appears at the wrong spot. The race might be easier to reproduce on slowest hardware (rpi) though.

I also found it weird to map the surface without being sure we received MAP_NOTIFY first.
Post by MoD
Thanks.
Post by ppaalanen
From: Louis-Francis Ratt?-Boulianne <lfrb at collabora.com>
Make sure XCB_MAP_NOTIFY has been received and the window id has
been
set before mapping the shell surface. It fixes race condition
making the
surface appears at wrong coordinates or with wrong size.
---
src/xwayland/window-manager.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-
manager.c
index 366f2e0..c2e680b 100644
--- a/src/xwayland/window-manager.c
+++ b/src/xwayland/window-manager.c
@@ -113,6 +113,7 @@ struct weston_wm_window {
int decorate;
int override_redirect;
int fullscreen;
+ int mapped;
};
static struct weston_wm_window *
@@ -121,6 +122,9 @@ get_wm_window(struct weston_surface *surface);
static void
weston_wm_window_schedule_repaint(struct weston_wm_window
*window);
+static void
+xserver_map_shell_surface(struct weston_wm *wm, struct
weston_wm_window *window);
+
const char *
get_atom_name(xcb_connection_t *c, xcb_atom_t atom)
{
@@ -723,6 +727,14 @@ static void
weston_wm_handle_map_notify(struct weston_wm *wm,
xcb_generic_event_t *event)
{
xcb_map_notify_event_t *map_notify = (xcb_map_notify_event_t *)
event;
+ struct weston_wm_window *window;
+
+ window = hash_table_lookup(wm->window_hash, map_notify->window);
+
+ if (window->surface != NULL)
+ xserver_map_shell_surface(wm, window);
+ else
+ window->mapped = 1;
if (our_resource(wm, map_notify->window)) {
weston_log("XCB_MAP_NOTIFY (window %d, ours)\n",
@@ -915,6 +927,8 @@ weston_wm_window_create(struct weston_wm *wm,
window->override_redirect = override;
window->width = width;
window->height = height;
+ window->surface = NULL;
+ window->mapped = 0;
hash_table_insert(wm->window_hash, id, window);
}
@@ -1874,7 +1888,9 @@ xserver_set_window_id(struct wl_client
*client, struct wl_resource *resource,
&window->surface_destroy_listener);
weston_wm_window_schedule_repaint(window);
- xserver_map_shell_surface(wm, window);
+
+ if (window->mapped)
+ xserver_map_shell_surface(wm, window);
}
const struct xserver_interface xserver_implementation = {
--
1.8.1.5
_______________________________________________
wayland-devel mailing list
wayland-devel at lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Loading...