-----BEGIN PGP SIGNATURE-----
 
 iQJOBAABCAA4FiEEcDKHej6x6uPk3J379jQS5glH1u8FAmTKgNAaHG1hcml1cy52
 bGFkQGNvbGxhYm9yYS5jb20ACgkQ9jQS5glH1u82JQ//f/n92pDChk/LMmGxN2iW
 1KYsB42vn6Fz0JNYue9HElnWNQzp1ZFYLBJFiks8fHx2kD7ppMRN7vgRrTS/hZjV
 qEUJI5OX5+U7My0q10OWJGXEYOPLM2vQOnjca4CDivvl66MebBYYI+h72/lo8oBe
 IojZY0BSNbI2wikAG3UTMoU4z3PwBj+ipn856AslXBf0a1cqzl2JFNX5l1B5DAwe
 E0XZ0KSu74sL8ObyqoW1kYLm9Cqid2iLbch9pBvDIqBlg7V2jySHVB2fvkfwHTxw
 Q4dl2NpeW5kKqj8Ql27nLEMG4g3hrAJq+dnNIWijSzO1a7M3BC2ZQ3YEWCaISmwN
 7rRFTXgAKIkn0YfXwBp5XG12oCNgyBhaCc8dUrefPZqyOiYRii2f4xYTM5TXhHv9
 fVvBj7iXigz3+iUkBe4aRVGVBJaKW6y7UkwMP4vhowyxpcb3XXHNszTEnfj7JiIs
 0xq8iA8KM9v2uYKpkLG6ND0IUmwiuZtGNKCIcaYd9Yr7vI0CohIZ7ZsI8YKYmSgK
 ONyAHDDzREDNcxuY4NBIqb0yr058yMhr3LuNJHaM6QCue+QOxjq4qJIpJ5sN/hgr
 GT6dbH6Rf/Pfld+/5Kdw9sdhSwQzPy8NxILRjF27GMRvZsnd7+5ZIA2eVvl5mfLw
 SegOoQASY1fY4ML0eaD5SIE=
 =VGPl
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEofGjA2bfgEEMn0uvXN7tFPSPp50FAmaabRUACgkQXN7tFPSP
 p5202xAAzEO1OrhT/UkyMLnIdY5OrPXAWtlx7fbOjQJpZ1bsRnuDg6Iae0WEr2go
 lkzrrkbO99sWFTqb+LmDf2AzPy2y6OQojrWSeyDC5m/woZPHehJwrdmG4oISQuwQ
 j70TPz0iKjNLjUeprD/bIOpEUbyjRLasltXoUv7wna39mY/4lDraaYZe8QRIdrTy
 oWqYj8Dnu2BR0IPawX1249v34nLY8ZG/v3MNn6TIlflZCQOYZ0+tQxLa2K+Bl18x
 yqAbvcw24TtrmJI8XWEz12bTuKzQu8EJXx0g/x7uQCkCdFRFYJMivt0l7mEjlERy
 mPqarpHaSdaS64fnxlRP0dmO7/LBNS/1QPxiGXOoUGUdDwLhhv57BQuUnSRsiCzi
 w1GgHKscqT48hsJNqj/+6r6jTavA2fs8YDWDkACYGso0dHnkVFma7rSH5pXf1LFv
 +jI2TlcP9BqAEtVXes7l0voryczQxKJijcaky7bwyIUKX2MK8oZjLdmFwpXi2CIR
 9Sd0SjQxOOMaguzCWZchanShSGwjjbo9zJEqepAn4P186yhwIdRaH0fAORRBfho/
 h8qBlZ+2aUN9rvxzfSGRCgz3MIEE9cQu0Pd0OQStZ2CedpZOr7vLEZ68CyvrvYV8
 8GCCVrmEdOT/3+dgMx4tMtAYfXUve4hKuOPuh5f9BxmiuaplWx8=
 =N3tk
 -----END PGP SIGNATURE-----

Merge tag '10.0.5' into backport-wl-shell

10.0.5

# -----BEGIN PGP SIGNATURE-----
#
# iQJOBAABCAA4FiEEcDKHej6x6uPk3J379jQS5glH1u8FAmTKgNAaHG1hcml1cy52
# bGFkQGNvbGxhYm9yYS5jb20ACgkQ9jQS5glH1u82JQ//f/n92pDChk/LMmGxN2iW
# 1KYsB42vn6Fz0JNYue9HElnWNQzp1ZFYLBJFiks8fHx2kD7ppMRN7vgRrTS/hZjV
# qEUJI5OX5+U7My0q10OWJGXEYOPLM2vQOnjca4CDivvl66MebBYYI+h72/lo8oBe
# IojZY0BSNbI2wikAG3UTMoU4z3PwBj+ipn856AslXBf0a1cqzl2JFNX5l1B5DAwe
# E0XZ0KSu74sL8ObyqoW1kYLm9Cqid2iLbch9pBvDIqBlg7V2jySHVB2fvkfwHTxw
# Q4dl2NpeW5kKqj8Ql27nLEMG4g3hrAJq+dnNIWijSzO1a7M3BC2ZQ3YEWCaISmwN
# 7rRFTXgAKIkn0YfXwBp5XG12oCNgyBhaCc8dUrefPZqyOiYRii2f4xYTM5TXhHv9
# fVvBj7iXigz3+iUkBe4aRVGVBJaKW6y7UkwMP4vhowyxpcb3XXHNszTEnfj7JiIs
# 0xq8iA8KM9v2uYKpkLG6ND0IUmwiuZtGNKCIcaYd9Yr7vI0CohIZ7ZsI8YKYmSgK
# ONyAHDDzREDNcxuY4NBIqb0yr058yMhr3LuNJHaM6QCue+QOxjq4qJIpJ5sN/hgr
# GT6dbH6Rf/Pfld+/5Kdw9sdhSwQzPy8NxILRjF27GMRvZsnd7+5ZIA2eVvl5mfLw
# SegOoQASY1fY4ML0eaD5SIE=
# =VGPl
# -----END PGP SIGNATURE-----
Nikita Tokarchuk 3 months ago
commit cf3c9c5182
  1. 4
      .gitlab-ci.yml
  2. 2
      clients/simple-dmabuf-egl.c
  3. 131
      clients/simple-dmabuf-feedback.c
  4. 2
      clients/simple-dmabuf-v4l.c
  5. 65
      clients/simple-egl.c
  6. 76
      clients/window.c
  7. 105
      desktop-shell/shell.c
  8. 3
      include/libweston/libweston.h
  9. 45
      kiosk-shell/kiosk-shell.c
  10. 2
      kiosk-shell/kiosk-shell.h
  11. 2
      libweston-desktop/xdg-shell.c
  12. 1
      libweston/backend-drm/drm-internal.h
  13. 6
      libweston/backend-drm/fb.c
  14. 2
      libweston/backend-drm/meson.build
  15. 3
      libweston/backend-drm/state-propose.c
  16. 80
      libweston/compositor.c
  17. 24
      libweston/input.c
  18. 67
      libweston/linux-dmabuf.c
  19. 43
      libweston/renderer-gl/fragment.glsl
  20. 4
      meson.build
  21. 2
      tests/devices-test.c
  22. 2
      tests/ivi-layout-test-plugin.c
  23. BIN
      tests/reference/subsurface_empty_mapping-00.png
  24. BIN
      tests/reference/subsurface_empty_mapping-01.png
  25. BIN
      tests/reference/subsurface_sync_damage_buffer-00.png
  26. BIN
      tests/reference/subsurface_sync_damage_buffer-01.png
  27. BIN
      tests/reference/subsurface_sync_damage_buffer-02.png
  28. 198
      tests/subsurface-shot-test.c

@ -296,7 +296,9 @@ x86_64-debian-full-build:
- .build-options-full
artifacts:
reports:
cobertura: $BUILDDIR/meson-logs/coverage.xml
coverage_report:
coverage_format: cobertura
path: $BUILDDIR/meson-logs/coverage.xml
aarch64-debian-full-build:
extends:

@ -131,7 +131,7 @@ struct buffer {
int release_fence_fd;
};
#define NUM_BUFFERS 3
#define NUM_BUFFERS 4
struct window {
struct display *display;

@ -26,11 +26,13 @@
#include "config.h"
#include <assert.h>
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <libudev.h>
#include <sys/mman.h>
#include <time.h>
#include "shared/helpers.h"
#include "shared/platform.h"
@ -47,7 +49,7 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#define NUM_BUFFERS 3
#define NUM_BUFFERS 4
/* We have to hack the DRM-backend to pretend that planes of the underlying
* hardware don't support this format. If you change the value of this constant,
@ -140,7 +142,11 @@ struct display {
struct buffer {
struct window *window;
struct wl_buffer *buffer;
bool busy;
enum {
NOT_CREATED,
IN_USE,
AVAILABLE
} status;
bool recreate;
int dmabuf_fds[4];
struct gbm_bo *bo;
@ -469,7 +475,7 @@ buffer_release(void *data, struct wl_buffer *buffer)
{
struct buffer *buf = data;
buf->busy = false;
buf->status = AVAILABLE;
if (buf->recreate)
buffer_recreate(buf);
@ -485,6 +491,7 @@ create_succeeded(void *data, struct zwp_linux_buffer_params_v1 *params,
{
struct buffer *buf = data;
buf->status = AVAILABLE;
buf->buffer = new_buffer;
wl_buffer_add_listener(buf->buffer, &buffer_listener, buf);
zwp_linux_buffer_params_v1_destroy(params);
@ -516,6 +523,7 @@ create_dmabuf_buffer(struct window *window, struct buffer *buf, uint32_t width,
struct zwp_linux_buffer_params_v1 *params;
int i;
buf->status = NOT_CREATED;
buf->window = window;
buf->width = width;
buf->height = height;
@ -573,8 +581,22 @@ window_next_buffer(struct window *window)
unsigned int i;
for (i = 0; i < NUM_BUFFERS; i++)
if (!window->buffers[i].busy)
if (window->buffers[i].status == AVAILABLE)
return &window->buffers[i];
/* In this client, we sometimes have to recreate the buffers. As we are
* not using the create_immed request from zwp_linux_dmabuf_v1, we need
* to wait an event from the server (what leads to create_succeeded()
* being called in this client). So if all buffers are busy, it may be
* the case in which all the buffers were recreated but the server still
* didn't send the events. This is very unlikely to happen, but a
* roundtrip() guarantees that we receive and process the events. */
wl_display_roundtrip(window->display->display);
for (i = 0; i < NUM_BUFFERS; i++)
if (window->buffers[i].status == AVAILABLE)
return &window->buffers[i];
return NULL;
}
@ -639,15 +661,13 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
window->callback = wl_surface_frame(window->surface);
wl_callback_add_listener(window->callback, &frame_listener, window);
wl_surface_commit(window->surface);
buf->busy = true;
buf->status = IN_USE;
region = wl_compositor_create_region(window->display->compositor);
wl_region_add(region, 0, 0, window->display->output.width,
window->display->output.height);
wl_surface_set_opaque_region(window->surface, region);
wl_region_destroy(region);
window->n_redraws++;
}
static const struct wl_callback_listener frame_listener = {
@ -1050,18 +1070,54 @@ dmabuf_feedback_tranche_formats(void *data,
}
}
static char
bits2graph(uint32_t value, unsigned bitoffset)
{
int c = (value >> bitoffset) & 0xff;
if (isgraph(c) || isspace(c))
return c;
return '?';
}
static void
fourcc2str(uint32_t format, char *str, int len)
{
int i;
assert(len >= 5);
for (i = 0; i < 4; i++)
str[i] = bits2graph(format, i * 8);
str[i] = '\0';
}
static void
print_tranche_format_modifier(uint32_t format, uint64_t modifier)
{
const struct pixel_format_info *fmt_info;
char *format_str;
char *mod_name;
int len;
fmt_info = pixel_format_get_info(format);
mod_name = pixel_format_get_modifier(modifier);
fmt_info = pixel_format_get_info(format);
if (fmt_info) {
len = asprintf(&format_str, "%s", fmt_info->drm_format_name);
} else {
char fourcc_str[5];
fourcc2str(format, fourcc_str, sizeof(fourcc_str));
len = asprintf(&format_str, "0x%08x (%s)", format, fourcc_str);
}
assert(len > 0);
fprintf(stderr, "โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€tranche format/modifier pair - format %s, modifier %s\n",
fmt_info ? fmt_info->drm_format_name : "UNKNOWN", mod_name);
format_str, mod_name);
free(format_str);
free(mod_name);
}
@ -1103,7 +1159,7 @@ dmabuf_feedback_tranche_done(void *data,
dmabuf_feedback_tranche_init(&feedback->pending_tranche);
}
static void
static bool
pick_initial_format_from_renderer_tranche(struct window *window,
struct dmabuf_feedback_tranche *tranche)
{
@ -1117,13 +1173,12 @@ pick_initial_format_from_renderer_tranche(struct window *window,
window->format.format = fmt->format;
wl_array_copy(&window->format.modifiers, &fmt->modifiers);
return;
return true;
}
assert(0 && "error: INITIAL_BUFFER_FORMAT not supported by the hardware");
return false;
}
static void
static bool
pick_format_from_scanout_tranche(struct window *window,
struct dmabuf_feedback_tranche *tranche)
{
@ -1132,8 +1187,9 @@ pick_format_from_scanout_tranche(struct window *window,
wl_array_for_each(fmt, &tranche->formats.arr) {
/* Ignore format that we're already using. */
if (fmt->format == window->format.format)
/* Ignore the format that we want to pick from the render
* tranche. */
if (fmt->format == INITIAL_BUFFER_FORMAT)
continue;
/* Format should be supported by the compositor. */
@ -1147,10 +1203,9 @@ pick_format_from_scanout_tranche(struct window *window,
window->format.format = fmt->format;
wl_array_copy(&window->format.modifiers, &fmt->modifiers);
return;
return true;
}
assert(0 && "error: no valid pair of format/modifier in the scanout tranche");
return false;
}
static void
@ -1158,25 +1213,37 @@ dmabuf_feedback_done(void *data, struct zwp_linux_dmabuf_feedback_v1 *dmabuf_fee
{
struct window *window = data;
struct dmabuf_feedback_tranche *tranche;
bool got_scanout_tranche = false;
unsigned int i;
fprintf(stderr, "โ””end of dma-buf feedback\n\n");
/* The first time that we receive dma-buf feedback for a surface it
* contains only the renderer tranche. We pick the INITIAL_BUFFER_FORMAT
* contains only the renderer tranches. We pick the INITIAL_BUFFER_FORMAT
* from there. Then the compositor should detect that the format is
* unsupported by the underlying hardware (not actually, but you should
* have faked this in the DRM-backend) and send the scanout tranche. We
* use the formats/modifiers of the scanout tranche to reallocate our
* have faked this in the DRM-backend) and send the scanout tranches. We
* use the formats/modifiers of the scanout tranches to reallocate our
* buffers. */
wl_array_for_each(tranche, &window->pending_dmabuf_feedback.tranches) {
if (tranche->is_scanout_tranche) {
pick_format_from_scanout_tranche(window, tranche);
for (i = 0; i < NUM_BUFFERS; i++)
window->buffers[i].recreate = true;
break;
got_scanout_tranche = true;
if (pick_format_from_scanout_tranche(window, tranche)) {
for (i = 0; i < NUM_BUFFERS; i++)
window->buffers[i].recreate = true;
break;
}
}
pick_initial_format_from_renderer_tranche(window, tranche);
if (pick_initial_format_from_renderer_tranche(window, tranche))
break;
}
if (got_scanout_tranche) {
assert(window->format.format != INITIAL_BUFFER_FORMAT &&
"error: no valid pair of format/modifier in the scanout tranches");
} else {
assert(window->format.format == INITIAL_BUFFER_FORMAT &&
"error: INITIAL_BUFFER_FORMAT not supported by the hardware");
}
dmabuf_feedback_fini(&window->dmabuf_feedback);
@ -1383,6 +1450,9 @@ main(int argc, char **argv)
struct display *display;
struct window *window;
int ret = 0;
struct timespec start_time, current_time;
const time_t MAX_TIME_SECONDS = 3;
time_t delta_time = 0;
fprintf(stderr, "This client was written with the purpose of manually test " \
"Weston's dma-buf feedback implementation. See main() " \
@ -1391,9 +1461,14 @@ main(int argc, char **argv)
display = create_display();
window = create_window(display);
clock_gettime(CLOCK_MONOTONIC, &start_time);
redraw(window, NULL, 0);
while (ret != -1 && window->n_redraws < 200)
while (ret != -1 && delta_time < MAX_TIME_SECONDS) {
ret = wl_display_dispatch(display->display);
clock_gettime(CLOCK_MONOTONIC, &current_time);
delta_time = current_time.tv_sec - start_time.tv_sec;
}
destroy_window(window);
destroy_display(display);

@ -127,7 +127,7 @@ struct buffer {
int data_offsets[VIDEO_MAX_PLANES];
};
#define NUM_BUFFERS 3
#define NUM_BUFFERS 4
struct window {
struct display *display;

@ -262,6 +262,19 @@ init_gl(struct window *window)
GLuint frag, vert;
GLuint program;
GLint status;
EGLBoolean ret;
window->native = wl_egl_window_create(window->surface,
window->geometry.width,
window->geometry.height);
window->egl_surface =
weston_platform_create_egl_surface(window->display->egl.dpy,
window->display->egl.conf,
window->native, NULL);
ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
window->egl_surface, window->display->egl.ctx);
assert(ret == EGL_TRUE);
frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER);
vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER);
@ -362,19 +375,9 @@ static void
create_surface(struct window *window)
{
struct display *display = window->display;
EGLBoolean ret;
window->surface = wl_compositor_create_surface(display->compositor);
window->native =
wl_egl_window_create(window->surface,
window->geometry.width,
window->geometry.height);
window->egl_surface =
weston_platform_create_egl_surface(display->egl.dpy,
display->egl.conf,
window->native, NULL);
window->xdg_surface = xdg_wm_base_get_xdg_surface(display->wm_base,
window->surface);
xdg_surface_add_listener(window->xdg_surface,
@ -389,21 +392,16 @@ create_surface(struct window *window)
xdg_toplevel_set_app_id(window->xdg_toplevel,
"org.freedesktop.weston.simple-egl");
if (window->fullscreen)
xdg_toplevel_set_fullscreen(window->xdg_toplevel, NULL);
else if (window->maximized)
xdg_toplevel_set_maximized(window->xdg_toplevel);
window->wait_for_configure = true;
wl_surface_commit(window->surface);
ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
window->egl_surface, window->display->egl.ctx);
assert(ret == EGL_TRUE);
if (!window->frame_sync)
eglSwapInterval(display->egl.dpy, 0);
if (!display->wm_base)
return;
if (window->fullscreen)
xdg_toplevel_set_fullscreen(window->xdg_toplevel, NULL);
}
static void
@ -806,6 +804,7 @@ usage(int error_code)
fprintf(stderr, "Usage: simple-egl [OPTIONS]\n\n"
" -d <us>\tBuffer swap delay in microseconds\n"
" -f\tRun in fullscreen mode\n"
" -m\tRun in maximized mode\n"
" -o\tCreate an opaque surface\n"
" -s\tUse a 16 bpp EGL config\n"
" -b\tDon't sync to compositor redraw (eglSwapInterval 0)\n"
@ -836,6 +835,8 @@ main(int argc, char **argv)
window.delay = atoi(argv[++i]);
else if (strcmp("-f", argv[i]) == 0)
window.fullscreen = 1;
else if (strcmp("-m", argv[i]) == 0)
window.maximized = 1;
else if (strcmp("-o", argv[i]) == 0)
window.opaque = 1;
else if (strcmp("-s", argv[i]) == 0)
@ -864,7 +865,17 @@ main(int argc, char **argv)
init_egl(&display, &window);
create_surface(&window);
init_gl(&window);
/* we already have wait_for_configure set after create_surface() */
while (running && ret != -1 && window.wait_for_configure) {
ret = wl_display_dispatch(display.display);
/* wait until xdg_surface::configure acks the new dimensions */
if (window.wait_for_configure)
continue;
init_gl(&window);
}
display.cursor_surface =
wl_compositor_create_surface(display.compositor);
@ -874,17 +885,9 @@ main(int argc, char **argv)
sigint.sa_flags = SA_RESETHAND;
sigaction(SIGINT, &sigint, NULL);
/* The mainloop here is a little subtle. Redrawing will cause
* EGL to read events so we can just call
* wl_display_dispatch_pending() to handle any events that got
* queued up as a side effect. */
while (running && ret != -1) {
if (window.wait_for_configure) {
ret = wl_display_dispatch(display.display);
} else {
ret = wl_display_dispatch_pending(display.display);
redraw(&window, NULL, 0);
}
ret = wl_display_dispatch_pending(display.display);
redraw(&window, NULL, 0);
}
fprintf(stderr, "simple-egl exiting\n");

@ -352,8 +352,11 @@ struct input {
struct toytimer cursor_timer;
bool cursor_timer_running;
struct wl_surface *pointer_surface;
bool pointer_surface_has_role;
int hotspot_x, hotspot_y;
uint32_t modifiers;
uint32_t pointer_enter_serial;
uint32_t cursor_serial;
float sx, sy;
struct wl_list link;
@ -2748,12 +2751,6 @@ input_remove_pointer_focus(struct input *input)
input->pointer_focus = NULL;
input->current_cursor = CURSOR_UNSET;
cancel_pointer_image_update(input);
wl_surface_destroy(input->pointer_surface);
input->pointer_surface = NULL;
if (input->cursor_frame_cb) {
wl_callback_destroy(input->cursor_frame_cb);
input->cursor_frame_cb = NULL;
}
}
static void
@ -2782,6 +2779,16 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
input->pointer_enter_serial = serial;
input->pointer_focus = window;
/* Some compositors advertise wl_seat before wl_compositor. This
* makes it potentially impossible to create the pointer surface
* when we bind the seat, so we need to create our pointer surface
* now instead.
*/
if (!input->pointer_surface)
input->pointer_surface = wl_compositor_create_surface(input->display->compositor);
input->pointer_surface_has_role = false;
input->sx = sx;
input->sy = sy;
@ -3793,8 +3800,7 @@ input_set_pointer_image_index(struct input *input, int index)
struct wl_buffer *buffer;
struct wl_cursor *cursor;
struct wl_cursor_image *image;
struct wl_surface *prev_surface;
struct display *d = input->display;
int dx = 0, dy = 0;
if (!input->pointer)
return;
@ -3813,21 +3819,24 @@ input_set_pointer_image_index(struct input *input, int index)
if (!buffer)
return;
/* Don't re-use the previous surface, otherwise the new buffer and the
* new hotspot aren't applied atomically. */
prev_surface = input->pointer_surface;
input->pointer_surface = wl_compositor_create_surface(d->compositor);
wl_surface_attach(input->pointer_surface, buffer, 0, 0);
if (input->pointer_surface_has_role) {
dx = input->hotspot_x - image->hotspot_x;
dy = input->hotspot_y - image->hotspot_y;
}
wl_surface_attach(input->pointer_surface, buffer, dx, dy);
wl_surface_damage(input->pointer_surface, 0, 0,
image->width, image->height);
wl_surface_commit(input->pointer_surface);
wl_pointer_set_cursor(input->pointer, input->pointer_enter_serial,
input->pointer_surface,
image->hotspot_x, image->hotspot_y);
if (prev_surface)
wl_surface_destroy(prev_surface);
if (!input->pointer_surface_has_role) {
wl_pointer_set_cursor(input->pointer,
input->pointer_enter_serial,
input->pointer_surface,
image->hotspot_x, image->hotspot_y);
input->pointer_surface_has_role = true;
}
input->hotspot_x = image->hotspot_x;
input->hotspot_y = image->hotspot_y;
}
static const struct wl_callback_listener pointer_surface_listener;
@ -3839,11 +3848,14 @@ input_set_pointer_special(struct input *input)
wl_pointer_set_cursor(input->pointer,
input->pointer_enter_serial,
NULL, 0, 0);
input->pointer_surface_has_role = false;
return true;
}
if (input->current_cursor == CURSOR_UNSET)
if (input->current_cursor == CURSOR_UNSET) {
input->pointer_surface_has_role = false;
return true;
}
return false;
}
@ -3883,7 +3895,6 @@ schedule_pointer_image_update(struct input *input,
wl_callback_add_listener(input->cursor_frame_cb,
&pointer_surface_listener, input);
wl_surface_commit(input->pointer_surface);
}
static void
@ -3933,11 +3944,11 @@ pointer_surface_frame_callback(void *data, struct wl_callback *callback,
time - input->cursor_anim_start,
&duration);
input_set_pointer_image_index(input, i);
if (cursor->image_count > 1)
schedule_pointer_image_update(input, cursor, duration,
force_frame);
input_set_pointer_image_index(input, i);
}
static void
@ -3967,15 +3978,30 @@ static const struct wl_callback_listener pointer_surface_listener = {
void
input_set_pointer_image(struct input *input, int pointer)
{
int force = 0;
if (!input->pointer)
return;
if (pointer == input->current_cursor)
if (input->pointer_enter_serial > input->cursor_serial)
force = 1;
if (!force && pointer == input->current_cursor)
return;
input->current_cursor = pointer;
input->cursor_serial = input->pointer_enter_serial;
if (!input->cursor_frame_cb)
pointer_surface_frame_callback(input, NULL, 0);
else if (force && !input_set_pointer_special(input)) {
/* The current frame callback may be stuck if, for instance,
* the set cursor request was processed by the server after
* this client lost the focus. In this case the cursor surface
* might not be mapped and the frame callback wouldn't ever
* complete. Send a set_cursor and attach to try to map the
* cursor surface again so that the callback will finish */
input_set_pointer_image_index(input, 0);
}
}
struct wl_data_device *
@ -5923,6 +5949,8 @@ display_add_input(struct display *d, uint32_t id, int display_seat_version)
input);
}
input->pointer_surface_has_role = false;
toytimer_init(&input->cursor_timer, CLOCK_MONOTONIC, d,
cursor_timer_func);

@ -101,6 +101,8 @@ struct shell_surface {
struct weston_desktop_surface *desktop_surface;
struct weston_view *view;
struct weston_surface *wsurface_anim_fade;
struct weston_view *wview_anim_fade;
int32_t last_width, last_height;
struct desktop_shell *shell;
@ -194,6 +196,10 @@ struct shell_seat {
};
static struct weston_view *
shell_fade_create_fade_out_view(struct shell_surface *shsurf,
struct weston_surface *surface);
static struct desktop_shell *
shell_surface_get_shell(struct shell_surface *shsurf);
@ -261,10 +267,12 @@ desktop_shell_destroy_surface(struct shell_surface *shsurf)
wl_list_init(&shsurf_child->children_link);
}
wl_list_remove(&shsurf->children_link);
weston_desktop_surface_unlink_view(shsurf->view);
weston_view_destroy(shsurf->view);
wl_signal_emit(&shsurf->destroy_signal, shsurf);
weston_surface_destroy(shsurf->wsurface_anim_fade);
weston_view_destroy(shsurf->view);
if (shsurf->output_destroy_listener.notify) {
wl_list_remove(&shsurf->output_destroy_listener.link);
shsurf->output_destroy_listener.notify = NULL;
@ -877,7 +885,7 @@ animate_focus_change(struct desktop_shell *shell, struct workspace *ws,
}
static void
desktop_shell_destroy_views_on_layer(struct weston_layer *layer);
desktop_shell_destroy_layer(struct weston_layer *layer);
static void
workspace_destroy(struct workspace *ws)
@ -892,7 +900,7 @@ workspace_destroy(struct workspace *ws)
if (ws->fsurf_back)
focus_surface_destroy(ws->fsurf_back);
desktop_shell_destroy_views_on_layer(&ws->layer);
desktop_shell_destroy_layer(&ws->layer);
free(ws);
}
@ -1381,7 +1389,7 @@ touch_move_grab_motion(struct weston_touch_grab *grab,
int dx = wl_fixed_to_int(grab->touch->grab_x + move->dx);
int dy = wl_fixed_to_int(grab->touch->grab_y + move->dy);
if (!shsurf || !move->active)
if (!shsurf || !shsurf->desktop_surface || !move->active)
return;
es = weston_desktop_surface_get_surface(shsurf->desktop_surface);
@ -1513,7 +1521,7 @@ move_grab_motion(struct weston_pointer_grab *grab,
int cx, cy;
weston_pointer_move(pointer, event);
if (!shsurf)
if (!shsurf || !shsurf->desktop_surface)
return;
surface = weston_desktop_surface_get_surface(shsurf->desktop_surface);
@ -2253,8 +2261,8 @@ fade_out_done(struct weston_view_animation *animation, void *data)
loop = wl_display_get_event_loop(shsurf->shell->compositor->wl_display);
if (weston_view_is_mapped(shsurf->view)) {
weston_view_unmap(shsurf->view);
if (weston_view_is_mapped(shsurf->wview_anim_fade)) {
weston_view_unmap(shsurf->wview_anim_fade);
wl_event_loop_add_idle(loop, fade_out_done_idle_cb, shsurf);
}
}
@ -2364,7 +2372,6 @@ desktop_surface_removed(struct weston_desktop_surface *desktop_surface,
weston_desktop_surface_set_user_data(shsurf->desktop_surface, NULL);
shsurf->desktop_surface = NULL;
weston_desktop_surface_unlink_view(shsurf->view);
if (weston_surface_is_mapped(surface) &&
shsurf->shell->win_close_animation_type == ANIMATION_FADE) {
@ -2373,11 +2380,26 @@ desktop_surface_removed(struct weston_desktop_surface *desktop_surface,
pixman_region32_init(&surface->pending.input);
pixman_region32_fini(&surface->input);
pixman_region32_init(&surface->input);
weston_fade_run(shsurf->view, 1.0, 0.0, 300.0,
/* its location might have changed, but also might've
* migrated to a different output, so re-compute this
* as the animation requires having the same output as
* the view */
weston_view_set_output(shsurf->wview_anim_fade,
shsurf->view->output);
weston_view_set_position(shsurf->wview_anim_fade,
shsurf->view->geometry.x,
shsurf->view->geometry.y);
weston_layer_entry_insert(&shsurf->view->layer_link,
&shsurf->wview_anim_fade->layer_link);
/* unmap the "original" view */
weston_view_unmap(shsurf->view);
weston_fade_run(shsurf->wview_anim_fade, 1.0, 0.0, 300.0,
fade_out_done, shsurf);
return;
} else {
weston_surface_destroy(surface);
}
}
@ -2500,8 +2522,14 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
if (!weston_surface_is_mapped(surface)) {
map(shell, shsurf, sx, sy);
surface->is_mapped = true;
if (shsurf->shell->win_close_animation_type == ANIMATION_FADE)
++surface->ref_count;
/* as we need to survive the weston_surface destruction we'll
* need to take another reference */
if (shsurf->shell->win_close_animation_type == ANIMATION_FADE) {
surface->ref_count++;
shsurf->wsurface_anim_fade = surface;
shsurf->wview_anim_fade =
shell_fade_create_fade_out_view(shsurf, surface);
}
return;
}
@ -3992,6 +4020,29 @@ shell_fade_create_surface_for_output(struct desktop_shell *shell, struct shell_o
return view;
}
static struct weston_view *
shell_fade_create_fade_out_view(struct shell_surface *shsurf,
struct weston_surface *surface)
{
struct weston_view *view;
struct weston_output *woutput;
view = weston_view_create(surface);
if (!view)
return NULL;
woutput = get_focused_output(surface->compositor);
/* set the initial position and output just in case we happen to not
* move it around and just destroy it */
weston_view_set_output(view, woutput);
weston_view_set_position(view,
shsurf->view->geometry.x,
shsurf->view->geometry.y);
view->is_mapped = true;
return view;
}
static void
shell_fade(struct desktop_shell *shell, enum fade_type type)
{
@ -4905,7 +4956,7 @@ setup_output_destroy_handler(struct weston_compositor *ec,
}
static void
desktop_shell_destroy_views_on_layer(struct weston_layer *layer)
desktop_shell_destroy_layer(struct weston_layer *layer)
{
struct weston_view *view, *view_next;
@ -4916,9 +4967,17 @@ desktop_shell_destroy_views_on_layer(struct weston_layer *layer)
* additional black_view created and added to its layer_link
* fullscreen view. See shell_ensure_fullscreen_black_view()
*
* As that black_view it is not a weston_desktop_surface
* we can't have a shsurf for it so we just destroy it like
* we do it in desktop_surface_removed() */
* Note that we do not choose to destroy all other potential
* views we find in the layer, but instead we explicitly verify
* if the view in question was explicitly created by
* desktop-shell, rather than libweston-desktop (in
* desktop_surface_added()).
*
* This is particularly important because libweston-desktop
* could create additional views, which are managed implicitly,
* but which are still being added to the layer list.
*
*/
if (shsurf)
desktop_shell_destroy_surface(shsurf);
else
@ -4970,12 +5029,12 @@ shell_destroy(struct wl_listener *listener, void *data)
workspace_destroy(*ws);
wl_array_release(&shell->workspaces.array);
desktop_shell_destroy_views_on_layer(&shell->panel_layer);
desktop_shell_destroy_views_on_layer(&shell->background_layer);
desktop_shell_destroy_views_on_layer(&shell->lock_layer);
desktop_shell_destroy_views_on_layer(&shell->input_panel_layer);
desktop_shell_destroy_views_on_layer(&shell->minimized_layer);
desktop_shell_destroy_views_on_layer(&shell->fullscreen_layer);
desktop_shell_destroy_layer(&shell->panel_layer);
desktop_shell_destroy_layer(&shell->background_layer);
desktop_shell_destroy_layer(&shell->lock_layer);
desktop_shell_destroy_layer(&shell->input_panel_layer);
desktop_shell_destroy_layer(&shell->minimized_layer);
desktop_shell_destroy_layer(&shell->fullscreen_layer);
free(shell->client);
free(shell);

@ -1289,6 +1289,7 @@ struct weston_view {
struct weston_surface *surface;
struct wl_list surface_link;
struct wl_signal destroy_signal;
struct wl_signal unmap_signal;
/* struct weston_paint_node::view_link */
struct wl_list paint_node_list;
@ -1441,7 +1442,7 @@ struct weston_pointer_constraint {
bool hint_is_pending;
struct wl_listener pointer_destroy_listener;
struct wl_listener surface_destroy_listener;
struct wl_listener view_unmap_listener;
struct wl_listener surface_commit_listener;
struct wl_listener surface_activate_listener;
};

@ -173,8 +173,10 @@ kiosk_shell_surface_find_best_output(struct kiosk_shell_surface *shsurf)
app_id = weston_desktop_surface_get_app_id(shsurf->desktop_surface);
if (app_id) {
wl_list_for_each(shoutput, &shsurf->shell->output_list, link) {
if (kiosk_shell_output_has_app_id(shoutput, app_id))
if (kiosk_shell_output_has_app_id(shoutput, app_id)) {
shsurf->appid_output_assigned = true;
return shoutput->output;
}
}
}
@ -354,6 +356,7 @@ kiosk_shell_surface_create(struct kiosk_shell *shell,
shsurf->desktop_surface = desktop_surface;
shsurf->view = view;
shsurf->shell = shell;
shsurf->appid_output_assigned = false;
weston_desktop_surface_set_user_data(desktop_surface, shsurf);
@ -387,8 +390,10 @@ kiosk_shell_surface_activate(struct kiosk_shell_surface *shsurf,
/* removes it from the normal_layer and move it to inactive
* one, without occluding the top-level window if the new one
* is a child to that */
if (!shsurf->parent) {
* is a child to that. Also, do not occlude another view
* (currently focused one) on a different output when activating
* a new one. */
if (!shsurf->parent && (shsurf->output == current_focus->output)) {
weston_layer_entry_remove(&current_focus->view->layer_link);
weston_layer_entry_insert(&shsurf->shell->inactive_layer.view_list,
&current_focus->view->layer_link);
@ -645,12 +650,18 @@ find_focus_successor(struct weston_layer *layer,
struct weston_view *top_view = NULL;
struct weston_view *view;
/* we need to take into account that the surface being destroyed it not
* always the same as the focus_surface, which could result in picking
* and *activating* the wrong window, so avoid returning a view for
* that case. A particular case is when a top-level child window, would
* pick a parent window below the focused_surface. */
if (focused_surface != shsurf->view->surface)
* pick a parent window below the focused_surface.
*
* Apply that only on the same output to avoid incorrectly returning an
* invalid/empty view, which could happen if the view being destroyed
* is on a output different than the focused_surface output */
if (focused_surface && focused_surface != shsurf->view->surface &&
shsurf->output == focused_surface->output)
return top_view;
wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
@ -660,6 +671,10 @@ find_focus_successor(struct weston_layer *layer,
if (!view->is_mapped || view == shsurf->view)
continue;
/* pick views only on the same output */
if (view->output != shsurf->output)
continue;
view_shsurf = get_kiosk_shell_surface(view->surface);
if (!view_shsurf)
continue;
@ -721,6 +736,8 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
weston_desktop_surface_get_user_data(desktop_surface);
struct weston_surface *surface =
weston_desktop_surface_get_surface(desktop_surface);
const char *app_id =
weston_desktop_surface_get_app_id(desktop_surface);
bool is_resized;
bool is_fullscreen;
@ -729,6 +746,24 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
if (surface->width == 0)
return;
if (!shsurf->appid_output_assigned && app_id) {
struct weston_output *output = NULL;
/* reset previous output being set in _added() as the output is
* being cached */
shsurf->output = NULL;
output = kiosk_shell_surface_find_best_output(shsurf);
kiosk_shell_surface_set_output(shsurf, output);
weston_desktop_surface_set_size(shsurf->desktop_surface,
shsurf->output->width,
shsurf->output->height);
/* even if we couldn't find an appid set for a particular
* output still flag the shsurf as to a avoid changing the
* output every time */
shsurf->appid_output_assigned = true;
}
/* TODO: When the top-level surface is committed with a new size after an
* output resize, sometimes the view appears scaled. What state are we not
* updating?

@ -73,6 +73,8 @@ struct kiosk_shell_surface {
int32_t x;
int32_t y;
} xwayland;
bool appid_output_assigned;
};
struct kiosk_shell_seat {

@ -713,7 +713,7 @@ weston_desktop_xdg_toplevel_committed(struct weston_desktop_xdg_toplevel *toplev
wl_resource_post_error(client_resource,
XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
"xdg_surface buffer (%" PRIi32 " x %" PRIi32 ") "
"xdg_surface geometry (%" PRIi32 " x %" PRIi32 ") "
"does not match the configured maximized state (%" PRIi32 " x %" PRIi32 ")",
geometry.width, geometry.height,
toplevel->next.size.width,

@ -236,6 +236,7 @@ enum try_view_on_plane_failure_reasons {
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE = (1 << 1),
FAILURE_REASONS_DMABUF_MODIFIER_INVALID = (1 << 2),
FAILURE_REASONS_ADD_FB_FAILED = (1 << 3),
FAILURE_REASONS_GBM_BO_IMPORT_FAILED = (1 << 4)
};
/**

@ -276,8 +276,12 @@ drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
fb->bo = gbm_bo_import(backend->gbm, GBM_BO_IMPORT_FD_MODIFIER,
&import_mod, GBM_BO_USE_SCANOUT);
if (!fb->bo)
if (!fb->bo) {
if (try_view_on_plane_failure_reasons)
*try_view_on_plane_failure_reasons |=
FAILURE_REASONS_GBM_BO_IMPORT_FAILED;
goto err_free;
}
fb->width = dmabuf->attributes.width;
fb->height = dmabuf->attributes.height;

@ -42,7 +42,7 @@ deps_drm = [
]
if get_option('renderer-gl')
dep_gbm = dependency('gbm', required: false)
dep_gbm = dependency('gbm', required: false, version: '>= 21.1.1')
if not dep_gbm.found()
error('drm-backend with GL renderer requires gbm which was not found. Or, you can use \'-Drenderer-gl=false\'.')
endif

@ -602,7 +602,8 @@ dmabuf_feedback_maybe_update(struct drm_backend *b, struct weston_view *ev,
if (try_view_on_plane_failure_reasons &
(FAILURE_REASONS_ADD_FB_FAILED |
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE |
FAILURE_REASONS_DMABUF_MODIFIER_INVALID))
FAILURE_REASONS_DMABUF_MODIFIER_INVALID |
FAILURE_REASONS_GBM_BO_IMPORT_FAILED))
action_needed |= ACTION_NEEDED_ADD_SCANOUT_TRANCHE;
assert(action_needed != (ACTION_NEEDED_REMOVE_SCANOUT_TRANCHE |

@ -393,6 +393,7 @@ weston_view_create(struct weston_surface *surface)
wl_list_insert(&surface->views, &view->surface_link);
wl_signal_init(&view->destroy_signal);
wl_signal_init(&view->unmap_signal);
wl_list_init(&view->link);
wl_list_init(&view->layer_link.link);
wl_list_init(&view->paint_node_list);
@ -2225,22 +2226,22 @@ weston_view_unmap(struct weston_view *view)
view->output_mask = 0;
weston_surface_assign_output(view->surface);
if (weston_surface_is_mapped(view->surface))
return;
wl_list_for_each(seat, &view->surface->compositor->seat_list, link) {
struct weston_touch *touch = weston_seat_get_touch(seat);
struct weston_pointer *pointer = weston_seat_get_pointer(seat);
struct weston_keyboard *keyboard =
weston_seat_get_keyboard(seat);
if (keyboard && keyboard->focus == view->surface)
weston_keyboard_set_focus(keyboard, NULL);
if (pointer && pointer->focus == view)
weston_pointer_clear_focus(pointer);
if (touch && touch->focus == view)
weston_touch_set_focus(touch, NULL);
if (!weston_surface_is_mapped(view->surface)) {
wl_list_for_each(seat, &view->surface->compositor->seat_list, link) {
struct weston_touch *touch = weston_seat_get_touch(seat);
struct weston_pointer *pointer = weston_seat_get_pointer(seat);
struct weston_keyboard *keyboard =
weston_seat_get_keyboard(seat);
if (keyboard && keyboard->focus == view->surface)
weston_keyboard_set_focus(keyboard, NULL);
if (pointer && pointer->focus == view)
weston_pointer_clear_focus(pointer);
if (touch && touch->focus == view)
weston_touch_set_focus(touch, NULL);
}
}
weston_signal_emit_mutable(&view->unmap_signal, view);
}
WL_EXPORT void
@ -2306,6 +2307,10 @@ weston_surface_destroy(struct weston_surface *surface)
struct weston_pointer_constraint *constraint, *next_constraint;
struct weston_paint_node *pnode, *pntmp;
if (!surface)
return;
assert(surface->ref_count > 0);
if (--surface->ref_count > 0)
return;
@ -4044,54 +4049,22 @@ static const struct wl_surface_interface surface_interface = {
surface_damage_buffer
};
static int
create_surface_dmabuf_feedback(struct weston_compositor *ec,
struct weston_surface *surface)
{
struct weston_dmabuf_feedback_tranche *tranche;
dev_t main_device = ec->default_dmabuf_feedback->main_device;
uint32_t flags = 0;
surface->dmabuf_feedback = weston_dmabuf_feedback_create(main_device);
if (!surface->dmabuf_feedback)
return -1;
tranche = weston_dmabuf_feedback_tranche_create(surface->dmabuf_feedback,
ec->dmabuf_feedback_format_table,
main_device, flags,
RENDERER_PREF);
if (!tranche) {
weston_dmabuf_feedback_destroy(surface->dmabuf_feedback);
surface->dmabuf_feedback = NULL;
return -1;
}
return 0;
}
static void
compositor_create_surface(struct wl_client *client,
struct wl_resource *resource, uint32_t id)
{
struct weston_compositor *ec = wl_resource_get_user_data(resource);
struct weston_surface *surface;
int ret;
surface = weston_surface_create(ec);
if (surface == NULL)
goto err;
if (ec->default_dmabuf_feedback) {
ret = create_surface_dmabuf_feedback(ec, surface);
if (ret < 0)
goto err_dmabuf_feedback;
}
surface->resource =
wl_resource_create(client, &wl_surface_interface,
wl_resource_get_version(resource), id);
if (surface->resource == NULL)
goto err_dmabuf_feedback;
goto err_res;
wl_resource_set_implementation(surface->resource, &surface_interface,
surface, destroy_surface);
@ -4099,7 +4072,7 @@ compositor_create_surface(struct wl_client *client,
return;
err_dmabuf_feedback:
err_res:
weston_surface_destroy(surface);
err:
wl_resource_post_no_memory(resource);
@ -4211,6 +4184,11 @@ weston_subsurface_commit_to_cache(struct weston_subsurface *sub)
&surface->pending.damage_surface);
pixman_region32_clear(&surface->pending.damage_surface);
pixman_region32_union(&sub->cached.damage_buffer,
&sub->cached.damage_buffer,
&surface->pending.damage_buffer);
pixman_region32_clear(&surface->pending.damage_buffer);
if (surface->pending.newly_attached) {
sub->cached.newly_attached = 1;
weston_surface_state_set_buffer(&sub->cached,
@ -4233,8 +4211,6 @@ weston_subsurface_commit_to_cache(struct weston_subsurface *sub)
sub->cached.sx += surface->pending.sx;
sub->cached.sy += surface->pending.sy;
apply_damage_buffer(&sub->cached.damage_surface, surface, &surface->pending);
sub->cached.buffer_viewport.changed |=
surface->pending.buffer_viewport.changed;
sub->cached.buffer_viewport.buffer =
@ -4361,7 +4337,7 @@ subsurface_committed(struct weston_surface *surface, int32_t dx, int32_t dy)
*/
if (!weston_surface_is_mapped(surface)) {
surface->is_mapped = true;
surface->is_mapped = surface->buffer_ref.buffer != NULL;
/* Cannot call weston_view_update_transform(),
* because that would call it also for the parent surface,

@ -3655,8 +3655,8 @@ enable_pointer_constraint(struct weston_pointer_constraint *constraint,
constraint->view = view;
pointer_constraint_notify_activated(constraint);
weston_pointer_start_grab(constraint->pointer, &constraint->grab);
wl_list_remove(&constraint->surface_destroy_listener.link);
wl_list_init(&constraint->surface_destroy_listener.link);