summaryrefslogtreecommitdiff
path: root/libweston
diff options
context:
space:
mode:
Diffstat (limited to 'libweston')
-rw-r--r--libweston/animation.c532
-rw-r--r--libweston/backend-drm/drm-gbm.c366
-rw-r--r--libweston/backend-drm/drm-internal.h825
-rw-r--r--libweston/backend-drm/drm-virtual.c362
-rw-r--r--libweston/backend-drm/drm.c3040
-rw-r--r--libweston/backend-drm/fb.c582
-rw-r--r--libweston/backend-drm/kms.c1525
-rw-r--r--libweston/backend-drm/libbacklight.c318
-rw-r--r--libweston/backend-drm/libbacklight.h79
-rw-r--r--libweston/backend-drm/meson.build93
-rw-r--r--libweston/backend-drm/modes.c783
-rw-r--r--libweston/backend-drm/state-helpers.c448
-rw-r--r--libweston/backend-drm/state-propose.c1149
-rw-r--r--libweston/backend-drm/vaapi-recorder.c1161
-rw-r--r--libweston/backend-drm/vaapi-recorder.h38
-rw-r--r--libweston/backend-fbdev/fbdev.c994
-rw-r--r--libweston/backend-fbdev/meson.build30
-rw-r--r--libweston/backend-headless/headless.c514
-rw-r--r--libweston/backend-headless/meson.build21
-rw-r--r--libweston/backend-rdp/meson.build39
-rw-r--r--libweston/backend-rdp/rdp.c1501
-rw-r--r--libweston/backend-tdm/meson.build35
-rw-r--r--libweston/backend-tdm/tdm-internal.h179
-rw-r--r--libweston/backend-tdm/tdm.c1280
-rw-r--r--libweston/backend-wayland/meson.build44
-rw-r--r--libweston/backend-wayland/wayland.c2906
-rw-r--r--libweston/backend-x11/meson.build58
-rw-r--r--libweston/backend-x11/x11.c1959
-rw-r--r--libweston/backend.h244
-rw-r--r--libweston/bindings.c588
-rw-r--r--libweston/clipboard.c307
-rw-r--r--libweston/compositor.c7882
-rw-r--r--libweston/content-protection.c347
-rw-r--r--libweston/data-device.c1369
-rw-r--r--libweston/dbus.c408
-rw-r--r--libweston/dbus.h110
-rw-r--r--libweston/git-version.h.meson1
-rw-r--r--libweston/input.c5086
-rw-r--r--libweston/launcher-direct.c345
-rw-r--r--libweston/launcher-impl.h49
-rw-r--r--libweston/launcher-logind.c856
-rw-r--r--libweston/launcher-util.c120
-rw-r--r--libweston/launcher-util.h55
-rw-r--r--libweston/launcher-weston-launch.c309
-rw-r--r--libweston/libinput-device.c761
-rw-r--r--libweston/libinput-device.h82
-rw-r--r--libweston/libinput-seat.c489
-rw-r--r--libweston/libinput-seat.h73
-rw-r--r--libweston/libweston-internal.h332
-rw-r--r--libweston/linux-dmabuf.c591
-rw-r--r--libweston/linux-dmabuf.h103
-rw-r--r--libweston/linux-explicit-synchronization.c287
-rw-r--r--libweston/linux-explicit-synchronization.h39
-rw-r--r--libweston/linux-sync-file-uapi.h30
-rw-r--r--libweston/linux-sync-file.c83
-rw-r--r--libweston/linux-sync-file.h38
-rw-r--r--libweston/log.c156
-rw-r--r--libweston/meson.build243
-rw-r--r--libweston/noop-renderer.c122
-rw-r--r--libweston/pixel-formats.c516
-rw-r--r--libweston/pixel-formats.h262
-rw-r--r--libweston/pixman-renderer.c968
-rw-r--r--libweston/pixman-renderer.h51
-rw-r--r--libweston/plugin-registry.c156
-rw-r--r--libweston/renderer-gl/egl-glue.c599
-rw-r--r--libweston/renderer-gl/gl-renderer-internal.h143
-rw-r--r--libweston/renderer-gl/gl-renderer.c3943
-rw-r--r--libweston/renderer-gl/gl-renderer.h205
-rw-r--r--libweston/renderer-gl/meson.build51
-rw-r--r--libweston/screenshooter.c494
-rw-r--r--libweston/spring-tool.c79
-rw-r--r--libweston/timeline.c461
-rw-r--r--libweston/timeline.h103
-rw-r--r--libweston/touch-calibration.c717
-rw-r--r--libweston/vertex-clipping.c330
-rw-r--r--libweston/vertex-clipping.h66
-rw-r--r--libweston/weston-direct-display.c92
-rw-r--r--libweston/weston-launch.c874
-rw-r--r--libweston/weston-launch.h52
-rw-r--r--libweston/weston-log-file.c100
-rw-r--r--libweston/weston-log-flight-rec.c294
-rw-r--r--libweston/weston-log-internal.h119
-rw-r--r--libweston/weston-log-wayland.c297
-rw-r--r--libweston/weston-log.c962
-rw-r--r--libweston/zoom.c184
85 files changed, 0 insertions, 54484 deletions
diff --git a/libweston/animation.c b/libweston/animation.c
deleted file mode 100644
index a81a8c19..00000000
--- a/libweston/animation.c
+++ /dev/null
@@ -1,532 +0,0 @@
-/*
- * Copyright © 2011 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <math.h>
-#include <inttypes.h>
-
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <libweston/libweston.h>
-#include "shared/helpers.h"
-#include "shared/timespec-util.h"
-
-WL_EXPORT void
-weston_spring_init(struct weston_spring *spring,
- double k, double current, double target)
-{
- spring->k = k;
- spring->friction = 400.0;
- spring->current = current;
- spring->previous = current;
- spring->target = target;
- spring->clip = WESTON_SPRING_OVERSHOOT;
- spring->min = 0.0;
- spring->max = 1.0;
-}
-
-WL_EXPORT void
-weston_spring_update(struct weston_spring *spring, const struct timespec *time)
-{
- double force, v, current, step;
-
- /* Limit the number of executions of the loop below by ensuring that
- * the timestamp for last update of the spring is no more than 1s ago.
- * This handles the case where time moves backwards or forwards in
- * large jumps.
- */
- if (timespec_sub_to_msec(time, &spring->timestamp) > 1000) {
- weston_log("unexpectedly large timestamp jump "
- "(from %" PRId64 " to %" PRId64 ")\n",
- timespec_to_msec(&spring->timestamp),
- timespec_to_msec(time));
- timespec_add_msec(&spring->timestamp, time, -1000);
- }
-
- step = 0.01;
- while (4 < timespec_sub_to_msec(time, &spring->timestamp)) {
- current = spring->current;
- v = current - spring->previous;
- force = spring->k * (spring->target - current) / 10.0 +
- (spring->previous - current) - v * spring->friction;
-
- spring->current =
- current + (current - spring->previous) +
- force * step * step;
- spring->previous = current;
-
- switch (spring->clip) {
- case WESTON_SPRING_OVERSHOOT:
- break;
-
- case WESTON_SPRING_CLAMP:
- if (spring->current > spring->max) {
- spring->current = spring->max;
- spring->previous = spring->max;
- } else if (spring->current < 0.0) {
- spring->current = spring->min;
- spring->previous = spring->min;
- }
- break;
-
- case WESTON_SPRING_BOUNCE:
- if (spring->current > spring->max) {
- spring->current =
- 2 * spring->max - spring->current;
- spring->previous =
- 2 * spring->max - spring->previous;
- } else if (spring->current < spring->min) {
- spring->current =
- 2 * spring->min - spring->current;
- spring->previous =
- 2 * spring->min - spring->previous;
- }
- break;
- }
-
- timespec_add_msec(&spring->timestamp, &spring->timestamp, 4);
- }
-}
-
-WL_EXPORT int
-weston_spring_done(struct weston_spring *spring)
-{
- return fabs(spring->previous - spring->target) < 0.002 &&
- fabs(spring->current - spring->target) < 0.002;
-}
-
-typedef void (*weston_view_animation_frame_func_t)(struct weston_view_animation *animation);
-
-struct weston_view_animation {
- struct weston_view *view;
- struct weston_animation animation;
- struct weston_spring spring;
- struct weston_transform transform;
- struct wl_listener listener;
- float start, stop;
- weston_view_animation_frame_func_t frame;
- weston_view_animation_frame_func_t reset;
- weston_view_animation_done_func_t done;
- void *data;
- void *private;
-};
-
-WL_EXPORT void
-weston_view_animation_destroy(struct weston_view_animation *animation)
-{
- wl_list_remove(&animation->animation.link);
- wl_list_remove(&animation->listener.link);
- wl_list_remove(&animation->transform.link);
- if (animation->reset)
- animation->reset(animation);
- weston_view_geometry_dirty(animation->view);
- if (animation->done)
- animation->done(animation, animation->data);
- free(animation);
-}
-
-static void
-handle_animation_view_destroy(struct wl_listener *listener, void *data)
-{
- struct weston_view_animation *animation =
- container_of(listener,
- struct weston_view_animation, listener);
-
- weston_view_animation_destroy(animation);
-}
-
-static void
-weston_view_animation_frame(struct weston_animation *base,
- struct weston_output *output,
- const struct timespec *time)
-{
- struct weston_view_animation *animation =
- container_of(base,
- struct weston_view_animation, animation);
- struct weston_compositor *compositor =
- animation->view->surface->compositor;
-
- if (base->frame_counter <= 1)
- animation->spring.timestamp = *time;
-
- weston_spring_update(&animation->spring, time);
-
- if (weston_spring_done(&animation->spring)) {
- weston_view_schedule_repaint(animation->view);
- weston_view_animation_destroy(animation);
- return;
- }
-
- if (animation->frame)
- animation->frame(animation);
-
- weston_view_geometry_dirty(animation->view);
- weston_view_schedule_repaint(animation->view);
-
- /* The view's output_mask will be zero if its position is
- * offscreen. Animations should always run but as they are also
- * run off the repaint cycle, if there's nothing to repaint
- * the animation stops running. Therefore if we catch this situation
- * and schedule a repaint on all outputs it will be avoided.
- */
- if (animation->view->output_mask == 0)
- weston_compositor_schedule_repaint(compositor);
-}
-
-static void
-idle_animation_destroy(void *data)
-{
- struct weston_view_animation *animation = data;
-
- weston_view_animation_destroy(animation);
-}
-
-static struct weston_view_animation *
-weston_view_animation_create(struct weston_view *view,
- float start, float stop,
- weston_view_animation_frame_func_t frame,
- weston_view_animation_frame_func_t reset,
- weston_view_animation_done_func_t done,
- void *data,
- void *private)
-{
- struct weston_view_animation *animation;
- struct weston_compositor *ec = view->surface->compositor;
- struct wl_event_loop *loop;
-
- animation = malloc(sizeof *animation);
- if (!animation)
- return NULL;
-
- animation->view = view;
- animation->frame = frame;
- animation->reset = reset;
- animation->done = done;
- animation->data = data;
- animation->start = start;
- animation->stop = stop;
- animation->private = private;
-
- weston_matrix_init(&animation->transform.matrix);
- wl_list_insert(&view->geometry.transformation_list,
- &animation->transform.link);
-
- animation->animation.frame = weston_view_animation_frame;
-
- animation->listener.notify = handle_animation_view_destroy;
- wl_signal_add(&view->destroy_signal, &animation->listener);
-
- if (view->output) {
- wl_list_insert(&view->output->animation_list,
- &animation->animation.link);
- } else {
- wl_list_init(&animation->animation.link);
- loop = wl_display_get_event_loop(ec->wl_display);
- wl_event_loop_add_idle(loop, idle_animation_destroy, animation);
- }
-
- return animation;
-}
-
-static void
-weston_view_animation_run(struct weston_view_animation *animation)
-{
- struct timespec zero_time = { 0 };
-
- animation->animation.frame_counter = 0;
- weston_view_animation_frame(&animation->animation, NULL, &zero_time);
-}
-
-static void
-reset_alpha(struct weston_view_animation *animation)
-{
- struct weston_view *view = animation->view;
-
- view->alpha = animation->stop;
-}
-
-static void
-zoom_frame(struct weston_view_animation *animation)
-{
- struct weston_view *es = animation->view;
- float scale;
-
- scale = animation->start +
- (animation->stop - animation->start) *
- animation->spring.current;
- weston_matrix_init(&animation->transform.matrix);
- weston_matrix_translate(&animation->transform.matrix,
- -0.5f * es->surface->width,
- -0.5f * es->surface->height, 0);
- weston_matrix_scale(&animation->transform.matrix, scale, scale, scale);
- weston_matrix_translate(&animation->transform.matrix,
- 0.5f * es->surface->width,
- 0.5f * es->surface->height, 0);
-
- es->alpha = animation->spring.current;
- if (es->alpha > 1.0)
- es->alpha = 1.0;
-}
-
-WL_EXPORT struct weston_view_animation *
-weston_zoom_run(struct weston_view *view, float start, float stop,
- weston_view_animation_done_func_t done, void *data)
-{
- struct weston_view_animation *zoom;
-
- zoom = weston_view_animation_create(view, start, stop,
- zoom_frame, reset_alpha,
- done, data, NULL);
-
- if (zoom == NULL)
- return NULL;
-
- weston_spring_init(&zoom->spring, 300.0, start, stop);
- zoom->spring.friction = 1400;
- zoom->spring.previous = start - (stop - start) * 0.03;
-
- weston_view_animation_run(zoom);
-
- return zoom;
-}
-
-static void
-fade_frame(struct weston_view_animation *animation)
-{
- if (animation->spring.current > 0.999)
- animation->view->alpha = 1;
- else if (animation->spring.current < 0.001 )
- animation->view->alpha = 0;
- else
- animation->view->alpha = animation->spring.current;
-}
-
-WL_EXPORT struct weston_view_animation *
-weston_fade_run(struct weston_view *view,
- float start, float end, float k,
- weston_view_animation_done_func_t done, void *data)
-{
- struct weston_view_animation *fade;
-
- fade = weston_view_animation_create(view, start, end,
- fade_frame, reset_alpha,
- done, data, NULL);
-
- if (fade == NULL)
- return NULL;
-
- weston_spring_init(&fade->spring, 1000.0, start, end);
- fade->spring.friction = 4000;
- fade->spring.previous = start - (end - start) * 0.1;
-
- view->alpha = start;
-
- weston_view_animation_run(fade);
-
- return fade;
-}
-
-WL_EXPORT void
-weston_fade_update(struct weston_view_animation *fade, float target)
-{
- fade->spring.target = target;
- fade->stop = target;
-}
-
-static void
-stable_fade_frame(struct weston_view_animation *animation)
-{
- struct weston_view *back_view;
-
- if (animation->spring.current > 0.999)
- animation->view->alpha = 1;
- else if (animation->spring.current < 0.001 )
- animation->view->alpha = 0;
- else
- animation->view->alpha = animation->spring.current;
-
- back_view = (struct weston_view *) animation->private;
- back_view->alpha =
- (animation->spring.target - animation->view->alpha) /
- (1.0 - animation->view->alpha);
- weston_view_geometry_dirty(back_view);
-}
-
-WL_EXPORT struct weston_view_animation *
-weston_stable_fade_run(struct weston_view *front_view, float start,
- struct weston_view *back_view, float end,
- weston_view_animation_done_func_t done, void *data)
-{
- struct weston_view_animation *fade;
-
- fade = weston_view_animation_create(front_view, 0, 0,
- stable_fade_frame, NULL,
- done, data, back_view);
-
- if (fade == NULL)
- return NULL;
-
- weston_spring_init(&fade->spring, 400, start, end);
- fade->spring.friction = 1150;
-
- front_view->alpha = start;
- back_view->alpha = end;
-
- weston_view_animation_run(fade);
-
- return fade;
-}
-
-static void
-slide_frame(struct weston_view_animation *animation)
-{
- float scale;
-
- scale = animation->start +
- (animation->stop - animation->start) *
- animation->spring.current;
- weston_matrix_init(&animation->transform.matrix);
- weston_matrix_translate(&animation->transform.matrix, 0, scale, 0);
-}
-
-WL_EXPORT struct weston_view_animation *
-weston_slide_run(struct weston_view *view, float start, float stop,
- weston_view_animation_done_func_t done, void *data)
-{
- struct weston_view_animation *animation;
-
- animation = weston_view_animation_create(view, start, stop,
- slide_frame, NULL, done,
- data, NULL);
- if (!animation)
- return NULL;
-
- weston_spring_init(&animation->spring, 400.0, 0.0, 1.0);
- animation->spring.friction = 600;
- animation->spring.clip = WESTON_SPRING_BOUNCE;
-
- weston_view_animation_run(animation);
-
- return animation;
-}
-
-struct weston_move_animation {
- int dx;
- int dy;
- bool reverse;
- bool scale;
- weston_view_animation_done_func_t done;
-};
-
-static void
-move_frame(struct weston_view_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);
- if (move->scale)
- 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_view_animation *animation, void *data)
-{
- struct weston_move_animation *move = animation->private;
-
- if (move->done)
- move->done(animation, data);
-
- free(move);
-}
-
-static struct weston_view_animation *
-weston_move_scale_run_internal(struct weston_view *view, int dx, int dy,
- float start, float end, bool reverse, bool scale,
- weston_view_animation_done_func_t done,
- void *data)
-{
- struct weston_move_animation *move;
- struct weston_view_animation *animation;
-
- move = malloc(sizeof(*move));
- if (!move)
- return NULL;
- move->dx = dx;
- move->dy = dy;
- move->reverse = reverse;
- move->scale = scale;
- move->done = done;
-
- animation = weston_view_animation_create(view, start, end, move_frame,
- NULL, move_done, data, move);
-
- if (animation == NULL){
- free(move);
- return NULL;
- }
-
- weston_spring_init(&animation->spring, 400.0, 0.0, 1.0);
- animation->spring.friction = 1150;
-
- weston_view_animation_run(animation);
-
- return animation;
-}
-
-WL_EXPORT struct weston_view_animation *
-weston_move_scale_run(struct weston_view *view, int dx, int dy,
- float start, float end, bool reverse,
- weston_view_animation_done_func_t done, void *data)
-{
- return weston_move_scale_run_internal(view, dx, dy, start, end, reverse,
- true, done, data);
-}
-
-WL_EXPORT struct weston_view_animation *
-weston_move_run(struct weston_view *view, int dx, int dy,
- float start, float end, bool reverse,
- weston_view_animation_done_func_t done, void *data)
-{
- return weston_move_scale_run_internal(view, dx, dy, start, end, reverse,
- false, done, data);
-}
diff --git a/libweston/backend-drm/drm-gbm.c b/libweston/backend-drm/drm-gbm.c
deleted file mode 100644
index 324c2a83..00000000
--- a/libweston/backend-drm/drm-gbm.c
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2011 Intel Corporation
- * Copyright © 2017, 2018 Collabora, Ltd.
- * Copyright © 2017, 2018 General Electric Company
- * Copyright (c) 2018 DisplayLink (UK) Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-#include <dlfcn.h>
-
-#include "drm-internal.h"
-#include "pixman-renderer.h"
-#include "pixel-formats.h"
-#include "renderer-gl/gl-renderer.h"
-#include "shared/weston-egl-ext.h"
-#include "linux-dmabuf.h"
-#include "linux-explicit-synchronization.h"
-
-struct gl_renderer_interface *gl_renderer;
-
-static struct gbm_device *
-create_gbm_device(int fd)
-{
- struct gbm_device *gbm;
-
- gl_renderer = weston_load_module("gl-renderer.so",
- "gl_renderer_interface");
- if (!gl_renderer)
- return NULL;
-
- /* GBM will load a dri driver, but even though they need symbols from
- * libglapi, in some version of Mesa they are not linked to it. Since
- * only the gl-renderer module links to it, the call above won't make
- * these symbols globally available, and loading the DRI driver fails.
- * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
- dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
-
- gbm = gbm_create_device(fd);
-
- return gbm;
-}
-
-/* When initializing EGL, if the preferred buffer format isn't available
- * we may be able to substitute an ARGB format for an XRGB one.
- *
- * This returns 0 if substitution isn't possible, but 0 might be a
- * legitimate format for other EGL platforms, so the caller is
- * responsible for checking for 0 before calling gl_renderer->create().
- *
- * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
- * but it's entirely possible we'll see this again on other implementations.
- */
-static uint32_t
-fallback_format_for(uint32_t format)
-{
- const struct pixel_format_info *pf;
-
- pf = pixel_format_get_info_by_opaque_substitute(format);
- if (!pf)
- return 0;
-
- return pf->format;
-}
-
-static int
-drm_backend_create_gl_renderer(struct drm_backend *b)
-{
- uint32_t format[3] = {
- b->gbm_format,
- fallback_format_for(b->gbm_format),
- 0,
- };
- unsigned n_formats = 2;
-
- if (format[1])
- n_formats = 3;
- if (gl_renderer->display_create(b->compositor,
- EGL_PLATFORM_GBM_KHR,
- (void *)b->gbm,
- EGL_WINDOW_BIT,
- format,
- n_formats) < 0) {
- return -1;
- }
-
- return 0;
-}
-
-int
-init_egl(struct drm_backend *b)
-{
- b->gbm = create_gbm_device(b->drm.fd);
-
- if (!b->gbm)
- return -1;
-
- if (drm_backend_create_gl_renderer(b) < 0) {
- gbm_device_destroy(b->gbm);
- return -1;
- }
-
- return 0;
-}
-
-static void drm_output_fini_cursor_egl(struct drm_output *output)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
- drm_fb_unref(output->gbm_cursor_fb[i]);
- output->gbm_cursor_fb[i] = NULL;
- }
-}
-
-static int
-drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
-{
- unsigned int i;
-
- /* No point creating cursors if we don't have a plane for them. */
- if (!output->cursor_plane)
- return 0;
-
- for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
- struct gbm_bo *bo;
-
- bo = gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
- GBM_FORMAT_ARGB8888,
- GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
- if (!bo)
- goto err;
-
- output->gbm_cursor_fb[i] =
- drm_fb_get_from_bo(bo, b, false, BUFFER_CURSOR);
- if (!output->gbm_cursor_fb[i]) {
- gbm_bo_destroy(bo);
- goto err;
- }
- output->gbm_cursor_handle[i] = gbm_bo_get_handle(bo).s32;
- }
-
- return 0;
-
-err:
- weston_log("cursor buffers unavailable, using gl cursors\n");
- b->cursors_are_broken = true;
- drm_output_fini_cursor_egl(output);
- return -1;
-}
-
-/* Init output state that depends on gl or gbm */
-int
-drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
-{
- uint32_t format[2] = {
- output->gbm_format,
- fallback_format_for(output->gbm_format),
- };
- unsigned n_formats = 1;
- struct weston_mode *mode = output->base.current_mode;
- struct drm_plane *plane = output->scanout_plane;
- unsigned int i;
-
- assert(output->gbm_surface == NULL);
-
- for (i = 0; i < plane->count_formats; i++) {
- if (plane->formats[i].format == output->gbm_format)
- break;
- }
-
- if (i == plane->count_formats) {
- weston_log("format 0x%x not supported by output %s\n",
- output->gbm_format, output->base.name);
- return -1;
- }
-
-#ifdef HAVE_GBM_MODIFIERS
- if (plane->formats[i].count_modifiers > 0) {
- output->gbm_surface =
- gbm_surface_create_with_modifiers(b->gbm,
- mode->width,
- mode->height,
- output->gbm_format,
- plane->formats[i].modifiers,
- plane->formats[i].count_modifiers);
- }
-
- /* If allocating with modifiers fails, try again without. This can
- * happen when the KMS display device supports modifiers but the
- * GBM driver does not, e.g. the old i915 Mesa driver. */
- if (!output->gbm_surface)
-#endif
- {
- output->gbm_surface =
- gbm_surface_create(b->gbm, mode->width, mode->height,
- output->gbm_format,
- output->gbm_bo_flags);
- }
-
- if (!output->gbm_surface) {
- weston_log("failed to create gbm surface\n");
- return -1;
- }
-
- if (format[1])
- n_formats = 2;
- if (gl_renderer->output_window_create(&output->base,
- (EGLNativeWindowType)output->gbm_surface,
- output->gbm_surface,
- format,
- n_formats) < 0) {
- weston_log("failed to create gl renderer output state\n");
- gbm_surface_destroy(output->gbm_surface);
- output->gbm_surface = NULL;
- return -1;
- }
-
- drm_output_init_cursor_egl(output, b);
-
- return 0;
-}
-
-void
-drm_output_fini_egl(struct drm_output *output)
-{
- struct drm_backend *b = to_drm_backend(output->base.compositor);
-
- /* Destroying the GBM surface will destroy all our GBM buffers,
- * regardless of refcount. Ensure we destroy them here. */
- if (!b->shutting_down &&
- output->scanout_plane->state_cur->fb &&
- output->scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE) {
- drm_plane_state_free(output->scanout_plane->state_cur, true);
- output->scanout_plane->state_cur =
- drm_plane_state_alloc(NULL, output->scanout_plane);
- output->scanout_plane->state_cur->complete = true;
- }
-
- gl_renderer->output_destroy(&output->base);
- gbm_surface_destroy(output->gbm_surface);
- output->gbm_surface = NULL;
- drm_output_fini_cursor_egl(output);
-}
-
-struct drm_fb *
-drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
-{
- struct drm_output *output = state->output;
- struct drm_backend *b = to_drm_backend(output->base.compositor);
- struct gbm_bo *bo;
- struct drm_fb *ret;
-
- output->base.compositor->renderer->repaint_output(&output->base,
- damage);
-
- bo = gbm_surface_lock_front_buffer(output->gbm_surface);
- if (!bo) {
- weston_log("failed to lock front buffer: %s\n",
- strerror(errno));
- return NULL;
- }
-
- /* The renderer always produces an opaque image. */
- ret = drm_fb_get_from_bo(bo, b, true, BUFFER_GBM_SURFACE);
- if (!ret) {
- weston_log("failed to get drm_fb for bo\n");
- gbm_surface_release_buffer(output->gbm_surface, bo);
- return NULL;
- }
- ret->gbm_surface = output->gbm_surface;
-
- return ret;
-}
-
-static void
-switch_to_gl_renderer(struct drm_backend *b)
-{
- struct drm_output *output;
- bool dmabuf_support_inited;
- bool linux_explicit_sync_inited;
-
- if (!b->use_pixman)
- return;
-
- dmabuf_support_inited = !!b->compositor->renderer->import_dmabuf;
- linux_explicit_sync_inited =
- b->compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC;
-
- weston_log("Switching to GL renderer\n");
-
- b->gbm = create_gbm_device(b->drm.fd);
- if (!b->gbm) {
- weston_log("Failed to create gbm device. "
- "Aborting renderer switch\n");
- return;
- }
-
- wl_list_for_each(output, &b->compositor->output_list, base.link)
- pixman_renderer_output_destroy(&output->base);
-
- b->compositor->renderer->destroy(b->compositor);
-
- if (drm_backend_create_gl_renderer(b) < 0) {
- gbm_device_destroy(b->gbm);
- weston_log("Failed to create GL renderer. Quitting.\n");
- /* FIXME: we need a function to shutdown cleanly */
- assert(0);
- }
-
- wl_list_for_each(output, &b->compositor->output_list, base.link)
- drm_output_init_egl(output, b);
-
- b->use_pixman = 0;
-
- if (!dmabuf_support_inited && b->compositor->renderer->import_dmabuf) {
- if (linux_dmabuf_setup(b->compositor) < 0)
- weston_log("Error: initializing dmabuf "
- "support failed.\n");
- }
-
- if (!linux_explicit_sync_inited &&
- (b->compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC)) {
- if (linux_explicit_synchronization_setup(b->compositor) < 0)
- weston_log("Error: initializing explicit "
- " synchronization support failed.\n");
- }
-}
-
-void
-renderer_switch_binding(struct weston_keyboard *keyboard,
- const struct timespec *time, uint32_t key, void *data)
-{
- struct drm_backend *b =
- to_drm_backend(keyboard->seat->compositor);
-
- switch_to_gl_renderer(b);
-}
-
diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h
deleted file mode 100644
index 2384a9ac..00000000
--- a/libweston/backend-drm/drm-internal.h
+++ /dev/null
@@ -1,825 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2011 Intel Corporation
- * Copyright © 2017, 2018 Collabora, Ltd.
- * Copyright © 2017, 2018 General Electric Company
- * Copyright (c) 2018 DisplayLink (UK) Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <linux/input.h>
-#include <linux/vt.h>
-#include <assert.h>
-#include <sys/mman.h>
-#include <time.h>
-
-
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-#include <drm_fourcc.h>
-
-#ifdef BUILD_DRM_GBM
-#include <gbm.h>
-#endif
-#include <libudev.h>
-
-#include <libweston/libweston.h>
-#include <libweston/backend-drm.h>
-#include <libweston/weston-log.h>
-#include "shared/helpers.h"
-#include "libinput-seat.h"
-#include "backend.h"
-#include "libweston-internal.h"
-
-#ifndef DRM_CLIENT_CAP_ASPECT_RATIO
-#define DRM_CLIENT_CAP_ASPECT_RATIO 4
-#endif
-
-#ifndef GBM_BO_USE_CURSOR
-#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
-#endif
-
-#ifndef GBM_BO_USE_LINEAR
-#define GBM_BO_USE_LINEAR (1 << 4)
-#endif
-
-#ifndef DRM_PLANE_ZPOS_INVALID_PLANE
-#define DRM_PLANE_ZPOS_INVALID_PLANE 0xffffffffffffffffULL
-#endif
-
-/**
- * A small wrapper to print information into the 'drm-backend' debug scope.
- *
- * The following conventions are used to print variables:
- *
- * - fixed uint32_t values, including Weston object IDs such as weston_output
- * IDs, DRM object IDs such as CRTCs or properties, and GBM/DRM formats:
- * "%lu (0x%lx)" (unsigned long) value, (unsigned long) value
- *
- * - fixed uint64_t values, such as DRM property values (including object IDs
- * when used as a value):
- * "%llu (0x%llx)" (unsigned long long) value, (unsigned long long) value
- *
- * - non-fixed-width signed int:
- * "%d" value
- *
- * - non-fixed-width unsigned int:
- * "%u (0x%x)" value, value
- *
- * - non-fixed-width unsigned long:
- * "%lu (0x%lx)" value, value
- *
- * Either the integer or hexadecimal forms may be omitted if it is known that
- * one representation is not useful (e.g. width/height in hex are rarely what
- * you want).
- *
- * This is to avoid implicit widening or narrowing when we use fixed-size
- * types: uint32_t can be resolved by either unsigned int or unsigned long
- * on a 32-bit system but only unsigned int on a 64-bit system, with uint64_t
- * being unsigned long long on a 32-bit system and unsigned long on a 64-bit
- * system. To avoid confusing side effects, we explicitly cast to the widest
- * possible type and use a matching format specifier.
- */
-#define drm_debug(b, ...) \
- weston_log_scope_printf((b)->debug, __VA_ARGS__)
-
-#define MAX_CLONED_CONNECTORS 4
-
-#ifndef DRM_MODE_PICTURE_ASPECT_64_27
-#define DRM_MODE_PICTURE_ASPECT_64_27 3
-#define DRM_MODE_FLAG_PIC_AR_64_27 \
- (DRM_MODE_PICTURE_ASPECT_64_27<<19)
-#endif
-#ifndef DRM_MODE_PICTURE_ASPECT_256_135
-#define DRM_MODE_PICTURE_ASPECT_256_135 4
-#define DRM_MODE_FLAG_PIC_AR_256_135 \
- (DRM_MODE_PICTURE_ASPECT_256_135<<19)
-#endif
-
-
-/**
- * Represents the values of an enum-type KMS property
- */
-struct drm_property_enum_info {
- const char *name; /**< name as string (static, not freed) */
- bool valid; /**< true if value is supported; ignore if false */
- uint64_t value; /**< raw value */
-};
-
-/**
- * Holds information on a DRM property, including its ID and the enum
- * values it holds.
- *
- * DRM properties are allocated dynamically, and maintained as DRM objects
- * within the normal object ID space; they thus do not have a stable ID
- * to refer to. This includes enum values, which must be referred to by
- * integer values, but these are not stable.
- *
- * drm_property_info allows a cache to be maintained where Weston can use
- * enum values internally to refer to properties, with the mapping to DRM
- * ID values being maintained internally.
- */
-struct drm_property_info {
- const char *name; /**< name as string (static, not freed) */
- uint32_t prop_id; /**< KMS property object ID */
- uint32_t flags;
- unsigned int num_enum_values; /**< number of enum values */
- struct drm_property_enum_info *enum_values; /**< array of enum values */
- unsigned int num_range_values;
- uint64_t range_values[2];
-};
-
-/**
- * List of properties attached to DRM planes
- */
-enum wdrm_plane_property {
- WDRM_PLANE_TYPE = 0,
- WDRM_PLANE_SRC_X,
- WDRM_PLANE_SRC_Y,
- WDRM_PLANE_SRC_W,
- WDRM_PLANE_SRC_H,
- WDRM_PLANE_CRTC_X,
- WDRM_PLANE_CRTC_Y,
- WDRM_PLANE_CRTC_W,
- WDRM_PLANE_CRTC_H,
- WDRM_PLANE_FB_ID,
- WDRM_PLANE_CRTC_ID,
- WDRM_PLANE_IN_FORMATS,
- WDRM_PLANE_IN_FENCE_FD,
- WDRM_PLANE_FB_DAMAGE_CLIPS,
- WDRM_PLANE_ZPOS,
- WDRM_PLANE__COUNT
-};
-
-/**
- * Possible values for the WDRM_PLANE_TYPE property.
- */
-enum wdrm_plane_type {
- WDRM_PLANE_TYPE_PRIMARY = 0,
- WDRM_PLANE_TYPE_CURSOR,
- WDRM_PLANE_TYPE_OVERLAY,
- WDRM_PLANE_TYPE__COUNT
-};
-
-/**
- * List of properties attached to a DRM connector
- */
-enum wdrm_connector_property {
- WDRM_CONNECTOR_EDID = 0,
- WDRM_CONNECTOR_DPMS,
- WDRM_CONNECTOR_CRTC_ID,
- WDRM_CONNECTOR_NON_DESKTOP,
- WDRM_CONNECTOR_CONTENT_PROTECTION,
- WDRM_CONNECTOR_HDCP_CONTENT_TYPE,
- WDRM_CONNECTOR__COUNT
-};
-
-enum wdrm_content_protection_state {
- WDRM_CONTENT_PROTECTION_UNDESIRED = 0,
- WDRM_CONTENT_PROTECTION_DESIRED,
- WDRM_CONTENT_PROTECTION_ENABLED,
- WDRM_CONTENT_PROTECTION__COUNT
-};
-
-enum wdrm_hdcp_content_type {
- WDRM_HDCP_CONTENT_TYPE0 = 0,
- WDRM_HDCP_CONTENT_TYPE1,
- WDRM_HDCP_CONTENT_TYPE__COUNT
-};
-
-enum wdrm_dpms_state {
- WDRM_DPMS_STATE_OFF = 0,
- WDRM_DPMS_STATE_ON,
- WDRM_DPMS_STATE_STANDBY, /* unused */
- WDRM_DPMS_STATE_SUSPEND, /* unused */
- WDRM_DPMS_STATE__COUNT
-};
-
-/**
- * List of properties attached to DRM CRTCs
- */
-enum wdrm_crtc_property {
- WDRM_CRTC_MODE_ID = 0,
- WDRM_CRTC_ACTIVE,
- WDRM_CRTC__COUNT
-};
-
-struct drm_backend {
- struct weston_backend base;
- struct weston_compositor *compositor;
-
- struct udev *udev;
- struct wl_event_source *drm_source;
-
- struct udev_monitor *udev_monitor;
- struct wl_event_source *udev_drm_source;
-
- struct {
- int id;
- int fd;
- char *filename;
- dev_t devnum;
- } drm;
- struct gbm_device *gbm;
- struct wl_listener session_listener;
- uint32_t gbm_format;
-
- /* we need these parameters in order to not fail drmModeAddFB2()
- * due to out of bounds dimensions, and then mistakenly set
- * sprites_are_broken:
- */
- int min_width, max_width;
- int min_height, max_height;
-
- struct wl_list plane_list;
-
- void *repaint_data;
-
- bool state_invalid;
-
- /* CRTC IDs not used by any enabled output. */
- struct wl_array unused_crtcs;
-
- bool sprites_are_broken;
- bool cursors_are_broken;
-
- bool universal_planes;
- bool atomic_modeset;
-
- bool use_pixman;
- bool use_pixman_shadow;
-
- struct udev_input input;
-
- int32_t cursor_width;
- int32_t cursor_height;
-
- uint32_t pageflip_timeout;
-
- bool shutting_down;
-
- bool aspect_ratio_supported;
-
- bool fb_modifiers;
-
- struct weston_log_scope *debug;
-};
-
-struct drm_mode {
- struct weston_mode base;
- drmModeModeInfo mode_info;
- uint32_t blob_id;
-};
-
-enum drm_fb_type {
- BUFFER_INVALID = 0, /**< never used */
- BUFFER_CLIENT, /**< directly sourced from client */
- BUFFER_DMABUF, /**< imported from linux_dmabuf client */
- BUFFER_PIXMAN_DUMB, /**< internal Pixman rendering */
- BUFFER_GBM_SURFACE, /**< internal EGL rendering */
- BUFFER_CURSOR, /**< internal cursor buffer */
-};
-
-struct drm_fb {
- enum drm_fb_type type;
-
- int refcnt;
-
- uint32_t fb_id, size;
- uint32_t handles[4];
- uint32_t strides[4];
- uint32_t offsets[4];
- int num_planes;
- const struct pixel_format_info *format;
- uint64_t modifier;
- int width, height;
- int fd;
- struct weston_buffer_reference buffer_ref;
- struct weston_buffer_release_reference buffer_release_ref;
-
- /* Used by gbm fbs */
- struct gbm_bo *bo;
- struct gbm_surface *gbm_surface;
-
- /* Used by dumb fbs */
- void *map;
-};
-
-struct drm_edid {
- char eisa_id[13];
- char monitor_name[13];
- char pnp_id[5];
- char serial_number[13];
-};
-
-/**
- * Pending state holds one or more drm_output_state structures, collected from
- * performing repaint. This pending state is transient, and only lives between
- * beginning a repaint group and flushing the results: after flush, each
- * output state will complete and be retired separately.
- */
-struct drm_pending_state {
- struct drm_backend *backend;
- struct wl_list output_list;
-};
-
-/*
- * Output state holds the dynamic state for one Weston output, i.e. a KMS CRTC,
- * plus >= 1 each of encoder/connector/plane. Since everything but the planes
- * is currently statically assigned per-output, we mainly use this to track
- * plane state.
- *
- * pending_state is set when the output state is owned by a pending_state,
- * i.e. when it is being constructed and has not yet been applied. When the
- * output state has been applied, the owning pending_state is freed.
- */
-struct drm_output_state {
- struct drm_pending_state *pending_state;
- struct drm_output *output;
- struct wl_list link;
- enum dpms_enum dpms;
- enum weston_hdcp_protection protection;
- struct wl_list plane_list;
-};
-
-/**
- * An instance of this class is created each time we believe we have a plane
- * suitable to be used by a view as a direct scan-out. The list is initalized
- * and populated locally.
- */
-struct drm_plane_zpos {
- struct drm_plane *plane;
- struct wl_list link; /**< :candidate_plane_zpos_list */
-};
-
-/**
- * Plane state holds the dynamic state for a plane: where it is positioned,
- * and which buffer it is currently displaying.
- *
- * The plane state is owned by an output state, except when setting an initial
- * state. See drm_output_state for notes on state object lifetime.
- */
-struct drm_plane_state {
- struct drm_plane *plane;
- struct drm_output *output;
- struct drm_output_state *output_state;
-
- struct drm_fb *fb;
-
- struct weston_view *ev; /**< maintained for drm_assign_planes only */
-
- int32_t src_x, src_y;
- uint32_t src_w, src_h;
- int32_t dest_x, dest_y;
- uint32_t dest_w, dest_h;
-
- uint64_t zpos;
-
- bool complete;
-
- /* We don't own the fd, so we shouldn't close it */
- int in_fence_fd;
-
- pixman_region32_t damage; /* damage to kernel */
-
- struct wl_list link; /* drm_output_state::plane_list */
-};
-
-/**
- * A plane represents one buffer, positioned within a CRTC, and stacked
- * relative to other planes on the same CRTC.
- *
- * Each CRTC has a 'primary plane', which use used to display the classic
- * framebuffer contents, as accessed through the legacy drmModeSetCrtc
- * call (which combines setting the CRTC's actual physical mode, and the
- * properties of the primary plane).
- *
- * The cursor plane also has its own alternate legacy API.
- *
- * Other planes are used opportunistically to display content we do not
- * wish to blit into the primary plane. These non-primary/cursor planes
- * are referred to as 'sprites'.
- */
-struct drm_plane {
- struct weston_plane base;
-
- struct drm_backend *backend;
-
- enum wdrm_plane_type type;
-
- uint32_t possible_crtcs;
- uint32_t plane_id;
- uint32_t count_formats;
-
- struct drm_property_info props[WDRM_PLANE__COUNT];
-
- /* The last state submitted to the kernel for this plane. */
- struct drm_plane_state *state_cur;
-
- uint64_t zpos_min;
- uint64_t zpos_max;
-
- struct wl_list link;
-
- struct {
- uint32_t format;
- uint32_t count_modifiers;
- uint64_t *modifiers;
- } formats[];
-};
-
-struct drm_head {
- struct weston_head base;
- struct drm_backend *backend;
-
- drmModeConnector *connector;
- uint32_t connector_id;
- struct drm_edid edid;
-
- /* Holds the properties for the connector */
- struct drm_property_info props_conn[WDRM_CONNECTOR__COUNT];
-
- struct backlight *backlight;
-
- drmModeModeInfo inherited_mode; /**< Original mode on the connector */
- uint32_t inherited_crtc_id; /**< Original CRTC assignment */
-};
-
-struct drm_output {
- struct weston_output base;
- struct drm_backend *backend;
-
- uint32_t crtc_id; /* object ID to pass to DRM functions */
- int pipe; /* index of CRTC in resource array / bitmasks */
-
- /* Holds the properties for the CRTC */
- struct drm_property_info props_crtc[WDRM_CRTC__COUNT];
-
- bool page_flip_pending;
- bool atomic_complete_pending;
- bool destroy_pending;
- bool disable_pending;
- bool dpms_off_pending;
-
- uint32_t gbm_cursor_handle[2];
- struct drm_fb *gbm_cursor_fb[2];
- struct drm_plane *cursor_plane;
- struct weston_view *cursor_view;
- int current_cursor;
-
- struct gbm_surface *gbm_surface;
- uint32_t gbm_format;
- uint32_t gbm_bo_flags;
-
- /* Plane being displayed directly on the CRTC */
- struct drm_plane *scanout_plane;
-
- /* The last state submitted to the kernel for this CRTC. */
- struct drm_output_state *state_cur;
- /* The previously-submitted state, where the hardware has not
- * yet acknowledged completion of state_cur. */
- struct drm_output_state *state_last;
-
- struct drm_fb *dumb[2];
- pixman_image_t *image[2];
- int current_image;
- pixman_region32_t previous_damage;
-
- struct vaapi_recorder *recorder;
- struct wl_listener recorder_frame_listener;
-
- struct wl_event_source *pageflip_timer;
-
- bool virtual;
-
- submit_frame_cb virtual_submit_frame;
-};
-
-static inline struct drm_head *
-to_drm_head(struct weston_head *base)
-{
- return container_of(base, struct drm_head, base);
-}
-
-static inline struct drm_output *
-to_drm_output(struct weston_output *base)
-{
- return container_of(base, struct drm_output, base);
-}
-
-static inline struct drm_backend *
-to_drm_backend(struct weston_compositor *base)
-{
- return container_of(base->backend, struct drm_backend, base);
-}
-
-static inline struct drm_mode *
-to_drm_mode(struct weston_mode *base)
-{
- return container_of(base, struct drm_mode, base);
-}
-
-static inline const char *
-drm_output_get_plane_type_name(struct drm_plane *p)
-{
- switch (p->type) {
- case WDRM_PLANE_TYPE_PRIMARY:
- return "primary";
- case WDRM_PLANE_TYPE_CURSOR:
- return "cursor";
- case WDRM_PLANE_TYPE_OVERLAY:
- return "overlay";
- default:
- assert(0);
- break;
- }
-}
-
-struct drm_output *
-drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id);
-
-struct drm_head *
-drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id);
-
-static inline bool
-drm_view_transform_supported(struct weston_view *ev, struct weston_output *output)
-{
- struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
-
- /* This will incorrectly disallow cases where the combination of
- * buffer and view transformations match the output transform.
- * Fixing this requires a full analysis of the transformation
- * chain. */
- if (ev->transform.enabled &&
- ev->transform.matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE)
- return false;
-
- if (viewport->buffer.transform != output->transform)
- return false;
-
- return true;
-}
-
-int
-drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode);
-
-struct drm_mode *
-drm_output_choose_mode(struct drm_output *output,
- struct weston_mode *target_mode);
-void
-update_head_from_connector(struct drm_head *head,
- drmModeObjectProperties *props);
-
-void
-drm_mode_list_destroy(struct drm_backend *backend, struct wl_list *mode_list);
-
-void
-drm_output_print_modes(struct drm_output *output);
-
-int
-drm_output_set_mode(struct weston_output *base,
- enum weston_drm_backend_output_mode mode,
- const char *modeline);
-
-void
-drm_property_info_populate(struct drm_backend *b,
- const struct drm_property_info *src,
- struct drm_property_info *info,
- unsigned int num_infos,
- drmModeObjectProperties *props);
-uint64_t
-drm_property_get_value(struct drm_property_info *info,
- const drmModeObjectProperties *props,
- uint64_t def);
-uint64_t *
-drm_property_get_range_values(struct drm_property_info *info,
- const drmModeObjectProperties *props);
-int
-drm_plane_populate_formats(struct drm_plane *plane, const drmModePlane *kplane,
- const drmModeObjectProperties *props);
-void
-drm_property_info_free(struct drm_property_info *info, int num_props);
-
-extern struct drm_property_enum_info plane_type_enums[];
-extern const struct drm_property_info plane_props[];
-extern struct drm_property_enum_info dpms_state_enums[];
-extern struct drm_property_enum_info content_protection_enums[];
-extern struct drm_property_enum_info hdcp_content_type_enums[];
-extern const struct drm_property_info connector_props[];
-extern const struct drm_property_info crtc_props[];
-
-int
-init_kms_caps(struct drm_backend *b);
-
-int
-drm_pending_state_test(struct drm_pending_state *pending_state);
-int
-drm_pending_state_apply(struct drm_pending_state *pending_state);
-int
-drm_pending_state_apply_sync(struct drm_pending_state *pending_state);
-
-void
-drm_output_set_gamma(struct weston_output *output_base,
- uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b);
-
-void
-drm_output_update_msc(struct drm_output *output, unsigned int seq);
-void
-drm_output_update_complete(struct drm_output *output, uint32_t flags,
- unsigned int sec, unsigned int usec);
-int
-on_drm_input(int fd, uint32_t mask, void *data);
-
-struct drm_plane_state *
-drm_output_state_get_existing_plane(struct drm_output_state *state_output,
- struct drm_plane *plane);
-void
-drm_plane_state_free(struct drm_plane_state *state, bool force);
-void
-drm_output_state_free(struct drm_output_state *state);
-void
-drm_pending_state_free(struct drm_pending_state *pending_state);
-
-struct drm_fb *
-drm_fb_ref(struct drm_fb *fb);
-void
-drm_fb_unref(struct drm_fb *fb);
-
-struct drm_fb *
-drm_fb_create_dumb(struct drm_backend *b, int width, int height,
- uint32_t format);
-struct drm_fb *
-drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
- bool is_opaque, enum drm_fb_type type);
-
-#ifdef BUILD_DRM_GBM
-extern struct drm_fb *
-drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev);
-extern bool
-drm_can_scanout_dmabuf(struct weston_compositor *ec,
- struct linux_dmabuf_buffer *dmabuf);
-#else
-static inline struct drm_fb *
-drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev)
-{
- return NULL;
-}
-static inline bool
-drm_can_scanout_dmabuf(struct weston_compositor *ec,
- struct linux_dmabuf_buffer *dmabuf)
-{
- return false;
-}
-#endif
-
-struct drm_pending_state *
-drm_pending_state_alloc(struct drm_backend *backend);
-void
-drm_pending_state_free(struct drm_pending_state *pending_state);
-struct drm_output_state *
-drm_pending_state_get_output(struct drm_pending_state *pending_state,
- struct drm_output *output);
-
-
-/**
- * Mode for drm_output_state_duplicate.
- */
-enum drm_output_state_duplicate_mode {
- DRM_OUTPUT_STATE_CLEAR_PLANES, /**< reset all planes to off */
- DRM_OUTPUT_STATE_PRESERVE_PLANES, /**< preserve plane state */
-};
-
-struct drm_output_state *
-drm_output_state_alloc(struct drm_output *output,
- struct drm_pending_state *pending_state);
-struct drm_output_state *
-drm_output_state_duplicate(struct drm_output_state *src,
- struct drm_pending_state *pending_state,
- enum drm_output_state_duplicate_mode plane_mode);
-void
-drm_output_state_free(struct drm_output_state *state);
-struct drm_plane_state *
-drm_output_state_get_plane(struct drm_output_state *state_output,
- struct drm_plane *plane);
-struct drm_plane_state *
-drm_output_state_get_existing_plane(struct drm_output_state *state_output,
- struct drm_plane *plane);
-
-
-
-struct drm_plane_state *
-drm_plane_state_alloc(struct drm_output_state *state_output,
- struct drm_plane *plane);
-struct drm_plane_state *
-drm_plane_state_duplicate(struct drm_output_state *state_output,
- struct drm_plane_state *src);
-void
-drm_plane_state_free(struct drm_plane_state *state, bool force);
-void
-drm_plane_state_put_back(struct drm_plane_state *state);
-bool
-drm_plane_state_coords_for_view(struct drm_plane_state *state,
- struct weston_view *ev, uint64_t zpos);
-
-void
-drm_assign_planes(struct weston_output *output_base, void *repaint_data);
-
-bool
-drm_plane_is_available(struct drm_plane *plane, struct drm_output *output);
-
-void
-drm_output_render(struct drm_output_state *state, pixman_region32_t *damage);
-
-int
-parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format);
-
-extern struct gl_renderer_interface *gl_renderer;
-
-#ifdef BUILD_DRM_VIRTUAL
-extern int
-drm_backend_init_virtual_output_api(struct weston_compositor *compositor);
-#else
-inline static int
-drm_backend_init_virtual_output_api(struct weston_compositor *compositor)
-{
- return 0;
-}
-#endif
-
-#ifdef BUILD_DRM_GBM
-int
-init_egl(struct drm_backend *b);
-
-int
-drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
-
-void
-drm_output_fini_egl(struct drm_output *output);
-
-struct drm_fb *
-drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage);
-
-void
-renderer_switch_binding(struct weston_keyboard *keyboard,
- const struct timespec *time, uint32_t key, void *data);
-#else
-inline static int
-init_egl(struct drm_backend *b)
-{
- weston_log("Compiled without GBM/EGL support\n");
- return -1;
-}
-
-inline static int
-drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
-{
- return -1;
-}
-
-inline static void
-drm_output_fini_egl(struct drm_output *output)
-{
-}
-
-inline static struct drm_fb *
-drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
-{
- return NULL;
-}
-
-inline static void
-renderer_switch_binding(struct weston_keyboard *keyboard,
- const struct timespec *time, uint32_t key, void *data)
-{
- weston_log("Compiled without GBM/EGL support\n");
-}
-#endif
diff --git a/libweston/backend-drm/drm-virtual.c b/libweston/backend-drm/drm-virtual.c
deleted file mode 100644
index ebebbbd2..00000000
--- a/libweston/backend-drm/drm-virtual.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2011 Intel Corporation
- * Copyright © 2017, 2018 Collabora, Ltd.
- * Copyright © 2017, 2018 General Electric Company
- * Copyright (c) 2018 DisplayLink (UK) Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-
-#include "drm-internal.h"
-#include "renderer-gl/gl-renderer.h"
-
-/**
- * Create a drm_plane for virtual output
- *
- * Call drm_virtual_plane_destroy to clean up the plane.
- *
- * @param b DRM compositor backend
- * @param output Output to create internal plane for
- */
-static struct drm_plane *
-drm_virtual_plane_create(struct drm_backend *b, struct drm_output *output)
-{
- struct drm_plane *plane;
-
- /* num of formats is one */
- plane = zalloc(sizeof(*plane) + sizeof(plane->formats[0]));
- if (!plane) {
- weston_log("%s: out of memory\n", __func__);
- return NULL;
- }
-
- plane->type = WDRM_PLANE_TYPE_PRIMARY;
- plane->backend = b;
- plane->state_cur = drm_plane_state_alloc(NULL, plane);
- plane->state_cur->complete = true;
- plane->formats[0].format = output->gbm_format;
- plane->count_formats = 1;
- if ((output->gbm_bo_flags & GBM_BO_USE_LINEAR) && b->fb_modifiers) {
- uint64_t *modifiers = zalloc(sizeof *modifiers);
- if (modifiers) {
- *modifiers = DRM_FORMAT_MOD_LINEAR;
- plane->formats[0].modifiers = modifiers;
- plane->formats[0].count_modifiers = 1;
- }
- }
-
- weston_plane_init(&plane->base, b->compositor, 0, 0);
- wl_list_insert(&b->plane_list, &plane->link);
-
- return plane;
-}
-
-/**
- * Destroy one DRM plane
- *
- * @param plane Plane to deallocate (will be freed)
- */
-static void
-drm_virtual_plane_destroy(struct drm_plane *plane)
-{
- drm_plane_state_free(plane->state_cur, true);
- weston_plane_release(&plane->base);
- wl_list_remove(&plane->link);
- if (plane->formats[0].modifiers)
- free(plane->formats[0].modifiers);
- free(plane);
-}
-
-static int
-drm_virtual_output_start_repaint_loop(struct weston_output *output_base)
-{
- weston_output_finish_frame(output_base, NULL,
- WP_PRESENTATION_FEEDBACK_INVALID);
-
- return 0;
-}
-
-static int
-drm_virtual_output_submit_frame(struct drm_output *output,
- struct drm_fb *fb)
-{
- struct drm_backend *b = to_drm_backend(output->base.compositor);
- int fd, ret;
-
- assert(fb->num_planes == 1);
- ret = drmPrimeHandleToFD(b->drm.fd, fb->handles[0], DRM_CLOEXEC, &fd);
- if (ret) {
- weston_log("drmPrimeHandleFD failed, errno=%d\n", errno);
- return -1;
- }
-
- drm_fb_ref(fb);
- ret = output->virtual_submit_frame(&output->base, fd, fb->strides[0],
- fb);
- if (ret < 0) {
- drm_fb_unref(fb);
- close(fd);
- }
- return ret;
-}
-
-static int
-drm_virtual_output_repaint(struct weston_output *output_base,
- pixman_region32_t *damage,
- void *repaint_data)
-{
- struct drm_pending_state *pending_state = repaint_data;
- struct drm_output_state *state = NULL;
- struct drm_output *output = to_drm_output(output_base);
- struct drm_plane *scanout_plane = output->scanout_plane;
- struct drm_plane_state *scanout_state;
-
- assert(output->virtual);
-
- if (output->disable_pending || output->destroy_pending)
- goto err;
-
- /* Drop frame if there isn't free buffers */
- if (!gbm_surface_has_free_buffers(output->gbm_surface)) {
- weston_log("%s: Drop frame!!\n", __func__);
- return -1;
- }
-
- assert(!output->state_last);
-
- /* If planes have been disabled in the core, we might not have
- * hit assign_planes at all, so might not have valid output state
- * here. */
- state = drm_pending_state_get_output(pending_state, output);
- if (!state)
- state = drm_output_state_duplicate(output->state_cur,
- pending_state,
- DRM_OUTPUT_STATE_CLEAR_PLANES);
-
- drm_output_render(state, damage);
- scanout_state = drm_output_state_get_plane(state, scanout_plane);
- if (!scanout_state || !scanout_state->fb)
- goto err;
-
- if (drm_virtual_output_submit_frame(output, scanout_state->fb) < 0)
- goto err;
-
- return 0;
-
-err:
- drm_output_state_free(state);
- return -1;
-}
-
-static void
-drm_virtual_output_deinit(struct weston_output *base)
-{
- struct drm_output *output = to_drm_output(base);
-
- drm_output_fini_egl(output);
-
- drm_virtual_plane_destroy(output->scanout_plane);
-}
-
-static void
-drm_virtual_output_destroy(struct weston_output *base)
-{
- struct drm_output *output = to_drm_output(base);
-
- assert(output->virtual);
-
- if (output->base.enabled)
- drm_virtual_output_deinit(&output->base);
-
- weston_output_release(&output->base);
-
- drm_output_state_free(output->state_cur);
-
- free(output);
-}
-
-static int
-drm_virtual_output_enable(struct weston_output *output_base)
-{
- struct drm_output *output = to_drm_output(output_base);
- struct drm_backend *b = to_drm_backend(output_base->compositor);
-
- assert(output->virtual);
-
- if (b->use_pixman) {
- weston_log("Not support pixman renderer on Virtual output\n");
- goto err;
- }
-
- if (!output->virtual_submit_frame) {
- weston_log("The virtual_submit_frame hook is not set\n");
- goto err;
- }
-
- output->scanout_plane = drm_virtual_plane_create(b, output);
- if (!output->scanout_plane) {
- weston_log("Failed to find primary plane for output %s\n",
- output->base.name);
- return -1;
- }
-
- if (drm_output_init_egl(output, b) < 0) {
- weston_log("Failed to init output gl state\n");
- goto err;
- }
-
- output->base.start_repaint_loop = drm_virtual_output_start_repaint_loop;
- output->base.repaint = drm_virtual_output_repaint;
- output->base.assign_planes = drm_assign_planes;
- output->base.set_dpms = NULL;
- output->base.switch_mode = NULL;
- output->base.gamma_size = 0;
- output->base.set_gamma = NULL;
-
- weston_compositor_stack_plane(b->compositor,
- &output->scanout_plane->base,
- &b->compositor->primary_plane);
-
- return 0;
-err:
- return -1;
-}
-
-static int
-drm_virtual_output_disable(struct weston_output *base)
-{
- struct drm_output *output = to_drm_output(base);
-
- assert(output->virtual);
-
- if (output->base.enabled)
- drm_virtual_output_deinit(&output->base);
-
- return 0;
-}
-
-static struct weston_output *
-drm_virtual_output_create(struct weston_compositor *c, char *name)
-{
- struct drm_output *output;
-
- output = zalloc(sizeof *output);
- if (!output)
- return NULL;
-
- output->virtual = true;
- output->gbm_bo_flags = GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING;
-
- weston_output_init(&output->base, c, name);
-
- output->base.enable = drm_virtual_output_enable;
- output->base.destroy = drm_virtual_output_destroy;
- output->base.disable = drm_virtual_output_disable;
- output->base.attach_head = NULL;
-
- output->state_cur = drm_output_state_alloc(output, NULL);
-
- weston_compositor_add_pending_output(&output->base, c);
-
- return &output->base;
-}
-
-static uint32_t
-drm_virtual_output_set_gbm_format(struct weston_output *base,
- const char *gbm_format)
-{
- struct drm_output *output = to_drm_output(base);
- struct drm_backend *b = to_drm_backend(base->compositor);
-
- if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
- output->gbm_format = b->gbm_format;
-
- return output->gbm_format;
-}
-
-static void
-drm_virtual_output_set_submit_frame_cb(struct weston_output *output_base,
- submit_frame_cb cb)
-{
- struct drm_output *output = to_drm_output(output_base);
-
- output->virtual_submit_frame = cb;
-}
-
-static int
-drm_virtual_output_get_fence_fd(struct weston_output *output_base)
-{
- return gl_renderer->create_fence_fd(output_base);
-}
-
-static void
-drm_virtual_output_buffer_released(struct drm_fb *fb)
-{
- drm_fb_unref(fb);
-}
-
-static void
-drm_virtual_output_finish_frame(struct weston_output *output_base,
- struct timespec *stamp,
- uint32_t presented_flags)
-{
- struct drm_output *output = to_drm_output(output_base);
- struct drm_plane_state *ps;
-
- wl_list_for_each(ps, &output->state_cur->plane_list, link)
- ps->complete = true;
-
- drm_output_state_free(output->state_last);
- output->state_last = NULL;
-
- weston_output_finish_frame(&output->base, stamp, presented_flags);
-
- /* We can't call this from frame_notify, because the output's
- * repaint needed flag is cleared just after that */
- if (output->recorder)
- weston_output_schedule_repaint(&output->base);
-}
-
-static const struct weston_drm_virtual_output_api virt_api = {
- drm_virtual_output_create,
- drm_virtual_output_set_gbm_format,
- drm_virtual_output_set_submit_frame_cb,
- drm_virtual_output_get_fence_fd,
- drm_virtual_output_buffer_released,
- drm_virtual_output_finish_frame
-};
-
-int drm_backend_init_virtual_output_api(struct weston_compositor *compositor)
-{
- return weston_plugin_api_register(compositor,
- WESTON_DRM_VIRTUAL_OUTPUT_API_NAME,
- &virt_api, sizeof(virt_api));
-}
diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c
deleted file mode 100644
index e0b1cbd7..00000000
--- a/libweston/backend-drm/drm.c
+++ /dev/null
@@ -1,3040 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2011 Intel Corporation
- * Copyright © 2017, 2018 Collabora, Ltd.
- * Copyright © 2017, 2018 General Electric Company
- * Copyright (c) 2018 DisplayLink (UK) Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <linux/input.h>
-#include <linux/vt.h>
-#include <assert.h>
-#include <sys/mman.h>
-#include <time.h>
-
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-#include <drm_fourcc.h>
-
-#include <libudev.h>
-
-#include <libweston/libweston.h>
-#include <libweston/backend-drm.h>
-#include <libweston/weston-log.h>
-#include "drm-internal.h"
-#include "shared/helpers.h"
-#include "shared/timespec-util.h"
-#include "shared/string-helpers.h"
-#include "pixman-renderer.h"
-#include "pixel-formats.h"
-#include "libbacklight.h"
-#include "libinput-seat.h"
-#include "launcher-util.h"
-#include "vaapi-recorder.h"
-#include "presentation-time-server-protocol.h"
-#include "linux-dmabuf.h"
-#include "linux-dmabuf-unstable-v1-server-protocol.h"
-#include "linux-explicit-synchronization.h"
-
-static const char default_seat[] = "seat0";
-
-static void
-drm_backend_create_faked_zpos(struct drm_backend *b)
-{
- struct drm_plane *plane;
- uint64_t zpos = 0ULL;
- uint64_t zpos_min_primary;
- uint64_t zpos_min_overlay;
- uint64_t zpos_min_cursor;
-
- zpos_min_primary = zpos;
- wl_list_for_each(plane, &b->plane_list, link) {
- /* if the property is there, bail out sooner */
- if (plane->props[WDRM_PLANE_ZPOS].prop_id != 0)
- return;
-
- if (plane->type != WDRM_PLANE_TYPE_PRIMARY)
- continue;
- zpos++;
- }
-
- zpos_min_overlay = zpos;
- wl_list_for_each(plane, &b->plane_list, link) {
- if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
- continue;
- zpos++;
- }
-
- zpos_min_cursor = zpos;
- wl_list_for_each(plane, &b->plane_list, link) {
- if (plane->type != WDRM_PLANE_TYPE_CURSOR)
- continue;
- zpos++;
- }
-
- drm_debug(b, "[drm-backend] zpos property not found. "
- "Using invented immutable zpos values:\n");
- /* assume that invented zpos values are immutable */
- wl_list_for_each(plane, &b->plane_list, link) {
- if (plane->type == WDRM_PLANE_TYPE_PRIMARY) {
- plane->zpos_min = zpos_min_primary;
- plane->zpos_max = zpos_min_primary;
- } else if (plane->type == WDRM_PLANE_TYPE_OVERLAY) {
- plane->zpos_min = zpos_min_overlay;
- plane->zpos_max = zpos_min_overlay;
- } else if (plane->type == WDRM_PLANE_TYPE_CURSOR) {
- plane->zpos_min = zpos_min_cursor;
- plane->zpos_max = zpos_min_cursor;
- }
- drm_debug(b, "\t[plane] %s plane %d, zpos_min %"PRIu64", "
- "zpos_max %"PRIu64"\n",
- drm_output_get_plane_type_name(plane),
- plane->plane_id, plane->zpos_min, plane->zpos_max);
- }
-}
-
-static void
-wl_array_remove_uint32(struct wl_array *array, uint32_t elm)
-{
- uint32_t *pos, *end;
-
- end = (uint32_t *) ((char *) array->data + array->size);
-
- wl_array_for_each(pos, array) {
- if (*pos != elm)
- continue;
-
- array->size -= sizeof(*pos);
- if (pos + 1 == end)
- break;
-
- memmove(pos, pos + 1, (char *) end - (char *) (pos + 1));
- break;
- }
-}
-
-static int
-pageflip_timeout(void *data) {
- /*
- * Our timer just went off, that means we're not receiving drm
- * page flip events anymore for that output. Let's gracefully exit
- * weston with a return value so devs can debug what's going on.
- */
- struct drm_output *output = data;
- struct weston_compositor *compositor = output->base.compositor;
-
- weston_log("Pageflip timeout reached on output %s, your "
- "driver is probably buggy! Exiting.\n",
- output->base.name);
- weston_compositor_exit_with_code(compositor, EXIT_FAILURE);
-
- return 0;
-}
-
-/* Creates the pageflip timer. Note that it isn't armed by default */
-static int
-drm_output_pageflip_timer_create(struct drm_output *output)
-{
- struct wl_event_loop *loop = NULL;
- struct weston_compositor *ec = output->base.compositor;
-
- loop = wl_display_get_event_loop(ec->wl_display);
- assert(loop);
- output->pageflip_timer = wl_event_loop_add_timer(loop,
- pageflip_timeout,
- output);
-
- if (output->pageflip_timer == NULL) {
- weston_log("creating drm pageflip timer failed: %s\n",
- strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-static void
-drm_output_destroy(struct weston_output *output_base);
-
-/**
- * Returns true if the plane can be used on the given output for its current
- * repaint cycle.
- */
-bool
-drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
-{
- assert(plane->state_cur);
-
- if (output->virtual)
- return false;
-
- /* The plane still has a request not yet completed by the kernel. */
- if (!plane->state_cur->complete)
- return false;
-
- /* The plane is still active on another output. */
- if (plane->state_cur->output && plane->state_cur->output != output)
- return false;
-
- /* Check whether the plane can be used with this CRTC; possible_crtcs
- * is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */
- return !!(plane->possible_crtcs & (1 << output->pipe));
-}
-
-struct drm_output *
-drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id)
-{
- struct drm_output *output;
-
- wl_list_for_each(output, &b->compositor->output_list, base.link) {
- if (output->crtc_id == crtc_id)
- return output;
- }
-
- return NULL;
-}
-
-struct drm_head *
-drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id)
-{
- struct weston_head *base;
- struct drm_head *head;
-
- wl_list_for_each(base,
- &backend->compositor->head_list, compositor_link) {
- head = to_drm_head(base);
- if (head->connector_id == connector_id)
- return head;
- }
-
- return NULL;
-}
-
-/**
- * Get output state to disable output
- *
- * Returns a pointer to an output_state object which can be used to disable
- * an output (e.g. DPMS off).
- *
- * @param pending_state The pending state object owning this update
- * @param output The output to disable
- * @returns A drm_output_state to disable the output
- */
-static struct drm_output_state *
-drm_output_get_disable_state(struct drm_pending_state *pending_state,
- struct drm_output *output)
-{
- struct drm_output_state *output_state;
-
- output_state = drm_output_state_duplicate(output->state_cur,
- pending_state,
- DRM_OUTPUT_STATE_CLEAR_PLANES);
- output_state->dpms = WESTON_DPMS_OFF;
-
- output_state->protection = WESTON_HDCP_DISABLE;
-
- return output_state;
-}
-
-
-/**
- * Mark a drm_output_state (the output's last state) as complete. This handles
- * any post-completion actions such as updating the repaint timer, disabling the
- * output, and finally freeing the state.
- */
-void
-drm_output_update_complete(struct drm_output *output, uint32_t flags,
- unsigned int sec, unsigned int usec)
-{
- struct drm_backend *b = to_drm_backend(output->base.compositor);
- struct drm_plane_state *ps;
- struct timespec ts;
-
- /* Stop the pageflip timer instead of rearming it here */
- if (output->pageflip_timer)
- wl_event_source_timer_update(output->pageflip_timer, 0);
-
- wl_list_for_each(ps, &output->state_cur->plane_list, link)
- ps->complete = true;
-
- drm_output_state_free(output->state_last);
- output->state_last = NULL;
-
- if (output->destroy_pending) {
- output->destroy_pending = false;
- output->disable_pending = false;
- output->dpms_off_pending = false;
- drm_output_destroy(&output->base);
- return;
- } else if (output->disable_pending) {
- output->disable_pending = false;
- output->dpms_off_pending = false;
- weston_output_disable(&output->base);
- return;
- } else if (output->dpms_off_pending) {
- struct drm_pending_state *pending = drm_pending_state_alloc(b);
- output->dpms_off_pending = false;
- drm_output_get_disable_state(pending, output);
- drm_pending_state_apply_sync(pending);
- } else if (output->state_cur->dpms == WESTON_DPMS_OFF &&
- output->base.repaint_status != REPAINT_AWAITING_COMPLETION) {
- /* DPMS can happen to us either in the middle of a repaint
- * cycle (when we have painted fresh content, only to throw it
- * away for DPMS off), or at any other random point. If the
- * latter is true, then we cannot go through finish_frame,
- * because the repaint machinery does not expect this. */
- return;
- }
-
- ts.tv_sec = sec;
- ts.tv_nsec = usec * 1000;
- weston_output_finish_frame(&output->base, &ts, flags);
-
- /* We can't call this from frame_notify, because the output's
- * repaint needed flag is cleared just after that */
- if (output->recorder)
- weston_output_schedule_repaint(&output->base);
-}
-
-static struct drm_fb *
-drm_output_render_pixman(struct drm_output_state *state,
- pixman_region32_t *damage)
-{
- struct drm_output *output = state->output;
- struct weston_compositor *ec = output->base.compositor;
-
- output->current_image ^= 1;
-
- pixman_renderer_output_set_buffer(&output->base,
- output->image[output->current_image]);
- pixman_renderer_output_set_hw_extra_damage(&output->base,
- &output->previous_damage);
-
- ec->renderer->repaint_output(&output->base, damage);
-
- pixman_region32_copy(&output->previous_damage, damage);
-
- return drm_fb_ref(output->dumb[output->current_image]);
-}
-
-void
-drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
-{
- struct drm_output *output = state->output;
- struct weston_compositor *c = output->base.compositor;
- struct drm_plane_state *scanout_state;
- struct drm_plane *scanout_plane = output->scanout_plane;
- struct drm_backend *b = to_drm_backend(c);
- struct drm_fb *fb;
-
- /* If we already have a client buffer promoted to scanout, then we don't
- * want to render. */
- scanout_state = drm_output_state_get_plane(state,
- output->scanout_plane);
- if (scanout_state->fb)
- return;
-
- if (!pixman_region32_not_empty(damage) &&
- scanout_plane->state_cur->fb &&
- (scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
- scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) &&
- scanout_plane->state_cur->fb->width ==
- output->base.current_mode->width &&
- scanout_plane->state_cur->fb->height ==
- output->base.current_mode->height) {
- fb = drm_fb_ref(scanout_plane->state_cur->fb);
- } else if (b->use_pixman) {
- fb = drm_output_render_pixman(state, damage);
- } else {
- fb = drm_output_render_gl(state, damage);
- }
-
- if (!fb) {
- drm_plane_state_put_back(scanout_state);
- return;
- }
-
- scanout_state->fb = fb;
- scanout_state->output = output;
-
- scanout_state->src_x = 0;
- scanout_state->src_y = 0;
- scanout_state->src_w = output->base.current_mode->width << 16;
- scanout_state->src_h = output->base.current_mode->height << 16;
-
- scanout_state->dest_x = 0;
- scanout_state->dest_y = 0;
- scanout_state->dest_w = scanout_state->src_w >> 16;
- scanout_state->dest_h = scanout_state->src_h >> 16;
-
- pixman_region32_copy(&scanout_state->damage, damage);
- if (output->base.zoom.active) {
- weston_matrix_transform_region(&scanout_state->damage,
- &output->base.matrix,
- &scanout_state->damage);
- } else {
- pixman_region32_translate(&scanout_state->damage,
- -output->base.x, -output->base.y);
- weston_transformed_region(output->base.width,
- output->base.height,
- output->base.transform,
- output->base.current_scale,
- &scanout_state->damage,
- &scanout_state->damage);
- }
-
- pixman_region32_subtract(&c->primary_plane.damage,
- &c->primary_plane.damage, damage);
-}
-
-static int
-drm_output_repaint(struct weston_output *output_base,
- pixman_region32_t *damage,
- void *repaint_data)
-{
- struct drm_pending_state *pending_state = repaint_data;
- struct drm_output *output = to_drm_output(output_base);
- struct drm_output_state *state = NULL;
- struct drm_plane_state *scanout_state;
-
- assert(!output->virtual);
-
- if (output->disable_pending || output->destroy_pending)
- goto err;
-
- assert(!output->state_last);
-
- /* If planes have been disabled in the core, we might not have
- * hit assign_planes at all, so might not have valid output state
- * here. */
- state = drm_pending_state_get_output(pending_state, output);
- if (!state)
- state = drm_output_state_duplicate(output->state_cur,
- pending_state,
- DRM_OUTPUT_STATE_CLEAR_PLANES);
- state->dpms = WESTON_DPMS_ON;
-
- if (output_base->allow_protection)
- state->protection = output_base->desired_protection;
- else
- state->protection = WESTON_HDCP_DISABLE;
-
- drm_output_render(state, damage);
- scanout_state = drm_output_state_get_plane(state,
- output->scanout_plane);
- if (!scanout_state || !scanout_state->fb)
- goto err;
-
- return 0;
-
-err:
- drm_output_state_free(state);
- return -1;
-}
-
-/* Determine the type of vblank synchronization to use for the output.
- *
- * The pipe parameter indicates which CRTC is in use. Knowing this, we
- * can determine which vblank sequence type to use for it. Traditional
- * cards had only two CRTCs, with CRTC 0 using no special flags, and
- * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
- * parameter indicates this.
- *
- * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
- * 0-31. If this is non-zero it indicates we're dealing with a
- * multi-gpu situation and we need to calculate the vblank sync
- * using DRM_BLANK_HIGH_CRTC_MASK.
- */
-static unsigned int
-drm_waitvblank_pipe(struct drm_output *output)
-{
- if (output->pipe > 1)
- return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
- DRM_VBLANK_HIGH_CRTC_MASK;
- else if (output->pipe > 0)
- return DRM_VBLANK_SECONDARY;
- else
- return 0;
-}
-
-static int
-drm_output_start_repaint_loop(struct weston_output *output_base)
-{
- struct drm_output *output = to_drm_output(output_base);
- struct drm_pending_state *pending_state;
- struct drm_plane *scanout_plane = output->scanout_plane;
- struct drm_backend *backend =
- to_drm_backend(output_base->compositor);
- struct timespec ts, tnow;
- struct timespec vbl2now;
- int64_t refresh_nsec;
- int ret;
- drmVBlank vbl = {
- .request.type = DRM_VBLANK_RELATIVE,
- .request.sequence = 0,
- .request.signal = 0,
- };
-
- if (output->disable_pending || output->destroy_pending)
- return 0;
-
- if (!output->scanout_plane->state_cur->fb) {
- /* We can't page flip if there's no mode set */
- goto finish_frame;
- }
-
- /* Need to smash all state in from scratch; current timings might not
- * be what we want, page flip might not work, etc.
- */
- if (backend->state_invalid)
- goto finish_frame;
-
- assert(scanout_plane->state_cur->output == output);
-
- /* Try to get current msc and timestamp via instant query */
- vbl.request.type |= drm_waitvblank_pipe(output);
- ret = drmWaitVBlank(backend->drm.fd, &vbl);
-
- /* Error ret or zero timestamp means failure to get valid timestamp */
- if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
- ts.tv_sec = vbl.reply.tval_sec;
- ts.tv_nsec = vbl.reply.tval_usec * 1000;
-
- /* Valid timestamp for most recent vblank - not stale?
- * Stale ts could happen on Linux 3.17+, so make sure it
- * is not older than 1 refresh duration since now.
- */
- weston_compositor_read_presentation_clock(backend->compositor,
- &tnow);
- timespec_sub(&vbl2now, &tnow, &ts);
- refresh_nsec =
- millihz_to_nsec(output->base.current_mode->refresh);
- if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
- drm_output_update_msc(output, vbl.reply.sequence);
- weston_output_finish_frame(output_base, &ts,
- WP_PRESENTATION_FEEDBACK_INVALID);
- return 0;
- }
- }
-
- /* Immediate query didn't provide valid timestamp.
- * Use pageflip fallback.
- */
-
- assert(!output->page_flip_pending);
- assert(!output->state_last);
-
- pending_state = drm_pending_state_alloc(backend);
- drm_output_state_duplicate(output->state_cur, pending_state,
- DRM_OUTPUT_STATE_PRESERVE_PLANES);
-
- ret = drm_pending_state_apply(pending_state);
- if (ret != 0) {
- weston_log("applying repaint-start state failed: %s\n",
- strerror(errno));
- if (ret == -EACCES)
- return -1;
- goto finish_frame;
- }
-
- return 0;
-
-finish_frame:
- /* if we cannot page-flip, immediately finish frame */
- weston_output_finish_frame(output_base, NULL,
- WP_PRESENTATION_FEEDBACK_INVALID);
- return 0;
-}
-
-/**
- * Begin a new repaint cycle
- *
- * Called by the core compositor at the beginning of a repaint cycle. Creates
- * a new pending_state structure to own any output state created by individual
- * output repaint functions until the repaint is flushed or cancelled.
- */
-static void *
-drm_repaint_begin(struct weston_compositor *compositor)
-{
- struct drm_backend *b = to_drm_backend(compositor);
- struct drm_pending_state *ret;
-
- ret = drm_pending_state_alloc(b);
- b->repaint_data = ret;
-
- if (weston_log_scope_is_enabled(b->debug)) {
- char *dbg = weston_compositor_print_scene_graph(compositor);
- drm_debug(b, "[repaint] Beginning repaint; pending_state %p\n",
- ret);
- drm_debug(b, "%s", dbg);
- free(dbg);
- }
-
- return ret;
-}
-
-/**
- * Flush a repaint set
- *
- * Called by the core compositor when a repaint cycle has been completed
- * and should be flushed. Frees the pending state, transitioning ownership
- * of the output state from the pending state, to the update itself. When
- * the update completes (see drm_output_update_complete), the output
- * state will be freed.
- */
-static int
-drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
-{
- struct drm_backend *b = to_drm_backend(compositor);
- struct drm_pending_state *pending_state = repaint_data;
- int ret;
-
- ret = drm_pending_state_apply(pending_state);
- if (ret != 0)
- weston_log("repaint-flush failed: %s\n", strerror(errno));
-
- drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state);
- b->repaint_data = NULL;
-
- return (ret == -EACCES) ? -1 : 0;
-}
-
-/**
- * Cancel a repaint set
- *
- * Called by the core compositor when a repaint has finished, so the data
- * held across the repaint cycle should be discarded.
- */
-static void
-drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
-{
- struct drm_backend *b = to_drm_backend(compositor);
- struct drm_pending_state *pending_state = repaint_data;
-
- drm_pending_state_free(pending_state);
- drm_debug(b, "[repaint] cancel pending_state %p\n", pending_state);
- b->repaint_data = NULL;
-}
-
-static int
-drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
-static void
-drm_output_fini_pixman(struct drm_output *output);
-
-static int
-drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
-{
- struct drm_output *output = to_drm_output(output_base);
- struct drm_backend *b = to_drm_backend(output_base->compositor);
- struct drm_mode *drm_mode = drm_output_choose_mode(output, mode);
-
- if (!drm_mode) {
- weston_log("%s: invalid resolution %dx%d\n",
- output_base->name, mode->width, mode->height);
- return -1;
- }
-
- if (&drm_mode->base == output->base.current_mode)
- return 0;
-
- output->base.current_mode->flags = 0;
-
- output->base.current_mode = &drm_mode->base;
- output->base.current_mode->flags =
- WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
-
- /* XXX: This drops our current buffer too early, before we've started
- * displaying it. Ideally this should be much more atomic and
- * integrated with a full repaint cycle, rather than doing a
- * sledgehammer modeswitch first, and only later showing new
- * content.
- */
- b->state_invalid = true;
-
- if (b->use_pixman) {
- drm_output_fini_pixman(output);
- if (drm_output_init_pixman(output, b) < 0) {
- weston_log("failed to init output pixman state with "
- "new mode\n");
- return -1;
- }
- } else {
- drm_output_fini_egl(output);
- if (drm_output_init_egl(output, b) < 0) {
- weston_log("failed to init output egl state with "
- "new mode");
- return -1;
- }
- }
-
- return 0;
-}
-
-static int
-init_pixman(struct drm_backend *b)
-{
- return pixman_renderer_init(b->compositor);
-}
-
-/**
- * Create a drm_plane for a hardware plane
- *
- * Creates one drm_plane structure for a hardware plane, and initialises its
- * properties and formats.
- *
- * In the absence of universal plane support, where KMS does not explicitly
- * expose the primary and cursor planes to userspace, this may also create
- * an 'internal' plane for internal management.
- *
- * This function does not add the plane to the list of usable planes in Weston
- * itself; the caller is responsible for this.
- *
- * Call drm_plane_destroy to clean up the plane.
- *
- * @sa drm_output_find_special_plane
- * @param b DRM compositor backend
- * @param kplane DRM plane to create, or NULL if creating internal plane
- * @param output Output to create internal plane for, or NULL
- * @param type Type to use when creating internal plane, or invalid
- * @param format Format to use for internal planes, or 0
- */
-static struct drm_plane *
-drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
- struct drm_output *output, enum wdrm_plane_type type,
- uint32_t format)
-{
- struct drm_plane *plane;
- drmModeObjectProperties *props;
- uint64_t *zpos_range_values;
- uint32_t num_formats = (kplane) ? kplane->count_formats : 1;
-
- plane = zalloc(sizeof(*plane) +
- (sizeof(plane->formats[0]) * num_formats));
- if (!plane) {
- weston_log("%s: out of memory\n", __func__);
- return NULL;
- }
-
- plane->backend = b;
- plane->count_formats = num_formats;
- plane->state_cur = drm_plane_state_alloc(NULL, plane);
- plane->state_cur->complete = true;
-
- if (kplane) {
- plane->possible_crtcs = kplane->possible_crtcs;
- plane->plane_id = kplane->plane_id;
-
- props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
- DRM_MODE_OBJECT_PLANE);
- if (!props) {
- weston_log("couldn't get plane properties\n");
- goto err;
- }
- drm_property_info_populate(b, plane_props, plane->props,
- WDRM_PLANE__COUNT, props);
- plane->type =
- drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
- props,
- WDRM_PLANE_TYPE__COUNT);
-
- zpos_range_values =
- drm_property_get_range_values(&plane->props[WDRM_PLANE_ZPOS],
- props);
-
- if (zpos_range_values) {
- plane->zpos_min = zpos_range_values[0];
- plane->zpos_max = zpos_range_values[1];
- } else {
- plane->zpos_min = DRM_PLANE_ZPOS_INVALID_PLANE;
- plane->zpos_max = DRM_PLANE_ZPOS_INVALID_PLANE;
- }
-
- if (drm_plane_populate_formats(plane, kplane, props) < 0) {
- drmModeFreeObjectProperties(props);
- goto err;
- }
-
- drmModeFreeObjectProperties(props);
- }
- else {
- plane->possible_crtcs = (1 << output->pipe);
- plane->plane_id = 0;
- plane->count_formats = 1;
- plane->formats[0].format = format;
- plane->type = type;
- plane->zpos_max = DRM_PLANE_ZPOS_INVALID_PLANE;
- plane->zpos_min = DRM_PLANE_ZPOS_INVALID_PLANE;
- }
-
- if (plane->type == WDRM_PLANE_TYPE__COUNT)
- goto err_props;
-
- /* With universal planes, everything is a DRM plane; without
- * universal planes, the only DRM planes are overlay planes.
- * Everything else is a fake plane. */
- if (b->universal_planes) {
- assert(kplane);
- } else {
- if (kplane)
- assert(plane->type == WDRM_PLANE_TYPE_OVERLAY);
- else
- assert(plane->type != WDRM_PLANE_TYPE_OVERLAY &&
- output);
- }
-
- weston_plane_init(&plane->base, b->compositor, 0, 0);
- wl_list_insert(&b->plane_list, &plane->link);
-
- return plane;
-
-err_props:
- drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
-err:
- drm_plane_state_free(plane->state_cur, true);
- free(plane);
- return NULL;
-}
-
-/**
- * Find, or create, a special-purpose plane
- *
- * Primary and cursor planes are a special case, in that before universal
- * planes, they are driven by non-plane API calls. Without universal plane
- * support, the only way to configure a primary plane is via drmModeSetCrtc,
- * and the only way to configure a cursor plane is drmModeSetCursor2.
- *
- * Although they may actually be regular planes in the hardware, without
- * universal plane support, these planes are not actually exposed to
- * userspace in the regular plane list.
- *
- * However, for ease of internal tracking, we want to manage all planes
- * through the same drm_plane structures. Therefore, when we are running
- * without universal plane support, we create fake drm_plane structures
- * to track these planes.
- *
- * @param b DRM backend
- * @param output Output to use for plane
- * @param type Type of plane
- */
-static struct drm_plane *
-drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
- enum wdrm_plane_type type)
-{
- struct drm_plane *plane;
-
- if (!b->universal_planes) {
- uint32_t format;
-
- switch (type) {
- case WDRM_PLANE_TYPE_CURSOR:
- format = DRM_FORMAT_ARGB8888;
- break;
- case WDRM_PLANE_TYPE_PRIMARY:
- /* We don't know what formats the primary plane supports
- * before universal planes, so we just assume that the
- * GBM format works; however, this isn't set until after
- * the output is created. */
- format = 0;
- break;
- default:
- assert(!"invalid type in drm_output_find_special_plane");
- break;
- }
-
- return drm_plane_create(b, NULL, output, type, format);
- }
-
- wl_list_for_each(plane, &b->plane_list, link) {
- struct drm_output *tmp;
- bool found_elsewhere = false;
-
- if (plane->type != type)
- continue;
- if (!drm_plane_is_available(plane, output))
- continue;
-
- /* On some platforms, primary/cursor planes can roam
- * between different CRTCs, so make sure we don't claim the
- * same plane for two outputs. */
- wl_list_for_each(tmp, &b->compositor->output_list,
- base.link) {
- if (tmp->cursor_plane == plane ||
- tmp->scanout_plane == plane) {
- found_elsewhere = true;
- break;
- }
- }
-
- if (found_elsewhere)
- continue;
-
- plane->possible_crtcs = (1 << output->pipe);
- return plane;
- }
-
- return NULL;
-}
-
-/**
- * Destroy one DRM plane
- *
- * Destroy a DRM plane, removing it from screen and releasing its retained
- * buffers in the process. The counterpart to drm_plane_create.
- *
- * @param plane Plane to deallocate (will be freed)
- */
-static void
-drm_plane_destroy(struct drm_plane *plane)
-{
- if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
- drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- drm_plane_state_free(plane->state_cur, true);
- drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
- weston_plane_release(&plane->base);
- wl_list_remove(&plane->link);
- free(plane);
-}
-
-/**
- * Initialise sprites (overlay planes)
- *
- * Walk the list of provided DRM planes, and add overlay planes.
- *
- * Call destroy_sprites to free these planes.
- *
- * @param b DRM compositor backend
- */
-static void
-create_sprites(struct drm_backend *b)
-{
- drmModePlaneRes *kplane_res;
- drmModePlane *kplane;
- struct drm_plane *drm_plane;
- uint32_t i;
- kplane_res = drmModeGetPlaneResources(b->drm.fd);
- if (!kplane_res) {
- weston_log("failed to get plane resources: %s\n",
- strerror(errno));
- return;
- }
-
- for (i = 0; i < kplane_res->count_planes; i++) {
- kplane = drmModeGetPlane(b->drm.fd, kplane_res->planes[i]);
- if (!kplane)
- continue;
-
- drm_plane = drm_plane_create(b, kplane, NULL,
- WDRM_PLANE_TYPE__COUNT, 0);
- drmModeFreePlane(kplane);
- if (!drm_plane)
- continue;
-
- if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
- weston_compositor_stack_plane(b->compositor,
- &drm_plane->base,
- &b->compositor->primary_plane);
- }
-
- drmModeFreePlaneResources(kplane_res);
-}
-
-/**
- * Clean up sprites (overlay planes)
- *
- * The counterpart to create_sprites.
- *
- * @param b DRM compositor backend
- */
-static void
-destroy_sprites(struct drm_backend *b)
-{
- struct drm_plane *plane, *next;
-
- wl_list_for_each_safe(plane, next, &b->plane_list, link)
- drm_plane_destroy(plane);
-}
-
-/* returns a value between 0-255 range, where higher is brighter */
-static uint32_t
-drm_get_backlight(struct drm_head *head)
-{
- long brightness, max_brightness, norm;
-
- brightness = backlight_get_brightness(head->backlight);
- max_brightness = backlight_get_max_brightness(head->backlight);
-
- /* convert it on a scale of 0 to 255 */
- norm = (brightness * 255)/(max_brightness);
-
- return (uint32_t) norm;
-}
-
-/* values accepted are between 0-255 range */
-static void
-drm_set_backlight(struct weston_output *output_base, uint32_t value)
-{
- struct drm_output *output = to_drm_output(output_base);
- struct drm_head *head;
- long max_brightness, new_brightness;
-
- if (value > 255)
- return;
-
- wl_list_for_each(head, &output->base.head_list, base.output_link) {
- if (!head->backlight)
- return;
-
- max_brightness = backlight_get_max_brightness(head->backlight);
-
- /* get denormalized value */
- new_brightness = (value * max_brightness) / 255;
-
- backlight_set_brightness(head->backlight, new_brightness);
- }
-}
-
-static void
-drm_output_init_backlight(struct drm_output *output)
-{
- struct weston_head *base;
- struct drm_head *head;
-
- output->base.set_backlight = NULL;
-
- wl_list_for_each(base, &output->base.head_list, output_link) {
- head = to_drm_head(base);
-
- if (head->backlight) {
- weston_log("Initialized backlight for head '%s', device %s\n",
- head->base.name, head->backlight->path);
-
- if (!output->base.set_backlight) {
- output->base.set_backlight = drm_set_backlight;
- output->base.backlight_current =
- drm_get_backlight(head);
- }
- }
- }
-}
-
-/**
- * Power output on or off
- *
- * The DPMS/power level of an output is used to switch it on or off. This
- * is DRM's hook for doing so, which can called either as part of repaint,
- * or independently of the repaint loop.
- *
- * If we are called as part of repaint, we simply set the relevant bit in
- * state and return.
- *
- * This function is never called on a virtual output.
- */
-static void
-drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
-{
- struct drm_output *output = to_drm_output(output_base);
- struct drm_backend *b = to_drm_backend(output_base->compositor);
- struct drm_pending_state *pending_state = b->repaint_data;
- struct drm_output_state *state;
- int ret;
-
- assert(!output->virtual);
-
- if (output->state_cur->dpms == level)
- return;
-
- /* If we're being called during the repaint loop, then this is
- * simple: discard any previously-generated state, and create a new
- * state where we disable everything. When we come to flush, this
- * will be applied.
- *
- * However, we need to be careful: we can be called whilst another
- * output is in its repaint cycle (pending_state exists), but our
- * output still has an incomplete state application outstanding.
- * In that case, we need to wait until that completes. */
- if (pending_state && !output->state_last) {
- /* The repaint loop already sets DPMS on; we don't need to
- * explicitly set it on here, as it will already happen
- * whilst applying the repaint state. */
- if (level == WESTON_DPMS_ON)
- return;
-
- state = drm_pending_state_get_output(pending_state, output);
- if (state)
- drm_output_state_free(state);
- state = drm_output_get_disable_state(pending_state, output);
- return;
- }
-
- /* As we throw everything away when disabling, just send us back through
- * a repaint cycle. */
- if (level == WESTON_DPMS_ON) {
- if (output->dpms_off_pending)
- output->dpms_off_pending = false;
- weston_output_schedule_repaint(output_base);
- return;
- }
-
- /* If we've already got a request in the pipeline, then we need to
- * park our DPMS request until that request has quiesced. */
- if (output->state_last) {
- output->dpms_off_pending = true;
- return;
- }
-
- pending_state = drm_pending_state_alloc(b);
- drm_output_get_disable_state(pending_state, output);
- ret = drm_pending_state_apply_sync(pending_state);
- if (ret != 0)
- weston_log("drm_set_dpms: couldn't disable output?\n");
-}
-
-static const char * const connector_type_names[] = {
- [DRM_MODE_CONNECTOR_Unknown] = "Unknown",
- [DRM_MODE_CONNECTOR_VGA] = "VGA",
- [DRM_MODE_CONNECTOR_DVII] = "DVI-I",
- [DRM_MODE_CONNECTOR_DVID] = "DVI-D",
- [DRM_MODE_CONNECTOR_DVIA] = "DVI-A",
- [DRM_MODE_CONNECTOR_Composite] = "Composite",
- [DRM_MODE_CONNECTOR_SVIDEO] = "SVIDEO",
- [DRM_MODE_CONNECTOR_LVDS] = "LVDS",
- [DRM_MODE_CONNECTOR_Component] = "Component",
- [DRM_MODE_CONNECTOR_9PinDIN] = "DIN",
- [DRM_MODE_CONNECTOR_DisplayPort] = "DP",
- [DRM_MODE_CONNECTOR_HDMIA] = "HDMI-A",
- [DRM_MODE_CONNECTOR_HDMIB] = "HDMI-B",
- [DRM_MODE_CONNECTOR_TV] = "TV",
- [DRM_MODE_CONNECTOR_eDP] = "eDP",
- [DRM_MODE_CONNECTOR_VIRTUAL] = "Virtual",
- [DRM_MODE_CONNECTOR_DSI] = "DSI",
- [DRM_MODE_CONNECTOR_DPI] = "DPI",
-};
-
-/** Create a name given a DRM connector
- *
- * \param con The DRM connector whose type and id form the name.
- * \return A newly allocate string, or NULL on error. Must be free()'d
- * after use.
- *
- * The name does not identify the DRM display device.
- */
-static char *
-make_connector_name(const drmModeConnector *con)
-{
- char *name;
- const char *type_name = NULL;
- int ret;
-
- if (con->connector_type < ARRAY_LENGTH(connector_type_names))
- type_name = connector_type_names[con->connector_type];
-
- if (!type_name)
- type_name = "UNNAMED";
-
- ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
- if (ret < 0)
- return NULL;
-
- return name;
-}
-
-static int
-drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
-{
- int w = output->base.current_mode->width;
- int h = output->base.current_mode->height;
- uint32_t format = output->gbm_format;
- uint32_t pixman_format;
- unsigned int i;
- uint32_t flags = 0;
-
- switch (format) {
- case DRM_FORMAT_XRGB8888:
- pixman_format = PIXMAN_x8r8g8b8;
- break;
- case DRM_FORMAT_RGB565:
- pixman_format = PIXMAN_r5g6b5;
- break;
- default:
- weston_log("Unsupported pixman format 0x%x\n", format);
- return -1;
- }
-
- /* FIXME error checking */
- for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
- output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
- if (!output->dumb[i])
- goto err;
-
- output->image[i] =
- pixman_image_create_bits(pixman_format, w, h,
- output->dumb[i]->map,
- output->dumb[i]->strides[0]);
- if (!output->image[i])
- goto err;
- }
-
- if (b->use_pixman_shadow)
- flags |= PIXMAN_RENDERER_OUTPUT_USE_SHADOW;
-
- if (pixman_renderer_output_create(&output->base, flags) < 0)
- goto err;
-
- weston_log("DRM: output %s %s shadow framebuffer.\n", output->base.name,
- b->use_pixman_shadow ? "uses" : "does not use");
-
- pixman_region32_init_rect(&output->previous_damage,
- output->base.x, output->base.y, output->base.width, output->base.height);
-
- return 0;
-
-err:
- for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
- if (output->dumb[i])
- drm_fb_unref(output->dumb[i]);
- if (output->image[i])
- pixman_image_unref(output->image[i]);
-
- output->dumb[i] = NULL;
- output->image[i] = NULL;
- }
-
- return -1;
-}
-
-static void
-drm_output_fini_pixman(struct drm_output *output)
-{
- struct drm_backend *b = to_drm_backend(output->base.compositor);
- unsigned int i;
-
- /* Destroying the Pixman surface will destroy all our buffers,
- * regardless of refcount. Ensure we destroy them here. */
- if (!b->shutting_down &&
- output->scanout_plane->state_cur->fb &&
- output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
- drm_plane_state_free(output->scanout_plane->state_cur, true);
- output->scanout_plane->state_cur =
- drm_plane_state_alloc(NULL, output->scanout_plane);
- output->scanout_plane->state_cur->complete = true;
- }
-
- pixman_renderer_output_destroy(&output->base);
- pixman_region32_fini(&output->previous_damage);
-
- for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
- pixman_image_unref(output->image[i]);
- drm_fb_unref(output->dumb[i]);
- output->dumb[i] = NULL;
- output->image[i] = NULL;
- }
-}
-
-static void
-setup_output_seat_constraint(struct drm_backend *b,
- struct weston_output *output,
- const char *s)
-{
- if (strcmp(s, "") != 0) {
- struct weston_pointer *pointer;
- struct udev_seat *seat;
-
- seat = udev_seat_get_named(&b->input, s);
- if (!seat)
- return;
-
- seat->base.output = output;
-
- pointer = weston_seat_get_pointer(&seat->base);
- if (pointer)
- weston_pointer_clamp(pointer,
- &pointer->x,
- &pointer->y);
- }
-}
-
-static int
-drm_output_attach_head(struct weston_output *output_base,
- struct weston_head *head_base)
-{
- struct drm_backend *b = to_drm_backend(output_base->compositor);
-
- if (wl_list_length(&output_base->head_list) >= MAX_CLONED_CONNECTORS)
- return -1;
-
- if (!output_base->enabled)
- return 0;
-
- /* XXX: ensure the configuration will work.
- * This is actually impossible without major infrastructure
- * work. */
-
- /* Need to go through modeset to add connectors. */
- /* XXX: Ideally we'd do this per-output, not globally. */
- /* XXX: Doing it globally, what guarantees another output's update
- * will not clear the flag before this output is updated?
- */
- b->state_invalid = true;
-
- weston_output_schedule_repaint(output_base);
-
- return 0;
-}
-
-static void
-drm_output_detach_head(struct weston_output *output_base,
- struct weston_head *head_base)
-{
- struct drm_backend *b = to_drm_backend(output_base->compositor);
-
- if (!output_base->enabled)
- return;
-
- /* Need to go through modeset to drop connectors that should no longer
- * be driven. */
- /* XXX: Ideally we'd do this per-output, not globally. */
- b->state_invalid = true;
-
- weston_output_schedule_repaint(output_base);
-}
-
-int
-parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format)
-{
- const struct pixel_format_info *pinfo;
-
- if (s == NULL) {
- *gbm_format = default_value;
-
- return 0;
- }
-
- pinfo = pixel_format_get_info_by_drm_name(s);
- if (!pinfo) {
- weston_log("fatal: unrecognized pixel format: %s\n", s);
-
- return -1;
- }
-
- /* GBM formats and DRM formats are identical. */
- *gbm_format = pinfo->format;
-
- return 0;
-}
-
-static int
-drm_head_read_current_setup(struct drm_head *head, struct drm_backend *backend)
-{
- int drm_fd = backend->drm.fd;
- drmModeEncoder *encoder;
- drmModeCrtc *crtc;
-
- /* Get the current mode on the crtc that's currently driving
- * this connector. */
- encoder = drmModeGetEncoder(drm_fd, head->connector->encoder_id);
- if (encoder != NULL) {
- head->inherited_crtc_id = encoder->crtc_id;
-
- crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
- drmModeFreeEncoder(encoder);
-
- if (crtc == NULL)
- return -1;
- if (crtc->mode_valid)
- head->inherited_mode = crtc->mode;
- drmModeFreeCrtc(crtc);
- }
-
- return 0;
-}
-
-static void
-drm_output_set_gbm_format(struct weston_output *base,
- const char *gbm_format)
-{
- struct drm_output *output = to_drm_output(base);
- struct drm_backend *b = to_drm_backend(base->compositor);
-
- if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
- output->gbm_format = b->gbm_format;
-
- /* Without universal planes, we can't discover which formats are
- * supported by the primary plane; we just hope that the GBM format
- * works. */
- if (!b->universal_planes)
- output->scanout_plane->formats[0].format = output->gbm_format;
-}
-
-static void
-drm_output_set_seat(struct weston_output *base,
- const char *seat)
-{
- struct drm_output *output = to_drm_output(base);
- struct drm_backend *b = to_drm_backend(base->compositor);
-
- setup_output_seat_constraint(b, &output->base,
- seat ? seat : "");
-}
-
-static int
-drm_output_init_gamma_size(struct drm_output *output)
-{
- struct drm_backend *backend = to_drm_backend(output->base.compositor);
- drmModeCrtc *crtc;
-
- assert(output->base.compositor);
- assert(output->crtc_id != 0);
- crtc = drmModeGetCrtc(backend->drm.fd, output->crtc_id);
- if (!crtc)
- return -1;
-
- output->base.gamma_size = crtc->gamma_size;
-
- drmModeFreeCrtc(crtc);
-
- return 0;
-}
-
-static uint32_t
-drm_head_get_possible_crtcs_mask(struct drm_head *head)
-{
- uint32_t possible_crtcs = 0;
- drmModeEncoder *encoder;
- int i;
-
- for (i = 0; i < head->connector->count_encoders; i++) {
- encoder = drmModeGetEncoder(head->backend->drm.fd,
- head->connector->encoders[i]);
- if (!encoder)
- continue;
-
- possible_crtcs |= encoder->possible_crtcs;
- drmModeFreeEncoder(encoder);
- }
-
- return possible_crtcs;
-}
-
-static int
-drm_crtc_get_index(drmModeRes *resources, uint32_t crtc_id)
-{
- int i;
-
- for (i = 0; i < resources->count_crtcs; i++) {
- if (resources->crtcs[i] == crtc_id)
- return i;
- }
-
- assert(0 && "unknown crtc id");
- return -1;
-}
-
-/** Pick a CRTC that might be able to drive all attached connectors
- *
- * @param output The output whose attached heads to include.
- * @param resources The DRM KMS resources.
- * @return CRTC index, or -1 on failure or not found.
- */
-static int
-drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources)
-{
- struct drm_backend *backend;
- struct weston_head *base;
- struct drm_head *head;
- uint32_t possible_crtcs = 0xffffffff;
- int existing_crtc[32];
- unsigned j, n = 0;
- uint32_t crtc_id;
- int best_crtc_index = -1;
- int fallback_crtc_index = -1;
- int i;
- bool match;
-
- backend = to_drm_backend(output->base.compositor);
-
- /* This algorithm ignores drmModeEncoder::possible_clones restriction,
- * because it is more often set wrong than not in the kernel. */
-
- /* Accumulate a mask of possible crtcs and find existing routings. */
- wl_list_for_each(base, &output->base.head_list, output_link) {
- head = to_drm_head(base);
-
- possible_crtcs &= drm_head_get_possible_crtcs_mask(head);
-
- crtc_id = head->inherited_crtc_id;
- if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
- existing_crtc[n++] = drm_crtc_get_index(resources,
- crtc_id);
- }
-
- /* Find a crtc that could drive each connector individually at least,
- * and prefer existing routings. */
- for (i = 0; i < resources->count_crtcs; i++) {
- crtc_id = resources->crtcs[i];
-
- /* Could the crtc not drive each connector? */
- if (!(possible_crtcs & (1 << i)))
- continue;
-
- /* Is the crtc already in use? */
- if (drm_output_find_by_crtc(backend, crtc_id))
- continue;
-
- /* Try to preserve the existing CRTC -> connector routing;
- * it makes initialisation faster, and also since we have a
- * very dumb picking algorithm, may preserve a better
- * choice. */
- for (j = 0; j < n; j++) {
- if (existing_crtc[j] == i)
- return i;
- }
-
- /* Check if any other head had existing routing to this CRTC.
- * If they did, this is not the best CRTC as it might be needed
- * for another output we haven't enabled yet. */
- match = false;
- wl_list_for_each(base, &backend->compositor->head_list,
- compositor_link) {
- head = to_drm_head(base);
-
- if (head->base.output == &output->base)
- continue;
-
- if (weston_head_is_enabled(&head->base))
- continue;
-
- if (head->inherited_crtc_id == crtc_id) {
- match = true;
- break;
- }
- }
- if (!match)
- best_crtc_index = i;
-
- fallback_crtc_index = i;
- }
-
- if (best_crtc_index != -1)
- return best_crtc_index;
-
- if (fallback_crtc_index != -1)
- return fallback_crtc_index;
-
- /* Likely possible_crtcs was empty due to asking for clones,
- * but since the DRM documentation says the kernel lies, let's
- * pick one crtc anyway. Trial and error is the only way to
- * be sure if something doesn't work. */
-
- /* First pick any existing assignment. */
- for (j = 0; j < n; j++) {
- crtc_id = resources->crtcs[existing_crtc[j]];
- if (!drm_output_find_by_crtc(backend, crtc_id))
- return existing_crtc[j];
- }
-
- /* Otherwise pick any available crtc. */
- for (i = 0; i < resources->count_crtcs; i++) {
- crtc_id = resources->crtcs[i];
-
- if (!drm_output_find_by_crtc(backend, crtc_id))
- return i;
- }
-
- return -1;
-}
-
-/** Allocate a CRTC for the output
- *
- * @param output The output with no allocated CRTC.
- * @param resources DRM KMS resources.
- * @return 0 on success, -1 on failure.
- *
- * Finds a free CRTC that might drive the attached connectors, reserves the CRTC
- * for the output, and loads the CRTC properties.
- *
- * Populates the cursor and scanout planes.
- *
- * On failure, the output remains without a CRTC.
- */
-static int
-drm_output_init_crtc(struct drm_output *output, drmModeRes *resources)
-{
- struct drm_backend *b = to_drm_backend(output->base.compositor);
- drmModeObjectPropertiesPtr props;
- int i;
-
- assert(output->crtc_id == 0);
-
- i = drm_output_pick_crtc(output, resources);
- if (i < 0) {
- weston_log("Output '%s': No available CRTCs.\n",
- output->base.name);
- return -1;
- }
-
- output->crtc_id = resources->crtcs[i];
- output->pipe = i;
-
- props = drmModeObjectGetProperties(b->drm.fd, output->crtc_id,
- DRM_MODE_OBJECT_CRTC);
- if (!props) {
- weston_log("failed to get CRTC properties\n");
- goto err_crtc;
- }
- drm_property_info_populate(b, crtc_props, output->props_crtc,
- WDRM_CRTC__COUNT, props);
- drmModeFreeObjectProperties(props);
-
- output->scanout_plane =
- drm_output_find_special_plane(b, output,
- WDRM_PLANE_TYPE_PRIMARY);
- if (!output->scanout_plane) {
- weston_log("Failed to find primary plane for output %s\n",
- output->base.name);
- goto err_crtc;
- }
-
- /* Failing to find a cursor plane is not fatal, as we'll fall back
- * to software cursor. */
- output->cursor_plane =
- drm_output_find_special_plane(b, output,
- WDRM_PLANE_TYPE_CURSOR);
-
- wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id);
-
- return 0;
-
-err_crtc:
- output->crtc_id = 0;
- output->pipe = 0;
-
- return -1;
-}
-
-/** Free the CRTC from the output
- *
- * @param output The output whose CRTC to deallocate.
- *
- * The CRTC reserved for the given output becomes free to use again.
- */
-static void
-drm_output_fini_crtc(struct drm_output *output)
-{
- struct drm_backend *b = to_drm_backend(output->base.compositor);
- uint32_t *unused;
-
- if (!b->universal_planes && !b->shutting_down) {
- /* With universal planes, the 'special' planes are allocated at
- * startup, freed at shutdown, and live on the plane list in
- * between. We want the planes to continue to exist and be freed
- * up for other outputs.
- *
- * Without universal planes, our special planes are
- * pseudo-planes allocated at output creation, freed at output
- * destruction, and not usable by other outputs.
- *
- * On the other hand, if the compositor is already shutting down,
- * the plane has already been destroyed.
- */
- if (output->cursor_plane)
- drm_plane_destroy(output->cursor_plane);
- if (output->scanout_plane)
- drm_plane_destroy(output->scanout_plane);
- }
-
- drm_property_info_free(output->props_crtc, WDRM_CRTC__COUNT);
-
- assert(output->crtc_id != 0);
-
- unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
- *unused = output->crtc_id;
-
- /* Force resetting unused CRTCs */
- b->state_invalid = true;
-
- output->crtc_id = 0;
- output->cursor_plane = NULL;
- output->scanout_plane = NULL;
-}
-
-static int
-drm_output_enable(struct weston_output *base)
-{
- struct drm_output *output = to_drm_output(base);
- struct drm_backend *b = to_drm_backend(base->compositor);
- drmModeRes *resources;
- int ret;
-
- assert(!output->virtual);
-
- resources = drmModeGetResources(b->drm.fd);
- if (!resources) {
- weston_log("drmModeGetResources failed\n");
- return -1;
- }
- ret = drm_output_init_crtc(output, resources);
- drmModeFreeResources(resources);
- if (ret < 0)
- return -1;
-
- if (drm_output_init_gamma_size(output) < 0)
- goto err;
-
- if (b->pageflip_timeout)
- drm_output_pageflip_timer_create(output);
-
- if (b->use_pixman) {
- if (drm_output_init_pixman(output, b) < 0) {
- weston_log("Failed to init output pixman state\n");
- goto err;
- }
- } else if (drm_output_init_egl(output, b) < 0) {
- weston_log("Failed to init output gl state\n");
- goto err;
- }
-
- drm_output_init_backlight(output);
-
- output->base.start_repaint_loop = drm_output_start_repaint_loop;
- output->base.repaint = drm_output_repaint;
- output->base.assign_planes = drm_assign_planes;
- output->base.set_dpms = drm_set_dpms;
- output->base.switch_mode = drm_output_switch_mode;
- output->base.set_gamma = drm_output_set_gamma;
-
- if (output->cursor_plane)
- weston_compositor_stack_plane(b->compositor,
- &output->cursor_plane->base,
- NULL);
- else
- b->cursors_are_broken = true;
-
- weston_compositor_stack_plane(b->compositor,
- &output->scanout_plane->base,
- &b->compositor->primary_plane);
-
- weston_log("Output %s (crtc %d) video modes:\n",
- output->base.name, output->crtc_id);
- drm_output_print_modes(output);
-
- return 0;
-
-err:
- drm_output_fini_crtc(output);
-
- return -1;
-}
-
-static void
-drm_output_deinit(struct weston_output *base)
-{
- struct drm_output *output = to_drm_output(base);
- struct drm_backend *b = to_drm_backend(base->compositor);
-
- if (b->use_pixman)
- drm_output_fini_pixman(output);
- else
- drm_output_fini_egl(output);
-
- /* Since our planes are no longer in use anywhere, remove their base
- * weston_plane's link from the plane stacking list, unless we're
- * shutting down, in which case the plane has already been
- * destroyed. */
- if (!b->shutting_down) {
- wl_list_remove(&output->scanout_plane->base.link);
- wl_list_init(&output->scanout_plane->base.link);
-
- if (output->cursor_plane) {
- wl_list_remove(&output->cursor_plane->base.link);
- wl_list_init(&output->cursor_plane->base.link);
- /* Turn off hardware cursor */
- drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
- }
- }
-
- drm_output_fini_crtc(output);
-}
-
-static void
-drm_head_destroy(struct drm_head *head);
-
-static void
-drm_output_destroy(struct weston_output *base)
-{
- struct drm_output *output = to_drm_output(base);
- struct drm_backend *b = to_drm_backend(base->compositor);
-
- assert(!output->virtual);
-
- if (output->page_flip_pending || output->atomic_complete_pending) {
- output->destroy_pending = true;
- weston_log("destroy output while page flip pending\n");
- return;
- }
-
- if (output->base.enabled)
- drm_output_deinit(&output->base);
-
- drm_mode_list_destroy(b, &output->base.mode_list);
-
- if (output->pageflip_timer)
- wl_event_source_remove(output->pageflip_timer);
-
- weston_output_release(&output->base);
-
- assert(!output->state_last);
- drm_output_state_free(output->state_cur);
-
- free(output);
-}
-
-static int
-drm_output_disable(struct weston_output *base)
-{
- struct drm_output *output = to_drm_output(base);
-
- assert(!output->virtual);
-
- if (output->page_flip_pending || output->atomic_complete_pending) {
- output->disable_pending = true;
- return -1;
- }
-
- weston_log("Disabling output %s\n", output->base.name);
-
- if (output->base.enabled)
- drm_output_deinit(&output->base);
-
- output->disable_pending = false;
-
- return 0;
-}
-
-/**
- * Update the list of unused connectors and CRTCs
- *
- * This keeps the unused_crtc arrays up to date.
- *
- * @param b Weston backend structure
- * @param resources DRM resources for this device
- */
-static void
-drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources)
-{
- int i;
-
- wl_array_release(&b->unused_crtcs);
- wl_array_init(&b->unused_crtcs);
-
- for (i = 0; i < resources->count_crtcs; i++) {
- struct drm_output *output;
- uint32_t *crtc_id;
-
- output = drm_output_find_by_crtc(b, resources->crtcs[i]);
- if (output && output->base.enabled)
- continue;
-
- crtc_id = wl_array_add(&b->unused_crtcs, sizeof(*crtc_id));
- *crtc_id = resources->crtcs[i];
- }
-}
-
-/*
- * This function converts the protection status from drm values to
- * weston_hdcp_protection status. The drm values as read from the connector
- * properties "Content Protection" and "HDCP Content Type" need to be converted
- * to appropriate weston values, that can be sent to a client application.
- */
-static int
-get_weston_protection_from_drm(enum wdrm_content_protection_state protection,
- enum wdrm_hdcp_content_type type,
- enum weston_hdcp_protection *weston_protection)
-
-{
- if (protection >= WDRM_CONTENT_PROTECTION__COUNT)
- return -1;
- if (protection == WDRM_CONTENT_PROTECTION_DESIRED ||
- protection == WDRM_CONTENT_PROTECTION_UNDESIRED) {
- *weston_protection = WESTON_HDCP_DISABLE;
- return 0;
- }
- if (type >= WDRM_HDCP_CONTENT_TYPE__COUNT)
- return -1;
- if (type == WDRM_HDCP_CONTENT_TYPE0) {
- *weston_protection = WESTON_HDCP_ENABLE_TYPE_0;
- return 0;
- }
- if (type == WDRM_HDCP_CONTENT_TYPE1) {
- *weston_protection = WESTON_HDCP_ENABLE_TYPE_1;
- return 0;
- }
- return -1;
-}
-
-/**
- * Get current content-protection status for a given head.
- *
- * @param head drm_head, whose protection is to be retrieved
- * @param props drm property object of the connector, related to the head
- * @return protection status in case of success, -1 otherwise
- */
-static enum weston_hdcp_protection
-drm_head_get_current_protection(struct drm_head *head,
- drmModeObjectProperties *props)
-{
- struct drm_property_info *info;
- enum wdrm_content_protection_state protection;
- enum wdrm_hdcp_content_type type;
- enum weston_hdcp_protection weston_hdcp = WESTON_HDCP_DISABLE;
-
- info = &head->props_conn[WDRM_CONNECTOR_CONTENT_PROTECTION];
- protection = drm_property_get_value(info, props,
- WDRM_CONTENT_PROTECTION__COUNT);
-
- if (protection == WDRM_CONTENT_PROTECTION__COUNT)
- return WESTON_HDCP_DISABLE;
-
- info = &head->props_conn[WDRM_CONNECTOR_HDCP_CONTENT_TYPE];
- type = drm_property_get_value(info, props,
- WDRM_HDCP_CONTENT_TYPE__COUNT);
-
- /*
- * In case of platforms supporting HDCP1.4, only property
- * 'Content Protection' is exposed and not the 'HDCP Content Type'
- * for such cases HDCP Type 0 should be considered as the content-type.
- */
-
- if (type == WDRM_HDCP_CONTENT_TYPE__COUNT)
- type = WDRM_HDCP_CONTENT_TYPE0;
-
- if (get_weston_protection_from_drm(protection, type,
- &weston_hdcp) == -1) {
- weston_log("Invalid drm protection:%d type:%d, for head:%s connector-id:%d\n",
- protection, type, head->base.name,
- head->connector_id);
- return WESTON_HDCP_DISABLE;
- }
-
- return weston_hdcp;
-}
-
-/** Replace connector data and monitor information
- *
- * @param head The head to update.
- * @param connector The connector data to be owned by the head, must match
- * the head's connector ID.
- * @return 0 on success, -1 on failure.
- *
- * Takes ownership of @c connector on success, not on failure.
- *
- * May schedule a heads changed call.
- */
-static int
-drm_head_assign_connector_info(struct drm_head *head,
- drmModeConnector *connector)
-{
- drmModeObjectProperties *props;
-
- assert(connector);
- assert(head->connector_id == connector->connector_id);
-
- props = drmModeObjectGetProperties(head->backend->drm.fd,
- head->connector_id,
- DRM_MODE_OBJECT_CONNECTOR);
- if (!props) {
- weston_log("Error: failed to get connector '%s' properties\n",
- head->base.name);
- return -1;
- }
-
- if (head->connector)
- drmModeFreeConnector(head->connector);
- head->connector = connector;
-
- drm_property_info_populate(head->backend, connector_props,
- head->props_conn,
- WDRM_CONNECTOR__COUNT, props);
- update_head_from_connector(head, props);
-
- weston_head_set_content_protection_status(&head->base,
- drm_head_get_current_protection(head, props));
- drmModeFreeObjectProperties(props);
-
- return 0;
-}
-
-static void
-drm_head_log_info(struct drm_head *head, const char *msg)
-{
- if (head->base.connected) {
- weston_log("DRM: head '%s' %s, connector %d is connected, "
- "EDID make '%s', model '%s', serial '%s'\n",
- head->base.name, msg, head->connector_id,
- head->base.make, head->base.model,
- head->base.serial_number ?: "");
- } else {
- weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
- head->base.name, msg, head->connector_id);
- }
-}
-
-/** Update connector and monitor information
- *
- * @param head The head to update.
- *
- * Re-reads the DRM property lists for the connector and updates monitor
- * information and connection status. This may schedule a heads changed call
- * to the user.
- */
-static void
-drm_head_update_info(struct drm_head *head)
-{
- drmModeConnector *connector;
-
- connector = drmModeGetConnector(head->backend->drm.fd,
- head->connector_id);
- if (!connector) {
- weston_log("DRM: getting connector info for '%s' failed.\n",
- head->base.name);
- return;
- }
-
- if (drm_head_assign_connector_info(head, connector) < 0)
- drmModeFreeConnector(connector);
-
- if (head->base.device_changed)
- drm_head_log_info(head, "updated");
-}
-
-/**
- * Create a Weston head for a connector
- *
- * Given a DRM connector, create a matching drm_head structure and add it
- * to Weston's head list.
- *
- * @param backend Weston backend structure
- * @param connector_id DRM connector ID for the head
- * @param drm_device udev device pointer
- * @returns The new head, or NULL on failure.
- */
-static struct drm_head *
-drm_head_create(struct drm_backend *backend, uint32_t connector_id,
- struct udev_device *drm_device)
-{
- struct drm_head *head;
- drmModeConnector *connector;
- char *name;
-
- head = zalloc(sizeof *head);
- if (!head)
- return NULL;
-
- connector = drmModeGetConnector(backend->drm.fd, connector_id);
- if (!connector)
- goto err_alloc;
-
- name = make_connector_name(connector);
- if (!name)
- goto err_alloc;
-
- weston_head_init(&head->base, name);
- free(name);
-
- head->connector_id = connector_id;
- head->backend = backend;
-
- head->backlight = backlight_init(drm_device, connector->connector_type);
-
- if (drm_head_assign_connector_info(head, connector) < 0)
- goto err_init;
-
- if (head->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
- head->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
- weston_head_set_internal(&head->base);
-
- if (drm_head_read_current_setup(head, backend) < 0) {
- weston_log("Failed to retrieve current mode from connector %d.\n",
- head->connector_id);
- /* Not fatal. */
- }
-
- weston_compositor_add_head(backend->compositor, &head->base);
- drm_head_log_info(head, "found");
-
- return head;
-
-err_init:
- weston_head_release(&head->base);
-
-err_alloc:
- if (connector)
- drmModeFreeConnector(connector);
-
- free(head);
-
- return NULL;
-}
-
-static void
-drm_head_destroy(struct drm_head *head)
-{
- weston_head_release(&head->base);
-
- drm_property_info_free(head->props_conn, WDRM_CONNECTOR__COUNT);
- drmModeFreeConnector(head->connector);
-
- if (head->backlight)
- backlight_destroy(head->backlight);
-
- free(head);
-}
-
-/**
- * Create a Weston output structure
- *
- * Create an "empty" drm_output. This is the implementation of
- * weston_backend::create_output.
- *
- * Creating an output is usually followed by drm_output_attach_head()
- * and drm_output_enable() to make use of it.
- *
- * @param compositor The compositor instance.
- * @param name Name for the new output.
- * @returns The output, or NULL on failure.
- */
-static struct weston_output *
-drm_output_create(struct weston_compositor *compositor, const char *name)
-{
- struct drm_backend *b = to_drm_backend(compositor);
- struct drm_output *output;
-
- output = zalloc(sizeof *output);
- if (output == NULL)
- return NULL;
-
- output->backend = b;
-#ifdef BUILD_DRM_GBM
- output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
-#endif
-
- weston_output_init(&output->base, compositor, name);
-
- output->base.enable = drm_output_enable;
- output->base.destroy = drm_output_destroy;
- output->base.disable = drm_output_disable;
- output->base.attach_head = drm_output_attach_head;
- output->base.detach_head = drm_output_detach_head;
-
- output->destroy_pending = false;
- output->disable_pending = false;
-
- output->state_cur = drm_output_state_alloc(output, NULL);
-
- weston_compositor_add_pending_output(&output->base, b->compositor);
-
- return &output->base;
-}
-
-static int
-drm_backend_create_heads(struct drm_backend *b, struct udev_device *drm_device)
-{
- struct drm_head *head;
- drmModeRes *resources;
- int i;
-
- resources = drmModeGetResources(b->drm.fd);
- if (!resources) {
- weston_log("drmModeGetResources failed\n");
- return -1;
- }
-
- b->min_width = resources->min_width;
- b->max_width = resources->max_width;
- b->min_height = resources->min_height;
- b->max_height = resources->max_height;
-
- for (i = 0; i < resources->count_connectors; i++) {
- uint32_t connector_id = resources->connectors[i];
-
- head = drm_head_create(b, connector_id, drm_device);
- if (!head) {
- weston_log("DRM: failed to create head for connector %d.\n",
- connector_id);
- }
- }
-
- drm_backend_update_unused_outputs(b, resources);
-
- drmModeFreeResources(resources);
-
- return 0;
-}
-
-static void
-drm_backend_update_heads(struct drm_backend *b, struct udev_device *drm_device)
-{
- drmModeRes *resources;
- struct weston_head *base, *next;
- struct drm_head *head;
- int i;
-
- resources = drmModeGetResources(b->drm.fd);
- if (!resources) {
- weston_log("drmModeGetResources failed\n");
- return;
- }
-
- /* collect new connectors that have appeared, e.g. MST */
- for (i = 0; i < resources->count_connectors; i++) {
- uint32_t connector_id = resources->connectors[i];
-
- head = drm_head_find_by_connector(b, connector_id);
- if (head) {
- drm_head_update_info(head);
- } else {
- head = drm_head_create(b, connector_id, drm_device);
- if (!head)
- weston_log("DRM: failed to create head for hot-added connector %d.\n",
- connector_id);
- }
- }
-
- /* Remove connectors that have disappeared. */
- wl_list_for_each_safe(base, next,
- &b->compositor->head_list, compositor_link) {
- bool removed = true;
-
- head = to_drm_head(base);
-
- for (i = 0; i < resources->count_connectors; i++) {
- if (resources->connectors[i] == head->connector_id) {
- removed = false;
- break;
- }
- }
-
- if (!removed)
- continue;
-
- weston_log("DRM: head '%s' (connector %d) disappeared.\n",
- head->base.name, head->connector_id);
- drm_head_destroy(head);
- }
-
- drm_backend_update_unused_outputs(b, resources);
-
- drmModeFreeResources(resources);
-}
-
-static enum wdrm_connector_property
-drm_head_find_property_by_id(struct drm_head *head, uint32_t property_id)
-{
- int i;
- enum wdrm_connector_property prop = WDRM_CONNECTOR__COUNT;
-
- if (!head || !property_id)
- return WDRM_CONNECTOR__COUNT;
-
- for (i = 0; i < WDRM_CONNECTOR__COUNT; i++)
- if (head->props_conn[i].prop_id == property_id) {
- prop = (enum wdrm_connector_property) i;
- break;
- }
- return prop;
-}
-
-static void
-drm_backend_update_conn_props(struct drm_backend *b,
- uint32_t connector_id,
- uint32_t property_id)
-{
- struct drm_head *head;
- enum wdrm_connector_property conn_prop;
- drmModeObjectProperties *props;
-
- head = drm_head_find_by_connector(b, connector_id);
- if (!head) {
- weston_log("DRM: failed to find head for connector id: %d.\n",
- connector_id);
- return;
- }
-
- conn_prop = drm_head_find_property_by_id(head, property_id);
- if (conn_prop >= WDRM_CONNECTOR__COUNT)
- return;
-
- props = drmModeObjectGetProperties(b->drm.fd,
- connector_id,
- DRM_MODE_OBJECT_CONNECTOR);
- if (!props) {
- weston_log("Error: failed to get connector '%s' properties\n",
- head->base.name);
- return;
- }
- if (conn_prop == WDRM_CONNECTOR_CONTENT_PROTECTION) {
- weston_head_set_content_protection_status(&head->base,
- drm_head_get_current_protection(head, props));
- }
- drmModeFreeObjectProperties(props);
-}
-
-static int
-udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
-{
- const char *sysnum;
- const char *val;
-
- sysnum = udev_device_get_sysnum(device);
- if (!sysnum || atoi(sysnum) != b->drm.id)
- return 0;
-
- val = udev_device_get_property_value(device, "HOTPLUG");
- if (!val)
- return 0;
-
- return strcmp(val, "1") == 0;
-}
-
-static int
-udev_event_is_conn_prop_change(struct drm_backend *b,
- struct udev_device *device,
- uint32_t *connector_id,
- uint32_t *property_id)
-
-{
- const char *val;
- int id;
-
- val = udev_device_get_property_value(device, "CONNECTOR");
- if (!val || !safe_strtoint(val, &id))
- return 0;
- else
- *connector_id = id;
-
- val = udev_device_get_property_value(device, "PROPERTY");
- if (!val || !safe_strtoint(val, &id))
- return 0;
- else
- *property_id = id;
-
- return 1;
-}
-
-static int
-udev_drm_event(int fd, uint32_t mask, void *data)
-{
- struct drm_backend *b = data;
- struct udev_device *event;
- uint32_t conn_id, prop_id;
-
- event = udev_monitor_receive_device(b->udev_monitor);
-
- if (udev_event_is_hotplug(b, event)) {
- if (udev_event_is_conn_prop_change(b, event, &conn_id, &prop_id))
- drm_backend_update_conn_props(b, conn_id, prop_id);
- else
- drm_backend_update_heads(b, event);
- }
-
- udev_device_unref(event);
-
- return 1;
-}
-
-static void
-drm_destroy(struct weston_compositor *ec)
-{
- struct drm_backend *b = to_drm_backend(ec);
- struct weston_head *base, *next;
-
- udev_input_destroy(&b->input);
-
- wl_event_source_remove(b->udev_drm_source);
- wl_event_source_remove(b->drm_source);
-
- b->shutting_down = true;
-
- destroy_sprites(b);
-
- weston_compositor_log_scope_destroy(b->debug);
- b->debug = NULL;
- weston_compositor_shutdown(ec);
-
- wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
- drm_head_destroy(to_drm_head(base));
-
-#ifdef BUILD_DRM_GBM
- if (b->gbm)
- gbm_device_destroy(b->gbm);
-#endif
-
- udev_monitor_unref(b->udev_monitor);
- udev_unref(b->udev);
-
- weston_launcher_destroy(ec->launcher);
-
- wl_array_release(&b->unused_crtcs);
-
- close(b->drm.fd);
- free(b->drm.filename);
- free(b);
-}
-
-static void
-session_notify(struct wl_listener *listener, void *data)
-{
- struct weston_compositor *compositor = data;
- struct drm_backend *b = to_drm_backend(compositor);
- struct drm_plane *plane;
- struct drm_output *output;
-
- if (compositor->session_active) {
- weston_log("activating session\n");
- weston_compositor_wake(compositor);
- weston_compositor_damage_all(compositor);
- b->state_invalid = true;
- udev_input_enable(&b->input);
- } else {
- weston_log("deactivating session\n");
- udev_input_disable(&b->input);
-
- weston_compositor_offscreen(compositor);
-
- /* If we have a repaint scheduled (either from a
- * pending pageflip or the idle handler), make sure we
- * cancel that so we don't try to pageflip when we're
- * vt switched away. The OFFSCREEN state will prevent
- * further attempts at repainting. When we switch
- * back, we schedule a repaint, which will process
- * pending frame callbacks. */
-
- wl_list_for_each(output, &compositor->output_list, base.link) {
- output->base.repaint_needed = false;
- if (output->cursor_plane)
- drmModeSetCursor(b->drm.fd, output->crtc_id,
- 0, 0, 0);
- }
-
- output = container_of(compositor->output_list.next,
- struct drm_output, base.link);
-
- wl_list_for_each(plane, &b->plane_list, link) {
- if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
- continue;
-
- drmModeSetPlane(b->drm.fd,
- plane->plane_id,
- output->crtc_id, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0);
- }
- }
-}
-
-
-/**
- * Handle KMS GPU being added/removed
- *
- * If the device being added/removed is the KMS device, we activate/deactivate
- * the compositor session.
- *
- * @param compositor The compositor instance.
- * @param device The device being added/removed.
- * @param added Whether the device is being added (or removed)
- */
-static void
-drm_device_changed(struct weston_compositor *compositor,
- dev_t device, bool added)
-{
- struct drm_backend *b = to_drm_backend(compositor);
-
- if (b->drm.fd < 0 || b->drm.devnum != device ||
- compositor->session_active == added)
- return;
-
- compositor->session_active = added;
- wl_signal_emit(&compositor->session_signal, compositor);
-}
-
-/**
- * Determines whether or not a device is capable of modesetting. If successful,
- * sets b->drm.fd and b->drm.filename to the opened device.
- */
-static bool
-drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
-{
- const char *filename = udev_device_get_devnode(device);
- const char *sysnum = udev_device_get_sysnum(device);
- dev_t devnum = udev_device_get_devnum(device);
- drmModeRes *res;
- int id = -1, fd;
-
- if (!filename)
- return false;
-
- fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
- if (fd < 0)
- return false;
-
- res = drmModeGetResources(fd);
- if (!res)
- goto out_fd;
-
- if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
- res->count_encoders <= 0)
- goto out_res;
-
- if (sysnum)
- id = atoi(sysnum);
- if (!sysnum || id < 0) {
- weston_log("couldn't get sysnum for device %s\n", filename);
- goto out_res;
- }
-
- /* We can be called successfully on multiple devices; if we have,
- * clean up old entries. */
- if (b->drm.fd >= 0)
- weston_launcher_close(b->compositor->launcher, b->drm.fd);
- free(b->drm.filename);
-
- b->drm.fd = fd;
- b->drm.id = id;
- b->drm.filename = strdup(filename);
- b->drm.devnum = devnum;
-
- drmModeFreeResources(res);
-
- return true;
-
-out_res:
- drmModeFreeResources(res);
-out_fd:
- weston_launcher_close(b->compositor->launcher, fd);
- return false;
-}
-
-/*
- * Find primary GPU
- * Some systems may have multiple DRM devices attached to a single seat. This
- * function loops over all devices and tries to find a PCI device with the
- * boot_vga sysfs attribute set to 1.
- * If no such device is found, the first DRM device reported by udev is used.
- * Devices are also vetted to make sure they are are capable of modesetting,
- * rather than pure render nodes (GPU with no display), or pure
- * memory-allocation devices (VGEM).
- */
-static struct udev_device*
-find_primary_gpu(struct drm_backend *b, const char *seat)
-{
- struct udev_enumerate *e;
- struct udev_list_entry *entry;
- const char *path, *device_seat, *id;
- struct udev_device *device, *drm_device, *pci;
-
- e = udev_enumerate_new(b->udev);
- udev_enumerate_add_match_subsystem(e, "drm");
- udev_enumerate_add_match_sysname(e, "card[0-9]*");
-
- udev_enumerate_scan_devices(e);
- drm_device = NULL;
- udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
- bool is_boot_vga = false;
-
- path = udev_list_entry_get_name(entry);
- device = udev_device_new_from_syspath(b->udev, path);
- if (!device)
- continue;
- device_seat = udev_device_get_property_value(device, "ID_SEAT");
- if (!device_seat)
- device_seat = default_seat;
- if (strcmp(device_seat, seat)) {
- udev_device_unref(device);
- continue;
- }
-
- pci = udev_device_get_parent_with_subsystem_devtype(device,
- "pci", NULL);
- if (pci) {
- id = udev_device_get_sysattr_value(pci, "boot_vga");
- if (id && !strcmp(id, "1"))
- is_boot_vga = true;
- }
-
- /* If we already have a modesetting-capable device, and this
- * device isn't our boot-VGA device, we aren't going to use
- * it. */
- if (!is_boot_vga && drm_device) {
- udev_device_unref(device);
- continue;
- }
-
- /* Make sure this device is actually capable of modesetting;
- * if this call succeeds, b->drm.{fd,filename} will be set,
- * and any old values freed. */
- if (!drm_device_is_kms(b, device)) {
- udev_device_unref(device);
- continue;
- }
-
- /* There can only be one boot_vga device, and we try to use it
- * at all costs. */
- if (is_boot_vga) {
- if (drm_device)
- udev_device_unref(drm_device);
- drm_device = device;
- break;
- }
-
- /* Per the (!is_boot_vga && drm_device) test above, we only
- * trump existing saved devices with boot-VGA devices, so if
- * we end up here, this must be the first device we've seen. */
- assert(!drm_device);
- drm_device = device;
- }
-
- /* If we're returning a device to use, we must have an open FD for
- * it. */
- assert(!!drm_device == (b->drm.fd >= 0));
-
- udev_enumerate_unref(e);
- return drm_device;
-}
-
-static struct udev_device *
-open_specific_drm_device(struct drm_backend *b, const char *name)
-{
- struct udev_device *device;
-
- device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
- if (!device) {
- weston_log("ERROR: could not open DRM device '%s'\n", name);
- return NULL;
- }
-
- if (!drm_device_is_kms(b, device)) {
- udev_device_unref(device);
- weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
- return NULL;
- }
-
- /* If we're returning a device to use, we must have an open FD for
- * it. */
- assert(b->drm.fd >= 0);
-
- return device;
-}
-
-static void
-planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
- uint32_t key, void *data)
-{
- struct drm_backend *b = data;
-
- switch (key) {
- case KEY_C:
- b->cursors_are_broken ^= true;
- break;
- case KEY_V:
- /* We don't support overlay-plane usage with legacy KMS. */
- if (b->atomic_modeset)
- b->sprites_are_broken ^= true;
- break;
- default:
- break;
- }
-}
-
-#ifdef BUILD_VAAPI_RECORDER
-static void
-recorder_destroy(struct drm_output *output)
-{
- vaapi_recorder_destroy(output->recorder);
- output->recorder = NULL;
-
- weston_output_disable_planes_decr(&output->base);
-
- wl_list_remove(&output->recorder_frame_listener.link);
- weston_log("[libva recorder] done\n");
-}
-
-static void
-recorder_frame_notify(struct wl_listener *listener, void *data)
-{
- struct drm_output *output;
- struct drm_backend *b;
- int fd, ret;
-
- output = container_of(listener, struct drm_output,
- recorder_frame_listener);
- b = to_drm_backend(output->base.compositor);
-
- if (!output->recorder)
- return;
-
- ret = drmPrimeHandleToFD(b->drm.fd,
- output->scanout_plane->state_cur->fb->handles[0],
- DRM_CLOEXEC, &fd);
- if (ret) {
- weston_log("[libva recorder] "
- "failed to create prime fd for front buffer\n");
- return;
- }
-
- ret = vaapi_recorder_frame(output->recorder, fd,
- output->scanout_plane->state_cur->fb->strides[0]);
- if (ret < 0) {
- weston_log("[libva recorder] aborted: %s\n", strerror(errno));
- recorder_destroy(output);
- }
-}
-
-static void *
-create_recorder(struct drm_backend *b, int width, int height,
- const char *filename)
-{
- int fd;
- drm_magic_t magic;
-
- fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
- if (fd < 0)
- return NULL;
-
- drmGetMagic(fd, &magic);
- drmAuthMagic(b->drm.fd, magic);
-
- return vaapi_recorder_create(fd, width, height, filename);
-}
-
-static void
-recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
- uint32_t key, void *data)
-{
- struct drm_backend *b = data;
- struct drm_output *output;
- int width, height;
-
- output = container_of(b->compositor->output_list.next,
- struct drm_output, base.link);
-
- if (!output->recorder) {
- if (output->gbm_format != DRM_FORMAT_XRGB8888) {
- weston_log("failed to start vaapi recorder: "
- "output format not supported\n");
- return;
- }
-
- width = output->base.current_mode->width;
- height = output->base.current_mode->height;
-
- output->recorder =
- create_recorder(b, width, height, "capture.h264");
- if (!output->recorder) {
- weston_log("failed to create vaapi recorder\n");
- return;
- }
-
- weston_output_disable_planes_incr(&output->base);
-
- output->recorder_frame_listener.notify = recorder_frame_notify;
- wl_signal_add(&output->base.frame_signal,
- &output->recorder_frame_listener);
-
- weston_output_schedule_repaint(&output->base);
-
- weston_log("[libva recorder] initialized\n");
- } else {
- recorder_destroy(output);
- }
-}
-#else
-static void
-recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
- uint32_t key, void *data)
-{
- weston_log("Compiled without libva support\n");
-}
-#endif
-
-
-static const struct weston_drm_output_api api = {
- drm_output_set_mode,
- drm_output_set_gbm_format,
- drm_output_set_seat,
-};
-
-static struct drm_backend *
-drm_backend_create(struct weston_compositor *compositor,
- struct weston_drm_backend_config *config)
-{
- struct drm_backend *b;
- struct udev_device *drm_device;
- struct wl_event_loop *loop;
- const char *seat_id = default_seat;
- const char *session_seat;
- int ret;
-
- session_seat = getenv("XDG_SEAT");
- if (session_seat)
- seat_id = session_seat;
-
- if (config->seat_id)
- seat_id = config->seat_id;
-
- weston_log("initializing drm backend\n");
-
- b = zalloc(sizeof *b);
- if (b == NULL)
- return NULL;
-
- b->state_invalid = true;
- b->drm.fd = -1;
- wl_array_init(&b->unused_crtcs);
-
- b->compositor = compositor;
- b->use_pixman = config->use_pixman;
- b->pageflip_timeout = config->pageflip_timeout;
- b->use_pixman_shadow = config->use_pixman_shadow;
-
- b->debug = weston_compositor_add_log_scope(compositor->weston_log_ctx,
- "drm-backend",
- "Debug messages from DRM/KMS backend\n",
- NULL, NULL, NULL);
-
- compositor->backend = &b->base;
-
- if (parse_gbm_format(config->gbm_format, DRM_FORMAT_XRGB8888, &b->gbm_format) < 0)
- goto err_compositor;
-
- /* Check if we run drm-backend using weston-launch */
- compositor->launcher = weston_launcher_connect(compositor, config->tty,
- seat_id, true);
- if (compositor->launcher == NULL) {
- weston_log("fatal: drm backend should be run using "
- "weston-launch binary, or your system should "
- "provide the logind D-Bus API.\n");
- goto err_compositor;
- }
-
- b->udev = udev_new();
- if (b->udev == NULL) {
- weston_log("failed to initialize udev context\n");
- goto err_launcher;
- }
-
- b->session_listener.notify = session_notify;
- wl_signal_add(&compositor->session_signal, &b->session_listener);
-
- if (config->specific_device)
- drm_device = open_specific_drm_device(b, config->specific_device);
- else
- drm_device = find_primary_gpu(b, seat_id);
- if (drm_device == NULL) {
- weston_log("no drm device found\n");
- goto err_udev;
- }
-
- if (init_kms_caps(b) < 0) {
- weston_log("failed to initialize kms\n");
- goto err_udev_dev;
- }
-
- if (b->use_pixman) {
- if (init_pixman(b) < 0) {
- weston_log("failed to initialize pixman renderer\n");
- goto err_udev_dev;
- }
- } else {
- if (init_egl(b) < 0) {
- weston_log("failed to initialize egl\n");
- goto err_udev_dev;
- }
- }
-
- b->base.destroy = drm_destroy;
- b->base.repaint_begin = drm_repaint_begin;
- b->base.repaint_flush = drm_repaint_flush;
- b->base.repaint_cancel = drm_repaint_cancel;
- b->base.create_output = drm_output_create;
- b->base.device_changed = drm_device_changed;
- b->base.can_scanout_dmabuf = drm_can_scanout_dmabuf;
-
- weston_setup_vt_switch_bindings(compositor);
-
- wl_list_init(&b->plane_list);
- create_sprites(b);
-
- if (udev_input_init(&b->input,
- compositor, b->udev, seat_id,
- config->configure_device) < 0) {
- weston_log("failed to create input devices\n");
- goto err_sprite;
- }
-
- if (drm_backend_create_heads(b, drm_device) < 0) {
- weston_log("Failed to create heads for %s\n", b->drm.filename);
- goto err_udev_input;
- }
-
- /* 'compute' faked zpos values in case HW doesn't expose any */
- drm_backend_create_faked_zpos(b);
-
- /* A this point we have some idea of whether or not we have a working
- * cursor plane. */
- if (!b->cursors_are_broken)
- compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
-
- loop = wl_display_get_event_loop(compositor->wl_display);
- b->drm_source =
- wl_event_loop_add_fd(loop, b->drm.fd,
- WL_EVENT_READABLE, on_drm_input, b);
-
- b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
- if (b->udev_monitor == NULL) {
- weston_log("failed to initialize udev monitor\n");
- goto err_drm_source;
- }
- udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
- "drm", NULL);
- b->udev_drm_source =
- wl_event_loop_add_fd(loop,
- udev_monitor_get_fd(b->udev_monitor),
- WL_EVENT_READABLE, udev_drm_event, b);
-
- if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
- weston_log("failed to enable udev-monitor receiving\n");
- goto err_udev_monitor;
- }
-
- udev_device_unref(drm_device);
-
- weston_compositor_add_debug_binding(compositor, KEY_O,
- planes_binding, b);
- weston_compositor_add_debug_binding(compositor, KEY_C,
- planes_binding, b);
- weston_compositor_add_debug_binding(compositor, KEY_V,
- planes_binding, b);
- weston_compositor_add_debug_binding(compositor, KEY_Q,
- recorder_binding, b);
- weston_compositor_add_debug_binding(compositor, KEY_W,
- renderer_switch_binding, b);
-
- if (compositor->renderer->import_dmabuf) {
- if (linux_dmabuf_setup(compositor) < 0)
- weston_log("Error: initializing dmabuf "
- "support failed.\n");
- if (weston_direct_display_setup(compositor) < 0)
- weston_log("Error: initializing direct-display "
- "support failed.\n");
- }
-
- if (compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC) {
- if (linux_explicit_synchronization_setup(compositor) < 0)
- weston_log("Error: initializing explicit "
- " synchronization support failed.\n");
- }
-
- if (b->atomic_modeset)
- if (weston_compositor_enable_content_protection(compositor) < 0)
- weston_log("Error: initializing content-protection "
- "support failed.\n");
-
- ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
- &api, sizeof(api));
-
- if (ret < 0) {
- weston_log("Failed to register output API.\n");
- goto err_udev_monitor;
- }
-
- ret = drm_backend_init_virtual_output_api(compositor);
- if (ret < 0) {
- weston_log("Failed to register virtual output API.\n");
- goto err_udev_monitor;
- }
-
- return b;
-
-err_udev_monitor:
- wl_event_source_remove(b->udev_drm_source);
- udev_monitor_unref(b->udev_monitor);
-err_drm_source:
- wl_event_source_remove(b->drm_source);
-err_udev_input:
- udev_input_destroy(&b->input);
-err_sprite:
-#ifdef BUILD_DRM_GBM
- if (b->gbm)
- gbm_device_destroy(b->gbm);
-#endif
- destroy_sprites(b);
-err_udev_dev:
- udev_device_unref(drm_device);
-err_launcher:
- weston_launcher_destroy(compositor->launcher);
-err_udev:
- udev_unref(b->udev);
-err_compositor:
- weston_compositor_shutdown(compositor);
- free(b);
- return NULL;
-}
-
-static void
-config_init_to_defaults(struct weston_drm_backend_config *config)
-{
- config->use_pixman_shadow = true;
-}
-
-WL_EXPORT int
-weston_backend_init(struct weston_compositor *compositor,
- struct weston_backend_config *config_base)
-{
- struct drm_backend *b;
- struct weston_drm_backend_config config = {{ 0, }};
-
- if (config_base == NULL ||
- config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
- config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
- weston_log("drm backend config structure is invalid\n");
- return -1;
- }
-
- config_init_to_defaults(&config);
- memcpy(&config, config_base, config_base->struct_size);
-
- b = drm_backend_create(compositor, &config);
- if (b == NULL)
- return -1;
-
- return 0;
-}
diff --git a/libweston/backend-drm/fb.c b/libweston/backend-drm/fb.c
deleted file mode 100644
index e7349c4b..00000000
--- a/libweston/backend-drm/fb.c
+++ /dev/null
@@ -1,582 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2011 Intel Corporation
- * Copyright © 2017, 2018 Collabora, Ltd.
- * Copyright © 2017, 2018 General Electric Company
- * Copyright (c) 2018 DisplayLink (UK) Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdint.h>
-
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-#include <drm_fourcc.h>
-
-#include <libweston/libweston.h>
-#include <libweston/backend-drm.h>
-#include <libweston/pixel-formats.h>
-#include <libweston/linux-dmabuf.h>
-#include "shared/helpers.h"
-#include "drm-internal.h"
-#include "linux-dmabuf.h"
-
-static void
-drm_fb_destroy(struct drm_fb *fb)
-{
- if (fb->fb_id != 0)
- drmModeRmFB(fb->fd, fb->fb_id);
- weston_buffer_reference(&fb->buffer_ref, NULL);
- weston_buffer_release_reference(&fb->buffer_release_ref, NULL);
- free(fb);
-}
-
-static void
-drm_fb_destroy_dumb(struct drm_fb *fb)
-{
- struct drm_mode_destroy_dumb destroy_arg;
-
- assert(fb->type == BUFFER_PIXMAN_DUMB);
-
- if (fb->map && fb->size > 0)
- munmap(fb->map, fb->size);
-
- memset(&destroy_arg, 0, sizeof(destroy_arg));
- destroy_arg.handle = fb->handles[0];
- drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
-
- drm_fb_destroy(fb);
-}
-
-static int
-drm_fb_addfb(struct drm_backend *b, struct drm_fb *fb)
-{
- int ret = -EINVAL;
- uint64_t mods[4] = { };
- size_t i;
-
- /* If we have a modifier set, we must only use the WithModifiers
- * entrypoint; we cannot import it through legacy ioctls. */
- if (b->fb_modifiers && fb->modifier != DRM_FORMAT_MOD_INVALID) {
- /* KMS demands that if a modifier is set, it must be the same
- * for all planes. */
- for (i = 0; i < ARRAY_LENGTH(mods) && fb->handles[i]; i++)
- mods[i] = fb->modifier;
- ret = drmModeAddFB2WithModifiers(fb->fd, fb->width, fb->height,
- fb->format->format,
- fb->handles, fb->strides,
- fb->offsets, mods, &fb->fb_id,
- DRM_MODE_FB_MODIFIERS);
- return ret;
- }
-
- ret = drmModeAddFB2(fb->fd, fb->width, fb->height, fb->format->format,
- fb->handles, fb->strides, fb->offsets, &fb->fb_id,
- 0);
- if (ret == 0)
- return 0;
-
- /* Legacy AddFB can't always infer the format from depth/bpp alone, so
- * check if our format is one of the lucky ones. */
- if (!fb->format->depth || !fb->format->bpp)
- return ret;
-
- /* Cannot fall back to AddFB for multi-planar formats either. */
- if (fb->handles[1] || fb->handles[2] || fb->handles[3])
- return ret;
-
- ret = drmModeAddFB(fb->fd, fb->width, fb->height,
- fb->format->depth, fb->format->bpp,
- fb->strides[0], fb->handles[0], &fb->fb_id);
- return ret;
-}
-
-struct drm_fb *
-drm_fb_create_dumb(struct drm_backend *b, int width, int height,
- uint32_t format)
-{
- struct drm_fb *fb;
- int ret;
-
- struct drm_mode_create_dumb create_arg;
- struct drm_mode_destroy_dumb destroy_arg;
- struct drm_mode_map_dumb map_arg;
-
- fb = zalloc(sizeof *fb);
- if (!fb)
- return NULL;
- fb->refcnt = 1;
-
- fb->format = pixel_format_get_info(format);
- if (!fb->format) {
- weston_log("failed to look up format 0x%lx\n",
- (unsigned long) format);
- goto err_fb;
- }
-
- if (!fb->format->depth || !fb->format->bpp) {
- weston_log("format 0x%lx is not compatible with dumb buffers\n",
- (unsigned long) format);
- goto err_fb;
- }
-
- memset(&create_arg, 0, sizeof create_arg);
- create_arg.bpp = fb->format->bpp;
- create_arg.width = width;
- create_arg.height = height;
-
- ret = drmIoctl(b->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
- if (ret)
- goto err_fb;
-
- fb->type = BUFFER_PIXMAN_DUMB;
- fb->modifier = DRM_FORMAT_MOD_INVALID;
- fb->handles[0] = create_arg.handle;
- fb->strides[0] = create_arg.pitch;
- fb->num_planes = 1;
- fb->size = create_arg.size;
- fb->width = width;
- fb->height = height;
- fb->fd = b->drm.fd;
-
- if (drm_fb_addfb(b, fb) != 0) {
- weston_log("failed to create kms fb: %s\n", strerror(errno));
- goto err_bo;
- }
-
- memset(&map_arg, 0, sizeof map_arg);
- map_arg.handle = fb->handles[0];
- ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
- if (ret)
- goto err_add_fb;
-
- fb->map = mmap(NULL, fb->size, PROT_WRITE,
- MAP_SHARED, b->drm.fd, map_arg.offset);
- if (fb->map == MAP_FAILED)
- goto err_add_fb;
-
- return fb;
-
-err_add_fb:
- drmModeRmFB(b->drm.fd, fb->fb_id);
-err_bo:
- memset(&destroy_arg, 0, sizeof(destroy_arg));
- destroy_arg.handle = create_arg.handle;
- drmIoctl(b->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
-err_fb:
- free(fb);
- return NULL;
-}
-
-struct drm_fb *
-drm_fb_ref(struct drm_fb *fb)
-{
- fb->refcnt++;
- return fb;
-}
-
-#ifdef BUILD_DRM_GBM
-static void
-drm_fb_destroy_gbm(struct gbm_bo *bo, void *data)
-{
- struct drm_fb *fb = data;
-
- assert(fb->type == BUFFER_GBM_SURFACE || fb->type == BUFFER_CLIENT ||
- fb->type == BUFFER_CURSOR);
- drm_fb_destroy(fb);
-}
-
-static void
-drm_fb_destroy_dmabuf(struct drm_fb *fb)
-{
- /* We deliberately do not close the GEM handles here; GBM manages
- * their lifetime through the BO. */
- if (fb->bo)
- gbm_bo_destroy(fb->bo);
- drm_fb_destroy(fb);
-}
-
-static struct drm_fb *
-drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
- struct drm_backend *backend, bool is_opaque)
-{
- struct drm_fb *fb;
- struct gbm_import_fd_data import_legacy = {
- .width = dmabuf->attributes.width,
- .height = dmabuf->attributes.height,
- .format = dmabuf->attributes.format,
- .stride = dmabuf->attributes.stride[0],
- .fd = dmabuf->attributes.fd[0],
- };
-#ifdef HAVE_GBM_FD_IMPORT
- struct gbm_import_fd_modifier_data import_mod = {
- .width = dmabuf->attributes.width,
- .height = dmabuf->attributes.height,
- .format = dmabuf->attributes.format,
- .num_fds = dmabuf->attributes.n_planes,
- .modifier = dmabuf->attributes.modifier[0],
- };
-#endif /* HAVE_GBM_FD_IMPORT */
-
- int i;
-
- /* XXX: TODO:
- *
- * Currently the buffer is rejected if any dmabuf attribute
- * flag is set. This keeps us from passing an inverted /
- * interlaced / bottom-first buffer (or any other type that may
- * be added in the future) through to an overlay. Ultimately,
- * these types of buffers should be handled through buffer
- * transforms and not as spot-checks requiring specific
- * knowledge. */
- if (dmabuf->attributes.flags)
- return NULL;
-
- fb = zalloc(sizeof *fb);
- if (fb == NULL)
- return NULL;
-
- fb->refcnt = 1;
- fb->type = BUFFER_DMABUF;
-
-#ifdef HAVE_GBM_FD_IMPORT
- static_assert(ARRAY_LENGTH(import_mod.fds) ==
- ARRAY_LENGTH(dmabuf->attributes.fd),
- "GBM and linux_dmabuf FD size must match");
- static_assert(sizeof(import_mod.fds) == sizeof(dmabuf->attributes.fd),
- "GBM and linux_dmabuf FD size must match");
- memcpy(import_mod.fds, dmabuf->attributes.fd, sizeof(import_mod.fds));
-
- static_assert(ARRAY_LENGTH(import_mod.strides) ==
- ARRAY_LENGTH(dmabuf->attributes.stride),
- "GBM and linux_dmabuf stride size must match");
- static_assert(sizeof(import_mod.strides) ==
- sizeof(dmabuf->attributes.stride),
- "GBM and linux_dmabuf stride size must match");
- memcpy(import_mod.strides, dmabuf->attributes.stride,
- sizeof(import_mod.strides));
-
- static_assert(ARRAY_LENGTH(import_mod.offsets) ==
- ARRAY_LENGTH(dmabuf->attributes.offset),
- "GBM and linux_dmabuf offset size must match");
- static_assert(sizeof(import_mod.offsets) ==
- sizeof(dmabuf->attributes.offset),
- "GBM and linux_dmabuf offset size must match");
- memcpy(import_mod.offsets, dmabuf->attributes.offset,
- sizeof(import_mod.offsets));
-#endif /* NOT HAVE_GBM_FD_IMPORT */
-
- /* The legacy FD-import path does not allow us to supply modifiers,
- * multiple planes, or buffer offsets. */
- if (dmabuf->attributes.modifier[0] != DRM_FORMAT_MOD_INVALID ||
- dmabuf->attributes.n_planes > 1 ||
- dmabuf->attributes.offset[0] > 0) {
-#ifdef HAVE_GBM_FD_IMPORT
- fb->bo = gbm_bo_import(backend->gbm, GBM_BO_IMPORT_FD_MODIFIER,
- &import_mod,
- GBM_BO_USE_SCANOUT);
-#else /* NOT HAVE_GBM_FD_IMPORT */
- drm_debug(backend, "\t\t\t[dmabuf] Unsupported use of modifiers.\n");
- goto err_free;
-#endif /* NOT HAVE_GBM_FD_IMPORT */
- } else {
- fb->bo = gbm_bo_import(backend->gbm, GBM_BO_IMPORT_FD,
- &import_legacy,
- GBM_BO_USE_SCANOUT);
- }
-
- if (!fb->bo)
- goto err_free;
-
- fb->width = dmabuf->attributes.width;
- fb->height = dmabuf->attributes.height;
- fb->modifier = dmabuf->attributes.modifier[0];
- fb->size = 0;
- fb->fd = backend->drm.fd;
-
- static_assert(ARRAY_LENGTH(fb->strides) ==
- ARRAY_LENGTH(dmabuf->attributes.stride),
- "drm_fb and dmabuf stride size must match");
- static_assert(sizeof(fb->strides) == sizeof(dmabuf->attributes.stride),
- "drm_fb and dmabuf stride size must match");
- memcpy(fb->strides, dmabuf->attributes.stride, sizeof(fb->strides));
- static_assert(ARRAY_LENGTH(fb->offsets) ==
- ARRAY_LENGTH(dmabuf->attributes.offset),
- "drm_fb and dmabuf offset size must match");
- static_assert(sizeof(fb->offsets) == sizeof(dmabuf->attributes.offset),
- "drm_fb and dmabuf offset size must match");
- memcpy(fb->offsets, dmabuf->attributes.offset, sizeof(fb->offsets));
-
- fb->format = pixel_format_get_info(dmabuf->attributes.format);
- if (!fb->format) {
- weston_log("couldn't look up format info for 0x%lx\n",
- (unsigned long) dmabuf->attributes.format);
- goto err_free;
- }
-
- if (is_opaque)
- fb->format = pixel_format_get_opaque_substitute(fb->format);
-
- if (backend->min_width > fb->width ||
- fb->width > backend->max_width ||
- backend->min_height > fb->height ||
- fb->height > backend->max_height) {
- weston_log("bo geometry out of bounds\n");
- goto err_free;
- }
-
-#ifdef HAVE_GBM_MODIFIERS
- fb->num_planes = dmabuf->attributes.n_planes;
- for (i = 0; i < dmabuf->attributes.n_planes; i++) {
- union gbm_bo_handle handle;
-
- handle = gbm_bo_get_handle_for_plane(fb->bo, i);
- if (handle.s32 == -1)
- goto err_free;
- fb->handles[i] = handle.u32;
- }
-#else /* NOT HAVE_GBM_MODIFIERS */
- {
- union gbm_bo_handle handle;
-
- fb->num_planes = 1;
-
- handle = gbm_bo_get_handle(fb->bo);
-
- if (handle.s32 == -1)
- goto err_free;
- fb->handles[0] = handle.u32;
- }
-#endif /* NOT HAVE_GBM_MODIFIERS */
-
-
- if (drm_fb_addfb(backend, fb) != 0)
- goto err_free;
-
- return fb;
-
-err_free:
- drm_fb_destroy_dmabuf(fb);
- return NULL;
-}
-
-struct drm_fb *
-drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
- bool is_opaque, enum drm_fb_type type)
-{
- struct drm_fb *fb = gbm_bo_get_user_data(bo);
-#ifdef HAVE_GBM_MODIFIERS
- int i;
-#endif
-
- if (fb) {
- assert(fb->type == type);
- return drm_fb_ref(fb);
- }
-
- fb = zalloc(sizeof *fb);
- if (fb == NULL)
- return NULL;
-
- fb->type = type;
- fb->refcnt = 1;
- fb->bo = bo;
- fb->fd = backend->drm.fd;
-
- fb->width = gbm_bo_get_width(bo);
- fb->height = gbm_bo_get_height(bo);
- fb->format = pixel_format_get_info(gbm_bo_get_format(bo));
- fb->size = 0;
-
-#ifdef HAVE_GBM_MODIFIERS
- fb->modifier = gbm_bo_get_modifier(bo);
- fb->num_planes = gbm_bo_get_plane_count(bo);
- for (i = 0; i < fb->num_planes; i++) {
- fb->strides[i] = gbm_bo_get_stride_for_plane(bo, i);
- fb->handles[i] = gbm_bo_get_handle_for_plane(bo, i).u32;
- fb->offsets[i] = gbm_bo_get_offset(bo, i);
- }
-#else
- fb->num_planes = 1;
- fb->strides[0] = gbm_bo_get_stride(bo);
- fb->handles[0] = gbm_bo_get_handle(bo).u32;
- fb->modifier = DRM_FORMAT_MOD_INVALID;
-#endif
-
- if (!fb->format) {
- weston_log("couldn't look up format 0x%lx\n",
- (unsigned long) gbm_bo_get_format(bo));
- goto err_free;
- }
-
- /* We can scanout an ARGB buffer if the surface's opaque region covers
- * the whole output, but we have to use XRGB as the KMS format code. */
- if (is_opaque)
- fb->format = pixel_format_get_opaque_substitute(fb->format);
-
- if (backend->min_width > fb->width ||
- fb->width > backend->max_width ||
- backend->min_height > fb->height ||
- fb->height > backend->max_height) {
- weston_log("bo geometry out of bounds\n");
- goto err_free;
- }
-
- if (drm_fb_addfb(backend, fb) != 0) {
- if (type == BUFFER_GBM_SURFACE)
- weston_log("failed to create kms fb: %s\n",
- strerror(errno));
- goto err_free;
- }
-
- gbm_bo_set_user_data(bo, fb, drm_fb_destroy_gbm);
-
- return fb;
-
-err_free:
- free(fb);
- return NULL;
-}
-
-static void
-drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer,
- struct weston_buffer_release *buffer_release)
-{
- assert(fb->buffer_ref.buffer == NULL);
- assert(fb->type == BUFFER_CLIENT || fb->type == BUFFER_DMABUF);
- weston_buffer_reference(&fb->buffer_ref, buffer);
- weston_buffer_release_reference(&fb->buffer_release_ref,
- buffer_release);
-}
-#endif
-
-void
-drm_fb_unref(struct drm_fb *fb)
-{
- if (!fb)
- return;
-
- assert(fb->refcnt > 0);
- if (--fb->refcnt > 0)
- return;
-
- switch (fb->type) {
- case BUFFER_PIXMAN_DUMB:
- drm_fb_destroy_dumb(fb);
- break;
-#ifdef BUILD_DRM_GBM
- case BUFFER_CURSOR:
- case BUFFER_CLIENT:
- gbm_bo_destroy(fb->bo);
- break;
- case BUFFER_GBM_SURFACE:
- gbm_surface_release_buffer(fb->gbm_surface, fb->bo);
- break;
- case BUFFER_DMABUF:
- drm_fb_destroy_dmabuf(fb);
- break;
-#endif
- default:
- assert(NULL);
- break;
- }
-}
-
-#ifdef BUILD_DRM_GBM
-bool
-drm_can_scanout_dmabuf(struct weston_compositor *ec,
- struct linux_dmabuf_buffer *dmabuf)
-{
- struct drm_fb *fb;
- struct drm_backend *b = to_drm_backend(ec);
- bool ret = false;
-
- fb = drm_fb_get_from_dmabuf(dmabuf, b, true);
- if (fb)
- ret = true;
-
- drm_fb_unref(fb);
- drm_debug(b, "[dmabuf] dmabuf %p, import test %s\n", dmabuf,
- ret ? "succeeded" : "failed");
- return ret;
-}
-
-struct drm_fb *
-drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev)
-{
- struct drm_output *output = state->output;
- struct drm_backend *b = to_drm_backend(output->base.compositor);
- struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
- bool is_opaque = weston_view_is_opaque(ev, &ev->transform.boundingbox);
- struct linux_dmabuf_buffer *dmabuf;
- struct drm_fb *fb;
-
- if (ev->alpha != 1.0f)
- return NULL;
-
- if (!drm_view_transform_supported(ev, &output->base))
- return NULL;
-
- if (ev->surface->protection_mode == WESTON_SURFACE_PROTECTION_MODE_ENFORCED &&
- ev->surface->desired_protection > output->base.current_protection)
- return NULL;
-
- if (!buffer)
- return NULL;
-
- if (wl_shm_buffer_get(buffer->resource))
- return NULL;
-
- /* GBM is used for dmabuf import as well as from client wl_buffer. */
- if (!b->gbm)
- return NULL;
-
- dmabuf = linux_dmabuf_buffer_get(buffer->resource);
- if (dmabuf) {
- fb = drm_fb_get_from_dmabuf(dmabuf, b, is_opaque);
- if (!fb)
- return NULL;
- } else {
- struct gbm_bo *bo;
-
- bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
- buffer->resource, GBM_BO_USE_SCANOUT);
- if (!bo)
- return NULL;
-
- fb = drm_fb_get_from_bo(bo, b, is_opaque, BUFFER_CLIENT);
- if (!fb) {
- gbm_bo_destroy(bo);
- return NULL;
- }
- }
-
- drm_debug(b, "\t\t\t[view] view %p format: %s\n",
- ev, fb->format->drm_format_name);
- drm_fb_set_buffer(fb, buffer,
- ev->surface->buffer_release_ref.buffer_release);
- return fb;
-}
-#endif
diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c
deleted file mode 100644
index 192435c7..00000000
--- a/libweston/backend-drm/kms.c
+++ /dev/null
@@ -1,1525 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2011 Intel Corporation
- * Copyright © 2017, 2018 Collabora, Ltd.
- * Copyright © 2017, 2018 General Electric Company
- * Copyright (c) 2018 DisplayLink (UK) Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdint.h>
-
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-#include <drm_fourcc.h>
-
-#include <libweston/libweston.h>
-#include <libweston/backend-drm.h>
-#include "shared/helpers.h"
-#include "drm-internal.h"
-#include "pixel-formats.h"
-#include "presentation-time-server-protocol.h"
-
-#ifndef DRM_FORMAT_MOD_LINEAR
-#define DRM_FORMAT_MOD_LINEAR 0
-#endif
-
-struct drm_property_enum_info plane_type_enums[] = {
- [WDRM_PLANE_TYPE_PRIMARY] = {
- .name = "Primary",
- },
- [WDRM_PLANE_TYPE_OVERLAY] = {
- .name = "Overlay",
- },
- [WDRM_PLANE_TYPE_CURSOR] = {
- .name = "Cursor",
- },
-};
-
-const struct drm_property_info plane_props[] = {
- [WDRM_PLANE_TYPE] = {
- .name = "type",
- .enum_values = plane_type_enums,
- .num_enum_values = WDRM_PLANE_TYPE__COUNT,
- },
- [WDRM_PLANE_SRC_X] = { .name = "SRC_X", },
- [WDRM_PLANE_SRC_Y] = { .name = "SRC_Y", },
- [WDRM_PLANE_SRC_W] = { .name = "SRC_W", },
- [WDRM_PLANE_SRC_H] = { .name = "SRC_H", },
- [WDRM_PLANE_CRTC_X] = { .name = "CRTC_X", },
- [WDRM_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
- [WDRM_PLANE_CRTC_W] = { .name = "CRTC_W", },
- [WDRM_PLANE_CRTC_H] = { .name = "CRTC_H", },
- [WDRM_PLANE_FB_ID] = { .name = "FB_ID", },
- [WDRM_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
- [WDRM_PLANE_IN_FORMATS] = { .name = "IN_FORMATS" },
- [WDRM_PLANE_IN_FENCE_FD] = { .name = "IN_FENCE_FD" },
- [WDRM_PLANE_FB_DAMAGE_CLIPS] = { .name = "FB_DAMAGE_CLIPS" },
- [WDRM_PLANE_ZPOS] = { .name = "zpos" },
-};
-
-struct drm_property_enum_info dpms_state_enums[] = {
- [WDRM_DPMS_STATE_OFF] = {
- .name = "Off",
- },
- [WDRM_DPMS_STATE_ON] = {
- .name = "On",
- },
- [WDRM_DPMS_STATE_STANDBY] = {
- .name = "Standby",
- },
- [WDRM_DPMS_STATE_SUSPEND] = {
- .name = "Suspend",
- },
-};
-
-struct drm_property_enum_info content_protection_enums[] = {
- [WDRM_CONTENT_PROTECTION_UNDESIRED] = {
- .name = "Undesired",
- },
- [WDRM_CONTENT_PROTECTION_DESIRED] = {
- .name = "Desired",
- },
- [WDRM_CONTENT_PROTECTION_ENABLED] = {
- .name = "Enabled",
- },
-};
-
-struct drm_property_enum_info hdcp_content_type_enums[] = {
- [WDRM_HDCP_CONTENT_TYPE0] = {
- .name = "HDCP Type0",
- },
- [WDRM_HDCP_CONTENT_TYPE1] = {
- .name = "HDCP Type1",
- },
-};
-
-const struct drm_property_info connector_props[] = {
- [WDRM_CONNECTOR_EDID] = { .name = "EDID" },
- [WDRM_CONNECTOR_DPMS] = {
- .name = "DPMS",
- .enum_values = dpms_state_enums,
- .num_enum_values = WDRM_DPMS_STATE__COUNT,
- },
- [WDRM_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
- [WDRM_CONNECTOR_NON_DESKTOP] = { .name = "non-desktop", },
- [WDRM_CONNECTOR_CONTENT_PROTECTION] = {
- .name = "Content Protection",
- .enum_values = content_protection_enums,
- .num_enum_values = WDRM_CONTENT_PROTECTION__COUNT,
- },
- [WDRM_CONNECTOR_HDCP_CONTENT_TYPE] = {
- .name = "HDCP Content Type",
- .enum_values = hdcp_content_type_enums,
- .num_enum_values = WDRM_HDCP_CONTENT_TYPE__COUNT,
- },
-};
-
-const struct drm_property_info crtc_props[] = {
- [WDRM_CRTC_MODE_ID] = { .name = "MODE_ID", },
- [WDRM_CRTC_ACTIVE] = { .name = "ACTIVE", },
-};
-
-
-/**
- * Mode for drm_pending_state_apply and co.
- */
-enum drm_state_apply_mode {
- DRM_STATE_APPLY_SYNC, /**< state fully processed */
- DRM_STATE_APPLY_ASYNC, /**< state pending event delivery */
- DRM_STATE_TEST_ONLY, /**< test if the state can be applied */
-};
-
-/**
- * Get the current value of a KMS property
- *
- * Given a drmModeObjectGetProperties return, as well as the drm_property_info
- * for the target property, return the current value of that property,
- * with an optional default. If the property is a KMS enum type, the return
- * value will be translated into the appropriate internal enum.
- *
- * If the property is not present, the default value will be returned.
- *
- * @param info Internal structure for property to look up
- * @param props Raw KMS properties for the target object
- * @param def Value to return if property is not found
- */
-uint64_t
-drm_property_get_value(struct drm_property_info *info,
- const drmModeObjectProperties *props,
- uint64_t def)
-{
- unsigned int i;
-
- if (info->prop_id == 0)
- return def;
-
- for (i = 0; i < props->count_props; i++) {
- unsigned int j;
-
- if (props->props[i] != info->prop_id)
- continue;
-
- /* Simple (non-enum) types can return the value directly */
- if (info->num_enum_values == 0)
- return props->prop_values[i];
-
- /* Map from raw value to enum value */
- for (j = 0; j < info->num_enum_values; j++) {
- if (!info->enum_values[j].valid)
- continue;
- if (info->enum_values[j].value != props->prop_values[i])
- continue;
-
- return j;
- }
-
- /* We don't have a mapping for this enum; return default. */
- break;
- }
-
- return def;
-}
-
-/**
- * Get the current range values of a KMS property
- *
- * Given a drmModeObjectGetProperties return, as well as the drm_property_info
- * for the target property, return the current range values of that property,
- *
- * If the property is not present, or there's no it is not a prop range then
- * NULL will be returned.
- *
- * @param info Internal structure for property to look up
- * @param props Raw KMS properties for the target object
- */
-uint64_t *
-drm_property_get_range_values(struct drm_property_info *info,
- const drmModeObjectProperties *props)
-{
- unsigned int i;
-
- if (info->prop_id == 0)
- return NULL;
-
- for (i = 0; i < props->count_props; i++) {
-
- if (props->props[i] != info->prop_id)
- continue;
-
- if (!(info->flags & DRM_MODE_PROP_RANGE) &&
- !(info->flags & DRM_MODE_PROP_SIGNED_RANGE))
- continue;
-
- return info->range_values;
- }
-
- return NULL;
-}
-
-/**
- * Cache DRM property values
- *
- * Update a per-object array of drm_property_info structures, given the
- * DRM properties of the object.
- *
- * Call this every time an object newly appears (note that only connectors
- * can be hotplugged), the first time it is seen, or when its status changes
- * in a way which invalidates the potential property values (currently, the
- * only case for this is connector hotplug).
- *
- * This updates the property IDs and enum values within the drm_property_info
- * array.
- *
- * DRM property enum values are dynamic at runtime; the user must query the
- * property to find out the desired runtime value for a requested string
- * name. Using the 'type' field on planes as an example, there is no single
- * hardcoded constant for primary plane types; instead, the property must be
- * queried at runtime to find the value associated with the string "Primary".
- *
- * This helper queries and caches the enum values, to allow us to use a set
- * of compile-time-constant enums portably across various implementations.
- * The values given in enum_names are searched for, and stored in the
- * same-indexed field of the map array.
- *
- * @param b DRM backend object
- * @param src DRM property info array to source from
- * @param info DRM property info array to copy into
- * @param num_infos Number of entries in the source array
- * @param props DRM object properties for the object
- */
-void
-drm_property_info_populate(struct drm_backend *b,
- const struct drm_property_info *src,
- struct drm_property_info *info,
- unsigned int num_infos,
- drmModeObjectProperties *props)
-{
- drmModePropertyRes *prop;
- unsigned i, j;
-
- for (i = 0; i < num_infos; i++) {
- unsigned int j;
-
- info[i].name = src[i].name;
- info[i].prop_id = 0;
- info[i].num_enum_values = src[i].num_enum_values;
-
- if (src[i].num_enum_values == 0)
- continue;
-
- info[i].enum_values =
- malloc(src[i].num_enum_values *
- sizeof(*info[i].enum_values));
- assert(info[i].enum_values);
- for (j = 0; j < info[i].num_enum_values; j++) {
- info[i].enum_values[j].name = src[i].enum_values[j].name;
- info[i].enum_values[j].valid = false;
- }
- }
-
- for (i = 0; i < props->count_props; i++) {
- unsigned int k;
-
- prop = drmModeGetProperty(b->drm.fd, props->props[i]);
- if (!prop)
- continue;
-
- for (j = 0; j < num_infos; j++) {
- if (!strcmp(prop->name, info[j].name))
- break;
- }
-
- /* We don't know/care about this property. */
- if (j == num_infos) {
-#ifdef DEBUG
- weston_log("DRM debug: unrecognized property %u '%s'\n",
- prop->prop_id, prop->name);
-#endif
- drmModeFreeProperty(prop);
- continue;
- }
-
- if (info[j].num_enum_values == 0 &&
- (prop->flags & DRM_MODE_PROP_ENUM)) {
- weston_log("DRM: expected property %s to not be an"
- " enum, but it is; ignoring\n", prop->name);
- drmModeFreeProperty(prop);
- continue;
- }
-
- info[j].prop_id = props->props[i];
- info[j].flags = prop->flags;
-
- if (prop->flags & DRM_MODE_PROP_RANGE ||
- prop->flags & DRM_MODE_PROP_SIGNED_RANGE) {
- info[j].num_range_values = prop->count_values;
- for (int i = 0; i < prop->count_values; i++)
- info[j].range_values[i] = prop->values[i];
- }
-
-
- if (info[j].num_enum_values == 0) {
- drmModeFreeProperty(prop);
- continue;
- }
-
- if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
- weston_log("DRM: expected property %s to be an enum,"
- " but it is not; ignoring\n", prop->name);
- drmModeFreeProperty(prop);
- info[j].prop_id = 0;
- continue;
- }
-
- for (k = 0; k < info[j].num_enum_values; k++) {
- int l;
-
- for (l = 0; l < prop->count_enums; l++) {
- if (!strcmp(prop->enums[l].name,
- info[j].enum_values[k].name))
- break;
- }
-
- if (l == prop->count_enums)
- continue;
-
- info[j].enum_values[k].valid = true;
- info[j].enum_values[k].value = prop->enums[l].value;
- }
-
- drmModeFreeProperty(prop);
- }
-
-#ifdef DEBUG
- for (i = 0; i < num_infos; i++) {
- if (info[i].prop_id == 0)
- weston_log("DRM warning: property '%s' missing\n",
- info[i].name);
- }
-#endif
-}
-
-/**
- * Free DRM property information
- *
- * Frees all memory associated with a DRM property info array and zeroes
- * it out, leaving it usable for a further drm_property_info_update() or
- * drm_property_info_free().
- *
- * @param info DRM property info array
- * @param num_props Number of entries in array to free
- */
-void
-drm_property_info_free(struct drm_property_info *info, int num_props)
-{
- int i;
-
- for (i = 0; i < num_props; i++)
- free(info[i].enum_values);
-
- memset(info, 0, sizeof(*info) * num_props);
-}
-
-static inline uint32_t *
-formats_ptr(struct drm_format_modifier_blob *blob)
-{
- return (uint32_t *)(((char *)blob) + blob->formats_offset);
-}
-
-static inline struct drm_format_modifier *
-modifiers_ptr(struct drm_format_modifier_blob *blob)
-{
- return (struct drm_format_modifier *)
- (((char *)blob) + blob->modifiers_offset);
-}
-
-/**
- * Populates the plane's formats array, using either the IN_FORMATS blob
- * property (if available), or the plane's format list if not.
- */
-int
-drm_plane_populate_formats(struct drm_plane *plane, const drmModePlane *kplane,
- const drmModeObjectProperties *props)
-{
- unsigned i;
- drmModePropertyBlobRes *blob;
- struct drm_format_modifier_blob *fmt_mod_blob;
- struct drm_format_modifier *blob_modifiers;
- uint32_t *blob_formats;
- uint32_t blob_id;
-
- blob_id = drm_property_get_value(&plane->props[WDRM_PLANE_IN_FORMATS],
- props,
- 0);
- if (blob_id == 0)
- goto fallback;
-
- blob = drmModeGetPropertyBlob(plane->backend->drm.fd, blob_id);
- if (!blob)
- goto fallback;
-
- fmt_mod_blob = blob->data;
- blob_formats = formats_ptr(fmt_mod_blob);
- blob_modifiers = modifiers_ptr(fmt_mod_blob);
-
- if (plane->count_formats != fmt_mod_blob->count_formats) {
- weston_log("DRM backend: format count differs between "
- "plane (%d) and IN_FORMATS (%d)\n",
- plane->count_formats,
- fmt_mod_blob->count_formats);
- weston_log("This represents a kernel bug; Weston is "
- "unable to continue.\n");
- abort();
- }
-
- for (i = 0; i < fmt_mod_blob->count_formats; i++) {
- uint32_t count_modifiers = 0;
- uint64_t *modifiers = NULL;
- unsigned j;
-
- for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
- struct drm_format_modifier *mod = &blob_modifiers[j];
-
- if ((i < mod->offset) || (i > mod->offset + 63))
- continue;
- if (!(mod->formats & (1 << (i - mod->offset))))
- continue;
-
- modifiers = realloc(modifiers,
- (count_modifiers + 1) *
- sizeof(modifiers[0]));
- assert(modifiers);
- modifiers[count_modifiers++] = mod->modifier;
- }
-
- if (count_modifiers == 0) {
- modifiers = malloc(sizeof(*modifiers));
- *modifiers = DRM_FORMAT_MOD_LINEAR;
- count_modifiers = 1;
- }
-
- plane->formats[i].format = blob_formats[i];
- plane->formats[i].modifiers = modifiers;
- plane->formats[i].count_modifiers = count_modifiers;
- }
-
- drmModeFreePropertyBlob(blob);
-
- return 0;
-
-fallback:
- /* No IN_FORMATS blob available, so just use the old. */
- assert(plane->count_formats == kplane->count_formats);
- for (i = 0; i < kplane->count_formats; i++) {
- plane->formats[i].format = kplane->formats[i];
- plane->formats[i].modifiers = malloc(sizeof(uint64_t));
- plane->formats[i].modifiers[0] = DRM_FORMAT_MOD_LINEAR;
- plane->formats[i].count_modifiers = 1;
- }
-
- return 0;
-}
-
-void
-drm_output_set_gamma(struct weston_output *output_base,
- uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
-{
- int rc;
- struct drm_output *output = to_drm_output(output_base);
- struct drm_backend *backend =
- to_drm_backend(output->base.compositor);
-
- /* check */
- if (output_base->gamma_size != size)
- return;
-
- rc = drmModeCrtcSetGamma(backend->drm.fd,
- output->crtc_id,
- size, r, g, b);
- if (rc)
- weston_log("set gamma failed: %s\n", strerror(errno));
-}
-
-/**
- * Mark an output state as current on the output, i.e. it has been
- * submitted to the kernel. The mode argument determines whether this
- * update will be applied synchronously (e.g. when calling drmModeSetCrtc),
- * or asynchronously (in which case we wait for events to complete).
- */
-static void
-drm_output_assign_state(struct drm_output_state *state,
- enum drm_state_apply_mode mode)
-{
- struct drm_output *output = state->output;
- struct drm_backend *b = to_drm_backend(output->base.compositor);
- struct drm_plane_state *plane_state;
- struct drm_head *head;
-
- assert(!output->state_last);
-
- if (mode == DRM_STATE_APPLY_ASYNC)
- output->state_last = output->state_cur;
- else
- drm_output_state_free(output->state_cur);
-
- wl_list_remove(&state->link);
- wl_list_init(&state->link);
- state->pending_state = NULL;
-
- output->state_cur = state;
-
- if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC) {
- drm_debug(b, "\t[CRTC:%u] setting pending flip\n", output->crtc_id);
- output->atomic_complete_pending = true;
- }
-
- if (b->atomic_modeset &&
- state->protection == WESTON_HDCP_DISABLE)
- wl_list_for_each(head, &output->base.head_list, base.output_link)
- weston_head_set_content_protection_status(&head->base,
- WESTON_HDCP_DISABLE);
-
- /* Replace state_cur on each affected plane with the new state, being
- * careful to dispose of orphaned (but only orphaned) previous state.
- * If the previous state is not orphaned (still has an output_state
- * attached), it will be disposed of by freeing the output_state. */
- wl_list_for_each(plane_state, &state->plane_list, link) {
- struct drm_plane *plane = plane_state->plane;
-
- if (plane->state_cur && !plane->state_cur->output_state)
- drm_plane_state_free(plane->state_cur, true);
- plane->state_cur = plane_state;
-
- if (mode != DRM_STATE_APPLY_ASYNC) {
- plane_state->complete = true;
- continue;
- }
-
- if (b->atomic_modeset)
- continue;
-
- assert(plane->type != WDRM_PLANE_TYPE_OVERLAY);
- if (plane->type == WDRM_PLANE_TYPE_PRIMARY)
- output->page_flip_pending = true;
- }
-}
-
-static void
-drm_output_set_cursor(struct drm_output_state *output_state)
-{
- struct drm_output *output = output_state->output;
- struct drm_backend *b = to_drm_backend(output->base.compositor);
- struct drm_plane *plane = output->cursor_plane;
- struct drm_plane_state *state;
- uint32_t handle;
-
- if (!plane)
- return;
-
- state = drm_output_state_get_existing_plane(output_state, plane);
- if (!state)
- return;
-
- if (!state->fb) {
- pixman_region32_fini(&plane->base.damage);
- pixman_region32_init(&plane->base.damage);
- drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
- return;
- }
-
- assert(state->fb == output->gbm_cursor_fb[output->current_cursor]);
- assert(!plane->state_cur->output || plane->state_cur->output == output);
-
- handle = output->gbm_cursor_handle[output->current_cursor];
- if (plane->state_cur->fb != state->fb) {
- if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
- b->cursor_width, b->cursor_height)) {
- weston_log("failed to set cursor: %s\n",
- strerror(errno));
- goto err;
- }
- }
-
- pixman_region32_fini(&plane->base.damage);
- pixman_region32_init(&plane->base.damage);
-
- if (drmModeMoveCursor(b->drm.fd, output->crtc_id,
- state->dest_x, state->dest_y)) {
- weston_log("failed to move cursor: %s\n", strerror(errno));
- goto err;
- }
-
- return;
-
-err:
- b->cursors_are_broken = true;
- drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
-}
-
-static int
-drm_output_apply_state_legacy(struct drm_output_state *state)
-{
- struct drm_output *output = state->output;
- struct drm_backend *backend = to_drm_backend(output->base.compositor);
- struct drm_plane *scanout_plane = output->scanout_plane;
- struct drm_property_info *dpms_prop;
- struct drm_plane_state *scanout_state;
- struct drm_mode *mode;
- struct drm_head *head;
- const struct pixel_format_info *pinfo = NULL;
- uint32_t connectors[MAX_CLONED_CONNECTORS];
- int n_conn = 0;
- struct timespec now;
- int ret = 0;
-
- wl_list_for_each(head, &output->base.head_list, base.output_link) {
- assert(n_conn < MAX_CLONED_CONNECTORS);
- connectors[n_conn++] = head->connector_id;
- }
-
- /* If disable_planes is set then assign_planes() wasn't
- * called for this render, so we could still have a stale
- * cursor plane set up.
- */
- if (output->base.disable_planes) {
- output->cursor_view = NULL;
- if (output->cursor_plane) {
- output->cursor_plane->base.x = INT32_MIN;
- output->cursor_plane->base.y = INT32_MIN;
- }
- }
-
- if (state->dpms != WESTON_DPMS_ON) {
- if (output->cursor_plane) {
- ret = drmModeSetCursor(backend->drm.fd, output->crtc_id,
- 0, 0, 0);
- if (ret)
- weston_log("drmModeSetCursor failed disable: %s\n",
- strerror(errno));
- }
-
- ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id, 0, 0, 0,
- NULL, 0, NULL);
- if (ret)
- weston_log("drmModeSetCrtc failed disabling: %s\n",
- strerror(errno));
-
- drm_output_assign_state(state, DRM_STATE_APPLY_SYNC);
- weston_compositor_read_presentation_clock(output->base.compositor, &now);
- drm_output_update_complete(output,
- WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION,
- now.tv_sec, now.tv_nsec / 1000);
-
- return 0;
- }
-
- scanout_state =
- drm_output_state_get_existing_plane(state, scanout_plane);
-
- /* The legacy SetCrtc API doesn't allow us to do scaling, and the
- * legacy PageFlip API doesn't allow us to do clipping either. */
- assert(scanout_state->src_x == 0);
- assert(scanout_state->src_y == 0);
- assert(scanout_state->src_w ==
- (unsigned) (output->base.current_mode->width << 16));
- assert(scanout_state->src_h ==
- (unsigned) (output->base.current_mode->height << 16));
- assert(scanout_state->dest_x == 0);
- assert(scanout_state->dest_y == 0);
- assert(scanout_state->dest_w == scanout_state->src_w >> 16);
- assert(scanout_state->dest_h == scanout_state->src_h >> 16);
- /* The legacy SetCrtc API doesn't support fences */
- assert(scanout_state->in_fence_fd == -1);
-
- mode = to_drm_mode(output->base.current_mode);
- if (backend->state_invalid ||
- !scanout_plane->state_cur->fb ||
- scanout_plane->state_cur->fb->strides[0] !=
- scanout_state->fb->strides[0]) {
-
- ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
- scanout_state->fb->fb_id,
- 0, 0,
- connectors, n_conn,
- &mode->mode_info);
- if (ret) {
- weston_log("set mode failed: %s\n", strerror(errno));
- goto err;
- }
- }
-
- pinfo = scanout_state->fb->format;
- drm_debug(backend, "\t[CRTC:%u, PLANE:%u] FORMAT: %s\n",
- output->crtc_id, scanout_state->plane->plane_id,
- pinfo ? pinfo->drm_format_name : "UNKNOWN");
-
- if (drmModePageFlip(backend->drm.fd, output->crtc_id,
- scanout_state->fb->fb_id,
- DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
- weston_log("queueing pageflip failed: %s\n", strerror(errno));
- goto err;
- }
-
- assert(!output->page_flip_pending);
-
- if (output->pageflip_timer)
- wl_event_source_timer_update(output->pageflip_timer,
- backend->pageflip_timeout);
-
- drm_output_set_cursor(state);
-
- if (state->dpms != output->state_cur->dpms) {
- wl_list_for_each(head, &output->base.head_list, base.output_link) {
- dpms_prop = &head->props_conn[WDRM_CONNECTOR_DPMS];
- if (dpms_prop->prop_id == 0)
- continue;
-
- ret = drmModeConnectorSetProperty(backend->drm.fd,
- head->connector_id,
- dpms_prop->prop_id,
- state->dpms);
- if (ret) {
- weston_log("DRM: DPMS: failed property set for %s\n",
- head->base.name);
- }
- }
- }
-
- drm_output_assign_state(state, DRM_STATE_APPLY_ASYNC);
-
- return 0;
-
-err:
- output->cursor_view = NULL;
- drm_output_state_free(state);
- return -1;
-}
-
-static int
-crtc_add_prop(drmModeAtomicReq *req, struct drm_output *output,
- enum wdrm_crtc_property prop, uint64_t val)
-{
- struct drm_property_info *info = &output->props_crtc[prop];
- int ret;
-
- if (info->prop_id == 0)
- return -1;
-
- ret = drmModeAtomicAddProperty(req, output->crtc_id, info->prop_id,
- val);
- drm_debug(output->backend, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx)\n",
- (unsigned long) output->crtc_id,
- (unsigned long) info->prop_id, info->name,
- (unsigned long long) val, (unsigned long long) val);
- return (ret <= 0) ? -1 : 0;
-}
-
-static int
-connector_add_prop(drmModeAtomicReq *req, struct drm_head *head,
- enum wdrm_connector_property prop, uint64_t val)
-{
- struct drm_property_info *info = &head->props_conn[prop];
- int ret;
-
- if (info->prop_id == 0)
- return -1;
-
- ret = drmModeAtomicAddProperty(req, head->connector_id,
- info->prop_id, val);
- drm_debug(head->backend, "\t\t\t[CONN:%lu] %lu (%s) -> %llu (0x%llx)\n",
- (unsigned long) head->connector_id,
- (unsigned long) info->prop_id, info->name,
- (unsigned long long) val, (unsigned long long) val);
- return (ret <= 0) ? -1 : 0;
-}
-
-static int
-plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
- enum wdrm_plane_property prop, uint64_t val)
-{
- struct drm_property_info *info = &plane->props[prop];
- int ret;
-
- if (info->prop_id == 0)
- return -1;
-
- ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
- val);
- drm_debug(plane->backend, "\t\t\t[PLANE:%lu] %lu (%s) -> %llu (0x%llx)\n",
- (unsigned long) plane->plane_id,
- (unsigned long) info->prop_id, info->name,
- (unsigned long long) val, (unsigned long long) val);
- return (ret <= 0) ? -1 : 0;
-}
-
-
-static int
-plane_add_damage(drmModeAtomicReq *req, struct drm_backend *backend,
- struct drm_plane_state *plane_state)
-{
- struct drm_plane *plane = plane_state->plane;
- struct drm_property_info *info =
- &plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
- pixman_box32_t *rects;
- uint32_t blob_id;
- int n_rects;
- int ret;
-
- if (!pixman_region32_not_empty(&plane_state->damage))
- return 0;
-
- /*
- * If a plane doesn't support fb damage blob property, kernel will
- * perform full plane update.
- */
- if (info->prop_id == 0)
- return 0;
-
- rects = pixman_region32_rectangles(&plane_state->damage, &n_rects);
-
- ret = drmModeCreatePropertyBlob(backend->drm.fd, rects,
- sizeof(*rects) * n_rects, &blob_id);
- if (ret != 0)
- return ret;
-
- ret = plane_add_prop(req, plane, WDRM_PLANE_FB_DAMAGE_CLIPS, blob_id);
- if (ret != 0)
- return ret;
-
- return 0;
-}
-
-static bool
-drm_head_has_prop(struct drm_head *head,
- enum wdrm_connector_property prop)
-{
- if (head && head->props_conn[prop].prop_id != 0)
- return true;
-
- return false;
-}
-
-/*
- * This function converts the protection requests from weston_hdcp_protection
- * corresponding drm values. These values can be set in "Content Protection"
- * & "HDCP Content Type" connector properties.
- */
-static void
-get_drm_protection_from_weston(enum weston_hdcp_protection weston_protection,
- enum wdrm_content_protection_state *drm_protection,
- enum wdrm_hdcp_content_type *drm_cp_type)
-{
-
- switch (weston_protection) {
- case WESTON_HDCP_DISABLE:
- *drm_protection = WDRM_CONTENT_PROTECTION_UNDESIRED;
- *drm_cp_type = WDRM_HDCP_CONTENT_TYPE0;
- break;
- case WESTON_HDCP_ENABLE_TYPE_0:
- *drm_protection = WDRM_CONTENT_PROTECTION_DESIRED;
- *drm_cp_type = WDRM_HDCP_CONTENT_TYPE0;
- break;
- case WESTON_HDCP_ENABLE_TYPE_1:
- *drm_protection = WDRM_CONTENT_PROTECTION_DESIRED;
- *drm_cp_type = WDRM_HDCP_CONTENT_TYPE1;
- break;
- default:
- assert(0 && "bad weston_hdcp_protection");
- }
-}
-
-static void
-drm_head_set_hdcp_property(struct drm_head *head,
- enum weston_hdcp_protection protection,
- drmModeAtomicReq *req)
-{
- int ret;
- enum wdrm_content_protection_state drm_protection;
- enum wdrm_hdcp_content_type drm_cp_type;
- struct drm_property_enum_info *enum_info;
- uint64_t prop_val;
-
- get_drm_protection_from_weston(protection, &drm_protection,
- &drm_cp_type);
-
- if (!drm_head_has_prop(head, WDRM_CONNECTOR_CONTENT_PROTECTION))
- return;
-
- /*
- * Content-type property is not exposed for platforms not supporting
- * HDCP2.2, therefore, type-1 cannot be supported. The type-0 content
- * still can be supported if the content-protection property is exposed.
- */
- if (!drm_head_has_prop(head, WDRM_CONNECTOR_HDCP_CONTENT_TYPE) &&
- drm_cp_type != WDRM_HDCP_CONTENT_TYPE0)
- return;
-
- enum_info = head->props_conn[WDRM_CONNECTOR_CONTENT_PROTECTION].enum_values;
- prop_val = enum_info[drm_protection].value;
- ret = connector_add_prop(req, head, WDRM_CONNECTOR_CONTENT_PROTECTION,
- prop_val);
- assert(ret == 0);
-
- if (!drm_head_has_prop(head, WDRM_CONNECTOR_HDCP_CONTENT_TYPE))
- return;
-
- enum_info = head->props_conn[WDRM_CONNECTOR_HDCP_CONTENT_TYPE].enum_values;
- prop_val = enum_info[drm_cp_type].value;
- ret = connector_add_prop(req, head, WDRM_CONNECTOR_HDCP_CONTENT_TYPE,
- prop_val);
- assert(ret == 0);
-}
-
-static int
-drm_output_apply_state_atomic(struct drm_output_state *state,
- drmModeAtomicReq *req,
- uint32_t *flags)
-{
- struct drm_output *output = state->output;
- struct drm_backend *b = to_drm_backend(output->base.compositor);
- struct drm_plane_state *plane_state;
- struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
- struct drm_head *head;
- int ret = 0;
-
- drm_debug(b, "\t\t[atomic] %s output %lu (%s) state\n",
- (*flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "testing" : "applying",
- (unsigned long) output->base.id, output->base.name);
-
- if (state->dpms != output->state_cur->dpms) {
- drm_debug(b, "\t\t\t[atomic] DPMS state differs, modeset OK\n");
- *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
- }
-
- if (state->dpms == WESTON_DPMS_ON) {
- ret = drm_mode_ensure_blob(b, current_mode);
- if (ret != 0)
- return ret;
-
- ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID,
- current_mode->blob_id);
- ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 1);
-
- /* No need for the DPMS property, since it is implicit in
- * routing and CRTC activity. */
- wl_list_for_each(head, &output->base.head_list, base.output_link) {
- ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID,
- output->crtc_id);
- }
- } else {
- ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID, 0);
- ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 0);
-
- /* No need for the DPMS property, since it is implicit in
- * routing and CRTC activity. */
- wl_list_for_each(head, &output->base.head_list, base.output_link)
- ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID, 0);
- }
-
- wl_list_for_each(head, &output->base.head_list, base.output_link)
- drm_head_set_hdcp_property(head, state->protection, req);
-
- if (ret != 0) {
- weston_log("couldn't set atomic CRTC/connector state\n");
- return ret;
- }
-
- wl_list_for_each(plane_state, &state->plane_list, link) {
- struct drm_plane *plane = plane_state->plane;
- const struct pixel_format_info *pinfo = NULL;
-
- ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_ID,
- plane_state->fb ? plane_state->fb->fb_id : 0);
- ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID,
- plane_state->fb ? output->crtc_id : 0);
- ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_X,
- plane_state->src_x);
- ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_Y,
- plane_state->src_y);
- ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_W,
- plane_state->src_w);
- ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_H,
- plane_state->src_h);
- ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_X,
- plane_state->dest_x);
- ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_Y,
- plane_state->dest_y);
- ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_W,
- plane_state->dest_w);
- ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_H,
- plane_state->dest_h);
- ret |= plane_add_damage(req, b, plane_state);
-
- if (plane_state->fb && plane_state->fb->format)
- pinfo = plane_state->fb->format;
-
- drm_debug(plane->backend, "\t\t\t[PLANE:%lu] FORMAT: %s\n",
- (unsigned long) plane->plane_id,
- pinfo ? pinfo->drm_format_name : "UNKNOWN");
-
- if (plane_state->in_fence_fd >= 0) {
- ret |= plane_add_prop(req, plane,
- WDRM_PLANE_IN_FENCE_FD,
- plane_state->in_fence_fd);
- }
-
- /* do note, that 'invented' zpos values are set as immutable */
- if (plane_state->zpos != DRM_PLANE_ZPOS_INVALID_PLANE &&
- plane_state->plane->zpos_min != plane_state->plane->zpos_max)
- ret |= plane_add_prop(req, plane,
- WDRM_PLANE_ZPOS,
- plane_state->zpos);
-
- if (ret != 0) {
- weston_log("couldn't set plane state\n");
- return ret;
- }
- }
-
- return 0;
-}
-
-/**
- * Helper function used only by drm_pending_state_apply, with the same
- * guarantees and constraints as that function.
- */
-static int
-drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
- enum drm_state_apply_mode mode)
-{
- struct drm_backend *b = pending_state->backend;
- struct drm_output_state *output_state, *tmp;
- struct drm_plane *plane;
- drmModeAtomicReq *req = drmModeAtomicAlloc();
- uint32_t flags;
- int ret = 0;
-
- if (!req)
- return -1;
-
- switch (mode) {
- case DRM_STATE_APPLY_SYNC:
- flags = 0;
- break;
- case DRM_STATE_APPLY_ASYNC:
- flags = DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
- break;
- case DRM_STATE_TEST_ONLY:
- flags = DRM_MODE_ATOMIC_TEST_ONLY;
- break;
- }
-
- if (b->state_invalid) {
- struct weston_head *head_base;
- struct drm_head *head;
- uint32_t *unused;
- int err;
-
- drm_debug(b, "\t\t[atomic] previous state invalid; "
- "starting with fresh state\n");
-
- /* If we need to reset all our state (e.g. because we've
- * just started, or just been VT-switched in), explicitly
- * disable all the CRTCs and connectors we aren't using. */
- wl_list_for_each(head_base,
- &b->compositor->head_list, compositor_link) {
- struct drm_property_info *info;
-
- if (weston_head_is_enabled(head_base))
- continue;
-
- head = to_drm_head(head_base);
-
- drm_debug(b, "\t\t[atomic] disabling inactive head %s\n",
- head_base->name);
-
- info = &head->props_conn[WDRM_CONNECTOR_CRTC_ID];
- err = drmModeAtomicAddProperty(req, head->connector_id,
- info->prop_id, 0);
- drm_debug(b, "\t\t\t[CONN:%lu] %lu (%s) -> 0\n",
- (unsigned long) head->connector_id,
- (unsigned long) info->prop_id,
- info->name);
- if (err <= 0)
- ret = -1;
- }
-
- wl_array_for_each(unused, &b->unused_crtcs) {
- struct drm_property_info infos[WDRM_CRTC__COUNT];
- struct drm_property_info *info;
- drmModeObjectProperties *props;
- uint64_t active;
-
- memset(infos, 0, sizeof(infos));
-
- /* We can't emit a disable on a CRTC that's already
- * off, as the kernel will refuse to generate an event
- * for an off->off state and fail the commit.
- */
- props = drmModeObjectGetProperties(b->drm.fd,
- *unused,
- DRM_MODE_OBJECT_CRTC);
- if (!props) {
- ret = -1;
- continue;
- }
-
- drm_property_info_populate(b, crtc_props, infos,
- WDRM_CRTC__COUNT,
- props);
-
- info = &infos[WDRM_CRTC_ACTIVE];
- active = drm_property_get_value(info, props, 0);
- drmModeFreeObjectProperties(props);
- if (active == 0) {
- drm_property_info_free(infos, WDRM_CRTC__COUNT);
- continue;
- }
-
- drm_debug(b, "\t\t[atomic] disabling unused CRTC %lu\n",
- (unsigned long) *unused);
-
- drm_debug(b, "\t\t\t[CRTC:%lu] %lu (%s) -> 0\n",
- (unsigned long) *unused,
- (unsigned long) info->prop_id, info->name);
- err = drmModeAtomicAddProperty(req, *unused,
- info->prop_id, 0);
- if (err <= 0)
- ret = -1;
-
- info = &infos[WDRM_CRTC_MODE_ID];
- drm_debug(b, "\t\t\t[CRTC:%lu] %lu (%s) -> 0\n",
- (unsigned long) *unused,
- (unsigned long) info->prop_id, info->name);
- err = drmModeAtomicAddProperty(req, *unused,
- info->prop_id, 0);
- if (err <= 0)
- ret = -1;
-
- drm_property_info_free(infos, WDRM_CRTC__COUNT);
- }
-
- /* Disable all the planes; planes which are being used will
- * override this state in the output-state application. */
- wl_list_for_each(plane, &b->plane_list, link) {
- drm_debug(b, "\t\t[atomic] starting with plane %lu disabled\n",
- (unsigned long) plane->plane_id);
- plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
- plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0);
- }
-
- flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
- }
-
- wl_list_for_each(output_state, &pending_state->output_list, link) {
- if (output_state->output->virtual)
- continue;
- if (mode == DRM_STATE_APPLY_SYNC)
- assert(output_state->dpms == WESTON_DPMS_OFF);
- ret |= drm_output_apply_state_atomic(output_state, req, &flags);
- }
-
- if (ret != 0) {
- weston_log("atomic: couldn't compile atomic state\n");
- goto out;
- }
-
- ret = drmModeAtomicCommit(b->drm.fd, req, flags, b);
- drm_debug(b, "[atomic] drmModeAtomicCommit\n");
-
- /* Test commits do not take ownership of the state; return
- * without freeing here. */
- if (mode == DRM_STATE_TEST_ONLY) {
- drmModeAtomicFree(req);
- return ret;
- }
-
- if (ret != 0) {
- weston_log("atomic: couldn't commit new state: %s\n",
- strerror(errno));
- goto out;
- }
-
- wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
- link)
- drm_output_assign_state(output_state, mode);
-
- b->state_invalid = false;
-
- assert(wl_list_empty(&pending_state->output_list));
-
-out:
- drmModeAtomicFree(req);
- drm_pending_state_free(pending_state);
- return ret;
-}
-
-/**
- * Tests a pending state, to see if the kernel will accept the update as
- * constructed.
- *
- * Using atomic modesetting, the kernel performs the same checks as it would
- * on a real commit, returning success or failure without actually modifying
- * the running state. It does not return -EBUSY if there are pending updates
- * in flight, so states may be tested at any point, however this means a
- * state which passed testing may fail on a real commit if the timing is not
- * respected (e.g. committing before the previous commit has completed).
- *
- * Without atomic modesetting, we have no way to check, so we optimistically
- * claim it will work.
- *
- * Unlike drm_pending_state_apply() and drm_pending_state_apply_sync(), this
- * function does _not_ take ownership of pending_state, nor does it clear
- * state_invalid.
- */
-int
-drm_pending_state_test(struct drm_pending_state *pending_state)
-{
- struct drm_backend *b = pending_state->backend;
-
- if (b->atomic_modeset)
- return drm_pending_state_apply_atomic(pending_state,
- DRM_STATE_TEST_ONLY);
-
- /* We have no way to test state before application on the legacy
- * modesetting API, so just claim it succeeded. */
- return 0;
-}
-
-/**
- * Applies all of a pending_state asynchronously: the primary entry point for
- * applying KMS state to a device. Updates the state for all outputs in the
- * pending_state, as well as disabling any unclaimed outputs.
- *
- * Unconditionally takes ownership of pending_state, and clears state_invalid.
- */
-int
-drm_pending_state_apply(struct drm_pending_state *pending_state)
-{
- struct drm_backend *b = pending_state->backend;
- struct drm_output_state *output_state, *tmp;
- uint32_t *unused;
-
- if (b->atomic_modeset)
- return drm_pending_state_apply_atomic(pending_state,
- DRM_STATE_APPLY_ASYNC);
-
- if (b->state_invalid) {
- /* If we need to reset all our state (e.g. because we've
- * just started, or just been VT-switched in), explicitly
- * disable all the CRTCs we aren't using. This also disables
- * all connectors on these CRTCs, so we don't need to do that
- * separately with the pre-atomic API. */
- wl_array_for_each(unused, &b->unused_crtcs)
- drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
- NULL);
- }
-
- wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
- link) {
- struct drm_output *output = output_state->output;
- int ret;
-
- if (output->virtual) {
- drm_output_assign_state(output_state,
- DRM_STATE_APPLY_ASYNC);
- continue;
- }
-
- ret = drm_output_apply_state_legacy(output_state);
- if (ret != 0) {
- weston_log("Couldn't apply state for output %s\n",
- output->base.name);
- }
- }
-
- b->state_invalid = false;
-
- assert(wl_list_empty(&pending_state->output_list));
-
- drm_pending_state_free(pending_state);
-
- return 0;
-}
-
-/**
- * The synchronous version of drm_pending_state_apply. May only be used to
- * disable outputs. Does so synchronously: the request is guaranteed to have
- * completed on return, and the output will not be touched afterwards.
- *
- * Unconditionally takes ownership of pending_state, and clears state_invalid.
- */
-int
-drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
-{
- struct drm_backend *b = pending_state->backend;
- struct drm_output_state *output_state, *tmp;
- uint32_t *unused;
-
- if (b->atomic_modeset)
- return drm_pending_state_apply_atomic(pending_state,
- DRM_STATE_APPLY_SYNC);
-
- if (b->state_invalid) {
- /* If we need to reset all our state (e.g. because we've
- * just started, or just been VT-switched in), explicitly
- * disable all the CRTCs we aren't using. This also disables
- * all connectors on these CRTCs, so we don't need to do that
- * separately with the pre-atomic API. */
- wl_array_for_each(unused, &b->unused_crtcs)
- drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
- NULL);
- }
-
- wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
- link) {
- int ret;
-
- assert(output_state->dpms == WESTON_DPMS_OFF);
- ret = drm_output_apply_state_legacy(output_state);
- if (ret != 0) {
- weston_log("Couldn't apply state for output %s\n",
- output_state->output->base.name);
- }
- }
-
- b->state_invalid = false;
-
- assert(wl_list_empty(&pending_state->output_list));
-
- drm_pending_state_free(pending_state);
-
- return 0;
-}
-
-void
-drm_output_update_msc(struct drm_output *output, unsigned int seq)
-{
- uint64_t msc_hi = output->base.msc >> 32;
-
- if (seq < (output->base.msc & 0xffffffff))
- msc_hi++;
-
- output->base.msc = (msc_hi << 32) + seq;
-}
-
-static void
-page_flip_handler(int fd, unsigned int frame,
- unsigned int sec, unsigned int usec, void *data)
-{
- struct drm_output *output = data;
- struct drm_backend *b = to_drm_backend(output->base.compositor);
- uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
- WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
- WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
-
- drm_output_update_msc(output, frame);
-
- assert(!b->atomic_modeset);
- assert(output->page_flip_pending);
- output->page_flip_pending = false;
-
- drm_output_update_complete(output, flags, sec, usec);
-}
-
-static void
-atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
- unsigned int usec, unsigned int crtc_id, void *data)
-{
- struct drm_backend *b = data;
- struct drm_output *output = drm_output_find_by_crtc(b, crtc_id);
- uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
- WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
- WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
-
- /* During the initial modeset, we can disable CRTCs which we don't
- * actually handle during normal operation; this will give us events
- * for unknown outputs. Ignore them. */
- if (!output || !output->base.enabled)
- return;
-
- drm_output_update_msc(output, frame);
-
- drm_debug(b, "[atomic][CRTC:%u] flip processing started\n", crtc_id);
- assert(b->atomic_modeset);
- assert(output->atomic_complete_pending);
- output->atomic_complete_pending = false;
-
- drm_output_update_complete(output, flags, sec, usec);
- drm_debug(b, "[atomic][CRTC:%u] flip processing completed\n", crtc_id);
-}
-
-int
-on_drm_input(int fd, uint32_t mask, void *data)
-{
- struct drm_backend *b = data;
- drmEventContext evctx;
-
- memset(&evctx, 0, sizeof evctx);
- evctx.version = 3;
- if (b->atomic_modeset)
- evctx.page_flip_handler2 = atomic_flip_handler;
- else
- evctx.page_flip_handler = page_flip_handler;
- drmHandleEvent(fd, &evctx);
-
- return 1;
-}
-
-int
-init_kms_caps(struct drm_backend *b)
-{
- uint64_t cap;
- int ret;
- clockid_t clk_id;
-
- weston_log("using %s\n", b->drm.filename);
-
- ret = drmGetCap(b->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
- if (ret == 0 && cap == 1)
- clk_id = CLOCK_MONOTONIC;
- else
- clk_id = CLOCK_REALTIME;
-
- if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
- weston_log("Error: failed to set presentation clock %d.\n",
- clk_id);
- return -1;
- }
-
- ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
- if (ret == 0)
- b->cursor_width = cap;
- else
- b->cursor_width = 64;
-
- ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
- if (ret == 0)
- b->cursor_height = cap;
- else
- b->cursor_height = 64;
-
- if (!getenv("WESTON_DISABLE_UNIVERSAL_PLANES")) {
- ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
- b->universal_planes = (ret == 0);
- }
- weston_log("DRM: %s universal planes\n",
- b->universal_planes ? "supports" : "does not support");
-
- if (b->universal_planes && !getenv("WESTON_DISABLE_ATOMIC")) {
- ret = drmGetCap(b->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
- if (ret != 0)
- cap = 0;
- ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
- b->atomic_modeset = ((ret == 0) && (cap == 1));
- }
- weston_log("DRM: %s atomic modesetting\n",
- b->atomic_modeset ? "supports" : "does not support");
-
- ret = drmGetCap(b->drm.fd, DRM_CAP_ADDFB2_MODIFIERS, &cap);
- if (ret == 0)
- b->fb_modifiers = cap;
- else
- b->fb_modifiers = 0;
-
- /*
- * KMS support for hardware planes cannot properly synchronize
- * without nuclear page flip. Without nuclear/atomic, hw plane
- * and cursor plane updates would either tear or cause extra
- * waits for vblanks which means dropping the compositor framerate
- * to a fraction. For cursors, it's not so bad, so they are
- * enabled.
- */
- if (!b->atomic_modeset || getenv("WESTON_FORCE_RENDERER"))
- b->sprites_are_broken = true;
-
- ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1);
- b->aspect_ratio_supported = (ret == 0);
- weston_log("DRM: %s picture aspect ratio\n",
- b->aspect_ratio_supported ? "supports" : "does not support");
-
- return 0;
-}
diff --git a/libweston/backend-drm/libbacklight.c b/libweston/backend-drm/libbacklight.c
deleted file mode 100644
index 4bbc6db4..00000000
--- a/libweston/backend-drm/libbacklight.c
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * libbacklight - userspace interface to Linux backlight control
- *
- * Copyright © 2012 Intel Corporation
- * Copyright 2010 Red Hat <mjg@redhat.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Matthew Garrett <mjg@redhat.com>
- * Tiago Vignatti <vignatti@freedesktop.org>
- */
-
-#include "config.h"
-
-#include "libbacklight.h"
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <linux/types.h>
-#include <dirent.h>
-#include <drm.h>
-#include <fcntl.h>
-#include <malloc.h>
-#include <string.h>
-#include <errno.h>
-
-#include "shared/string-helpers.h"
-
-static long backlight_get(struct backlight *backlight, char *node)
-{
- char buffer[100];
- char *path;
- int fd, value;
- long ret;
-
- if (asprintf(&path, "%s/%s", backlight->path, node) < 0)
- return -ENOMEM;
- fd = open(path, O_RDONLY);
- if (fd < 0) {
- ret = -1;
- goto out;
- }
-
- ret = read(fd, &buffer, sizeof(buffer));
- if (ret < 1) {
- ret = -1;
- goto out;
- }
-
- if (!safe_strtoint(buffer, &value)) {
- ret = -1;
- goto out;
- }
-
- ret = value;
-
-out:
- if (fd >= 0)
- close(fd);
- free(path);
- return ret;
-}
-
-long backlight_get_brightness(struct backlight *backlight)
-{
- return backlight_get(backlight, "brightness");
-}
-
-long backlight_get_max_brightness(struct backlight *backlight)
-{
- return backlight_get(backlight, "max_brightness");
-}
-
-long backlight_get_actual_brightness(struct backlight *backlight)
-{
- return backlight_get(backlight, "actual_brightness");
-}
-
-long backlight_set_brightness(struct backlight *backlight, long brightness)
-{
- char *path;
- char *buffer = NULL;
- int fd;
- long ret;
-
- if (asprintf(&path, "%s/%s", backlight->path, "brightness") < 0)
- return -ENOMEM;
-
- fd = open(path, O_RDWR);
- if (fd < 0) {
- ret = -1;
- goto out;
- }
-
- ret = read(fd, &buffer, sizeof(buffer));
- if (ret < 1) {
- ret = -1;
- goto out;
- }
-
- if (asprintf(&buffer, "%ld", brightness) < 0) {
- ret = -1;
- goto out;
- }
-
- ret = write(fd, buffer, strlen(buffer));
- if (ret < 0) {
- ret = -1;
- goto out;
- }
-
- ret = backlight_get_brightness(backlight);
- backlight->brightness = ret;
-out:
- free(buffer);
- free(path);
- if (fd >= 0)
- close(fd);
- return ret;
-}
-
-void backlight_destroy(struct backlight *backlight)
-{
- if (!backlight)
- return;
-
- if (backlight->path)
- free(backlight->path);
-
- free(backlight);
-}
-
-struct backlight *backlight_init(struct udev_device *drm_device,
- uint32_t connector_type)
-{
- const char *syspath = NULL;
- char *pci_name = NULL;
- char *chosen_path = NULL;
- char *path = NULL;
- DIR *backlights = NULL;
- struct dirent *entry;
- enum backlight_type type = 0;
- char buffer[100];
- struct backlight *backlight = NULL;
- int ret;
-
- if (!drm_device)
- return NULL;
-
- syspath = udev_device_get_syspath(drm_device);
- if (!syspath)
- return NULL;
-
- if (asprintf(&path, "%s/%s", syspath, "device") < 0)
- return NULL;
-
- ret = readlink(path, buffer, sizeof(buffer) - 1);
- free(path);
- if (ret < 0)
- return NULL;
-
- buffer[ret] = '\0';
- pci_name = basename(buffer);
-
- if (connector_type <= 0)
- return NULL;
-
- backlights = opendir("/sys/class/backlight");
- if (!backlights)
- return NULL;
-
- /* Find the "best" backlight for the device. Firmware
- interfaces are preferred over platform interfaces are
- preferred over raw interfaces. For raw interfaces we'll
- check if the device ID in the form of pci match, while
- for firmware interfaces we require the pci ID to
- match. It's assumed that platform interfaces always match,
- since we can't actually associate them with IDs.
-
- A further awkwardness is that, while it's theoretically
- possible for an ACPI interface to include support for
- changing the backlight of external devices, it's unlikely
- to ever be done. It's effectively impossible for a platform
- interface to do so. So if we get asked about anything that
- isn't LVDS or eDP, we pretty much have to require that the
- control be supplied via a raw interface */
-
- while ((entry = readdir(backlights))) {
- char *backlight_path;
- char *parent;
- enum backlight_type entry_type;
- int fd;
-
- if (entry->d_name[0] == '.')
- continue;
-
- if (asprintf(&backlight_path, "%s/%s", "/sys/class/backlight",
- entry->d_name) < 0)
- goto err;
-
- if (asprintf(&path, "%s/%s", backlight_path, "type") < 0) {
- free(backlight_path);
- goto err;
- }
-
- fd = open(path, O_RDONLY);
-
- if (fd < 0)
- goto out;
-
- ret = read (fd, &buffer, sizeof(buffer));
- close (fd);
-
- if (ret < 1)
- goto out;
-
- buffer[ret] = '\0';
-
- if (!strncmp(buffer, "raw\n", sizeof(buffer)))
- entry_type = BACKLIGHT_RAW;
- else if (!strncmp(buffer, "platform\n", sizeof(buffer)))
- entry_type = BACKLIGHT_PLATFORM;
- else if (!strncmp(buffer, "firmware\n", sizeof(buffer)))
- entry_type = BACKLIGHT_FIRMWARE;
- else
- goto out;
-
- if (connector_type != DRM_MODE_CONNECTOR_LVDS &&
- connector_type != DRM_MODE_CONNECTOR_eDP) {
- /* External displays are assumed to require
- gpu control at the moment */
- if (entry_type != BACKLIGHT_RAW)
- goto out;
- }
-
- free (path);
-
- if (asprintf(&path, "%s/%s", backlight_path, "device") < 0)
- goto err;
-
- ret = readlink(path, buffer, sizeof(buffer) - 1);
-
- if (ret < 0)
- goto out;
-
- buffer[ret] = '\0';
-
- parent = basename(buffer);
-
- /* Perform matching for raw and firmware backlights -
- platform backlights have to be assumed to match */
- if (entry_type == BACKLIGHT_RAW ||
- entry_type == BACKLIGHT_FIRMWARE) {
- if (!(pci_name && !strcmp(pci_name, parent)))
- goto out;
- }
-
- if (entry_type < type)
- goto out;
-
- type = entry_type;
-
- if (chosen_path)
- free(chosen_path);
- chosen_path = strdup(backlight_path);
-
- out:
- free(backlight_path);
- free(path);
- }
-
- if (!chosen_path)
- goto err;
-
- backlight = malloc(sizeof(struct backlight));
-
- if (!backlight)
- goto err;
-
- backlight->path = chosen_path;
- backlight->type = type;
-
- backlight->max_brightness = backlight_get_max_brightness(backlight);
- if (backlight->max_brightness < 0)
- goto err;
-
- backlight->brightness = backlight_get_actual_brightness(backlight);
- if (backlight->brightness < 0)
- goto err;
-
- closedir(backlights);
- return backlight;
-err:
- closedir(backlights);
- free (chosen_path);
- free (backlight);
- return NULL;
-}
diff --git a/libweston/backend-drm/libbacklight.h b/libweston/backend-drm/libbacklight.h
deleted file mode 100644
index 20078242..00000000
--- a/libweston/backend-drm/libbacklight.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * libbacklight - userspace interface to Linux backlight control
- *
- * Copyright © 2012 Intel Corporation
- * Copyright 2010 Red Hat <mjg@redhat.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Matthew Garrett <mjg@redhat.com>
- * Tiago Vignatti <vignatti@freedesktop.org>
- */
-#ifndef LIBBACKLIGHT_H
-#define LIBBACKLIGHT_H
-#include <libudev.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-enum backlight_type {
- BACKLIGHT_RAW,
- BACKLIGHT_PLATFORM,
- BACKLIGHT_FIRMWARE
-};
-
-struct backlight {
- char *path;
- int max_brightness;
- int brightness;
- enum backlight_type type;
-};
-
-/*
- * Find and set up a backlight for a valid udev connector device, i.e. one
- * matching drm subsystem and with status of connected.
- */
-struct backlight *backlight_init(struct udev_device *drm_device,
- uint32_t connector_type);
-
-/* Free backlight resources */
-void backlight_destroy(struct backlight *backlight);
-
-/* Provide the maximum backlight value */
-long backlight_get_max_brightness(struct backlight *backlight);
-
-/* Provide the cached backlight value */
-long backlight_get_brightness(struct backlight *backlight);
-
-/* Provide the hardware backlight value */
-long backlight_get_actual_brightness(struct backlight *backlight);
-
-/* Set the backlight to a value between 0 and max */
-long backlight_set_brightness(struct backlight *backlight, long brightness);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBBACKLIGHT_H */
diff --git a/libweston/backend-drm/meson.build b/libweston/backend-drm/meson.build
deleted file mode 100644
index a7f62965..00000000
--- a/libweston/backend-drm/meson.build
+++ /dev/null
@@ -1,93 +0,0 @@
-if not get_option('backend-drm')
- subdir_done()
-endif
-
-lib_backlight = static_library(
- 'backlight',
- 'libbacklight.c',
- dependencies: [
- dep_libdrm_headers,
- dependency('libudev')
- ],
- include_directories: common_inc,
- install: false
-)
-dep_backlight = declare_dependency(
- link_with: lib_backlight,
- include_directories: include_directories('.')
-)
-
-config_h.set('BUILD_DRM_COMPOSITOR', '1')
-
-srcs_drm = [
- 'drm.c',
- 'fb.c',
- 'modes.c',
- 'kms.c',
- 'state-helpers.c',
- 'state-propose.c',
- linux_dmabuf_unstable_v1_protocol_c,
- linux_dmabuf_unstable_v1_server_protocol_h,
- presentation_time_server_protocol_h,
-]
-
-deps_drm = [
- dep_libdl,
- dep_libweston_private,
- dep_session_helper,
- dep_libdrm,
- dep_libinput_backend,
- dependency('libudev', version: '>= 136'),
- dep_backlight
-]
-
-if get_option('renderer-gl')
- dep_gbm = dependency('gbm', required: false)
- 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
- if dep_gbm.version().version_compare('>= 17.1')
- config_h.set('HAVE_GBM_MODIFIERS', '1')
- endif
- if dep_gbm.version().version_compare('>= 17.2')
- config_h.set('HAVE_GBM_FD_IMPORT', '1')
- endif
- deps_drm += dep_gbm
- srcs_drm += 'drm-gbm.c'
- config_h.set('BUILD_DRM_GBM', '1')
-endif
-
-if get_option('backend-drm-screencast-vaapi')
- foreach name : [ 'libva', 'libva-drm' ]
- d = dependency(name, version: '>= 0.34.0', required: false)
- if not d.found()
- error('VA-API recorder requires @0@ >= 0.34.0 which was not found. Or, you can use \'-Dbackend-drm-screencast-vaapi=false\'.'.format(name))
- endif
- deps_drm += d
- endforeach
-
- srcs_drm += 'vaapi-recorder.c'
- deps_drm += dependency('threads')
- config_h.set('BUILD_VAAPI_RECORDER', '1')
-endif
-
-if get_option('remoting')
- if not get_option('renderer-gl')
- warning('DRM virtual requires renderer-gl.')
- endif
- srcs_drm += 'drm-virtual.c'
- config_h.set('BUILD_DRM_VIRTUAL', '1')
-endif
-
-plugin_drm = shared_library(
- 'drm-backend',
- srcs_drm,
- include_directories: common_inc,
- dependencies: deps_drm,
- name_prefix: '',
- install: true,
- install_dir: dir_module_libweston
-)
-env_modmap += 'drm-backend.so=@0@;'.format(plugin_drm.full_path())
-
-install_headers(backend_drm_h, subdir: dir_include_libweston_install)
diff --git a/libweston/backend-drm/modes.c b/libweston/backend-drm/modes.c
deleted file mode 100644
index 7c45e50a..00000000
--- a/libweston/backend-drm/modes.c
+++ /dev/null
@@ -1,783 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2011 Intel Corporation
- * Copyright © 2017, 2018 Collabora, Ltd.
- * Copyright © 2017, 2018 General Electric Company
- * Copyright (c) 2018 DisplayLink (UK) Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-#include <drm_fourcc.h>
-
-#include "drm-internal.h"
-
-static const char *const aspect_ratio_as_string[] = {
- [WESTON_MODE_PIC_AR_NONE] = "",
- [WESTON_MODE_PIC_AR_4_3] = " 4:3",
- [WESTON_MODE_PIC_AR_16_9] = " 16:9",
- [WESTON_MODE_PIC_AR_64_27] = " 64:27",
- [WESTON_MODE_PIC_AR_256_135] = " 256:135",
-};
-
-/*
- * Get the aspect-ratio from drmModeModeInfo mode flags.
- *
- * @param drm_mode_flags- flags from drmModeModeInfo structure.
- * @returns aspect-ratio as encoded in enum 'weston_mode_aspect_ratio'.
- */
-static enum weston_mode_aspect_ratio
-drm_to_weston_mode_aspect_ratio(uint32_t drm_mode_flags)
-{
- switch (drm_mode_flags & DRM_MODE_FLAG_PIC_AR_MASK) {
- case DRM_MODE_FLAG_PIC_AR_4_3:
- return WESTON_MODE_PIC_AR_4_3;
- case DRM_MODE_FLAG_PIC_AR_16_9:
- return WESTON_MODE_PIC_AR_16_9;
- case DRM_MODE_FLAG_PIC_AR_64_27:
- return WESTON_MODE_PIC_AR_64_27;
- case DRM_MODE_FLAG_PIC_AR_256_135:
- return WESTON_MODE_PIC_AR_256_135;
- case DRM_MODE_FLAG_PIC_AR_NONE:
- default:
- return WESTON_MODE_PIC_AR_NONE;
- }
-}
-
-static const char *
-aspect_ratio_to_string(enum weston_mode_aspect_ratio ratio)
-{
- if (ratio < 0 || ratio >= ARRAY_LENGTH(aspect_ratio_as_string) ||
- !aspect_ratio_as_string[ratio])
- return " (unknown aspect ratio)";
-
- return aspect_ratio_as_string[ratio];
-}
-
-static int
-drm_subpixel_to_wayland(int drm_value)
-{
- switch (drm_value) {
- default:
- case DRM_MODE_SUBPIXEL_UNKNOWN:
- return WL_OUTPUT_SUBPIXEL_UNKNOWN;
- case DRM_MODE_SUBPIXEL_NONE:
- return WL_OUTPUT_SUBPIXEL_NONE;
- case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
- return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
- case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
- return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
- case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
- return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
- case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
- return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
- }
-}
-
-int
-drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode)
-{
- int ret;
-
- if (mode->blob_id)
- return 0;
-
- ret = drmModeCreatePropertyBlob(backend->drm.fd,
- &mode->mode_info,
- sizeof(mode->mode_info),
- &mode->blob_id);
- if (ret != 0)
- weston_log("failed to create mode property blob: %s\n",
- strerror(errno));
-
- drm_debug(backend, "\t\t\t[atomic] created new mode blob %lu for %s\n",
- (unsigned long) mode->blob_id, mode->mode_info.name);
-
- return ret;
-}
-
-static bool
-check_non_desktop(struct drm_head *head, drmModeObjectPropertiesPtr props)
-{
- struct drm_property_info *non_desktop_info =
- &head->props_conn[WDRM_CONNECTOR_NON_DESKTOP];
-
- return drm_property_get_value(non_desktop_info, props, 0);
-}
-
-static int
-parse_modeline(const char *s, drmModeModeInfo *mode)
-{
- char hsync[16];
- char vsync[16];
- float fclock;
-
- memset(mode, 0, sizeof *mode);
-
- mode->type = DRM_MODE_TYPE_USERDEF;
- mode->hskew = 0;
- mode->vscan = 0;
- mode->vrefresh = 0;
- mode->flags = 0;
-
- if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
- &fclock,
- &mode->hdisplay,
- &mode->hsync_start,
- &mode->hsync_end,
- &mode->htotal,
- &mode->vdisplay,
- &mode->vsync_start,
- &mode->vsync_end,
- &mode->vtotal, hsync, vsync) != 11)
- return -1;
-
- mode->clock = fclock * 1000;
- if (strcasecmp(hsync, "+hsync") == 0)
- mode->flags |= DRM_MODE_FLAG_PHSYNC;
- else if (strcasecmp(hsync, "-hsync") == 0)
- mode->flags |= DRM_MODE_FLAG_NHSYNC;
- else
- return -1;
-
- if (strcasecmp(vsync, "+vsync") == 0)
- mode->flags |= DRM_MODE_FLAG_PVSYNC;
- else if (strcasecmp(vsync, "-vsync") == 0)
- mode->flags |= DRM_MODE_FLAG_NVSYNC;
- else
- return -1;
-
- snprintf(mode->name, sizeof mode->name, "%dx%d@%.3f",
- mode->hdisplay, mode->vdisplay, fclock);
-
- return 0;
-}
-
-static void
-edid_parse_string(const uint8_t *data, char text[])
-{
- int i;
- int replaced = 0;
-
- /* this is always 12 bytes, but we can't guarantee it's null
- * terminated or not junk. */
- strncpy(text, (const char *) data, 12);
-
- /* guarantee our new string is null-terminated */
- text[12] = '\0';
-
- /* remove insane chars */
- for (i = 0; text[i] != '\0'; i++) {
- if (text[i] == '\n' ||
- text[i] == '\r') {
- text[i] = '\0';
- break;
- }
- }
-
- /* ensure string is printable */
- for (i = 0; text[i] != '\0'; i++) {
- if (!isprint(text[i])) {
- text[i] = '-';
- replaced++;
- }
- }
-
- /* if the string is random junk, ignore the string */
- if (replaced > 4)
- text[0] = '\0';
-}
-
-#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
-#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
-#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
-#define EDID_OFFSET_DATA_BLOCKS 0x36
-#define EDID_OFFSET_LAST_BLOCK 0x6c
-#define EDID_OFFSET_PNPID 0x08
-#define EDID_OFFSET_SERIAL 0x0c
-
-static int
-edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
-{
- int i;
- uint32_t serial_number;
-
- /* check header */
- if (length < 128)
- return -1;
- if (data[0] != 0x00 || data[1] != 0xff)
- return -1;
-
- /* decode the PNP ID from three 5 bit words packed into 2 bytes
- * /--08--\/--09--\
- * 7654321076543210
- * |\---/\---/\---/
- * R C1 C2 C3 */
- edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
- edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
- edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
- edid->pnp_id[3] = '\0';
-
- /* maybe there isn't a ASCII serial number descriptor, so use this instead */
- serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
- serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
- serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
- serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
- if (serial_number > 0)
- sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
-
- /* parse EDID data */
- for (i = EDID_OFFSET_DATA_BLOCKS;
- i <= EDID_OFFSET_LAST_BLOCK;
- i += 18) {
- /* ignore pixel clock data */
- if (data[i] != 0)
- continue;
- if (data[i+2] != 0)
- continue;
-
- /* any useful blocks? */
- if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
- edid_parse_string(&data[i+5],
- edid->monitor_name);
- } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
- edid_parse_string(&data[i+5],
- edid->serial_number);
- } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
- edid_parse_string(&data[i+5],
- edid->eisa_id);
- }
- }
- return 0;
-}
-
-/** Parse monitor make, model and serial from EDID
- *
- * \param head The head whose \c drm_edid to fill in.
- * \param props The DRM connector properties to get the EDID from.
- * \param[out] make The monitor make (PNP ID).
- * \param[out] model The monitor model (name).
- * \param[out] serial_number The monitor serial number.
- *
- * Each of \c *make, \c *model and \c *serial_number are set only if the
- * information is found in the EDID. The pointers they are set to must not
- * be free()'d explicitly, instead they get implicitly freed when the
- * \c drm_head is destroyed.
- */
-static void
-find_and_parse_output_edid(struct drm_head *head,
- drmModeObjectPropertiesPtr props,
- const char **make,
- const char **model,
- const char **serial_number)
-{
- drmModePropertyBlobPtr edid_blob = NULL;
- uint32_t blob_id;
- int rc;
-
- blob_id =
- drm_property_get_value(&head->props_conn[WDRM_CONNECTOR_EDID],
- props, 0);
- if (!blob_id)
- return;
-
- edid_blob = drmModeGetPropertyBlob(head->backend->drm.fd, blob_id);
- if (!edid_blob)
- return;
-
- rc = edid_parse(&head->edid,
- edid_blob->data,
- edid_blob->length);
- if (!rc) {
- if (head->edid.pnp_id[0] != '\0')
- *make = head->edid.pnp_id;
- if (head->edid.monitor_name[0] != '\0')
- *model = head->edid.monitor_name;
- if (head->edid.serial_number[0] != '\0')
- *serial_number = head->edid.serial_number;
- }
- drmModeFreePropertyBlob(edid_blob);
-}
-
-static uint32_t
-drm_refresh_rate_mHz(const drmModeModeInfo *info)
-{
- uint64_t refresh;
-
- /* Calculate higher precision (mHz) refresh rate */
- refresh = (info->clock * 1000000LL / info->htotal +
- info->vtotal / 2) / info->vtotal;
-
- if (info->flags & DRM_MODE_FLAG_INTERLACE)
- refresh *= 2;
- if (info->flags & DRM_MODE_FLAG_DBLSCAN)
- refresh /= 2;
- if (info->vscan > 1)
- refresh /= info->vscan;
-
- return refresh;
-}
-
-/**
- * Add a mode to output's mode list
- *
- * Copy the supplied DRM mode into a Weston mode structure, and add it to the
- * output's mode list.
- *
- * @param output DRM output to add mode to
- * @param info DRM mode structure to add
- * @returns Newly-allocated Weston/DRM mode structure
- */
-static struct drm_mode *
-drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
-{
- struct drm_mode *mode;
-
- mode = malloc(sizeof *mode);
- if (mode == NULL)
- return NULL;
-
- mode->base.flags = 0;
- mode->base.width = info->hdisplay;
- mode->base.height = info->vdisplay;
-
- mode->base.refresh = drm_refresh_rate_mHz(info);
- mode->mode_info = *info;
- mode->blob_id = 0;
-
- if (info->type & DRM_MODE_TYPE_PREFERRED)
- mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
-
- mode->base.aspect_ratio = drm_to_weston_mode_aspect_ratio(info->flags);
-
- wl_list_insert(output->base.mode_list.prev, &mode->base.link);
-
- return mode;
-}
-
-/**
- * Destroys a mode, and removes it from the list.
- */
-static void
-drm_output_destroy_mode(struct drm_backend *backend, struct drm_mode *mode)
-{
- if (mode->blob_id)
- drmModeDestroyPropertyBlob(backend->drm.fd, mode->blob_id);
- wl_list_remove(&mode->base.link);
- free(mode);
-}
-
-/** Destroy a list of drm_modes
- *
- * @param backend The backend for releasing mode property blobs.
- * @param mode_list The list linked by drm_mode::base.link.
- */
-void
-drm_mode_list_destroy(struct drm_backend *backend, struct wl_list *mode_list)
-{
- struct drm_mode *mode, *next;
-
- wl_list_for_each_safe(mode, next, mode_list, base.link)
- drm_output_destroy_mode(backend, mode);
-}
-
-void
-drm_output_print_modes(struct drm_output *output)
-{
- struct weston_mode *m;
- struct drm_mode *dm;
- const char *aspect_ratio;
-
- wl_list_for_each(m, &output->base.mode_list, link) {
- dm = to_drm_mode(m);
-
- aspect_ratio = aspect_ratio_to_string(m->aspect_ratio);
- weston_log_continue(STAMP_SPACE "%dx%d@%.1f%s%s%s, %.1f MHz\n",
- m->width, m->height, m->refresh / 1000.0,
- aspect_ratio,
- m->flags & WL_OUTPUT_MODE_PREFERRED ?
- ", preferred" : "",
- m->flags & WL_OUTPUT_MODE_CURRENT ?
- ", current" : "",
- dm->mode_info.clock / 1000.0);
- }
-}
-
-
-/**
- * Find the closest-matching mode for a given target
- *
- * Given a target mode, find the most suitable mode amongst the output's
- * current mode list to use, preferring the current mode if possible, to
- * avoid an expensive mode switch.
- *
- * @param output DRM output
- * @param target_mode Mode to attempt to match
- * @returns Pointer to a mode from the output's mode list
- */
-struct drm_mode *
-drm_output_choose_mode(struct drm_output *output,
- struct weston_mode *target_mode)
-{
- struct drm_mode *tmp_mode = NULL, *mode_fall_back = NULL, *mode;
- enum weston_mode_aspect_ratio src_aspect = WESTON_MODE_PIC_AR_NONE;
- enum weston_mode_aspect_ratio target_aspect = WESTON_MODE_PIC_AR_NONE;
- struct drm_backend *b;
-
- b = to_drm_backend(output->base.compositor);
- target_aspect = target_mode->aspect_ratio;
- src_aspect = output->base.current_mode->aspect_ratio;
- if (output->base.current_mode->width == target_mode->width &&
- output->base.current_mode->height == target_mode->height &&
- (output->base.current_mode->refresh == target_mode->refresh ||
- target_mode->refresh == 0)) {
- if (!b->aspect_ratio_supported || src_aspect == target_aspect)
- return to_drm_mode(output->base.current_mode);
- }
-
- wl_list_for_each(mode, &output->base.mode_list, base.link) {
-
- src_aspect = mode->base.aspect_ratio;
- if (mode->mode_info.hdisplay == target_mode->width &&
- mode->mode_info.vdisplay == target_mode->height) {
- if (mode->base.refresh == target_mode->refresh ||
- target_mode->refresh == 0) {
- if (!b->aspect_ratio_supported ||
- src_aspect == target_aspect)
- return mode;
- else if (!mode_fall_back)
- mode_fall_back = mode;
- } else if (!tmp_mode) {
- tmp_mode = mode;
- }
- }
- }
-
- if (mode_fall_back)
- return mode_fall_back;
-
- return tmp_mode;
-}
-
-void
-update_head_from_connector(struct drm_head *head,
- drmModeObjectProperties *props)
-{
- const char *make = "unknown";
- const char *model = "unknown";
- const char *serial_number = "unknown";
-
- find_and_parse_output_edid(head, props, &make, &model, &serial_number);
- weston_head_set_monitor_strings(&head->base, make, model, serial_number);
- weston_head_set_non_desktop(&head->base,
- check_non_desktop(head, props));
- weston_head_set_subpixel(&head->base,
- drm_subpixel_to_wayland(head->connector->subpixel));
-
- weston_head_set_physical_size(&head->base, head->connector->mmWidth,
- head->connector->mmHeight);
-
- /* Unknown connection status is assumed disconnected. */
- weston_head_set_connection_status(&head->base,
- head->connector->connection == DRM_MODE_CONNECTED);
-}
-
-/**
- * Choose suitable mode for an output
- *
- * Find the most suitable mode to use for initial setup (or reconfiguration on
- * hotplug etc) for a DRM output.
- *
- * @param backend the DRM backend
- * @param output DRM output to choose mode for
- * @param mode Strategy and preference to use when choosing mode
- * @param modeline Manually-entered mode (may be NULL)
- * @param current_mode Mode currently being displayed on this output
- * @returns A mode from the output's mode list, or NULL if none available
- */
-static struct drm_mode *
-drm_output_choose_initial_mode(struct drm_backend *backend,
- struct drm_output *output,
- enum weston_drm_backend_output_mode mode,
- const char *modeline,
- const drmModeModeInfo *current_mode)
-{
- struct drm_mode *preferred = NULL;
- struct drm_mode *current = NULL;
- struct drm_mode *configured = NULL;
- struct drm_mode *config_fall_back = NULL;
- struct drm_mode *best = NULL;
- struct drm_mode *drm_mode;
- drmModeModeInfo drm_modeline;
- int32_t width = 0;
- int32_t height = 0;
- uint32_t refresh = 0;
- uint32_t aspect_width = 0;
- uint32_t aspect_height = 0;
- enum weston_mode_aspect_ratio aspect_ratio = WESTON_MODE_PIC_AR_NONE;
- int n;
-
- if (mode == WESTON_DRM_BACKEND_OUTPUT_PREFERRED && modeline) {
- n = sscanf(modeline, "%dx%d@%d %u:%u", &width, &height,
- &refresh, &aspect_width, &aspect_height);
- if (backend->aspect_ratio_supported && n == 5) {
- if (aspect_width == 4 && aspect_height == 3)
- aspect_ratio = WESTON_MODE_PIC_AR_4_3;
- else if (aspect_width == 16 && aspect_height == 9)
- aspect_ratio = WESTON_MODE_PIC_AR_16_9;
- else if (aspect_width == 64 && aspect_height == 27)
- aspect_ratio = WESTON_MODE_PIC_AR_64_27;
- else if (aspect_width == 256 && aspect_height == 135)
- aspect_ratio = WESTON_MODE_PIC_AR_256_135;
- else
- weston_log("Invalid modeline \"%s\" for output %s\n",
- modeline, output->base.name);
- }
- if (n != 2 && n != 3 && n != 5) {
- width = -1;
-
- if (parse_modeline(modeline, &drm_modeline) == 0) {
- configured = drm_output_add_mode(output, &drm_modeline);
- if (!configured)
- return NULL;
- } else {
- weston_log("Invalid modeline \"%s\" for output %s\n",
- modeline, output->base.name);
- }
- }
- }
-
- wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
- if (width == drm_mode->base.width &&
- height == drm_mode->base.height &&
- (refresh == 0 || refresh == drm_mode->mode_info.vrefresh)) {
- if (!backend->aspect_ratio_supported ||
- aspect_ratio == drm_mode->base.aspect_ratio)
- configured = drm_mode;
- else
- config_fall_back = drm_mode;
- }
-
- if (memcmp(current_mode, &drm_mode->mode_info,
- sizeof *current_mode) == 0)
- current = drm_mode;
-
- if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
- preferred = drm_mode;
-
- best = drm_mode;
- }
-
- if (current == NULL && current_mode->clock != 0) {
- current = drm_output_add_mode(output, current_mode);
- if (!current)
- return NULL;
- }
-
- if (mode == WESTON_DRM_BACKEND_OUTPUT_CURRENT)
- configured = current;
-
- if (configured)
- return configured;
-
- if (config_fall_back)
- return config_fall_back;
-
- if (preferred)
- return preferred;
-
- if (current)
- return current;
-
- if (best)
- return best;
-
- weston_log("no available modes for %s\n", output->base.name);
- return NULL;
-}
-
-static uint32_t
-u32distance(uint32_t a, uint32_t b)
-{
- if (a < b)
- return b - a;
- else
- return a - b;
-}
-
-/** Choose equivalent mode
- *
- * If the two modes are not equivalent, return NULL.
- * Otherwise return the mode that is more likely to work in place of both.
- *
- * None of the fuzzy matching criteria in this function have any justification.
- *
- * typedef struct _drmModeModeInfo {
- * uint32_t clock;
- * uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
- * uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
- *
- * uint32_t vrefresh;
- *
- * uint32_t flags;
- * uint32_t type;
- * char name[DRM_DISPLAY_MODE_LEN];
- * } drmModeModeInfo, *drmModeModeInfoPtr;
- */
-static const drmModeModeInfo *
-drm_mode_pick_equivalent(const drmModeModeInfo *a, const drmModeModeInfo *b)
-{
- uint32_t refresh_a, refresh_b;
-
- if (a->hdisplay != b->hdisplay || a->vdisplay != b->vdisplay)
- return NULL;
-
- if (a->flags != b->flags)
- return NULL;
-
- /* kHz */
- if (u32distance(a->clock, b->clock) > 500)
- return NULL;
-
- refresh_a = drm_refresh_rate_mHz(a);
- refresh_b = drm_refresh_rate_mHz(b);
- if (u32distance(refresh_a, refresh_b) > 50)
- return NULL;
-
- if ((a->type ^ b->type) & DRM_MODE_TYPE_PREFERRED) {
- if (a->type & DRM_MODE_TYPE_PREFERRED)
- return a;
- else
- return b;
- }
-
- return a;
-}
-
-/* If the given mode info is not already in the list, add it.
- * If it is in the list, either keep the existing or replace it,
- * depending on which one is "better".
- */
-static int
-drm_output_try_add_mode(struct drm_output *output, const drmModeModeInfo *info)
-{
- struct weston_mode *base;
- struct drm_mode *mode;
- struct drm_backend *backend;
- const drmModeModeInfo *chosen = NULL;
-
- assert(info);
-
- wl_list_for_each(base, &output->base.mode_list, link) {
- mode = to_drm_mode(base);
- chosen = drm_mode_pick_equivalent(&mode->mode_info, info);
- if (chosen)
- break;
- }
-
- if (chosen == info) {
- backend = to_drm_backend(output->base.compositor);
- drm_output_destroy_mode(backend, mode);
- chosen = NULL;
- }
-
- if (!chosen) {
- mode = drm_output_add_mode(output, info);
- if (!mode)
- return -1;
- }
- /* else { the equivalent mode is already in the list } */
-
- return 0;
-}
-
-/** Rewrite the output's mode list
- *
- * @param output The output.
- * @return 0 on success, -1 on failure.
- *
- * Destroy all existing modes in the list, and reconstruct a new list from
- * scratch, based on the currently attached heads.
- *
- * On failure the output's mode list may contain some modes.
- */
-static int
-drm_output_update_modelist_from_heads(struct drm_output *output)
-{
- struct drm_backend *backend = to_drm_backend(output->base.compositor);
- struct weston_head *head_base;
- struct drm_head *head;
- int i;
- int ret;
-
- assert(!output->base.enabled);
-
- drm_mode_list_destroy(backend, &output->base.mode_list);
-
- wl_list_for_each(head_base, &output->base.head_list, output_link) {
- head = to_drm_head(head_base);
- for (i = 0; i < head->connector->count_modes; i++) {
- ret = drm_output_try_add_mode(output,
- &head->connector->modes[i]);
- if (ret < 0)
- return -1;
- }
- }
-
- return 0;
-}
-
-int
-drm_output_set_mode(struct weston_output *base,
- enum weston_drm_backend_output_mode mode,
- const char *modeline)
-{
- struct drm_output *output = to_drm_output(base);
- struct drm_backend *b = to_drm_backend(base->compositor);
- struct drm_head *head = to_drm_head(weston_output_get_first_head(base));
-
- struct drm_mode *current;
-
- if (output->virtual)
- return -1;
-
- if (drm_output_update_modelist_from_heads(output) < 0)
- return -1;
-
- current = drm_output_choose_initial_mode(b, output, mode, modeline,
- &head->inherited_mode);
- if (!current)
- return -1;
-
- output->base.current_mode = &current->base;
- output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
-
- /* Set native_ fields, so weston_output_mode_switch_to_native() works */
- output->base.native_mode = output->base.current_mode;
- output->base.native_scale = output->base.current_scale;
-
- return 0;
-}
diff --git a/libweston/backend-drm/state-helpers.c b/libweston/backend-drm/state-helpers.c
deleted file mode 100644
index 7b1d9241..00000000
--- a/libweston/backend-drm/state-helpers.c
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2011 Intel Corporation
- * Copyright © 2017, 2018 Collabora, Ltd.
- * Copyright © 2017, 2018 General Electric Company
- * Copyright (c) 2018 DisplayLink (UK) Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-#include <drm_fourcc.h>
-
-#include "drm-internal.h"
-
-/**
- * Allocate a new, empty, plane state.
- */
-struct drm_plane_state *
-drm_plane_state_alloc(struct drm_output_state *state_output,
- struct drm_plane *plane)
-{
- struct drm_plane_state *state = zalloc(sizeof(*state));
-
- assert(state);
- state->output_state = state_output;
- state->plane = plane;
- state->in_fence_fd = -1;
- state->zpos = DRM_PLANE_ZPOS_INVALID_PLANE;
- pixman_region32_init(&state->damage);
-
- /* Here we only add the plane state to the desired link, and not
- * set the member. Having an output pointer set means that the
- * plane will be displayed on the output; this won't be the case
- * when we go to disable a plane. In this case, it must be part of
- * the commit (and thus the output state), but the member must be
- * NULL, as it will not be on any output when the state takes
- * effect.
- */
- if (state_output)
- wl_list_insert(&state_output->plane_list, &state->link);
- else
- wl_list_init(&state->link);
-
- return state;
-}
-
-/**
- * Free an existing plane state. As a special case, the state will not
- * normally be freed if it is the current state; see drm_plane_set_state.
- */
-void
-drm_plane_state_free(struct drm_plane_state *state, bool force)
-{
- if (!state)
- return;
-
- wl_list_remove(&state->link);
- wl_list_init(&state->link);
- state->output_state = NULL;
- state->in_fence_fd = -1;
- state->zpos = DRM_PLANE_ZPOS_INVALID_PLANE;
- pixman_region32_fini(&state->damage);
-
- if (force || state != state->plane->state_cur) {
- drm_fb_unref(state->fb);
- free(state);
- }
-}
-
-/**
- * Duplicate an existing plane state into a new plane state, storing it within
- * the given output state. If the output state already contains a plane state
- * for the drm_plane referenced by 'src', that plane state is freed first.
- */
-struct drm_plane_state *
-drm_plane_state_duplicate(struct drm_output_state *state_output,
- struct drm_plane_state *src)
-{
- struct drm_plane_state *dst = malloc(sizeof(*dst));
- struct drm_plane_state *old, *tmp;
-
- assert(src);
- assert(dst);
- *dst = *src;
- wl_list_init(&dst->link);
-
- wl_list_for_each_safe(old, tmp, &state_output->plane_list, link) {
- /* Duplicating a plane state into the same output state, so
- * it can replace itself with an identical copy of itself,
- * makes no sense. */
- assert(old != src);
- if (old->plane == dst->plane)
- drm_plane_state_free(old, false);
- }
-
- wl_list_insert(&state_output->plane_list, &dst->link);
- if (src->fb)
- dst->fb = drm_fb_ref(src->fb);
- dst->output_state = state_output;
- pixman_region32_init(&dst->damage);
- dst->complete = false;
-
- return dst;
-}
-
-/**
- * Remove a plane state from an output state; if the plane was previously
- * enabled, then replace it with a disabling state. This ensures that the
- * output state was untouched from it was before the plane state was
- * modified by the caller of this function.
- *
- * This is required as drm_output_state_get_plane may either allocate a
- * new plane state, in which case this function will just perform a matching
- * drm_plane_state_free, or it may instead repurpose an existing disabling
- * state (if the plane was previously active), in which case this function
- * will reset it.
- */
-void
-drm_plane_state_put_back(struct drm_plane_state *state)
-{
- struct drm_output_state *state_output;
- struct drm_plane *plane;
-
- if (!state)
- return;
-
- state_output = state->output_state;
- plane = state->plane;
- drm_plane_state_free(state, false);
-
- /* Plane was previously disabled; no need to keep this temporary
- * state around. */
- if (!plane->state_cur->fb)
- return;
-
- (void) drm_plane_state_alloc(state_output, plane);
-}
-
-/**
- * Given a weston_view, fill the drm_plane_state's co-ordinates to display on
- * a given plane.
- */
-bool
-drm_plane_state_coords_for_view(struct drm_plane_state *state,
- struct weston_view *ev, uint64_t zpos)
-{
- struct drm_output *output = state->output;
- struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
- pixman_region32_t dest_rect, src_rect;
- pixman_box32_t *box, tbox;
- float sxf1, syf1, sxf2, syf2;
-
- if (!drm_view_transform_supported(ev, &output->base))
- return false;
-
- /* Update the base weston_plane co-ordinates. */
- box = pixman_region32_extents(&ev->transform.boundingbox);
- state->plane->base.x = box->x1;
- state->plane->base.y = box->y1;
-
- /* First calculate the destination co-ordinates by taking the
- * area of the view which is visible on this output, performing any
- * transforms to account for output rotation and scale as necessary. */
- pixman_region32_init(&dest_rect);
- pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
- &output->base.region);
- pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
- box = pixman_region32_extents(&dest_rect);
- tbox = weston_transformed_rect(output->base.width,
- output->base.height,
- output->base.transform,
- output->base.current_scale,
- *box);
- state->dest_x = tbox.x1;
- state->dest_y = tbox.y1;
- state->dest_w = tbox.x2 - tbox.x1;
- state->dest_h = tbox.y2 - tbox.y1;
- pixman_region32_fini(&dest_rect);
-
- /* Now calculate the source rectangle, by finding the extents of the
- * view, and working backwards to source co-ordinates. */
- pixman_region32_init(&src_rect);
- pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
- &output->base.region);
- box = pixman_region32_extents(&src_rect);
- weston_view_from_global_float(ev, box->x1, box->y1, &sxf1, &syf1);
- weston_surface_to_buffer_float(ev->surface, sxf1, syf1, &sxf1, &syf1);
- weston_view_from_global_float(ev, box->x2, box->y2, &sxf2, &syf2);
- weston_surface_to_buffer_float(ev->surface, sxf2, syf2, &sxf2, &syf2);
- pixman_region32_fini(&src_rect);
-
- /* Buffer transforms may mean that x2 is to the left of x1, and/or that
- * y2 is above y1. */
- if (sxf2 < sxf1) {
- double tmp = sxf1;
- sxf1 = sxf2;
- sxf2 = tmp;
- }
- if (syf2 < syf1) {
- double tmp = syf1;
- syf1 = syf2;
- syf2 = tmp;
- }
-
- /* Shift from S23.8 wl_fixed to U16.16 KMS fixed-point encoding. */
- state->src_x = wl_fixed_from_double(sxf1) << 8;
- state->src_y = wl_fixed_from_double(syf1) << 8;
- state->src_w = wl_fixed_from_double(sxf2 - sxf1) << 8;
- state->src_h = wl_fixed_from_double(syf2 - syf1) << 8;
-
- /* Clamp our source co-ordinates to surface bounds; it's possible
- * for intermediate translations to give us slightly incorrect
- * co-ordinates if we have, for example, multiple zooming
- * transformations. View bounding boxes are also explicitly rounded
- * greedily. */
- if (state->src_x < 0)
- state->src_x = 0;
- if (state->src_y < 0)
- state->src_y = 0;
- if (state->src_w > (uint32_t) ((buffer->width << 16) - state->src_x))
- state->src_w = (buffer->width << 16) - state->src_x;
- if (state->src_h > (uint32_t) ((buffer->height << 16) - state->src_y))
- state->src_h = (buffer->height << 16) - state->src_y;
-
- /* apply zpos if available */
- state->zpos = zpos;
-
- return true;
-}
-
-/**
- * Return a plane state from a drm_output_state.
- */
-struct drm_plane_state *
-drm_output_state_get_existing_plane(struct drm_output_state *state_output,
- struct drm_plane *plane)
-{
- struct drm_plane_state *ps;
-
- wl_list_for_each(ps, &state_output->plane_list, link) {
- if (ps->plane == plane)
- return ps;
- }
-
- return NULL;
-}
-
-/**
- * Return a plane state from a drm_output_state, either existing or
- * freshly allocated.
- */
-struct drm_plane_state *
-drm_output_state_get_plane(struct drm_output_state *state_output,
- struct drm_plane *plane)
-{
- struct drm_plane_state *ps;
-
- ps = drm_output_state_get_existing_plane(state_output, plane);
- if (ps)
- return ps;
-
- return drm_plane_state_alloc(state_output, plane);
-}
-
-/**
- * Allocate a new, empty drm_output_state. This should not generally be used
- * in the repaint cycle; see drm_output_state_duplicate.
- */
-struct drm_output_state *
-drm_output_state_alloc(struct drm_output *output,
- struct drm_pending_state *pending_state)
-{
- struct drm_output_state *state = zalloc(sizeof(*state));
-
- assert(state);
- state->output = output;
- state->dpms = WESTON_DPMS_OFF;
- state->protection = WESTON_HDCP_DISABLE;
- state->pending_state = pending_state;
- if (pending_state)
- wl_list_insert(&pending_state->output_list, &state->link);
- else
- wl_list_init(&state->link);
-
- wl_list_init(&state->plane_list);
-
- return state;
-}
-
-/**
- * Duplicate an existing drm_output_state into a new one. This is generally
- * used during the repaint cycle, to capture the existing state of an output
- * and modify it to create a new state to be used.
- *
- * The mode determines whether the output will be reset to an a blank state,
- * or an exact mirror of the current state.
- */
-struct drm_output_state *
-drm_output_state_duplicate(struct drm_output_state *src,
- struct drm_pending_state *pending_state,
- enum drm_output_state_duplicate_mode plane_mode)
-{
- struct drm_output_state *dst = malloc(sizeof(*dst));
- struct drm_plane_state *ps;
-
- assert(dst);
-
- /* Copy the whole structure, then individually modify the
- * pending_state, as well as the list link into our pending
- * state. */
- *dst = *src;
-
- dst->pending_state = pending_state;
- if (pending_state)
- wl_list_insert(&pending_state->output_list, &dst->link);
- else
- wl_list_init(&dst->link);
-
- wl_list_init(&dst->plane_list);
-
- wl_list_for_each(ps, &src->plane_list, link) {
- /* Don't carry planes which are now disabled; these should be
- * free for other outputs to reuse. */
- if (!ps->output)
- continue;
-
- if (plane_mode == DRM_OUTPUT_STATE_CLEAR_PLANES)
- (void) drm_plane_state_alloc(dst, ps->plane);
- else
- (void) drm_plane_state_duplicate(dst, ps);
- }
-
- return dst;
-}
-
-/**
- * Free an unused drm_output_state.
- */
-void
-drm_output_state_free(struct drm_output_state *state)
-{
- struct drm_plane_state *ps, *next;
-
- if (!state)
- return;
-
- wl_list_for_each_safe(ps, next, &state->plane_list, link)
- drm_plane_state_free(ps, false);
-
- wl_list_remove(&state->link);
-
- free(state);
-}
-
-/**
- * Allocate a new drm_pending_state
- *
- * Allocate a new, empty, 'pending state' structure to be used across a
- * repaint cycle or similar.
- *
- * @param backend DRM backend
- * @returns Newly-allocated pending state structure
- */
-struct drm_pending_state *
-drm_pending_state_alloc(struct drm_backend *backend)
-{
- struct drm_pending_state *ret;
-
- ret = calloc(1, sizeof(*ret));
- if (!ret)
- return NULL;
-
- ret->backend = backend;
- wl_list_init(&ret->output_list);
-
- return ret;
-}
-
-/**
- * Free a drm_pending_state structure
- *
- * Frees a pending_state structure, as well as any output_states connected
- * to this pending state.
- *
- * @param pending_state Pending state structure to free
- */
-void
-drm_pending_state_free(struct drm_pending_state *pending_state)
-{
- struct drm_output_state *output_state, *tmp;
-
- if (!pending_state)
- return;
-
- wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
- link) {
- drm_output_state_free(output_state);
- }
-
- free(pending_state);
-}
-
-/**
- * Find an output state in a pending state
- *
- * Given a pending_state structure, find the output_state for a particular
- * output.
- *
- * @param pending_state Pending state structure to search
- * @param output Output to find state for
- * @returns Output state if present, or NULL if not
- */
-struct drm_output_state *
-drm_pending_state_get_output(struct drm_pending_state *pending_state,
- struct drm_output *output)
-{
- struct drm_output_state *output_state;
-
- wl_list_for_each(output_state, &pending_state->output_list, link) {
- if (output_state->output == output)
- return output_state;
- }
-
- return NULL;
-}
diff --git a/libweston/backend-drm/state-propose.c b/libweston/backend-drm/state-propose.c
deleted file mode 100644
index 767c34f4..00000000
--- a/libweston/backend-drm/state-propose.c
+++ /dev/null
@@ -1,1149 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2011 Intel Corporation
- * Copyright © 2017, 2018 Collabora, Ltd.
- * Copyright © 2017, 2018 General Electric Company
- * Copyright (c) 2018 DisplayLink (UK) Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-
-#include <libweston/libweston.h>
-#include <libweston/backend-drm.h>
-#include <libweston/pixel-formats.h>
-
-#include "drm-internal.h"
-
-#include "linux-dmabuf.h"
-#include "presentation-time-server-protocol.h"
-
-enum drm_output_propose_state_mode {
- DRM_OUTPUT_PROPOSE_STATE_MIXED, /**< mix renderer & planes */
- DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY, /**< only assign to renderer & cursor */
- DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY, /**< no renderer use, only planes */
-};
-
-static const char *const drm_output_propose_state_mode_as_string[] = {
- [DRM_OUTPUT_PROPOSE_STATE_MIXED] = "mixed state",
- [DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY] = "render-only state",
- [DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY] = "plane-only state"
-};
-
-static const char *
-drm_propose_state_mode_to_string(enum drm_output_propose_state_mode mode)
-{
- if (mode < 0 || mode >= ARRAY_LENGTH(drm_output_propose_state_mode_as_string))
- return " unknown compositing mode";
-
- return drm_output_propose_state_mode_as_string[mode];
-}
-
-static void
-drm_output_add_zpos_plane(struct drm_plane *plane, struct wl_list *planes)
-{
- struct drm_backend *b = plane->backend;
- struct drm_plane_zpos *h_plane;
- struct drm_plane_zpos *plane_zpos;
-
- plane_zpos = zalloc(sizeof(*plane_zpos));
- if (!plane_zpos)
- return;
-
- plane_zpos->plane = plane;
-
- drm_debug(b, "\t\t\t\t[plane] plane %d added to candidate list\n",
- plane->plane_id);
-
- if (wl_list_empty(planes)) {
- wl_list_insert(planes, &plane_zpos->link);
- return;
- }
-
- h_plane = wl_container_of(planes->next, h_plane, link);
- if (h_plane->plane->zpos_max >= plane->zpos_max) {
- wl_list_insert(planes->prev, &plane_zpos->link);
- } else {
- struct drm_plane_zpos *p_zpos = NULL;
-
- if (wl_list_length(planes) == 1) {
- wl_list_insert(planes->prev, &plane_zpos->link);
- return;
- }
-
- wl_list_for_each(p_zpos, planes, link) {
- if (p_zpos->plane->zpos_max >
- plane_zpos->plane->zpos_max)
- break;
- }
-
- wl_list_insert(p_zpos->link.prev, &plane_zpos->link);
- }
-}
-
-static void
-drm_output_destroy_zpos_plane(struct drm_plane_zpos *plane_zpos)
-{
- wl_list_remove(&plane_zpos->link);
- free(plane_zpos);
-}
-
-static bool
-drm_output_check_plane_has_view_assigned(struct drm_plane *plane,
- struct drm_output_state *output_state)
-{
- struct drm_plane_state *ps;
- wl_list_for_each(ps, &output_state->plane_list, link) {
- if (ps->plane == plane && ps->fb)
- return true;
- }
- return false;
-}
-
-static bool
-drm_output_plane_has_valid_format(struct drm_plane *plane,
- struct drm_output_state *state,
- struct drm_fb *fb)
-{
- struct drm_backend *b = plane->backend;
- unsigned int i;
-
- if (!fb)
- return false;
-
- /* Check whether the format is supported */
- for (i = 0; i < plane->count_formats; i++) {
- unsigned int j;
-
- if (plane->formats[i].format != fb->format->format)
- continue;
-
- if (fb->modifier == DRM_FORMAT_MOD_INVALID)
- return true;
-
- for (j = 0; j < plane->formats[i].count_modifiers; j++) {
- if (plane->formats[i].modifiers[j] == fb->modifier)
- return true;
- }
- }
-
- drm_debug(b, "\t\t\t\t[%s] not placing view on %s: "
- "no free %s planes matching format %s (0x%lx) "
- "modifier 0x%llx\n",
- drm_output_get_plane_type_name(plane),
- drm_output_get_plane_type_name(plane),
- drm_output_get_plane_type_name(plane),
- fb->format->drm_format_name,
- (unsigned long) fb->format,
- (unsigned long long) fb->modifier);
-
- return false;
-}
-
-static bool
-drm_output_plane_cursor_has_valid_format(struct weston_view *ev)
-{
- struct wl_shm_buffer *shmbuf =
- wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource);
-
- if (shmbuf && wl_shm_buffer_get_format(shmbuf) == WL_SHM_FORMAT_ARGB8888)
- return true;
-
- return false;
-}
-
-static struct drm_plane_state *
-drm_output_prepare_overlay_view(struct drm_plane *plane,
- struct drm_output_state *output_state,
- struct weston_view *ev,
- enum drm_output_propose_state_mode mode,
- struct drm_fb *fb, uint64_t zpos)
-{
- struct drm_output *output = output_state->output;
- struct weston_compositor *ec = output->base.compositor;
- struct drm_backend *b = to_drm_backend(ec);
- struct drm_plane_state *state = NULL;
- int ret;
-
- assert(!b->sprites_are_broken);
- assert(b->atomic_modeset);
-
- if (!fb) {
- drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
- " couldn't get fb\n", ev);
- return NULL;
- }
-
- state = drm_output_state_get_plane(output_state, plane);
- /* we can't have a 'pending' framebuffer as never set one before reaching here */
- assert(!state->fb);
-
- state->ev = ev;
- state->output = output;
-
- if (!drm_plane_state_coords_for_view(state, ev, zpos)) {
- drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
- "unsuitable transform\n", ev);
- drm_plane_state_put_back(state);
- state = NULL;
- goto out;
- }
-
- /* If the surface buffer has an in-fence fd, but the plane
- * doesn't support fences, we can't place the buffer on this
- * plane. */
- if (ev->surface->acquire_fence_fd >= 0 &&
- plane->props[WDRM_PLANE_IN_FENCE_FD].prop_id == 0) {
- drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
- "no in-fence support\n", ev);
- drm_plane_state_put_back(state);
- state = NULL;
- goto out;
- }
-
- /* We hold one reference for the lifetime of this function; from
- * calling drm_fb_get_from_view() in drm_output_prepare_plane_view(),
- * so, we take another reference here to live within the state. */
- state->fb = drm_fb_ref(fb);
-
- state->in_fence_fd = ev->surface->acquire_fence_fd;
-
- /* In planes-only mode, we don't have an incremental state to
- * test against, so we just hope it'll work. */
- if (mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY) {
- drm_debug(b, "\t\t\t[overlay] provisionally placing "
- "view %p on overlay %lu in planes-only mode\n",
- ev, (unsigned long) plane->plane_id);
- goto out;
- }
-
- ret = drm_pending_state_test(output_state->pending_state);
- if (ret == 0) {
- drm_debug(b, "\t\t\t[overlay] provisionally placing "
- "view %p on overlay %d in mixed mode\n",
- ev, plane->plane_id);
- goto out;
- }
-
- drm_debug(b, "\t\t\t[overlay] not placing view %p on overlay %lu "
- "in mixed mode: kernel test failed\n",
- ev, (unsigned long) plane->plane_id);
-
- drm_plane_state_put_back(state);
- state = NULL;
-
-out:
- return state;
-}
-
-#ifdef BUILD_DRM_GBM
-/**
- * Update the image for the current cursor surface
- *
- * @param plane_state DRM cursor plane state
- * @param ev Source view for cursor
- */
-static void
-cursor_bo_update(struct drm_plane_state *plane_state, struct weston_view *ev)
-{
- struct drm_backend *b = plane_state->plane->backend;
- struct gbm_bo *bo = plane_state->fb->bo;
- struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
- uint32_t buf[b->cursor_width * b->cursor_height];
- int32_t stride;
- uint8_t *s;
- int i;
-
- assert(buffer && buffer->shm_buffer);
- assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
- assert(buffer->width <= b->cursor_width);
- assert(buffer->height <= b->cursor_height);
-
- memset(buf, 0, sizeof buf);
- stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
- s = wl_shm_buffer_get_data(buffer->shm_buffer);
-
- wl_shm_buffer_begin_access(buffer->shm_buffer);
- for (i = 0; i < buffer->height; i++)
- memcpy(buf + i * b->cursor_width,
- s + i * stride,
- buffer->width * 4);
- wl_shm_buffer_end_access(buffer->shm_buffer);
-
- if (gbm_bo_write(bo, buf, sizeof buf) < 0)
- weston_log("failed update cursor: %s\n", strerror(errno));
-}
-
-static struct drm_plane_state *
-drm_output_prepare_cursor_view(struct drm_output_state *output_state,
- struct weston_view *ev, uint64_t zpos)
-{
- struct drm_output *output = output_state->output;
- struct drm_backend *b = to_drm_backend(output->base.compositor);
- struct drm_plane *plane = output->cursor_plane;
- struct drm_plane_state *plane_state;
- bool needs_update = false;
- const char *p_name = drm_output_get_plane_type_name(plane);
-
- assert(!b->cursors_are_broken);
-
- if (!plane)
- return NULL;
-
- if (!plane->state_cur->complete)
- return NULL;
-
- if (plane->state_cur->output && plane->state_cur->output != output)
- return NULL;
-
- /* We use GBM to import SHM buffers. */
- if (b->gbm == NULL)
- return NULL;
-
- plane_state =
- drm_output_state_get_plane(output_state, output->cursor_plane);
-
- if (plane_state && plane_state->fb)
- return NULL;
-
- /* We can't scale with the legacy API, and we don't try to account for
- * simple cropping/translation in cursor_bo_update. */
- plane_state->output = output;
- if (!drm_plane_state_coords_for_view(plane_state, ev, zpos)) {
- drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
- "unsuitable transform\n", p_name, ev, p_name);
- goto err;
- }
-
- if (plane_state->src_x != 0 || plane_state->src_y != 0 ||
- plane_state->src_w > (unsigned) b->cursor_width << 16 ||
- plane_state->src_h > (unsigned) b->cursor_height << 16 ||
- plane_state->src_w != plane_state->dest_w << 16 ||
- plane_state->src_h != plane_state->dest_h << 16) {
- drm_debug(b, "\t\t\t\t[%s] not assigning view %p to %s plane "
- "(positioning requires cropping or scaling)\n",
- p_name, ev, p_name);
- goto err;
- }
-
- /* Since we're setting plane state up front, we need to work out
- * whether or not we need to upload a new cursor. We can't use the
- * plane damage, since the planes haven't actually been calculated
- * yet: instead try to figure it out directly. KMS cursor planes are
- * pretty unique here, in that they lie partway between a Weston plane
- * (direct scanout) and a renderer. */
- if (ev != output->cursor_view ||
- pixman_region32_not_empty(&ev->surface->damage)) {
- output->current_cursor++;
- output->current_cursor =
- output->current_cursor %
- ARRAY_LENGTH(output->gbm_cursor_fb);
- needs_update = true;
- }
-
- output->cursor_view = ev;
- plane_state->ev = ev;
-
- plane_state->fb =
- drm_fb_ref(output->gbm_cursor_fb[output->current_cursor]);
-
- if (needs_update) {
- drm_debug(b, "\t\t\t\t[%s] copying new content to cursor BO\n", p_name);
- cursor_bo_update(plane_state, ev);
- }
-
- /* The cursor API is somewhat special: in cursor_bo_update(), we upload
- * a buffer which is always cursor_width x cursor_height, even if the
- * surface we want to promote is actually smaller than this. Manually
- * mangle the plane state to deal with this. */
- plane_state->src_w = b->cursor_width << 16;
- plane_state->src_h = b->cursor_height << 16;
- plane_state->dest_w = b->cursor_width;
- plane_state->dest_h = b->cursor_height;
-
- drm_debug(b, "\t\t\t\t[%s] provisionally assigned view %p to cursor\n",
- p_name, ev);
-
- return plane_state;
-
-err:
- drm_plane_state_put_back(plane_state);
- return NULL;
-}
-#else
-static struct drm_plane_state *
-drm_output_prepare_cursor_view(struct drm_output_state *output_state,
- struct weston_view *ev, uint64_t zpos)
-{
- return NULL;
-}
-#endif
-
-static struct drm_plane_state *
-drm_output_prepare_scanout_view(struct drm_output_state *output_state,
- struct weston_view *ev,
- enum drm_output_propose_state_mode mode,
- struct drm_fb *fb, uint64_t zpos)
-{
- struct drm_output *output = output_state->output;
- struct drm_backend *b = to_drm_backend(output->base.compositor);
- struct drm_plane *scanout_plane = output->scanout_plane;
- struct drm_plane_state *state;
- const char *p_name = drm_output_get_plane_type_name(scanout_plane);
-
- assert(!b->sprites_are_broken);
- assert(b->atomic_modeset);
- assert(mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY);
-
- /* Check the view spans exactly the output size, calculated in the
- * logical co-ordinate space. */
- if (!weston_view_matches_output_entirely(ev, &output->base)) {
- drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
- " view does not match output entirely\n",
- p_name, ev, p_name);
- return NULL;
- }
-
- /* If the surface buffer has an in-fence fd, but the plane doesn't
- * support fences, we can't place the buffer on this plane. */
- if (ev->surface->acquire_fence_fd >= 0 &&
- scanout_plane->props[WDRM_PLANE_IN_FENCE_FD].prop_id == 0) {
- drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
- "no in-fence support\n", p_name, ev, p_name);
- return NULL;
- }
-
- if (!fb) {
- drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
- " couldn't get fb\n", p_name, ev, p_name);
- return NULL;
- }
-
- state = drm_output_state_get_plane(output_state, scanout_plane);
-
- /* The only way we can already have a buffer in the scanout plane is
- * if we are in mixed mode, or if a client buffer has already been
- * placed into scanout. The former case will never call into here,
- * and in the latter case, the view must have been marked as occluded,
- * meaning we should never have ended up here. */
- assert(!state->fb);
-
- /* take another reference here to live within the state */
- state->fb = drm_fb_ref(fb);
- state->ev = ev;
- state->output = output;
- if (!drm_plane_state_coords_for_view(state, ev, zpos)) {
- drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
- "unsuitable transform\n", p_name, ev, p_name);
- goto err;
- }
-
- if (state->dest_x != 0 || state->dest_y != 0 ||
- state->dest_w != (unsigned) output->base.current_mode->width ||
- state->dest_h != (unsigned) output->base.current_mode->height) {
- drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
- " invalid plane state\n", p_name, ev, p_name);
- goto err;
- }
-
- state->in_fence_fd = ev->surface->acquire_fence_fd;
-
- /* In plane-only mode, we don't need to test the state now, as we
- * will only test it once at the end. */
- return state;
-
-err:
- drm_plane_state_put_back(state);
- return NULL;
-}
-
-static bool
-drm_output_plane_view_has_valid_format(struct drm_plane *plane,
- struct drm_output_state *state,
- struct weston_view *ev,
- struct drm_fb *fb)
-{
- /* depending on the type of the plane we have different requirements */
- switch (plane->type) {
- case WDRM_PLANE_TYPE_CURSOR:
- return drm_output_plane_cursor_has_valid_format(ev);
- case WDRM_PLANE_TYPE_OVERLAY:
- return drm_output_plane_has_valid_format(plane, state, fb);
- case WDRM_PLANE_TYPE_PRIMARY:
- return drm_output_plane_has_valid_format(plane, state, fb);
- default:
- assert(0);
- return false;
- }
-
- return false;
-}
-
-static struct drm_plane_state *
-drm_output_try_view_on_plane(struct drm_plane *plane,
- struct drm_output_state *state,
- struct weston_view *ev,
- enum drm_output_propose_state_mode mode,
- struct drm_fb *fb, uint64_t zpos)
-{
- struct drm_backend *b = state->pending_state->backend;
- struct weston_output *wet_output = &state->output->base;
- bool view_matches_entire_output, scanout_has_view_assigned;
- struct drm_plane *scanout_plane = state->output->scanout_plane;
- struct drm_plane_state *ps = NULL;
- const char *p_name = drm_output_get_plane_type_name(plane);
- enum {
- NO_PLANES, /* generic err-handle */
- NO_PLANES_ACCEPTED,
- PLACED_ON_PLANE,
- } availability = NO_PLANES;
-
- /* sanity checks in case we over/underflow zpos or pass incorrect
- * values */
- assert(zpos <= plane->zpos_max ||
- zpos != DRM_PLANE_ZPOS_INVALID_PLANE);
-
- switch (plane->type) {
- case WDRM_PLANE_TYPE_CURSOR:
- if (b->cursors_are_broken) {
- availability = NO_PLANES_ACCEPTED;
- goto out;
- }
-
- ps = drm_output_prepare_cursor_view(state, ev, zpos);
- if (ps)
- availability = PLACED_ON_PLANE;
- break;
- case WDRM_PLANE_TYPE_OVERLAY:
- /* do not attempt to place it in the overlay if we don't have
- * anything in the scanout/primary and the view doesn't cover
- * the entire output */
- view_matches_entire_output =
- weston_view_matches_output_entirely(ev, wet_output);
- scanout_has_view_assigned =
- drm_output_check_plane_has_view_assigned(scanout_plane,
- state);
-
- if (view_matches_entire_output && !scanout_has_view_assigned) {
- availability = NO_PLANES_ACCEPTED;
- goto out;
- }
-
- ps = drm_output_prepare_overlay_view(plane, state, ev, mode,
- fb, zpos);
- if (ps)
- availability = PLACED_ON_PLANE;
- break;
- case WDRM_PLANE_TYPE_PRIMARY:
- if (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY) {
- availability = NO_PLANES_ACCEPTED;
- goto out;
- }
-
- ps = drm_output_prepare_scanout_view(state, ev, mode,
- fb, zpos);
- if (ps)
- availability = PLACED_ON_PLANE;
- break;
- default:
- assert(0);
- break;
- }
-
-out:
- switch (availability) {
- case NO_PLANES:
- /* set initial to this catch-all case, such that
- * prepare_cursor/overlay/scanout() should have/contain the
- * reason for failling */
- break;
- case NO_PLANES_ACCEPTED:
- drm_debug(b, "\t\t\t\t[plane] plane %d refusing to "
- "place view %p in %s\n",
- plane->plane_id, ev, p_name);
- break;
- case PLACED_ON_PLANE:
- break;
- }
-
-
- return ps;
-}
-
-static void
-drm_output_check_zpos_plane_states(struct drm_output_state *state)
-{
- struct drm_plane_state *ps;
-
- wl_list_for_each(ps, &state->plane_list, link) {
- struct wl_list *next_node = ps->link.next;
- bool found_dup = false;
-
- /* skip any plane that is not enabled */
- if (!ps->fb)
- continue;
-
- assert(ps->zpos != DRM_PLANE_ZPOS_INVALID_PLANE);
-
- /* find another plane with the same zpos value */
- if (next_node == &state->plane_list)
- break;
-
- while (next_node && next_node != &state->plane_list) {
- struct drm_plane_state *ps_next;
-
- ps_next = container_of(next_node,
- struct drm_plane_state,
- link);
-
- if (ps->zpos == ps_next->zpos) {
- found_dup = true;
- break;
- }
- next_node = next_node->next;
- }
-
- /* this should never happen so exit hard in case
- * we screwed up that bad */
- assert(!found_dup);
- }
-}
-
-static struct drm_plane_state *
-drm_output_prepare_plane_view(struct drm_output_state *state,
- struct weston_view *ev,
- enum drm_output_propose_state_mode mode,
- struct drm_plane_state *scanout_state,
- uint64_t current_lowest_zpos)
-{
- struct drm_output *output = state->output;
- struct drm_backend *b = to_drm_backend(output->base.compositor);
-
- struct drm_plane_state *ps = NULL;
- struct drm_plane *plane;
- struct drm_plane_zpos *p_zpos, *p_zpos_next;
- struct wl_list zpos_candidate_list;
-
- struct drm_fb *fb;
-
- wl_list_init(&zpos_candidate_list);
-
- /* check view for valid buffer, doesn't make sense to even try */
- if (!weston_view_has_valid_buffer(ev))
- return ps;
-
- fb = drm_fb_get_from_view(state, ev);
-
- /* assemble a list with possible candidates */
- wl_list_for_each(plane, &b->plane_list, link) {
- if (!drm_plane_is_available(plane, output))
- continue;
-
- if (drm_output_check_plane_has_view_assigned(plane, state)) {
- drm_debug(b, "\t\t\t\t[plane] not adding plane %d to"
- " candidate list: view already assigned "
- "to a plane\n", plane->plane_id);
- continue;
- }
-
- if (plane->zpos_min >= current_lowest_zpos) {
- drm_debug(b, "\t\t\t\t[plane] not adding plane %d to "
- "candidate list: minium zpos (%"PRIu64") "
- "plane's above current lowest zpos "
- "(%"PRIu64")\n", plane->plane_id,
- plane->zpos_min, current_lowest_zpos);
- continue;
- }
-
- if (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED) {
- assert(scanout_state != NULL);
- if (scanout_state->zpos >= plane->zpos_max) {
- drm_debug(b, "\t\t\t\t[plane] not adding plane %d to "
- "candidate list: primary's zpos "
- "value (%"PRIu64") higher than "
- "plane's maximum value (%"PRIu64")\n",
- plane->plane_id, scanout_state->zpos,
- plane->zpos_max);
- continue;
- }
- }
-
- if (mode == DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY &&
- (plane->type == WDRM_PLANE_TYPE_OVERLAY ||
- plane->type == WDRM_PLANE_TYPE_PRIMARY)) {
- drm_debug(b, "\t\t\t\t[plane] not adding plane %d to "
- "candidate list: renderer-only mode\n",
- plane->plane_id);
- continue;
- }
-
- if (plane->type != WDRM_PLANE_TYPE_CURSOR &&
- b->sprites_are_broken) {
- drm_debug(b, "\t\t\t\t[plane] not adding plane %d, type %s to "
- "candidate list: sprites are broken!\n",
- plane->plane_id,
- drm_output_get_plane_type_name(plane));
- continue;
- }
-
- if (!drm_output_plane_view_has_valid_format(plane, state, ev, fb)) {
- drm_debug(b, "\t\t\t\t[plane] not adding plane %d to "
- "candidate list: invalid pixel format\n",
- plane->plane_id);
- continue;
- }
-
- drm_output_add_zpos_plane(plane, &zpos_candidate_list);
- }
-
- /* go over the potential candidate list and try to find a possible
- * plane suitable for \c ev; start with the highest zpos value of a
- * plane to maximize our chances, but do note we pass the zpos value
- * based on current tracked value by \c current_lowest_zpos_in_use */
- while (!wl_list_empty(&zpos_candidate_list)) {
- struct drm_plane_zpos *head_p_zpos =
- wl_container_of(zpos_candidate_list.next,
- head_p_zpos, link);
- struct drm_plane *plane = head_p_zpos->plane;
- const char *p_name = drm_output_get_plane_type_name(plane);
- uint64_t zpos;
-
- if (current_lowest_zpos == DRM_PLANE_ZPOS_INVALID_PLANE)
- zpos = plane->zpos_max;
- else
- zpos = MIN(current_lowest_zpos - 1, plane->zpos_max);
-
- drm_debug(b, "\t\t\t\t[plane] plane %d picked "
- "from candidate list, type: %s\n",
- plane->plane_id, p_name);
-
- ps = drm_output_try_view_on_plane(plane, state, ev,
- mode, fb, zpos);
- drm_output_destroy_zpos_plane(head_p_zpos);
- if (ps) {
- drm_debug(b, "\t\t\t\t[view] view %p has been placed to "
- "%s plane with computed zpos %"PRIu64"\n",
- ev, p_name, zpos);
- break;
- }
- }
-
- wl_list_for_each_safe(p_zpos, p_zpos_next, &zpos_candidate_list, link)
- drm_output_destroy_zpos_plane(p_zpos);
-
- drm_fb_unref(fb);
- return ps;
-}
-
-static struct drm_output_state *
-drm_output_propose_state(struct weston_output *output_base,
- struct drm_pending_state *pending_state,
- enum drm_output_propose_state_mode mode)
-{
- struct drm_output *output = to_drm_output(output_base);
- struct drm_backend *b = to_drm_backend(output->base.compositor);
- struct drm_output_state *state;
- struct drm_plane_state *scanout_state = NULL;
- struct weston_view *ev;
-
- pixman_region32_t surface_overlap, renderer_region, planes_region;
- pixman_region32_t occluded_region;
-
- bool renderer_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY);
- int ret;
- uint64_t current_lowest_zpos = DRM_PLANE_ZPOS_INVALID_PLANE;
-
- assert(!output->state_last);
- state = drm_output_state_duplicate(output->state_cur,
- pending_state,
- DRM_OUTPUT_STATE_CLEAR_PLANES);
-
- /* We implement mixed mode by progressively creating and testing
- * incremental states, of scanout + overlay + cursor. Since we
- * walk our views top to bottom, the scanout plane is last, however
- * we always need it in our scene for the test modeset to be
- * meaningful. To do this, we steal a reference to the last
- * renderer framebuffer we have, if we think it's basically
- * compatible. If we don't have that, then we conservatively fall
- * back to only using the renderer for this repaint. */
- if (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED) {
- struct drm_plane *plane = output->scanout_plane;
- struct drm_fb *scanout_fb = plane->state_cur->fb;
-
- if (!scanout_fb ||
- (scanout_fb->type != BUFFER_GBM_SURFACE &&
- scanout_fb->type != BUFFER_PIXMAN_DUMB)) {
- drm_debug(b, "\t\t[state] cannot propose mixed mode: "
- "for output %s (%lu): no previous renderer "
- "fb\n",
- output->base.name,
- (unsigned long) output->base.id);
- drm_output_state_free(state);
- return NULL;
- }
-
- if (scanout_fb->width != output_base->current_mode->width ||
- scanout_fb->height != output_base->current_mode->height) {
- drm_debug(b, "\t\t[state] cannot propose mixed mode "
- "for output %s (%lu): previous fb has "
- "different size\n",
- output->base.name,
- (unsigned long) output->base.id);
- drm_output_state_free(state);
- return NULL;
- }
-
- scanout_state = drm_plane_state_duplicate(state,
- plane->state_cur);
- /* assign the primary primary the lowest zpos value */
- scanout_state->zpos = plane->zpos_min;
- drm_debug(b, "\t\t[state] using renderer FB ID %lu for mixed "
- "mode for output %s (%lu)\n",
- (unsigned long) scanout_fb->fb_id, output->base.name,
- (unsigned long) output->base.id);
- drm_debug(b, "\t\t[state] scanout will use for zpos %"PRIu64"\n",
- scanout_state->zpos);
- }
-
- /* - renderer_region contains the total region which which will be
- * covered by the renderer
- * - planes_region contains the total region which has been covered by
- * hardware planes
- * - occluded_region contains the total region which which will be
- * covered by the renderer and hardware planes, where the view's
- * visible-and-opaque region is added in both cases (the view's
- * opaque region accumulates there for each view); it is being used
- * to skip the view, if it is completely occluded; includes the
- * situation where occluded_region covers entire output's region.
- */
- pixman_region32_init(&renderer_region);
- pixman_region32_init(&planes_region);
- pixman_region32_init(&occluded_region);
-
- wl_list_for_each(ev, &output_base->compositor->view_list, link) {
- struct drm_plane_state *ps = NULL;
- bool force_renderer = false;
- pixman_region32_t clipped_view;
- bool totally_occluded = false;
-
- drm_debug(b, "\t\t\t[view] evaluating view %p for "
- "output %s (%lu)\n",
- ev, output->base.name,
- (unsigned long) output->base.id);
-
- /* If this view doesn't touch our output at all, there's no
- * reason to do anything with it. */
- if (!(ev->output_mask & (1u << output->base.id))) {
- drm_debug(b, "\t\t\t\t[view] ignoring view %p "
- "(not on our output)\n", ev);
- continue;
- }
-
- /* We only assign planes to views which are exclusively present
- * on our output. */
- if (ev->output_mask != (1u << output->base.id)) {
- drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
- "(on multiple outputs)\n", ev);
- force_renderer = true;
- }
-
- if (!weston_view_has_valid_buffer(ev)) {
- drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
- "(no buffer available)\n", ev);
- force_renderer = true;
- }
-
- /* Ignore views we know to be totally occluded. */
- pixman_region32_init(&clipped_view);
- pixman_region32_intersect(&clipped_view,
- &ev->transform.boundingbox,
- &output->base.region);
-
- pixman_region32_init(&surface_overlap);
- pixman_region32_subtract(&surface_overlap, &clipped_view,
- &occluded_region);
- /* if the view is completely occluded then ignore that
- * view; includes the case where occluded_region covers
- * the entire output */
- totally_occluded = !pixman_region32_not_empty(&surface_overlap);
- if (totally_occluded) {
- drm_debug(b, "\t\t\t\t[view] ignoring view %p "
- "(occluded on our output)\n", ev);
- pixman_region32_fini(&surface_overlap);
- pixman_region32_fini(&clipped_view);
- continue;
- }
-
- /* Since we process views from top to bottom, we know that if
- * the view intersects the calculated renderer region, it must
- * be part of, or occluded by, it, and cannot go on a plane. */
- pixman_region32_intersect(&surface_overlap, &renderer_region,
- &clipped_view);
- if (pixman_region32_not_empty(&surface_overlap)) {
- drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
- "(occluded by renderer views)\n", ev);
- force_renderer = true;
- }
- pixman_region32_fini(&surface_overlap);
-
- /* In case of enforced mode of content-protection do not
- * assign planes for a protected surface on an unsecured output.
- */
- if (ev->surface->protection_mode == WESTON_SURFACE_PROTECTION_MODE_ENFORCED &&
- ev->surface->desired_protection > output_base->current_protection) {
- drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
- "(enforced protection mode on unsecured output)\n", ev);
- force_renderer = true;
- }
-
- if (!force_renderer) {
- drm_debug(b, "\t\t\t[plane] started with zpos %"PRIu64"\n",
- current_lowest_zpos);
- ps = drm_output_prepare_plane_view(state, ev, mode,
- scanout_state,
- current_lowest_zpos);
- }
-
- if (ps) {
- current_lowest_zpos = ps->zpos;
- drm_debug(b, "\t\t\t[plane] next zpos to use %"PRIu64"\n",
- current_lowest_zpos);
-
- /* If we have been assigned to an overlay or scanout
- * plane, add this area to the occluded region, so
- * other views are known to be behind it. The cursor
- * plane, however, is special, in that it blends with
- * the content underneath it: the area should neither
- * be added to the renderer region nor the occluded
- * region. */
- if (ps->plane->type != WDRM_PLANE_TYPE_CURSOR) {
- pixman_region32_union(&planes_region,
- &planes_region,
- &clipped_view);
-
- if (!weston_view_is_opaque(ev, &clipped_view))
- pixman_region32_intersect(&clipped_view,
- &clipped_view,
- &ev->transform.opaque);
- /* the visible-and-opaque region of this view
- * will occlude views underneath it */
- pixman_region32_union(&occluded_region,
- &occluded_region,
- &clipped_view);
-
- pixman_region32_fini(&clipped_view);
-
- }
- continue;
- }
-
- /* We have been assigned to the primary (renderer) plane:
- * check if this is OK, and add ourselves to the renderer
- * region if so. */
- if (!renderer_ok) {
- drm_debug(b, "\t\t[view] failing state generation: "
- "placing view %p to renderer not allowed\n",
- ev);
- pixman_region32_fini(&clipped_view);
- goto err_region;
- }
-
- pixman_region32_union(&renderer_region,
- &renderer_region,
- &clipped_view);
-
- if (!weston_view_is_opaque(ev, &clipped_view))
- pixman_region32_intersect(&clipped_view,
- &clipped_view,
- &ev->transform.opaque);
-
- pixman_region32_union(&occluded_region,
- &occluded_region,
- &clipped_view);
-
- pixman_region32_fini(&clipped_view);
-
- drm_debug(b, "\t\t\t\t[view] view %p will be placed "
- "on the renderer\n", ev);
- }
-
- pixman_region32_fini(&renderer_region);
- pixman_region32_fini(&planes_region);
- pixman_region32_fini(&occluded_region);
-
- /* In renderer-only mode, we can't test the state as we don't have a
- * renderer buffer yet. */
- if (mode == DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY)
- return state;
-
- /* check if we have invalid zpos values, like duplicate(s) */
- drm_output_check_zpos_plane_states(state);
-
- /* Check to see if this state will actually work. */
- ret = drm_pending_state_test(state->pending_state);
- if (ret != 0) {
- drm_debug(b, "\t\t[view] failing state generation: "
- "atomic test not OK\n");
- goto err;
- }
-
- /* Counterpart to duplicating scanout state at the top of this
- * function: if we have taken a renderer framebuffer and placed it in
- * the pending state in order to incrementally test overlay planes,
- * remove it now. */
- if (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED) {
- assert(scanout_state->fb->type == BUFFER_GBM_SURFACE ||
- scanout_state->fb->type == BUFFER_PIXMAN_DUMB);
- drm_plane_state_put_back(scanout_state);
- }
- return state;
-
-err_region:
- pixman_region32_fini(&renderer_region);
- pixman_region32_fini(&occluded_region);
-err:
- drm_output_state_free(state);
- return NULL;
-}
-
-void
-drm_assign_planes(struct weston_output *output_base, void *repaint_data)
-{
- struct drm_backend *b = to_drm_backend(output_base->compositor);
- struct drm_pending_state *pending_state = repaint_data;
- struct drm_output *output = to_drm_output(output_base);
- struct drm_output_state *state = NULL;
- struct drm_plane_state *plane_state;
- struct weston_view *ev;
- struct weston_plane *primary = &output_base->compositor->primary_plane;
- enum drm_output_propose_state_mode mode = DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY;
-
- drm_debug(b, "\t[repaint] preparing state for output %s (%lu)\n",
- output_base->name, (unsigned long) output_base->id);
-
- if (!b->sprites_are_broken && !output->virtual) {
- drm_debug(b, "\t[repaint] trying planes-only build state\n");
- state = drm_output_propose_state(output_base, pending_state, mode);
- if (!state) {
- drm_debug(b, "\t[repaint] could not build planes-only "
- "state, trying mixed\n");
- mode = DRM_OUTPUT_PROPOSE_STATE_MIXED;
- state = drm_output_propose_state(output_base,
- pending_state,
- mode);
- }
- if (!state) {
- drm_debug(b, "\t[repaint] could not build mixed-mode "
- "state, trying renderer-only\n");
- }
- } else {
- drm_debug(b, "\t[state] no overlay plane support\n");
- }
-
- if (!state) {
- mode = DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY;
- state = drm_output_propose_state(output_base, pending_state,
- mode);
- }
-
- assert(state);
- drm_debug(b, "\t[repaint] Using %s composition\n",
- drm_propose_state_mode_to_string(mode));
-
- wl_list_for_each(ev, &output_base->compositor->view_list, link) {
- struct drm_plane *target_plane = NULL;
-
- /* If this view doesn't touch our output at all, there's no
- * reason to do anything with it. */
- if (!(ev->output_mask & (1u << output->base.id)))
- continue;
-
- /* Test whether this buffer can ever go into a plane:
- * non-shm, or small enough to be a cursor.
- *
- * Also, keep a reference when using the pixman renderer.
- * That makes it possible to do a seamless switch to the GL
- * renderer and since the pixman renderer keeps a reference
- * to the buffer anyway, there is no side effects.
- */
- if (b->use_pixman ||
- (weston_view_has_valid_buffer(ev) &&
- (!wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
- (ev->surface->width <= b->cursor_width &&
- ev->surface->height <= b->cursor_height))))
- ev->surface->keep_buffer = true;
- else
- ev->surface->keep_buffer = false;
-
- /* This is a bit unpleasant, but lacking a temporary place to
- * hang a plane off the view, we have to do a nested walk.
- * Our first-order iteration has to be planes rather than
- * views, because otherwise we won't reset views which were
- * previously on planes to being on the primary plane. */
- wl_list_for_each(plane_state, &state->plane_list, link) {
- if (plane_state->ev == ev) {
- plane_state->ev = NULL;
- target_plane = plane_state->plane;
- break;
- }
- }
-
- if (target_plane) {
- drm_debug(b, "\t[repaint] view %p on %s plane %lu\n",
- ev, plane_type_enums[target_plane->type].name,
- (unsigned long) target_plane->plane_id);
- weston_view_move_to_plane(ev, &target_plane->base);
- } else {
- drm_debug(b, "\t[repaint] view %p using renderer "
- "composition\n", ev);
- weston_view_move_to_plane(ev, primary);
- }
-
- if (!target_plane ||
- target_plane->type == WDRM_PLANE_TYPE_CURSOR) {
- /* cursor plane & renderer involve a copy */
- ev->psf_flags = 0;
- } else {
- /* All other planes are a direct scanout of a
- * single client buffer.
- */
- ev->psf_flags = WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
- }
- }
-
- /* We rely on output->cursor_view being both an accurate reflection of
- * the cursor plane's state, but also being maintained across repaints
- * to avoid unnecessary damage uploads, per the comment in
- * drm_output_prepare_cursor_view. In the event that we go from having
- * a cursor view to not having a cursor view, we need to clear it. */
- if (output->cursor_view) {
- plane_state =
- drm_output_state_get_existing_plane(state,
- output->cursor_plane);
- if (!plane_state || !plane_state->fb)
- output->cursor_view = NULL;
- }
-}
diff --git a/libweston/backend-drm/vaapi-recorder.c b/libweston/backend-drm/vaapi-recorder.c
deleted file mode 100644
index 0a743570..00000000
--- a/libweston/backend-drm/vaapi-recorder.c
+++ /dev/null
@@ -1,1161 +0,0 @@
-/*
- * Copyright (c) 2012 Intel Corporation. All Rights Reserved.
- * Copyright © 2013 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include <pthread.h>
-
-#include <va/va.h>
-#include <va/va_drm.h>
-#include <va/va_drmcommon.h>
-#include <va/va_enc_h264.h>
-#include <va/va_vpp.h>
-
-#include <libweston/libweston.h>
-#include "vaapi-recorder.h"
-
-#define NAL_REF_IDC_NONE 0
-#define NAL_REF_IDC_LOW 1
-#define NAL_REF_IDC_MEDIUM 2
-#define NAL_REF_IDC_HIGH 3
-
-#define NAL_NON_IDR 1
-#define NAL_IDR 5
-#define NAL_SPS 7
-#define NAL_PPS 8
-#define NAL_SEI 6
-
-#define SLICE_TYPE_P 0
-#define SLICE_TYPE_B 1
-#define SLICE_TYPE_I 2
-
-#define ENTROPY_MODE_CAVLC 0
-#define ENTROPY_MODE_CABAC 1
-
-#define PROFILE_IDC_BASELINE 66
-#define PROFILE_IDC_MAIN 77
-#define PROFILE_IDC_HIGH 100
-
-struct vaapi_recorder {
- int drm_fd, output_fd;
- int width, height;
- int frame_count;
-
- int error;
- int destroying;
- pthread_t worker_thread;
- pthread_mutex_t mutex;
- pthread_cond_t input_cond;
-
- struct {
- int valid;
- int prime_fd, stride;
- } input;
-
- VADisplay va_dpy;
-
- /* video post processing is used for colorspace conversion */
- struct {
- VAConfigID cfg;
- VAContextID ctx;
- VABufferID pipeline_buf;
- VASurfaceID output;
- } vpp;
-
- struct {
- VAConfigID cfg;
- VAContextID ctx;
- VASurfaceID reference_picture[3];
-
- int intra_period;
- int output_size;
- int constraint_set_flag;
-
- struct {
- VAEncSequenceParameterBufferH264 seq;
- VAEncPictureParameterBufferH264 pic;
- VAEncSliceParameterBufferH264 slice;
- } param;
- } encoder;
-};
-
-static void *
-worker_thread_function(void *);
-
-/* bitstream code used for writing the packed headers */
-
-#define BITSTREAM_ALLOCATE_STEPPING 4096
-
-struct bitstream {
- unsigned int *buffer;
- int bit_offset;
- int max_size_in_dword;
-};
-
-static unsigned int
-va_swap32(unsigned int val)
-{
- unsigned char *pval = (unsigned char *)&val;
-
- return ((pval[0] << 24) |
- (pval[1] << 16) |
- (pval[2] << 8) |
- (pval[3] << 0));
-}
-
-static void
-bitstream_start(struct bitstream *bs)
-{
- bs->max_size_in_dword = BITSTREAM_ALLOCATE_STEPPING;
- bs->buffer = calloc(bs->max_size_in_dword * sizeof(unsigned int), 1);
- bs->bit_offset = 0;
-}
-
-static void
-bitstream_end(struct bitstream *bs)
-{
- int pos = (bs->bit_offset >> 5);
- int bit_offset = (bs->bit_offset & 0x1f);
- int bit_left = 32 - bit_offset;
-
- if (bit_offset) {
- bs->buffer[pos] = va_swap32((bs->buffer[pos] << bit_left));
- }
-}
-
-static void
-bitstream_put_ui(struct bitstream *bs, unsigned int val, int size_in_bits)
-{
- int pos = (bs->bit_offset >> 5);
- int bit_offset = (bs->bit_offset & 0x1f);
- int bit_left = 32 - bit_offset;
-
- if (!size_in_bits)
- return;
-
- bs->bit_offset += size_in_bits;
-
- if (bit_left > size_in_bits) {
- bs->buffer[pos] = (bs->buffer[pos] << size_in_bits | val);
- return;
- }
-
- size_in_bits -= bit_left;
- bs->buffer[pos] =
- (bs->buffer[pos] << bit_left) | (val >> size_in_bits);
- bs->buffer[pos] = va_swap32(bs->buffer[pos]);
-
- if (pos + 1 == bs->max_size_in_dword) {
- bs->max_size_in_dword += BITSTREAM_ALLOCATE_STEPPING;
- bs->buffer =
- realloc(bs->buffer,
- bs->max_size_in_dword * sizeof(unsigned int));
- }
-
- bs->buffer[pos + 1] = val;
-}
-
-static void
-bitstream_put_ue(struct bitstream *bs, unsigned int val)
-{
- int size_in_bits = 0;
- int tmp_val = ++val;
-
- while (tmp_val) {
- tmp_val >>= 1;
- size_in_bits++;
- }
-
- bitstream_put_ui(bs, 0, size_in_bits - 1); /* leading zero */
- bitstream_put_ui(bs, val, size_in_bits);
-}
-
-static void
-bitstream_put_se(struct bitstream *bs, int val)
-{
- unsigned int new_val;
-
- if (val <= 0)
- new_val = -2 * val;
- else
- new_val = 2 * val - 1;
-
- bitstream_put_ue(bs, new_val);
-}
-
-static void
-bitstream_byte_aligning(struct bitstream *bs, int bit)
-{
- int bit_offset = (bs->bit_offset & 0x7);
- int bit_left = 8 - bit_offset;
- int new_val;
-
- if (!bit_offset)
- return;
-
- if (bit)
- new_val = (1 << bit_left) - 1;
- else
- new_val = 0;
-
- bitstream_put_ui(bs, new_val, bit_left);
-}
-
-static VAStatus
-encoder_create_config(struct vaapi_recorder *r)
-{
- VAConfigAttrib attrib[2];
- VAStatus status;
-
- /* FIXME: should check if VAEntrypointEncSlice is supported */
-
- /* FIXME: should check if specified attributes are supported */
-
- attrib[0].type = VAConfigAttribRTFormat;
- attrib[0].value = VA_RT_FORMAT_YUV420;
-
- attrib[1].type = VAConfigAttribRateControl;
- attrib[1].value = VA_RC_CQP;
-
- status = vaCreateConfig(r->va_dpy, VAProfileH264Main,
- VAEntrypointEncSlice, attrib, 2,
- &r->encoder.cfg);
- if (status != VA_STATUS_SUCCESS)
- return status;
-
- status = vaCreateContext(r->va_dpy, r->encoder.cfg,
- r->width, r->height, VA_PROGRESSIVE, 0, 0,
- &r->encoder.ctx);
- if (status != VA_STATUS_SUCCESS) {
- vaDestroyConfig(r->va_dpy, r->encoder.cfg);
- return status;
- }
-
- return VA_STATUS_SUCCESS;
-}
-
-static void
-encoder_destroy_config(struct vaapi_recorder *r)
-{
- vaDestroyContext(r->va_dpy, r->encoder.ctx);
- vaDestroyConfig(r->va_dpy, r->encoder.cfg);
-}
-
-static void
-encoder_init_seq_parameters(struct vaapi_recorder *r)
-{
- int width_in_mbs, height_in_mbs;
- int frame_cropping_flag = 0;
- int frame_crop_bottom_offset = 0;
-
- width_in_mbs = (r->width + 15) / 16;
- height_in_mbs = (r->height + 15) / 16;
-
- r->encoder.param.seq.level_idc = 41;
- r->encoder.param.seq.intra_period = r->encoder.intra_period;
- r->encoder.param.seq.max_num_ref_frames = 4;
- r->encoder.param.seq.picture_width_in_mbs = width_in_mbs;
- r->encoder.param.seq.picture_height_in_mbs = height_in_mbs;
- r->encoder.param.seq.seq_fields.bits.frame_mbs_only_flag = 1;
-
- /* Tc = num_units_in_tick / time_scale */
- r->encoder.param.seq.time_scale = 1800;
- r->encoder.param.seq.num_units_in_tick = 15;
-
- if (height_in_mbs * 16 - r->height > 0) {
- frame_cropping_flag = 1;
- frame_crop_bottom_offset = (height_in_mbs * 16 - r->height) / 2;
- }
-
- r->encoder.param.seq.frame_cropping_flag = frame_cropping_flag;
- r->encoder.param.seq.frame_crop_bottom_offset = frame_crop_bottom_offset;
-
- r->encoder.param.seq.seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 = 2;
-}
-
-static VABufferID
-encoder_update_seq_parameters(struct vaapi_recorder *r)
-{
- VABufferID seq_buf;
- VAStatus status;
-
- status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
- VAEncSequenceParameterBufferType,
- sizeof(r->encoder.param.seq),
- 1, &r->encoder.param.seq,
- &seq_buf);
-
- if (status == VA_STATUS_SUCCESS)
- return seq_buf;
- else
- return VA_INVALID_ID;
-}
-
-static void
-encoder_init_pic_parameters(struct vaapi_recorder *r)
-{
- VAEncPictureParameterBufferH264 *pic = &r->encoder.param.pic;
-
- pic->pic_init_qp = 0;
-
- /* ENTROPY_MODE_CABAC */
- pic->pic_fields.bits.entropy_coding_mode_flag = 1;
-
- pic->pic_fields.bits.deblocking_filter_control_present_flag = 1;
-}
-
-static VABufferID
-encoder_update_pic_parameters(struct vaapi_recorder *r,
- VABufferID output_buf)
-{
- VAEncPictureParameterBufferH264 *pic = &r->encoder.param.pic;
- VAStatus status;
- VABufferID pic_param_buf;
- VASurfaceID curr_pic, pic0;
-
- curr_pic = r->encoder.reference_picture[r->frame_count % 2];
- pic0 = r->encoder.reference_picture[(r->frame_count + 1) % 2];
-
- pic->CurrPic.picture_id = curr_pic;
- pic->CurrPic.TopFieldOrderCnt = r->frame_count * 2;
- pic->ReferenceFrames[0].picture_id = pic0;
- pic->ReferenceFrames[1].picture_id = r->encoder.reference_picture[2];
- pic->ReferenceFrames[2].picture_id = VA_INVALID_ID;
-
- pic->coded_buf = output_buf;
- pic->frame_num = r->frame_count;
-
- pic->pic_fields.bits.idr_pic_flag = (r->frame_count == 0);
- pic->pic_fields.bits.reference_pic_flag = 1;
-
- status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
- VAEncPictureParameterBufferType,
- sizeof(VAEncPictureParameterBufferH264), 1,
- pic, &pic_param_buf);
-
- if (status == VA_STATUS_SUCCESS)
- return pic_param_buf;
- else
- return VA_INVALID_ID;
-}
-
-static VABufferID
-encoder_update_slice_parameter(struct vaapi_recorder *r, int slice_type)
-{
- VABufferID slice_param_buf;
- VAStatus status;
-
- int width_in_mbs = (r->width + 15) / 16;
- int height_in_mbs = (r->height + 15) / 16;
-
- memset(&r->encoder.param.slice, 0, sizeof r->encoder.param.slice);
-
- r->encoder.param.slice.num_macroblocks = width_in_mbs * height_in_mbs;
- r->encoder.param.slice.slice_type = slice_type;
-
- r->encoder.param.slice.slice_alpha_c0_offset_div2 = 2;
- r->encoder.param.slice.slice_beta_offset_div2 = 2;
-
- status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
- VAEncSliceParameterBufferType,
- sizeof(r->encoder.param.slice), 1,
- &r->encoder.param.slice,
- &slice_param_buf);
-
- if (status == VA_STATUS_SUCCESS)
- return slice_param_buf;
- else
- return VA_INVALID_ID;
-}
-
-static VABufferID
-encoder_update_misc_hdr_parameter(struct vaapi_recorder *r)
-{
- VAEncMiscParameterBuffer *misc_param;
- VAEncMiscParameterHRD *hrd;
- VABufferID buffer;
- VAStatus status;
-
- int total_size =
- sizeof(VAEncMiscParameterBuffer) +
- sizeof(VAEncMiscParameterRateControl);
-
- status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
- VAEncMiscParameterBufferType, total_size,
- 1, NULL, &buffer);
- if (status != VA_STATUS_SUCCESS)
- return VA_INVALID_ID;
-
- status = vaMapBuffer(r->va_dpy, buffer, (void **) &misc_param);
- if (status != VA_STATUS_SUCCESS) {
- vaDestroyBuffer(r->va_dpy, buffer);
- return VA_INVALID_ID;
- }
-
- misc_param->type = VAEncMiscParameterTypeHRD;
- hrd = (VAEncMiscParameterHRD *) misc_param->data;
-
- hrd->initial_buffer_fullness = 0;
- hrd->buffer_size = 0;
-
- vaUnmapBuffer(r->va_dpy, buffer);
-
- return buffer;
-}
-
-static int
-setup_encoder(struct vaapi_recorder *r)
-{
- VAStatus status;
-
- status = encoder_create_config(r);
- if (status != VA_STATUS_SUCCESS) {
- return -1;
- }
-
- status = vaCreateSurfaces(r->va_dpy, VA_RT_FORMAT_YUV420,
- r->width, r->height,
- r->encoder.reference_picture, 3,
- NULL, 0);
- if (status != VA_STATUS_SUCCESS) {
- encoder_destroy_config(r);
- return -1;
- }
-
- /* VAProfileH264Main */
- r->encoder.constraint_set_flag |= (1 << 1); /* Annex A.2.2 */
-
- r->encoder.output_size = r->width * r->height;
-
- r->encoder.intra_period = 30;
-
- encoder_init_seq_parameters(r);
- encoder_init_pic_parameters(r);
-
- return 0;
-}
-
-static void
-encoder_destroy(struct vaapi_recorder *r)
-{
- vaDestroySurfaces(r->va_dpy, r->encoder.reference_picture, 3);
-
- encoder_destroy_config(r);
-}
-
-static void
-nal_start_code_prefix(struct bitstream *bs)
-{
- bitstream_put_ui(bs, 0x00000001, 32);
-}
-
-static void
-nal_header(struct bitstream *bs, int nal_ref_idc, int nal_unit_type)
-{
- /* forbidden_zero_bit: 0 */
- bitstream_put_ui(bs, 0, 1);
-
- bitstream_put_ui(bs, nal_ref_idc, 2);
- bitstream_put_ui(bs, nal_unit_type, 5);
-}
-
-static void
-rbsp_trailing_bits(struct bitstream *bs)
-{
- bitstream_put_ui(bs, 1, 1);
- bitstream_byte_aligning(bs, 0);
-}
-
-static void sps_rbsp(struct bitstream *bs,
- VAEncSequenceParameterBufferH264 *seq,
- int constraint_set_flag)
-{
- int i;
-
- bitstream_put_ui(bs, PROFILE_IDC_MAIN, 8);
-
- /* constraint_set[0-3] flag */
- for (i = 0; i < 4; i++) {
- int set = (constraint_set_flag & (1 << i)) ? 1 : 0;
- bitstream_put_ui(bs, set, 1);
- }
-
- /* reserved_zero_4bits */
- bitstream_put_ui(bs, 0, 4);
- bitstream_put_ui(bs, seq->level_idc, 8);
- bitstream_put_ue(bs, seq->seq_parameter_set_id);
-
- bitstream_put_ue(bs, seq->seq_fields.bits.log2_max_frame_num_minus4);
- bitstream_put_ue(bs, seq->seq_fields.bits.pic_order_cnt_type);
- bitstream_put_ue(bs,
- seq->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4);
-
- bitstream_put_ue(bs, seq->max_num_ref_frames);
-
- /* gaps_in_frame_num_value_allowed_flag */
- bitstream_put_ui(bs, 0, 1);
-
- /* pic_width_in_mbs_minus1, pic_height_in_map_units_minus1 */
- bitstream_put_ue(bs, seq->picture_width_in_mbs - 1);
- bitstream_put_ue(bs, seq->picture_height_in_mbs - 1);
-
- bitstream_put_ui(bs, seq->seq_fields.bits.frame_mbs_only_flag, 1);
- bitstream_put_ui(bs, seq->seq_fields.bits.direct_8x8_inference_flag, 1);
-
- bitstream_put_ui(bs, seq->frame_cropping_flag, 1);
-
- if (seq->frame_cropping_flag) {
- bitstream_put_ue(bs, seq->frame_crop_left_offset);
- bitstream_put_ue(bs, seq->frame_crop_right_offset);
- bitstream_put_ue(bs, seq->frame_crop_top_offset);
- bitstream_put_ue(bs, seq->frame_crop_bottom_offset);
- }
-
- /* vui_parameters_present_flag */
- bitstream_put_ui(bs, 1, 1);
-
- /* aspect_ratio_info_present_flag */
- bitstream_put_ui(bs, 0, 1);
- /* overscan_info_present_flag */
- bitstream_put_ui(bs, 0, 1);
-
- /* video_signal_type_present_flag */
- bitstream_put_ui(bs, 0, 1);
- /* chroma_loc_info_present_flag */
- bitstream_put_ui(bs, 0, 1);
-
- /* timing_info_present_flag */
- bitstream_put_ui(bs, 1, 1);
- bitstream_put_ui(bs, seq->num_units_in_tick, 32);
- bitstream_put_ui(bs, seq->time_scale, 32);
- /* fixed_frame_rate_flag */
- bitstream_put_ui(bs, 1, 1);
-
- /* nal_hrd_parameters_present_flag */
- bitstream_put_ui(bs, 0, 1);
-
- /* vcl_hrd_parameters_present_flag */
- bitstream_put_ui(bs, 0, 1);
-
- /* low_delay_hrd_flag */
- bitstream_put_ui(bs, 0, 1);
-
- /* pic_struct_present_flag */
- bitstream_put_ui(bs, 0, 1);
- /* bitstream_restriction_flag */
- bitstream_put_ui(bs, 0, 1);
-
- rbsp_trailing_bits(bs);
-}
-
-static void pps_rbsp(struct bitstream *bs,
- VAEncPictureParameterBufferH264 *pic)
-{
- /* pic_parameter_set_id, seq_parameter_set_id */
- bitstream_put_ue(bs, pic->pic_parameter_set_id);
- bitstream_put_ue(bs, pic->seq_parameter_set_id);
-
- bitstream_put_ui(bs, pic->pic_fields.bits.entropy_coding_mode_flag, 1);
-
- /* pic_order_present_flag: 0 */
- bitstream_put_ui(bs, 0, 1);
-
- /* num_slice_groups_minus1 */
- bitstream_put_ue(bs, 0);
-
- bitstream_put_ue(bs, pic->num_ref_idx_l0_active_minus1);
- bitstream_put_ue(bs, pic->num_ref_idx_l1_active_minus1);
-
- bitstream_put_ui(bs, pic->pic_fields.bits.weighted_pred_flag, 1);
- bitstream_put_ui(bs, pic->pic_fields.bits.weighted_bipred_idc, 2);
-
- /* pic_init_qp_minus26, pic_init_qs_minus26, chroma_qp_index_offset */
- bitstream_put_se(bs, pic->pic_init_qp - 26);
- bitstream_put_se(bs, 0);
- bitstream_put_se(bs, 0);
-
- bitstream_put_ui(bs, pic->pic_fields.bits.deblocking_filter_control_present_flag, 1);
-
- /* constrained_intra_pred_flag, redundant_pic_cnt_present_flag */
- bitstream_put_ui(bs, 0, 1);
- bitstream_put_ui(bs, 0, 1);
-
- bitstream_put_ui(bs, pic->pic_fields.bits.transform_8x8_mode_flag, 1);
-
- /* pic_scaling_matrix_present_flag */
- bitstream_put_ui(bs, 0, 1);
- bitstream_put_se(bs, pic->second_chroma_qp_index_offset );
-
- rbsp_trailing_bits(bs);
-}
-
-static int
-build_packed_pic_buffer(struct vaapi_recorder *r,
- void **header_buffer)
-{
- struct bitstream bs;
-
- bitstream_start(&bs);
- nal_start_code_prefix(&bs);
- nal_header(&bs, NAL_REF_IDC_HIGH, NAL_PPS);
- pps_rbsp(&bs, &r->encoder.param.pic);
- bitstream_end(&bs);
-
- *header_buffer = bs.buffer;
- return bs.bit_offset;
-}
-
-static int
-build_packed_seq_buffer(struct vaapi_recorder *r,
- void **header_buffer)
-{
- struct bitstream bs;
-
- bitstream_start(&bs);
- nal_start_code_prefix(&bs);
- nal_header(&bs, NAL_REF_IDC_HIGH, NAL_SPS);
- sps_rbsp(&bs, &r->encoder.param.seq, r->encoder.constraint_set_flag);
- bitstream_end(&bs);
-
- *header_buffer = bs.buffer;
- return bs.bit_offset;
-}
-
-static int
-create_packed_header_buffers(struct vaapi_recorder *r, VABufferID *buffers,
- VAEncPackedHeaderType type,
- void *data, int bit_length)
-{
- VAEncPackedHeaderParameterBuffer packed_header;
- VAStatus status;
-
- packed_header.type = type;
- packed_header.bit_length = bit_length;
- packed_header.has_emulation_bytes = 0;
-
- status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
- VAEncPackedHeaderParameterBufferType,
- sizeof packed_header, 1, &packed_header,
- &buffers[0]);
- if (status != VA_STATUS_SUCCESS)
- return 0;
-
- status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
- VAEncPackedHeaderDataBufferType,
- (bit_length + 7) / 8, 1, data, &buffers[1]);
- if (status != VA_STATUS_SUCCESS) {
- vaDestroyBuffer(r->va_dpy, buffers[0]);
- return 0;
- }
-
- return 2;
-}
-
-static int
-encoder_prepare_headers(struct vaapi_recorder *r, VABufferID *buffers)
-{
- VABufferID *p;
-
- int bit_length;
- void *data;
-
- p = buffers;
-
- bit_length = build_packed_seq_buffer(r, &data);
- p += create_packed_header_buffers(r, p, VAEncPackedHeaderSequence,
- data, bit_length);
- free(data);
-
- bit_length = build_packed_pic_buffer(r, &data);
- p += create_packed_header_buffers(r, p, VAEncPackedHeaderPicture,
- data, bit_length);
- free(data);
-
- return p - buffers;
-}
-
-static VAStatus
-encoder_render_picture(struct vaapi_recorder *r, VASurfaceID input,
- VABufferID *buffers, int count)
-{
- VAStatus status;
-
- status = vaBeginPicture(r->va_dpy, r->encoder.ctx, input);
- if (status != VA_STATUS_SUCCESS)
- return status;
-
- status = vaRenderPicture(r->va_dpy, r->encoder.ctx, buffers, count);
- if (status != VA_STATUS_SUCCESS)
- return status;
-
- status = vaEndPicture(r->va_dpy, r->encoder.ctx);
- if (status != VA_STATUS_SUCCESS)
- return status;
-
- return vaSyncSurface(r->va_dpy, input);
-}
-
-static VABufferID
-encoder_create_output_buffer(struct vaapi_recorder *r)
-{
- VABufferID output_buf;
- VAStatus status;
-
- status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
- VAEncCodedBufferType, r->encoder.output_size,
- 1, NULL, &output_buf);
- if (status == VA_STATUS_SUCCESS)
- return output_buf;
- else
- return VA_INVALID_ID;
-}
-
-enum output_write_status {
- OUTPUT_WRITE_SUCCESS,
- OUTPUT_WRITE_OVERFLOW,
- OUTPUT_WRITE_FATAL
-};
-
-static enum output_write_status
-encoder_write_output(struct vaapi_recorder *r, VABufferID output_buf)
-{
- VACodedBufferSegment *segment;
- VAStatus status;
- int count;
-
- status = vaMapBuffer(r->va_dpy, output_buf, (void **) &segment);
- if (status != VA_STATUS_SUCCESS)
- return OUTPUT_WRITE_FATAL;
-
- if (segment->status & VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK) {
- r->encoder.output_size *= 2;
- vaUnmapBuffer(r->va_dpy, output_buf);
- return OUTPUT_WRITE_OVERFLOW;
- }
-
- count = write(r->output_fd, segment->buf, segment->size);
-
- vaUnmapBuffer(r->va_dpy, output_buf);
-
- if (count < 0)
- return OUTPUT_WRITE_FATAL;
-
- return OUTPUT_WRITE_SUCCESS;
-}
-
-static void
-encoder_encode(struct vaapi_recorder *r, VASurfaceID input)
-{
- VABufferID output_buf = VA_INVALID_ID;
-
- VABufferID buffers[8];
- int count = 0;
- int i, slice_type;
- enum output_write_status ret;
-
- if ((r->frame_count % r->encoder.intra_period) == 0)
- slice_type = SLICE_TYPE_I;
- else
- slice_type = SLICE_TYPE_P;
-
- buffers[count++] = encoder_update_seq_parameters(r);
- buffers[count++] = encoder_update_misc_hdr_parameter(r);
- buffers[count++] = encoder_update_slice_parameter(r, slice_type);
-
- for (i = 0; i < count; i++)
- if (buffers[i] == VA_INVALID_ID)
- goto bail;
-
- if (r->frame_count == 0)
- count += encoder_prepare_headers(r, buffers + count);
-
- do {
- output_buf = encoder_create_output_buffer(r);
- if (output_buf == VA_INVALID_ID)
- goto bail;
-
- buffers[count++] =
- encoder_update_pic_parameters(r, output_buf);
- if (buffers[count - 1] == VA_INVALID_ID)
- goto bail;
-
- encoder_render_picture(r, input, buffers, count);
- ret = encoder_write_output(r, output_buf);
-
- vaDestroyBuffer(r->va_dpy, output_buf);
- output_buf = VA_INVALID_ID;
-
- vaDestroyBuffer(r->va_dpy, buffers[--count]);
- } while (ret == OUTPUT_WRITE_OVERFLOW);
-
- if (ret == OUTPUT_WRITE_FATAL)
- r->error = errno;
-
- for (i = 0; i < count; i++)
- vaDestroyBuffer(r->va_dpy, buffers[i]);
-
- r->frame_count++;
- return;
-
-bail:
- for (i = 0; i < count; i++)
- vaDestroyBuffer(r->va_dpy, buffers[i]);
- if (output_buf != VA_INVALID_ID)
- vaDestroyBuffer(r->va_dpy, output_buf);
-}
-
-
-static int
-setup_vpp(struct vaapi_recorder *r)
-{
- VAStatus status;
-
- status = vaCreateConfig(r->va_dpy, VAProfileNone,
- VAEntrypointVideoProc, NULL, 0,
- &r->vpp.cfg);
- if (status != VA_STATUS_SUCCESS) {
- weston_log("vaapi: failed to create VPP config\n");
- return -1;
- }
-
- status = vaCreateContext(r->va_dpy, r->vpp.cfg, r->width, r->height,
- 0, NULL, 0, &r->vpp.ctx);
- if (status != VA_STATUS_SUCCESS) {
- weston_log("vaapi: failed to create VPP context\n");
- goto err_cfg;
- }
-
- status = vaCreateBuffer(r->va_dpy, r->vpp.ctx,
- VAProcPipelineParameterBufferType,
- sizeof(VAProcPipelineParameterBuffer),
- 1, NULL, &r->vpp.pipeline_buf);
- if (status != VA_STATUS_SUCCESS) {
- weston_log("vaapi: failed to create VPP pipeline buffer\n");
- goto err_ctx;
- }
-
- status = vaCreateSurfaces(r->va_dpy, VA_RT_FORMAT_YUV420,
- r->width, r->height, &r->vpp.output, 1,
- NULL, 0);
- if (status != VA_STATUS_SUCCESS) {
- weston_log("vaapi: failed to create YUV surface\n");
- goto err_buf;
- }
-
- return 0;
-
-err_buf:
- vaDestroyBuffer(r->va_dpy, r->vpp.pipeline_buf);
-err_ctx:
- vaDestroyConfig(r->va_dpy, r->vpp.ctx);
-err_cfg:
- vaDestroyConfig(r->va_dpy, r->vpp.cfg);
-
- return -1;
-}
-
-static void
-vpp_destroy(struct vaapi_recorder *r)
-{
- vaDestroySurfaces(r->va_dpy, &r->vpp.output, 1);
- vaDestroyBuffer(r->va_dpy, r->vpp.pipeline_buf);
- vaDestroyConfig(r->va_dpy, r->vpp.ctx);
- vaDestroyConfig(r->va_dpy, r->vpp.cfg);
-}
-
-static int
-setup_worker_thread(struct vaapi_recorder *r)
-{
- pthread_mutex_init(&r->mutex, NULL);
- pthread_cond_init(&r->input_cond, NULL);
- pthread_create(&r->worker_thread, NULL, worker_thread_function, r);
-
- return 1;
-}
-
-static void
-destroy_worker_thread(struct vaapi_recorder *r)
-{
- pthread_mutex_lock(&r->mutex);
-
- /* Make sure the worker thread finishes */
- r->destroying = 1;
- pthread_cond_signal(&r->input_cond);
-
- pthread_mutex_unlock(&r->mutex);
-
- pthread_join(r->worker_thread, NULL);
-
- pthread_mutex_destroy(&r->mutex);
- pthread_cond_destroy(&r->input_cond);
-}
-
-struct vaapi_recorder *
-vaapi_recorder_create(int drm_fd, int width, int height, const char *filename)
-{
- struct vaapi_recorder *r;
- VAStatus status;
- int major, minor;
- int flags;
-
- r = zalloc(sizeof *r);
- if (r == NULL)
- return NULL;
-
- r->width = width;
- r->height = height;
- r->drm_fd = drm_fd;
-
- if (setup_worker_thread(r) < 0)
- goto err_free;
-
- flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC;
- r->output_fd = open(filename, flags, 0644);
- if (r->output_fd < 0)
- goto err_thread;
-
- r->va_dpy = vaGetDisplayDRM(drm_fd);
- if (!r->va_dpy) {
- weston_log("failed to create VA display\n");
- goto err_fd;
- }
-
- status = vaInitialize(r->va_dpy, &major, &minor);
- if (status != VA_STATUS_SUCCESS) {
- weston_log("vaapi: failed to initialize display\n");
- goto err_fd;
- }
-
- if (setup_vpp(r) < 0) {
- weston_log("vaapi: failed to initialize VPP pipeline\n");
- goto err_va_dpy;
- }
-
- if (setup_encoder(r) < 0) {
- goto err_vpp;
- }
-
- return r;
-
-err_vpp:
- vpp_destroy(r);
-err_va_dpy:
- vaTerminate(r->va_dpy);
-err_fd:
- close(r->output_fd);
-err_thread:
- destroy_worker_thread(r);
-err_free:
- free(r);
-
- return NULL;
-}
-
-void
-vaapi_recorder_destroy(struct vaapi_recorder *r)
-{
- destroy_worker_thread(r);
-
- encoder_destroy(r);
- vpp_destroy(r);
-
- vaTerminate(r->va_dpy);
-
- close(r->output_fd);
- close(r->drm_fd);
-
- free(r);
-}
-
-static VAStatus
-create_surface_from_fd(struct vaapi_recorder *r, int prime_fd,
- int stride, VASurfaceID *surface)
-{
- VASurfaceAttrib va_attribs[2];
- VASurfaceAttribExternalBuffers va_attrib_extbuf;
- VAStatus status;
-
- unsigned long buffer_fd = prime_fd;
-
- va_attrib_extbuf.pixel_format = VA_FOURCC_BGRX;
- va_attrib_extbuf.width = r->width;
- va_attrib_extbuf.height = r->height;
- va_attrib_extbuf.data_size = r->height * stride;
- va_attrib_extbuf.num_planes = 1;
- va_attrib_extbuf.pitches[0] = stride;
- va_attrib_extbuf.offsets[0] = 0;
- va_attrib_extbuf.buffers = &buffer_fd;
- va_attrib_extbuf.num_buffers = 1;
- va_attrib_extbuf.flags = 0;
- va_attrib_extbuf.private_data = NULL;
-
- va_attribs[0].type = VASurfaceAttribMemoryType;
- va_attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
- va_attribs[0].value.type = VAGenericValueTypeInteger;
- va_attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
-
- va_attribs[1].type = VASurfaceAttribExternalBufferDescriptor;
- va_attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
- va_attribs[1].value.type = VAGenericValueTypePointer;
- va_attribs[1].value.value.p = &va_attrib_extbuf;
-
- status = vaCreateSurfaces(r->va_dpy, VA_RT_FORMAT_RGB32,
- r->width, r->height, surface, 1,
- va_attribs, 2);
-
- return status;
-}
-
-static VAStatus
-convert_rgb_to_yuv(struct vaapi_recorder *r, VASurfaceID rgb_surface)
-{
- VAProcPipelineParameterBuffer *pipeline_param;
- VAStatus status;
-
- status = vaMapBuffer(r->va_dpy, r->vpp.pipeline_buf,
- (void **) &pipeline_param);
- if (status != VA_STATUS_SUCCESS)
- return status;
-
- memset(pipeline_param, 0, sizeof *pipeline_param);
-
- pipeline_param->surface = rgb_surface;
- pipeline_param->surface_color_standard = VAProcColorStandardNone;
-
- pipeline_param->output_background_color = 0xff000000;
- pipeline_param->output_color_standard = VAProcColorStandardNone;
-
- status = vaUnmapBuffer(r->va_dpy, r->vpp.pipeline_buf);
- if (status != VA_STATUS_SUCCESS)
- return status;
-
- status = vaBeginPicture(r->va_dpy, r->vpp.ctx, r->vpp.output);
- if (status != VA_STATUS_SUCCESS)
- return status;
-
- status = vaRenderPicture(r->va_dpy, r->vpp.ctx,
- &r->vpp.pipeline_buf, 1);
- if (status != VA_STATUS_SUCCESS)
- return status;
-
- status = vaEndPicture(r->va_dpy, r->vpp.ctx);
- if (status != VA_STATUS_SUCCESS)
- return status;
-
- return status;
-}
-
-static void
-recorder_frame(struct vaapi_recorder *r)
-{
- VASurfaceID rgb_surface;
- VAStatus status;
-
- status = create_surface_from_fd(r, r->input.prime_fd,
- r->input.stride, &rgb_surface);
- if (status != VA_STATUS_SUCCESS) {
- weston_log("[libva recorder] "
- "failed to create surface from bo\n");
- return;
- }
-
- close(r->input.prime_fd);
-
- status = convert_rgb_to_yuv(r, rgb_surface);
- if (status != VA_STATUS_SUCCESS) {
- weston_log("[libva recorder] "
- "color space conversion failed\n");
- return;
- }
-
- encoder_encode(r, r->vpp.output);
-
- vaDestroySurfaces(r->va_dpy, &rgb_surface, 1);
-}
-
-static void *
-worker_thread_function(void *data)
-{
- struct vaapi_recorder *r = data;
-
- pthread_mutex_lock(&r->mutex);
-
- while (!r->destroying) {
- if (!r->input.valid)
- pthread_cond_wait(&r->input_cond, &r->mutex);
-
- /* If the thread is awaken by destroy_worker_thread(),
- * there might not be valid input */
- if (!r->input.valid)
- continue;
-
- recorder_frame(r);
- r->input.valid = 0;
- }
-
- pthread_mutex_unlock(&r->mutex);
-
- return NULL;
-}
-
-int
-vaapi_recorder_frame(struct vaapi_recorder *r, int prime_fd, int stride)
-{
- int ret = 0;
-
- pthread_mutex_lock(&r->mutex);
-
- if (r->error) {
- errno = r->error;
- ret = -1;
- goto unlock;
- }
-
- /* The mutex is never released while encoding, so this point should
- * never be reached if input.valid is true. */
- assert(!r->input.valid);
-
- r->input.prime_fd = prime_fd;
- r->input.stride = stride;
- r->input.valid = 1;
- pthread_cond_signal(&r->input_cond);
-
-unlock:
- pthread_mutex_unlock(&r->mutex);
-
- return ret;
-}
diff --git a/libweston/backend-drm/vaapi-recorder.h b/libweston/backend-drm/vaapi-recorder.h
deleted file mode 100644
index 6b194aa8..00000000
--- a/libweston/backend-drm/vaapi-recorder.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright © 2013 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _VAAPI_RECORDER_H_
-#define _VAAPI_RECORDER_H_
-
-struct vaapi_recorder;
-
-struct vaapi_recorder *
-vaapi_recorder_create(int drm_fd, int width, int height, const char *filename);
-void
-vaapi_recorder_destroy(struct vaapi_recorder *r);
-int
-vaapi_recorder_frame(struct vaapi_recorder *r, int fd, int stride);
-
-#endif /* _VAAPI_RECORDER_H_ */
diff --git a/libweston/backend-fbdev/fbdev.c b/libweston/backend-fbdev/fbdev.c
deleted file mode 100644
index ae289cc0..00000000
--- a/libweston/backend-fbdev/fbdev.c
+++ /dev/null
@@ -1,994 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2011 Intel Corporation
- * Copyright © 2012 Raspberry Pi Foundation
- * Copyright © 2013 Philip Withnall
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <linux/fb.h>
-#include <linux/input.h>
-#include <assert.h>
-
-#include <libudev.h>
-
-#include "shared/helpers.h"
-#include <libweston/libweston.h>
-#include <libweston/backend-fbdev.h>
-#include "launcher-util.h"
-#include "pixman-renderer.h"
-#include "libinput-seat.h"
-#include "presentation-time-server-protocol.h"
-
-struct fbdev_backend {
- struct weston_backend base;
- struct weston_compositor *compositor;
- uint32_t prev_state;
-
- struct udev *udev;
- struct udev_input input;
- uint32_t output_transform;
- struct wl_listener session_listener;
-};
-
-struct fbdev_screeninfo {
- unsigned int x_resolution; /* pixels, visible area */
- unsigned int y_resolution; /* pixels, visible area */
- unsigned int width_mm; /* visible screen width in mm */
- unsigned int height_mm; /* visible screen height in mm */
- unsigned int bits_per_pixel;
-
- size_t buffer_length; /* length of frame buffer memory in bytes */
- size_t line_length; /* length of a line in bytes */
- char id[16]; /* screen identifier */
-
- pixman_format_code_t pixel_format; /* frame buffer pixel format */
- unsigned int refresh_rate; /* Hertz */
-};
-
-struct fbdev_head {
- struct weston_head base;
-
- /* Frame buffer details. */
- char *device;
- struct fbdev_screeninfo fb_info;
-};
-
-struct fbdev_output {
- struct fbdev_backend *backend;
- struct weston_output base;
-
- struct weston_mode mode;
- struct wl_event_source *finish_frame_timer;
-
- /* framebuffer mmap details */
- size_t buffer_length;
- void *fb;
-
- /* pixman details. */
- pixman_image_t *hw_surface;
-};
-
-static const char default_seat[] = "seat0";
-
-static inline struct fbdev_head *
-to_fbdev_head(struct weston_head *base)
-{
- return container_of(base, struct fbdev_head, base);
-}
-
-static inline struct fbdev_output *
-to_fbdev_output(struct weston_output *base)
-{
- return container_of(base, struct fbdev_output, base);
-}
-
-static inline struct fbdev_backend *
-to_fbdev_backend(struct weston_compositor *base)
-{
- return container_of(base->backend, struct fbdev_backend, base);
-}
-
-static struct fbdev_head *
-fbdev_output_get_head(struct fbdev_output *output)
-{
- if (wl_list_length(&output->base.head_list) != 1)
- return NULL;
-
- return container_of(output->base.head_list.next,
- struct fbdev_head, base.output_link);
-}
-
-static int
-fbdev_output_start_repaint_loop(struct weston_output *output)
-{
- struct timespec ts;
-
- weston_compositor_read_presentation_clock(output->compositor, &ts);
- weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
-
- return 0;
-}
-
-static int
-fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage,
- void *repaint_data)
-{
- struct fbdev_output *output = to_fbdev_output(base);
- struct weston_compositor *ec = output->base.compositor;
-
- /* Repaint the damaged region onto the back buffer. */
- pixman_renderer_output_set_buffer(base, output->hw_surface);
- ec->renderer->repaint_output(base, damage);
-
- /* Update the damage region. */
- pixman_region32_subtract(&ec->primary_plane.damage,
- &ec->primary_plane.damage, damage);
-
- /* Schedule the end of the frame. We do not sync this to the frame
- * buffer clock because users who want that should be using the DRM
- * compositor. FBIO_WAITFORVSYNC blocks and FB_ACTIVATE_VBL requires
- * panning, which is broken in most kernel drivers.
- *
- * Finish the frame synchronised to the specified refresh rate. The
- * refresh rate is given in mHz and the interval in ms. */
- wl_event_source_timer_update(output->finish_frame_timer,
- 1000000 / output->mode.refresh);
-
- return 0;
-}
-
-static int
-finish_frame_handler(void *data)
-{
- struct fbdev_output *output = data;
- struct timespec ts;
-
- weston_compositor_read_presentation_clock(output->base.compositor, &ts);
- weston_output_finish_frame(&output->base, &ts, 0);
-
- return 1;
-}
-
-static pixman_format_code_t
-calculate_pixman_format(struct fb_var_screeninfo *vinfo,
- struct fb_fix_screeninfo *finfo)
-{
- /* Calculate the pixman format supported by the frame buffer from the
- * buffer's metadata. Return 0 if no known pixman format is supported
- * (since this has depth 0 it's guaranteed to not conflict with any
- * actual pixman format).
- *
- * Documentation on the vinfo and finfo structures:
- * http://www.mjmwired.net/kernel/Documentation/fb/api.txt
- *
- * TODO: Try a bit harder to support other formats, including setting
- * the preferred format in the hardware. */
- int type;
-
- weston_log("Calculating pixman format from:\n"
- STAMP_SPACE " - type: %i (aux: %i)\n"
- STAMP_SPACE " - visual: %i\n"
- STAMP_SPACE " - bpp: %i (grayscale: %i)\n"
- STAMP_SPACE " - red: offset: %i, length: %i, MSB: %i\n"
- STAMP_SPACE " - green: offset: %i, length: %i, MSB: %i\n"
- STAMP_SPACE " - blue: offset: %i, length: %i, MSB: %i\n"
- STAMP_SPACE " - transp: offset: %i, length: %i, MSB: %i\n",
- finfo->type, finfo->type_aux, finfo->visual,
- vinfo->bits_per_pixel, vinfo->grayscale,
- vinfo->red.offset, vinfo->red.length, vinfo->red.msb_right,
- vinfo->green.offset, vinfo->green.length,
- vinfo->green.msb_right,
- vinfo->blue.offset, vinfo->blue.length,
- vinfo->blue.msb_right,
- vinfo->transp.offset, vinfo->transp.length,
- vinfo->transp.msb_right);
-
- /* We only handle packed formats at the moment. */
- if (finfo->type != FB_TYPE_PACKED_PIXELS)
- return 0;
-
- /* We only handle true-colour frame buffers at the moment. */
- switch(finfo->visual) {
- case FB_VISUAL_TRUECOLOR:
- case FB_VISUAL_DIRECTCOLOR:
- if (vinfo->grayscale != 0)
- return 0;
- break;
- default:
- return 0;
- }
-
- /* We only support formats with MSBs on the left. */
- if (vinfo->red.msb_right != 0 || vinfo->green.msb_right != 0 ||
- vinfo->blue.msb_right != 0)
- return 0;
-
- /* Work out the format type from the offsets. We only support RGBA, ARGB
- * and ABGR at the moment. */
- type = PIXMAN_TYPE_OTHER;
-
- if ((vinfo->transp.offset >= vinfo->red.offset ||
- vinfo->transp.length == 0) &&
- vinfo->red.offset >= vinfo->green.offset &&
- vinfo->green.offset >= vinfo->blue.offset)
- type = PIXMAN_TYPE_ARGB;
- else if (vinfo->red.offset >= vinfo->green.offset &&
- vinfo->green.offset >= vinfo->blue.offset &&
- vinfo->blue.offset >= vinfo->transp.offset)
- type = PIXMAN_TYPE_RGBA;
- else if (vinfo->transp.offset >= vinfo->blue.offset &&
- vinfo->blue.offset >= vinfo->green.offset &&
- vinfo->green.offset >= vinfo->red.offset)
- type = PIXMAN_TYPE_ABGR;
-
- if (type == PIXMAN_TYPE_OTHER)
- return 0;
-
- /* Build the format. */
- return PIXMAN_FORMAT(vinfo->bits_per_pixel, type,
- vinfo->transp.length,
- vinfo->red.length,
- vinfo->green.length,
- vinfo->blue.length);
-}
-
-static int
-calculate_refresh_rate(struct fb_var_screeninfo *vinfo)
-{
- uint64_t quot;
-
- /* Calculate monitor refresh rate. Default is 60 Hz. Units are mHz. */
- quot = (vinfo->upper_margin + vinfo->lower_margin + vinfo->yres);
- quot *= (vinfo->left_margin + vinfo->right_margin + vinfo->xres);
- quot *= vinfo->pixclock;
-
- if (quot > 0) {
- uint64_t refresh_rate;
-
- refresh_rate = 1000000000000000LLU / quot;
- if (refresh_rate > 200000)
- refresh_rate = 200000; /* cap at 200 Hz */
-
- if (refresh_rate >= 1000) /* at least 1 Hz */
- return refresh_rate;
- }
-
- return 60 * 1000; /* default to 60 Hz */
-}
-
-static int
-fbdev_query_screen_info(int fd, struct fbdev_screeninfo *info)
-{
- struct fb_var_screeninfo varinfo;
- struct fb_fix_screeninfo fixinfo;
-
- /* Probe the device for screen information. */
- if (ioctl(fd, FBIOGET_FSCREENINFO, &fixinfo) < 0 ||
- ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
- return -1;
- }
-
- /* Store the pertinent data. */
- info->x_resolution = varinfo.xres;
- info->y_resolution = varinfo.yres;
- info->width_mm = varinfo.width;
- info->height_mm = varinfo.height;
- info->bits_per_pixel = varinfo.bits_per_pixel;
-
- info->buffer_length = fixinfo.smem_len;
- info->line_length = fixinfo.line_length;
- strncpy(info->id, fixinfo.id, sizeof(info->id));
- info->id[sizeof(info->id)-1] = '\0';
-
- info->pixel_format = calculate_pixman_format(&varinfo, &fixinfo);
- info->refresh_rate = calculate_refresh_rate(&varinfo);
-
- if (info->pixel_format == 0) {
- weston_log("Frame buffer uses an unsupported format.\n");
- return -1;
- }
-
- return 1;
-}
-
-static int
-fbdev_set_screen_info(int fd, struct fbdev_screeninfo *info)
-{
- struct fb_var_screeninfo varinfo;
-
- /* Grab the current screen information. */
- if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
- return -1;
- }
-
- /* Update the information. */
- varinfo.xres = info->x_resolution;
- varinfo.yres = info->y_resolution;
- varinfo.width = info->width_mm;
- varinfo.height = info->height_mm;
- varinfo.bits_per_pixel = info->bits_per_pixel;
-
- /* Try to set up an ARGB (x8r8g8b8) pixel format. */
- varinfo.grayscale = 0;
- varinfo.transp.offset = 24;
- varinfo.transp.length = 0;
- varinfo.transp.msb_right = 0;
- varinfo.red.offset = 16;
- varinfo.red.length = 8;
- varinfo.red.msb_right = 0;
- varinfo.green.offset = 8;
- varinfo.green.length = 8;
- varinfo.green.msb_right = 0;
- varinfo.blue.offset = 0;
- varinfo.blue.length = 8;
- varinfo.blue.msb_right = 0;
-
- /* Set the device's screen information. */
- if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
- return -1;
- }
-
- return 1;
-}
-
-static int
-fbdev_wakeup_screen(int fd, struct fbdev_screeninfo *info)
-{
- struct fb_var_screeninfo varinfo;
-
- /* Grab the current screen information. */
- if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
- return -1;
- }
-
- /* force the framebuffer to wake up */
- varinfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
-
- /* Set the device's screen information. */
- if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
- return -1;
- }
-
- return 1;
-}
-
-/* Returns an FD for the frame buffer device. */
-static int
-fbdev_frame_buffer_open(const char *fb_dev,
- struct fbdev_screeninfo *screen_info)
-{
- int fd = -1;
-
- weston_log("Opening fbdev frame buffer.\n");
-
- /* Open the frame buffer device. */
- fd = open(fb_dev, O_RDWR | O_CLOEXEC);
- if (fd < 0) {
- weston_log("Failed to open frame buffer device ‘%s’: %s\n",
- fb_dev, strerror(errno));
- return -1;
- }
-
- /* Grab the screen info. */
- if (fbdev_query_screen_info(fd, screen_info) < 0) {
- weston_log("Failed to get frame buffer info: %s\n",
- strerror(errno));
-
- close(fd);
- return -1;
- }
-
- /* Attempt to wake up the framebuffer device, needed for secondary
- * framebuffer devices */
- if (fbdev_wakeup_screen(fd, screen_info) < 0) {
- weston_log("Failed to activate framebuffer display. "
- "Attempting to open output anyway.\n");
- }
-
-
- return fd;
-}
-
-/* Closes the FD on success or failure. */
-static int
-fbdev_frame_buffer_map(struct fbdev_output *output, int fd)
-{
- struct fbdev_head *head;
- int retval = -1;
-
- head = fbdev_output_get_head(output);
-
- weston_log("Mapping fbdev frame buffer.\n");
-
- /* Map the frame buffer. Write-only mode, since we don't want to read
- * anything back (because it's slow). */
- output->buffer_length = head->fb_info.buffer_length;
- output->fb = mmap(NULL, output->buffer_length,
- PROT_WRITE, MAP_SHARED, fd, 0);
- if (output->fb == MAP_FAILED) {
- weston_log("Failed to mmap frame buffer: %s\n",
- strerror(errno));
- output->fb = NULL;
- goto out_close;
- }
-
- /* Create a pixman image to wrap the memory mapped frame buffer. */
- output->hw_surface =
- pixman_image_create_bits(head->fb_info.pixel_format,
- head->fb_info.x_resolution,
- head->fb_info.y_resolution,
- output->fb,
- head->fb_info.line_length);
- if (output->hw_surface == NULL) {
- weston_log("Failed to create surface for frame buffer.\n");
- goto out_unmap;
- }
-
- /* Success! */
- retval = 0;
-
-out_unmap:
- if (retval != 0 && output->fb != NULL) {
- munmap(output->fb, output->buffer_length);
- output->fb = NULL;
- }
-
-out_close:
- if (fd >= 0)
- close(fd);
-
- return retval;
-}
-
-static void
-fbdev_frame_buffer_unmap(struct fbdev_output *output)
-{
- if (!output->fb) {
- assert(!output->hw_surface);
- return;
- }
-
- weston_log("Unmapping fbdev frame buffer.\n");
-
- if (output->hw_surface)
- pixman_image_unref(output->hw_surface);
- output->hw_surface = NULL;
-
- if (munmap(output->fb, output->buffer_length) < 0)
- weston_log("Failed to munmap frame buffer: %s\n",
- strerror(errno));
-
- output->fb = NULL;
-}
-
-
-static int
-fbdev_output_attach_head(struct weston_output *output_base,
- struct weston_head *head_base)
-{
- struct fbdev_output *output = to_fbdev_output(output_base);
- struct fbdev_head *head = to_fbdev_head(head_base);
-
- /* Clones not supported. */
- if (!wl_list_empty(&output->base.head_list))
- return -1;
-
- /* only one static mode in list */
- output->mode.flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
- output->mode.width = head->fb_info.x_resolution;
- output->mode.height = head->fb_info.y_resolution;
- output->mode.refresh = head->fb_info.refresh_rate;
- wl_list_init(&output->base.mode_list);
- wl_list_insert(&output->base.mode_list, &output->mode.link);
- output->base.current_mode = &output->mode;
-
- return 0;
-}
-
-static void fbdev_output_destroy(struct weston_output *base);
-
-static int
-fbdev_output_enable(struct weston_output *base)
-{
- struct fbdev_output *output = to_fbdev_output(base);
- struct fbdev_backend *backend = to_fbdev_backend(base->compositor);
- struct fbdev_head *head;
- int fb_fd;
- struct wl_event_loop *loop;
-
- head = fbdev_output_get_head(output);
-
- /* Create the frame buffer. */
- fb_fd = fbdev_frame_buffer_open(head->device, &head->fb_info);
- if (fb_fd < 0) {
- weston_log("Creating frame buffer failed.\n");
- return -1;
- }
-
- if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
- weston_log("Mapping frame buffer failed.\n");
- return -1;
- }
-
- output->base.start_repaint_loop = fbdev_output_start_repaint_loop;
- output->base.repaint = fbdev_output_repaint;
-
- if (pixman_renderer_output_create(&output->base,
- PIXMAN_RENDERER_OUTPUT_USE_SHADOW) < 0)
- goto out_hw_surface;
-
- loop = wl_display_get_event_loop(backend->compositor->wl_display);
- output->finish_frame_timer =
- wl_event_loop_add_timer(loop, finish_frame_handler, output);
-
- weston_log("fbdev output %d×%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);
-
- return 0;
-
-out_hw_surface:
- fbdev_frame_buffer_unmap(output);
-
- return -1;
-}
-
-static int
-fbdev_output_disable(struct weston_output *base)
-{
- struct fbdev_output *output = to_fbdev_output(base);
-
- if (!base->enabled)
- return 0;
-
- wl_event_source_remove(output->finish_frame_timer);
- output->finish_frame_timer = NULL;
-
- pixman_renderer_output_destroy(&output->base);
- fbdev_frame_buffer_unmap(output);
-
- return 0;
-}
-
-static struct fbdev_head *
-fbdev_head_create(struct fbdev_backend *backend, const char *device)
-{
- struct fbdev_head *head;
- int fb_fd;
-
- head = zalloc(sizeof *head);
- if (!head)
- return NULL;
-
- head->device = strdup(device);
-
- /* Create the frame buffer. */
- fb_fd = fbdev_frame_buffer_open(head->device, &head->fb_info);
- if (fb_fd < 0) {
- weston_log("Creating frame buffer head failed.\n");
- goto out_free;
- }
- close(fb_fd);
-
- weston_head_init(&head->base, "fbdev");
- weston_head_set_connection_status(&head->base, true);
- weston_head_set_monitor_strings(&head->base, "unknown",
- head->fb_info.id, NULL);
- weston_head_set_subpixel(&head->base, WL_OUTPUT_SUBPIXEL_UNKNOWN);
- weston_head_set_physical_size(&head->base, head->fb_info.width_mm,
- head->fb_info.height_mm);
-
- weston_compositor_add_head(backend->compositor, &head->base);
-
- weston_log("Created head '%s' for device %s (%s)\n",
- head->base.name, head->device, head->base.model);
-
- return head;
-
-out_free:
- free(head->device);
- free(head);
-
- return NULL;
-}
-
-static void
-fbdev_head_destroy(struct fbdev_head *head)
-{
- weston_head_release(&head->base);
- free(head->device);
- free(head);
-}
-
-static struct weston_output *
-fbdev_output_create(struct weston_compositor *compositor,
- const char *name)
-{
- struct fbdev_output *output;
-
- weston_log("Creating fbdev output.\n");
-
- output = zalloc(sizeof *output);
- if (output == NULL)
- return NULL;
-
- output->backend = to_fbdev_backend(compositor);
-
- weston_output_init(&output->base, compositor, name);
-
- output->base.destroy = fbdev_output_destroy;
- output->base.disable = fbdev_output_disable;
- output->base.enable = fbdev_output_enable;
- output->base.attach_head = fbdev_output_attach_head;
-
- weston_compositor_add_pending_output(&output->base, compositor);
-
- return &output->base;
-}
-
-static void
-fbdev_output_destroy(struct weston_output *base)
-{
- struct fbdev_output *output = to_fbdev_output(base);
-
- weston_log("Destroying fbdev output.\n");
-
- fbdev_output_disable(base);
-
- /* Remove the output. */
- weston_output_release(&output->base);
-
- free(output);
-}
-
-/* strcmp()-style return values. */
-static int
-compare_screen_info (const struct fbdev_screeninfo *a,
- const struct fbdev_screeninfo *b)
-{
- if (a->x_resolution == b->x_resolution &&
- a->y_resolution == b->y_resolution &&
- a->width_mm == b->width_mm &&
- a->height_mm == b->height_mm &&
- a->bits_per_pixel == b->bits_per_pixel &&
- a->pixel_format == b->pixel_format &&
- a->refresh_rate == b->refresh_rate)
- return 0;
-
- return 1;
-}
-
-static int
-fbdev_output_reenable(struct fbdev_backend *backend,
- struct weston_output *base)
-{
- struct fbdev_output *output = to_fbdev_output(base);
- struct fbdev_head *head;
- struct fbdev_screeninfo new_screen_info;
- int fb_fd;
-
- head = fbdev_output_get_head(output);
-
- weston_log("Re-enabling fbdev output.\n");
- assert(output->base.enabled);
-
- /* Create the frame buffer. */
- fb_fd = fbdev_frame_buffer_open(head->device, &new_screen_info);
- if (fb_fd < 0) {
- weston_log("Creating frame buffer failed.\n");
- return -1;
- }
-
- /* Check whether the frame buffer details have changed since we were
- * disabled. */
- if (compare_screen_info(&head->fb_info, &new_screen_info) != 0) {
- /* Perform a mode-set to restore the old mode. */
- if (fbdev_set_screen_info(fb_fd, &head->fb_info) < 0) {
- weston_log("Failed to restore mode settings. "
- "Attempting to re-open output anyway.\n");
- }
-
- close(fb_fd);
-
- /* Disable and enable the output so that resources depending on
- * the frame buffer X/Y resolution (such as the shadow buffer)
- * are re-initialised. */
- fbdev_output_disable(&output->base);
- return fbdev_output_enable(&output->base);
- }
-
- /* Map the device if it has the same details as before. */
- if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
- weston_log("Mapping frame buffer failed.\n");
- return -1;
- }
-
- return 0;
-}
-
-static void
-fbdev_backend_destroy(struct weston_compositor *base)
-{
- struct fbdev_backend *backend = to_fbdev_backend(base);
- struct weston_head *head, *next;
-
- udev_input_destroy(&backend->input);
-
- /* Destroy the output. */
- weston_compositor_shutdown(base);
-
- wl_list_for_each_safe(head, next, &base->head_list, compositor_link)
- fbdev_head_destroy(to_fbdev_head(head));
-
- /* Chain up. */
- weston_launcher_destroy(base->launcher);
-
- udev_unref(backend->udev);
-
- free(backend);
-}
-
-static void
-session_notify(struct wl_listener *listener, void *data)
-{
- struct weston_compositor *compositor = data;
- struct fbdev_backend *backend = to_fbdev_backend(compositor);
- struct weston_output *output;
-
- if (compositor->session_active) {
- weston_log("entering VT\n");
- compositor->state = backend->prev_state;
-
- wl_list_for_each(output, &compositor->output_list, link) {
- fbdev_output_reenable(backend, output);
- }
-
- weston_compositor_damage_all(compositor);
-
- udev_input_enable(&backend->input);
- } else {
- weston_log("leaving VT\n");
- udev_input_disable(&backend->input);
-
- wl_list_for_each(output, &compositor->output_list, link) {
- fbdev_frame_buffer_unmap(to_fbdev_output(output));
- }
-
- backend->prev_state = compositor->state;
- weston_compositor_offscreen(compositor);
-
- /* If we have a repaint scheduled (from the idle handler), make
- * sure we cancel that so we don't try to pageflip when we're
- * vt switched away. The OFFSCREEN state will prevent
- * further attempts at repainting. When we switch
- * back, we schedule a repaint, which will process
- * pending frame callbacks. */
-
- wl_list_for_each(output,
- &compositor->output_list, link) {
- output->repaint_needed = false;
- }
- }
-}
-
-static char *
-find_framebuffer_device(struct fbdev_backend *b, const char *seat)
-{
- struct udev_enumerate *e;
- struct udev_list_entry *entry;
- const char *path, *device_seat, *id;
- char *fb_device_path = NULL;
- struct udev_device *device, *fb_device, *pci;
-
- e = udev_enumerate_new(b->udev);
- udev_enumerate_add_match_subsystem(e, "graphics");
- udev_enumerate_add_match_sysname(e, "fb[0-9]*");
-
- udev_enumerate_scan_devices(e);
- fb_device = NULL;
- udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
- bool is_boot_vga = false;
-
- path = udev_list_entry_get_name(entry);
- device = udev_device_new_from_syspath(b->udev, path);
- if (!device)
- continue;
- device_seat = udev_device_get_property_value(device, "ID_SEAT");
- if (!device_seat)
- device_seat = default_seat;
- if (strcmp(device_seat, seat)) {
- udev_device_unref(device);
- continue;
- }
-
- pci = udev_device_get_parent_with_subsystem_devtype(device,
- "pci", NULL);
- if (pci) {
- id = udev_device_get_sysattr_value(pci, "boot_vga");
- if (id && !strcmp(id, "1"))
- is_boot_vga = true;
- }
-
- /* If a framebuffer device was found, and this device isn't
- * the boot-VGA device, don't use it. */
- if (!is_boot_vga && fb_device) {
- udev_device_unref(device);
- continue;
- }
-
- /* There can only be one boot_vga device. Try to use it
- * at all costs. */
- if (is_boot_vga) {
- if (fb_device)
- udev_device_unref(fb_device);
- fb_device = device;
- break;
- }
-
- /* Per the (!is_boot_vga && fb_device) test above, only
- * trump existing saved devices with boot-VGA devices, so if
- * the test ends up here, this must be the first device seen. */
- assert(!fb_device);
- fb_device = device;
- }
-
- udev_enumerate_unref(e);
-
- if (fb_device) {
- fb_device_path = strdup(udev_device_get_devnode(fb_device));
- udev_device_unref(fb_device);
- }
-
- return fb_device_path;
-}
-
-static struct fbdev_backend *
-fbdev_backend_create(struct weston_compositor *compositor,
- struct weston_fbdev_backend_config *param)
-{
- struct fbdev_backend *backend;
- const char *seat_id = default_seat;
- const char *session_seat;
-
- session_seat = getenv("XDG_SEAT");
- if (session_seat)
- seat_id = session_seat;
- if (param->seat_id)
- seat_id = param->seat_id;
-
- weston_log("initializing fbdev backend\n");
-
- backend = zalloc(sizeof *backend);
- if (backend == NULL)
- return NULL;
-
- backend->compositor = compositor;
- compositor->backend = &backend->base;
- if (weston_compositor_set_presentation_clock_software(
- compositor) < 0)
- goto out_compositor;
-
- backend->udev = udev_new();
- if (backend->udev == NULL) {
- weston_log("Failed to initialize udev context.\n");
- goto out_compositor;
- }
-
- if (!param->device)
- param->device = find_framebuffer_device(backend, seat_id);
- if (!param->device) {
- weston_log("fatal: no framebuffer devices detected.\n");
- goto out_udev;
- }
-
- /* Set up the TTY. */
- backend->session_listener.notify = session_notify;
- wl_signal_add(&compositor->session_signal,
- &backend->session_listener);
- compositor->launcher =
- weston_launcher_connect(compositor, param->tty, seat_id, false);
- if (!compositor->launcher) {
- weston_log("fatal: fbdev backend should be run using "
- "weston-launch binary, or your system should "
- "provide the logind D-Bus API.\n");
- goto out_udev;
- }
-
- backend->base.destroy = fbdev_backend_destroy;
- backend->base.create_output = fbdev_output_create;
-
- backend->prev_state = WESTON_COMPOSITOR_ACTIVE;
-
- weston_setup_vt_switch_bindings(compositor);
-
- if (pixman_renderer_init(compositor) < 0)
- goto out_launcher;
-
- if (!fbdev_head_create(backend, param->device))
- goto out_launcher;
-
- free(param->device);
-
- udev_input_init(&backend->input, compositor, backend->udev,
- seat_id, param->configure_device);
-
- return backend;
-
-out_launcher:
- free(param->device);
- weston_launcher_destroy(compositor->launcher);
-
-out_udev:
- udev_unref(backend->udev);
-
-out_compositor:
- weston_compositor_shutdown(compositor);
- free(backend);
-
- return NULL;
-}
-
-static void
-config_init_to_defaults(struct weston_fbdev_backend_config *config)
-{
- config->tty = 0; /* default to current tty */
- config->device = NULL;
- config->seat_id = NULL;
-}
-
-WL_EXPORT int
-weston_backend_init(struct weston_compositor *compositor,
- struct weston_backend_config *config_base)
-{
- struct fbdev_backend *b;
- struct weston_fbdev_backend_config config = {{ 0, }};
-
- if (config_base == NULL ||
- config_base->struct_version != WESTON_FBDEV_BACKEND_CONFIG_VERSION ||
- config_base->struct_size > sizeof(struct weston_fbdev_backend_config)) {
- weston_log("fbdev backend config structure is invalid\n");
- return -1;
- }
-
- config_init_to_defaults(&config);
- memcpy(&config, config_base, config_base->struct_size);
-
- b = fbdev_backend_create(compositor, &config);
- if (b == NULL)
- return -1;
- return 0;
-}
diff --git a/libweston/backend-fbdev/meson.build b/libweston/backend-fbdev/meson.build
deleted file mode 100644
index e7b1544c..00000000
--- a/libweston/backend-fbdev/meson.build
+++ /dev/null
@@ -1,30 +0,0 @@
-if not get_option('backend-fbdev')
- subdir_done()
-endif
-
-config_h.set('BUILD_FBDEV_COMPOSITOR', '1')
-
-srcs_fbdev = [
- 'fbdev.c',
- presentation_time_server_protocol_h,
-]
-
-deps_fbdev = [
- dep_libweston_private,
- dep_session_helper,
- dep_libinput_backend,
- dependency('libudev', version: '>= 136'),
-]
-
-plugin_fbdev = shared_library(
- 'fbdev-backend',
- srcs_fbdev,
- include_directories: common_inc,
- dependencies: deps_fbdev,
- name_prefix: '',
- install: true,
- install_dir: dir_module_libweston
-)
-env_modmap += 'fbdev-backend.so=@0@;'.format(plugin_fbdev.full_path())
-
-install_headers(backend_fbdev_h, subdir: dir_include_libweston_install)
diff --git a/libweston/backend-headless/headless.c b/libweston/backend-headless/headless.c
deleted file mode 100644
index c98bdc24..00000000
--- a/libweston/backend-headless/headless.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * Copyright © 2010-2011 Benjamin Franzke
- * Copyright © 2012 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <stdbool.h>
-#include <drm_fourcc.h>
-
-#include <libweston/libweston.h>
-#include <libweston/backend-headless.h>
-#include "shared/helpers.h"
-#include "linux-explicit-synchronization.h"
-#include "pixman-renderer.h"
-#include "renderer-gl/gl-renderer.h"
-#include "shared/weston-egl-ext.h"
-#include "linux-dmabuf.h"
-#include "presentation-time-server-protocol.h"
-#include <libweston/windowed-output-api.h>
-
-enum headless_renderer_type {
- HEADLESS_NOOP,
- HEADLESS_PIXMAN,
- HEADLESS_GL,
-};
-
-struct headless_backend {
- struct weston_backend base;
- struct weston_compositor *compositor;
-
- struct weston_seat fake_seat;
- enum headless_renderer_type renderer_type;
-
- struct gl_renderer_interface *glri;
-};
-
-struct headless_head {
- struct weston_head base;
-};
-
-struct headless_output {
- struct weston_output base;
-
- struct weston_mode mode;
- struct wl_event_source *finish_frame_timer;
- uint32_t *image_buf;
- pixman_image_t *image;
-};
-
-static const uint32_t headless_formats[] = {
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_ARGB8888,
-};
-
-static inline struct headless_head *
-to_headless_head(struct weston_head *base)
-{
- return container_of(base, struct headless_head, base);
-}
-
-static inline struct headless_output *
-to_headless_output(struct weston_output *base)
-{
- return container_of(base, struct headless_output, base);
-}
-
-static inline struct headless_backend *
-to_headless_backend(struct weston_compositor *base)
-{
- return container_of(base->backend, struct headless_backend, base);
-}
-
-static int
-headless_output_start_repaint_loop(struct weston_output *output)
-{
- struct timespec ts;
-
- weston_compositor_read_presentation_clock(output->compositor, &ts);
- weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
-
- return 0;
-}
-
-static int
-finish_frame_handler(void *data)
-{
- struct headless_output *output = data;
- struct timespec ts;
-
- weston_compositor_read_presentation_clock(output->base.compositor, &ts);
- weston_output_finish_frame(&output->base, &ts, 0);
-
- return 1;
-}
-
-static int
-headless_output_repaint(struct weston_output *output_base,
- pixman_region32_t *damage,
- void *repaint_data)
-{
- struct headless_output *output = to_headless_output(output_base);
- struct weston_compositor *ec = output->base.compositor;
-
- ec->renderer->repaint_output(&output->base, damage);
-
- pixman_region32_subtract(&ec->primary_plane.damage,
- &ec->primary_plane.damage, damage);
-
- wl_event_source_timer_update(output->finish_frame_timer, 16);
-
- return 0;
-}
-
-static void
-headless_output_disable_gl(struct headless_output *output)
-{
- struct weston_compositor *compositor = output->base.compositor;
- struct headless_backend *b = to_headless_backend(compositor);
-
- b->glri->output_destroy(&output->base);
-}
-
-static void
-headless_output_disable_pixman(struct headless_output *output)
-{
- pixman_renderer_output_destroy(&output->base);
- pixman_image_unref(output->image);
- free(output->image_buf);
-}
-
-static int
-headless_output_disable(struct weston_output *base)
-{
- struct headless_output *output = to_headless_output(base);
- struct headless_backend *b = to_headless_backend(base->compositor);
-
- if (!output->base.enabled)
- return 0;
-
- wl_event_source_remove(output->finish_frame_timer);
-
- switch (b->renderer_type) {
- case HEADLESS_GL:
- headless_output_disable_gl(output);
- break;
- case HEADLESS_PIXMAN:
- headless_output_disable_pixman(output);
- break;
- case HEADLESS_NOOP:
- break;
- }
-
- return 0;
-}
-
-static void
-headless_output_destroy(struct weston_output *base)
-{
- struct headless_output *output = to_headless_output(base);
-
- headless_output_disable(&output->base);
- weston_output_release(&output->base);
-
- free(output);
-}
-
-static int
-headless_output_enable_gl(struct headless_output *output)
-{
- struct weston_compositor *compositor = output->base.compositor;
- struct headless_backend *b = to_headless_backend(compositor);
-
- if (b->glri->output_pbuffer_create(&output->base,
- output->base.current_mode->width,
- output->base.current_mode->height,
- headless_formats,
- ARRAY_LENGTH(headless_formats)) < 0) {
- weston_log("failed to create gl renderer output state\n");
- return -1;
- }
-
- return 0;
-}
-
-static int
-headless_output_enable_pixman(struct headless_output *output)
-{
- output->image_buf = malloc(output->base.current_mode->width *
- output->base.current_mode->height * 4);
- if (!output->image_buf)
- return -1;
-
- output->image = pixman_image_create_bits(PIXMAN_x8r8g8b8,
- output->base.current_mode->width,
- output->base.current_mode->height,
- output->image_buf,
- output->base.current_mode->width * 4);
-
- if (pixman_renderer_output_create(&output->base,
- PIXMAN_RENDERER_OUTPUT_USE_SHADOW) < 0)
- goto err_renderer;
-
- pixman_renderer_output_set_buffer(&output->base, output->image);
-
- return 0;
-
-err_renderer:
- pixman_image_unref(output->image);
- free(output->image_buf);
-
- return -1;
-}
-
-static int
-headless_output_enable(struct weston_output *base)
-{
- struct headless_output *output = to_headless_output(base);
- struct headless_backend *b = to_headless_backend(base->compositor);
- struct wl_event_loop *loop;
- int ret = 0;
-
- loop = wl_display_get_event_loop(b->compositor->wl_display);
- output->finish_frame_timer =
- wl_event_loop_add_timer(loop, finish_frame_handler, output);
-
- switch (b->renderer_type) {
- case HEADLESS_GL:
- ret = headless_output_enable_gl(output);
- break;
- case HEADLESS_PIXMAN:
- ret = headless_output_enable_pixman(output);
- break;
- case HEADLESS_NOOP:
- break;
- }
-
- if (ret < 0) {
- wl_event_source_remove(output->finish_frame_timer);
- return -1;
- }
-
- return 0;
-}
-
-static int
-headless_output_set_size(struct weston_output *base,
- int width, int height)
-{
- struct headless_output *output = to_headless_output(base);
- struct weston_head *head;
- int output_width, output_height;
-
- /* We can only be called once. */
- assert(!output->base.current_mode);
-
- /* Make sure we have scale set. */
- assert(output->base.scale);
-
- wl_list_for_each(head, &output->base.head_list, output_link) {
- weston_head_set_monitor_strings(head, "weston", "headless",
- NULL);
-
- /* XXX: Calculate proper size. */
- weston_head_set_physical_size(head, width, height);
- }
-
- output_width = width * output->base.scale;
- output_height = height * output->base.scale;
-
- output->mode.flags =
- WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
- output->mode.width = output_width;
- output->mode.height = output_height;
- output->mode.refresh = 60000;
- wl_list_insert(&output->base.mode_list, &output->mode.link);
-
- output->base.current_mode = &output->mode;
-
- output->base.start_repaint_loop = headless_output_start_repaint_loop;
- output->base.repaint = headless_output_repaint;
- output->base.assign_planes = NULL;
- output->base.set_backlight = NULL;
- output->base.set_dpms = NULL;
- output->base.switch_mode = NULL;
-
- return 0;
-}
-
-static struct weston_output *
-headless_output_create(struct weston_compositor *compositor, const char *name)
-{
- struct headless_output *output;
-
- /* name can't be NULL. */
- assert(name);
-
- output = zalloc(sizeof *output);
- if (!output)
- return NULL;
-
- weston_output_init(&output->base, compositor, name);
-
- output->base.destroy = headless_output_destroy;
- output->base.disable = headless_output_disable;
- output->base.enable = headless_output_enable;
- output->base.attach_head = NULL;
-
- weston_compositor_add_pending_output(&output->base, compositor);
-
- return &output->base;
-}
-
-static int
-headless_head_create(struct weston_compositor *compositor,
- const char *name)
-{
- struct headless_head *head;
-
- /* name can't be NULL. */
- assert(name);
-
- head = zalloc(sizeof *head);
- if (head == NULL)
- return -1;
-
- weston_head_init(&head->base, name);
- weston_head_set_connection_status(&head->base, true);
-
- /* Ideally all attributes of the head would be set here, so that the
- * user has all the information when deciding to create outputs.
- * We do not have those until set_size() time through.
- */
-
- weston_compositor_add_head(compositor, &head->base);
-
- return 0;
-}
-
-static void
-headless_head_destroy(struct headless_head *head)
-{
- weston_head_release(&head->base);
- free(head);
-}
-
-static void
-headless_destroy(struct weston_compositor *ec)
-{
- struct headless_backend *b = to_headless_backend(ec);
- struct weston_head *base, *next;
-
- weston_compositor_shutdown(ec);
-
- wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
- headless_head_destroy(to_headless_head(base));
-
- free(b);
-}
-
-static int
-headless_gl_renderer_init(struct headless_backend *b)
-{
- b->glri = weston_load_module("gl-renderer.so", "gl_renderer_interface");
- if (!b->glri)
- return -1;
-
- if (b->glri->display_create(b->compositor,
- EGL_PLATFORM_SURFACELESS_MESA,
- EGL_DEFAULT_DISPLAY,
- EGL_PBUFFER_BIT,
- headless_formats,
- ARRAY_LENGTH(headless_formats)) < 0) {
- return -1;
- }
-
- return 0;
-}
-
-static const struct weston_windowed_output_api api = {
- headless_output_set_size,
- headless_head_create,
-};
-
-static struct headless_backend *
-headless_backend_create(struct weston_compositor *compositor,
- struct weston_headless_backend_config *config)
-{
- struct headless_backend *b;
- int ret;
-
- b = zalloc(sizeof *b);
- if (b == NULL)
- return NULL;
-
- b->compositor = compositor;
- compositor->backend = &b->base;
-
- if (weston_compositor_set_presentation_clock_software(compositor) < 0)
- goto err_free;
-
- b->base.destroy = headless_destroy;
- b->base.create_output = headless_output_create;
-
- if (config->use_pixman && config->use_gl) {
- weston_log("Error: cannot use both Pixman *and* GL renderers.\n");
- goto err_free;
- }
-
- if (config->use_gl)
- b->renderer_type = HEADLESS_GL;
- else if (config->use_pixman)
- b->renderer_type = HEADLESS_PIXMAN;
- else
- b->renderer_type = HEADLESS_NOOP;
-
- switch (b->renderer_type) {
- case HEADLESS_GL:
- ret = headless_gl_renderer_init(b);
- break;
- case HEADLESS_PIXMAN:
- ret = pixman_renderer_init(compositor);
- break;
- case HEADLESS_NOOP:
- ret = noop_renderer_init(compositor);
- break;
- }
-
- if (ret < 0)
- goto err_input;
-
- if (compositor->renderer->import_dmabuf) {
- if (linux_dmabuf_setup(compositor) < 0) {
- weston_log("Error: dmabuf protocol setup failed.\n");
- goto err_input;
- }
- }
-
- /* Support zwp_linux_explicit_synchronization_unstable_v1 to enable
- * testing. */
- if (linux_explicit_synchronization_setup(compositor) < 0)
- goto err_input;
-
- ret = weston_plugin_api_register(compositor, WESTON_WINDOWED_OUTPUT_API_NAME,
- &api, sizeof(api));
-
- if (ret < 0) {
- weston_log("Failed to register output API.\n");
- goto err_input;
- }
-
- return b;
-
-err_input:
- weston_compositor_shutdown(compositor);
-err_free:
- free(b);
- return NULL;
-}
-
-static void
-config_init_to_defaults(struct weston_headless_backend_config *config)
-{
-}
-
-WL_EXPORT int
-weston_backend_init(struct weston_compositor *compositor,
- struct weston_backend_config *config_base)
-{
- struct headless_backend *b;
- struct weston_headless_backend_config config = {{ 0, }};
-
- if (config_base == NULL ||
- config_base->struct_version != WESTON_HEADLESS_BACKEND_CONFIG_VERSION ||
- config_base->struct_size > sizeof(struct weston_headless_backend_config)) {
- weston_log("headless backend config structure is invalid\n");
- return -1;
- }
-
- config_init_to_defaults(&config);
- memcpy(&config, config_base, config_base->struct_size);
-
- b = headless_backend_create(compositor, &config);
- if (b == NULL)
- return -1;
-
- return 0;
-}
diff --git a/libweston/backend-headless/meson.build b/libweston/backend-headless/meson.build
deleted file mode 100644
index c603bb0b..00000000
--- a/libweston/backend-headless/meson.build
+++ /dev/null
@@ -1,21 +0,0 @@
-if not get_option('backend-headless')
- subdir_done()
-endif
-
-config_h.set('BUILD_HEADLESS_COMPOSITOR', '1')
-
-srcs_headless = [
- 'headless.c',
- presentation_time_server_protocol_h,
-]
-plugin_headless = shared_library(
- 'headless-backend',
- srcs_headless,
- include_directories: common_inc,
- dependencies: [ dep_libweston_private, dep_libdrm_headers ],
- name_prefix: '',
- install: true,
- install_dir: dir_module_libweston,
-)
-env_modmap += 'headless-backend.so=@0@;'.format(plugin_headless.full_path())
-install_headers(backend_headless_h, subdir: dir_include_libweston_install)
diff --git a/libweston/backend-rdp/meson.build b/libweston/backend-rdp/meson.build
deleted file mode 100644
index 237cd0a7..00000000
--- a/libweston/backend-rdp/meson.build
+++ /dev/null
@@ -1,39 +0,0 @@
-if not get_option('backend-rdp')
- subdir_done()
-endif
-
-config_h.set('BUILD_RDP_COMPOSITOR', '1')
-
-dep_frdp = dependency('freerdp2', version: '>= 2.0.0', required: false)
-if not dep_frdp.found()
- error('RDP-backend requires freerdp2 which was not found. Or, you can use \'-Dbackend-rdp=false\'.')
-endif
-
-if cc.has_header('freerdp/version.h', dependencies: dep_frdp)
- config_h.set('HAVE_FREERDP_VERSION_H', '1')
-endif
-
-if cc.has_member(
- 'SURFACE_BITS_COMMAND', 'bmp',
- dependencies : dep_frdp,
- prefix : '#include <freerdp/update.h>'
-)
- config_h.set('HAVE_SURFACE_BITS_BMP', '1')
-endif
-
-deps_rdp = [
- dep_libweston_private,
- dep_frdp,
-]
-plugin_rdp = shared_library(
- 'rdp-backend',
- 'rdp.c',
- include_directories: common_inc,
- dependencies: deps_rdp,
- name_prefix: '',
- override_options: [ 'b_lundef=false' ],
- install: true,
- install_dir: dir_module_libweston
-)
-env_modmap += 'rdp-backend.so=@0@;'.format(plugin_rdp.full_path())
-install_headers(backend_rdp_h, subdir: dir_include_libweston_install)
diff --git a/libweston/backend-rdp/rdp.c b/libweston/backend-rdp/rdp.c
deleted file mode 100644
index ce91cedd..00000000
--- a/libweston/backend-rdp/rdp.c
+++ /dev/null
@@ -1,1501 +0,0 @@
-/*
- * Copyright © 2013 Hardening <rdp.effort@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <linux/input.h>
-
-#if HAVE_FREERDP_VERSION_H
-#include <freerdp/version.h>
-#else
-/* assume it's a early 1.1 version */
-#define FREERDP_VERSION_MAJOR 1
-#define FREERDP_VERSION_MINOR 1
-#define FREERDP_VERSION_REVISION 0
-#endif
-
-#define FREERDP_VERSION_NUMBER ((FREERDP_VERSION_MAJOR * 0x10000) + \
- (FREERDP_VERSION_MINOR * 0x100) + FREERDP_VERSION_REVISION)
-
-
-#if FREERDP_VERSION_NUMBER >= 0x10201
-#define HAVE_SKIP_COMPRESSION
-#endif
-
-#if FREERDP_VERSION_NUMBER < 0x10202
-# define FREERDP_CB_RET_TYPE void
-# define FREERDP_CB_RETURN(V) return
-# define NSC_RESET(C, W, H)
-# define RFX_RESET(C, W, H) do { rfx_context_reset(C); C->width = W; C->height = H; } while(0)
-#else
-#if FREERDP_VERSION_MAJOR >= 2
-# define NSC_RESET(C, W, H) nsc_context_reset(C, W, H)
-# define RFX_RESET(C, W, H) rfx_context_reset(C, W, H)
-#else
-# define NSC_RESET(C, W, H) do { nsc_context_reset(C); C->width = W; C->height = H; } while(0)
-# define RFX_RESET(C, W, H) do { rfx_context_reset(C); C->width = W; C->height = H; } while(0)
-#endif
-#define FREERDP_CB_RET_TYPE BOOL
-#define FREERDP_CB_RETURN(V) return TRUE
-#endif
-
-#ifdef HAVE_SURFACE_BITS_BMP
-#define SURFACE_BPP(cmd) cmd.bmp.bpp
-#define SURFACE_CODECID(cmd) cmd.bmp.codecID
-#define SURFACE_WIDTH(cmd) cmd.bmp.width
-#define SURFACE_HEIGHT(cmd) cmd.bmp.height
-#define SURFACE_BITMAP_DATA(cmd) cmd.bmp.bitmapData
-#define SURFACE_BITMAP_DATA_LEN(cmd) cmd.bmp.bitmapDataLength
-#else
-#define SURFACE_BPP(cmd) cmd.bpp
-#define SURFACE_CODECID(cmd) cmd.codecID
-#define SURFACE_WIDTH(cmd) cmd.width
-#define SURFACE_HEIGHT(cmd) cmd.height
-#define SURFACE_BITMAP_DATA(cmd) cmd.bitmapData
-#define SURFACE_BITMAP_DATA_LEN(cmd) cmd.bitmapDataLength
-#endif
-
-#include <freerdp/freerdp.h>
-#include <freerdp/listener.h>
-#include <freerdp/update.h>
-#include <freerdp/input.h>
-#include <freerdp/codec/color.h>
-#include <freerdp/codec/rfx.h>
-#include <freerdp/codec/nsc.h>
-#include <freerdp/locale/keyboard.h>
-#include <winpr/input.h>
-
-#if FREERDP_VERSION_MAJOR >= 2
-#include <winpr/ssl.h>
-#endif
-
-#include "shared/helpers.h"
-#include "shared/timespec-util.h"
-#include <libweston/libweston.h>
-#include <libweston/backend-rdp.h>
-#include "pixman-renderer.h"
-
-#define MAX_FREERDP_FDS 32
-#define DEFAULT_AXIS_STEP_DISTANCE 10
-#define RDP_MODE_FREQ 60 * 1000
-
-#if FREERDP_VERSION_MAJOR >= 2 && defined(PIXEL_FORMAT_BGRA32) && !defined(PIXEL_FORMAT_B8G8R8A8)
- /* The RDP API is truly wonderful: the pixel format definition changed
- * from BGRA32 to B8G8R8A8, but some versions ship with a definition of
- * PIXEL_FORMAT_BGRA32 which doesn't actually build. Try really, really,
- * hard to find one which does. */
-# define DEFAULT_PIXEL_FORMAT PIXEL_FORMAT_BGRA32
-#else
-# define DEFAULT_PIXEL_FORMAT RDP_PIXEL_FORMAT_B8G8R8A8
-#endif
-
-struct rdp_output;
-
-struct rdp_backend {
- struct weston_backend base;
- struct weston_compositor *compositor;
-
- freerdp_listener *listener;
- struct wl_event_source *listener_events[MAX_FREERDP_FDS];
- struct rdp_output *output;
-
- char *server_cert;
- char *server_key;
- char *rdp_key;
- int tls_enabled;
- int no_clients_resize;
- int force_no_compression;
-};
-
-enum peer_item_flags {
- RDP_PEER_ACTIVATED = (1 << 0),
- RDP_PEER_OUTPUT_ENABLED = (1 << 1),
-};
-
-struct rdp_peers_item {
- int flags;
- freerdp_peer *peer;
- struct weston_seat *seat;
-
- struct wl_list link;
-};
-
-struct rdp_head {
- struct weston_head base;
-};
-
-struct rdp_output {
- struct weston_output base;
- struct wl_event_source *finish_frame_timer;
- pixman_image_t *shadow_surface;
-
- struct wl_list peers;
-};
-
-struct rdp_peer_context {
- rdpContext _p;
-
- struct rdp_backend *rdpBackend;
- struct wl_event_source *events[MAX_FREERDP_FDS];
- RFX_CONTEXT *rfx_context;
- wStream *encode_stream;
- RFX_RECT *rfx_rects;
- NSC_CONTEXT *nsc_context;
-
- struct rdp_peers_item item;
-};
-typedef struct rdp_peer_context RdpPeerContext;
-
-static inline struct rdp_head *
-to_rdp_head(struct weston_head *base)
-{
- return container_of(base, struct rdp_head, base);
-}
-
-static inline struct rdp_output *
-to_rdp_output(struct weston_output *base)
-{
- return container_of(base, struct rdp_output, base);
-}
-
-static inline struct rdp_backend *
-to_rdp_backend(struct weston_compositor *base)
-{
- return container_of(base->backend, struct rdp_backend, base);
-}
-
-static void
-rdp_peer_refresh_rfx(pixman_region32_t *damage, pixman_image_t *image, freerdp_peer *peer)
-{
- int width, height, nrects, i;
- pixman_box32_t *region, *rects;
- uint32_t *ptr;
- RFX_RECT *rfxRect;
- rdpUpdate *update = peer->update;
- SURFACE_BITS_COMMAND cmd;
- RdpPeerContext *context = (RdpPeerContext *)peer->context;
-
- Stream_Clear(context->encode_stream);
- Stream_SetPosition(context->encode_stream, 0);
-
- width = (damage->extents.x2 - damage->extents.x1);
- height = (damage->extents.y2 - damage->extents.y1);
-
-#ifdef HAVE_SKIP_COMPRESSION
- cmd.skipCompression = TRUE;
-#else
- memset(&cmd, 0, sizeof(*cmd));
-#endif
- cmd.destLeft = damage->extents.x1;
- cmd.destTop = damage->extents.y1;
- cmd.destRight = damage->extents.x2;
- cmd.destBottom = damage->extents.y2;
- SURFACE_BPP(cmd) = 32;
- SURFACE_CODECID(cmd) = peer->settings->RemoteFxCodecId;
- SURFACE_WIDTH(cmd) = width;
- SURFACE_HEIGHT(cmd) = height;
-
- ptr = pixman_image_get_data(image) + damage->extents.x1 +
- damage->extents.y1 * (pixman_image_get_stride(image) / sizeof(uint32_t));
-
- rects = pixman_region32_rectangles(damage, &nrects);
- context->rfx_rects = realloc(context->rfx_rects, nrects * sizeof *rfxRect);
-
- for (i = 0; i < nrects; i++) {
- region = &rects[i];
- rfxRect = &context->rfx_rects[i];
-
- rfxRect->x = (region->x1 - damage->extents.x1);
- rfxRect->y = (region->y1 - damage->extents.y1);
- rfxRect->width = (region->x2 - region->x1);
- rfxRect->height = (region->y2 - region->y1);
- }
-
- rfx_compose_message(context->rfx_context, context->encode_stream, context->rfx_rects, nrects,
- (BYTE *)ptr, width, height,
- pixman_image_get_stride(image)
- );
-
- SURFACE_BITMAP_DATA_LEN(cmd) = Stream_GetPosition(context->encode_stream);
- SURFACE_BITMAP_DATA(cmd) = Stream_Buffer(context->encode_stream);
-
- update->SurfaceBits(update->context, &cmd);
-}
-
-
-static void
-rdp_peer_refresh_nsc(pixman_region32_t *damage, pixman_image_t *image, freerdp_peer *peer)
-{
- int width, height;
- uint32_t *ptr;
- rdpUpdate *update = peer->update;
- SURFACE_BITS_COMMAND cmd;
- RdpPeerContext *context = (RdpPeerContext *)peer->context;
-
- Stream_Clear(context->encode_stream);
- Stream_SetPosition(context->encode_stream, 0);
-
- width = (damage->extents.x2 - damage->extents.x1);
- height = (damage->extents.y2 - damage->extents.y1);
-
-#ifdef HAVE_SKIP_COMPRESSION
- cmd.skipCompression = TRUE;
-#else
- memset(cmd, 0, sizeof(*cmd));
-#endif
-
- cmd.destLeft = damage->extents.x1;
- cmd.destTop = damage->extents.y1;
- cmd.destRight = damage->extents.x2;
- cmd.destBottom = damage->extents.y2;
- SURFACE_BPP(cmd) = 32;
- SURFACE_CODECID(cmd) = peer->settings->NSCodecId;
- SURFACE_WIDTH(cmd) = width;
- SURFACE_HEIGHT(cmd) = height;
-
- ptr = pixman_image_get_data(image) + damage->extents.x1 +
- damage->extents.y1 * (pixman_image_get_stride(image) / sizeof(uint32_t));
-
- nsc_compose_message(context->nsc_context, context->encode_stream, (BYTE *)ptr,
- width, height,
- pixman_image_get_stride(image));
-
- SURFACE_BITMAP_DATA_LEN(cmd) = Stream_GetPosition(context->encode_stream);
- SURFACE_BITMAP_DATA(cmd) = Stream_Buffer(context->encode_stream);
-
- update->SurfaceBits(update->context, &cmd);
-}
-
-static void
-pixman_image_flipped_subrect(const pixman_box32_t *rect, pixman_image_t *img, BYTE *dest)
-{
- int stride = pixman_image_get_stride(img);
- int h;
- int toCopy = (rect->x2 - rect->x1) * 4;
- int height = (rect->y2 - rect->y1);
- const BYTE *src = (const BYTE *)pixman_image_get_data(img);
- src += ((rect->y2-1) * stride) + (rect->x1 * 4);
-
- for (h = 0; h < height; h++, src -= stride, dest += toCopy)
- memcpy(dest, src, toCopy);
-}
-
-static void
-rdp_peer_refresh_raw(pixman_region32_t *region, pixman_image_t *image, freerdp_peer *peer)
-{
- rdpUpdate *update = peer->update;
- SURFACE_BITS_COMMAND cmd;
- SURFACE_FRAME_MARKER marker;
- pixman_box32_t *rect, subrect;
- int nrects, i;
- int heightIncrement, remainingHeight, top;
-
- rect = pixman_region32_rectangles(region, &nrects);
- if (!nrects)
- return;
-
- marker.frameId++;
- marker.frameAction = SURFACECMD_FRAMEACTION_BEGIN;
- update->SurfaceFrameMarker(peer->context, &marker);
-
- memset(&cmd, 0, sizeof(cmd));
- SURFACE_BPP(cmd) = 32;
- SURFACE_CODECID(cmd) = 0;
-
- for (i = 0; i < nrects; i++, rect++) {
- /*weston_log("rect(%d,%d, %d,%d)\n", rect->x1, rect->y1, rect->x2, rect->y2);*/
- cmd.destLeft = rect->x1;
- cmd.destRight = rect->x2;
- SURFACE_WIDTH(cmd) = rect->x2 - rect->x1;
-
- heightIncrement = peer->settings->MultifragMaxRequestSize / (16 + SURFACE_WIDTH(cmd) * 4);
- remainingHeight = rect->y2 - rect->y1;
- top = rect->y1;
-
- subrect.x1 = rect->x1;
- subrect.x2 = rect->x2;
-
- while (remainingHeight) {
- SURFACE_HEIGHT(cmd) = (remainingHeight > heightIncrement) ? heightIncrement : remainingHeight;
- cmd.destTop = top;
- cmd.destBottom = top + SURFACE_HEIGHT(cmd);
- SURFACE_BITMAP_DATA_LEN(cmd) = SURFACE_WIDTH(cmd) * SURFACE_HEIGHT(cmd) * 4;
- SURFACE_BITMAP_DATA(cmd) = (BYTE *)realloc(SURFACE_BITMAP_DATA(cmd), SURFACE_BITMAP_DATA_LEN(cmd));
-
- subrect.y1 = top;
- subrect.y2 = top + SURFACE_HEIGHT(cmd);
- pixman_image_flipped_subrect(&subrect, image, SURFACE_BITMAP_DATA(cmd));
-
- /*weston_log("* sending (%d,%d, %d,%d)\n", subrect.x1, subrect.y1, subrect.x2, subrect.y2); */
- update->SurfaceBits(peer->context, &cmd);
-
- remainingHeight -= SURFACE_HEIGHT(cmd);
- top += SURFACE_HEIGHT(cmd);
- }
- }
-
- free(SURFACE_BITMAP_DATA(cmd));
-
- marker.frameAction = SURFACECMD_FRAMEACTION_END;
- update->SurfaceFrameMarker(peer->context, &marker);
-}
-
-static void
-rdp_peer_refresh_region(pixman_region32_t *region, freerdp_peer *peer)
-{
- RdpPeerContext *context = (RdpPeerContext *)peer->context;
- struct rdp_output *output = context->rdpBackend->output;
- rdpSettings *settings = peer->settings;
-
- if (settings->RemoteFxCodec)
- rdp_peer_refresh_rfx(region, output->shadow_surface, peer);
- else if (settings->NSCodec)
- rdp_peer_refresh_nsc(region, output->shadow_surface, peer);
- else
- rdp_peer_refresh_raw(region, output->shadow_surface, peer);
-}
-
-static int
-rdp_output_start_repaint_loop(struct weston_output *output)
-{
- struct timespec ts;
-
- weston_compositor_read_presentation_clock(output->compositor, &ts);
- weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
-
- return 0;
-}
-
-static int
-rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage,
- void *repaint_data)
-{
- struct rdp_output *output = container_of(output_base, struct rdp_output, base);
- struct weston_compositor *ec = output->base.compositor;
- struct rdp_peers_item *outputPeer;
-
- pixman_renderer_output_set_buffer(output_base, output->shadow_surface);
- ec->renderer->repaint_output(&output->base, damage);
-
- if (pixman_region32_not_empty(damage)) {
- wl_list_for_each(outputPeer, &output->peers, link) {
- if ((outputPeer->flags & RDP_PEER_ACTIVATED) &&
- (outputPeer->flags & RDP_PEER_OUTPUT_ENABLED))
- {
- rdp_peer_refresh_region(damage, outputPeer->peer);
- }
- }
- }
-
- pixman_region32_subtract(&ec->primary_plane.damage,
- &ec->primary_plane.damage, damage);
-
- wl_event_source_timer_update(output->finish_frame_timer, 16);
- return 0;
-}
-
-static int
-finish_frame_handler(void *data)
-{
- struct rdp_output *output = data;
- struct timespec ts;
-
- weston_compositor_read_presentation_clock(output->base.compositor, &ts);
- weston_output_finish_frame(&output->base, &ts, 0);
-
- return 1;
-}
-
-static struct weston_mode *
-rdp_insert_new_mode(struct weston_output *output, int width, int height, int rate)
-{
- struct weston_mode *ret;
- ret = zalloc(sizeof *ret);
- if (!ret)
- return NULL;
- ret->width = width;
- ret->height = height;
- ret->refresh = rate;
- wl_list_insert(&output->mode_list, &ret->link);
- return ret;
-}
-
-static struct weston_mode *
-ensure_matching_mode(struct weston_output *output, struct weston_mode *target)
-{
- struct weston_mode *local;
-
- wl_list_for_each(local, &output->mode_list, link) {
- if ((local->width == target->width) && (local->height == target->height))
- return local;
- }
-
- return rdp_insert_new_mode(output, target->width, target->height, RDP_MODE_FREQ);
-}
-
-static int
-rdp_switch_mode(struct weston_output *output, struct weston_mode *target_mode)
-{
- struct rdp_output *rdpOutput = container_of(output, struct rdp_output, base);
- struct rdp_peers_item *rdpPeer;
- rdpSettings *settings;
- pixman_image_t *new_shadow_buffer;
- struct weston_mode *local_mode;
-
- local_mode = ensure_matching_mode(output, target_mode);
- if (!local_mode) {
- weston_log("mode %dx%d not available\n", target_mode->width, target_mode->height);
- return -ENOENT;
- }
-
- if (local_mode == output->current_mode)
- return 0;
-
- output->current_mode->flags &= ~WL_OUTPUT_MODE_CURRENT;
-
- output->current_mode = local_mode;
- output->current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
-
- pixman_renderer_output_destroy(output);
- pixman_renderer_output_create(output, 0);
-
- new_shadow_buffer = pixman_image_create_bits(PIXMAN_x8r8g8b8, target_mode->width,
- target_mode->height, 0, target_mode->width * 4);
- pixman_image_composite32(PIXMAN_OP_SRC, rdpOutput->shadow_surface, 0, new_shadow_buffer,
- 0, 0, 0, 0, 0, 0, target_mode->width, target_mode->height);
- pixman_image_unref(rdpOutput->shadow_surface);
- rdpOutput->shadow_surface = new_shadow_buffer;
-
- wl_list_for_each(rdpPeer, &rdpOutput->peers, link) {
- settings = rdpPeer->peer->settings;
- if (settings->DesktopWidth == (UINT32)target_mode->width &&
- settings->DesktopHeight == (UINT32)target_mode->height)
- continue;
-
- if (!settings->DesktopResize) {
- /* too bad this peer does not support desktop resize */
- rdpPeer->peer->Close(rdpPeer->peer);
- } else {
- settings->DesktopWidth = target_mode->width;
- settings->DesktopHeight = target_mode->height;
- rdpPeer->peer->update->DesktopResize(rdpPeer->peer->context);
- }
- }
- return 0;
-}
-
-static int
-rdp_output_set_size(struct weston_output *base,
- int width, int height)
-{
- struct rdp_output *output = to_rdp_output(base);
- struct weston_head *head;
- struct weston_mode *currentMode;
- struct weston_mode initMode;
-
- /* We can only be called once. */
- assert(!output->base.current_mode);
-
- wl_list_for_each(head, &output->base.head_list, output_link) {
- weston_head_set_monitor_strings(head, "weston", "rdp", NULL);
-
- /* This is a virtual output, so report a zero physical size.
- * It's better to let frontends/clients use their defaults. */
- weston_head_set_physical_size(head, 0, 0);
- }
-
- wl_list_init(&output->peers);
-
- initMode.flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
- initMode.width = width;
- initMode.height = height;
- initMode.refresh = RDP_MODE_FREQ;
-
- currentMode = ensure_matching_mode(&output->base, &initMode);
- if (!currentMode)
- return -1;
-
- output->base.current_mode = output->base.native_mode = currentMode;
-
- output->base.start_repaint_loop = rdp_output_start_repaint_loop;
- output->base.repaint = rdp_output_repaint;
- output->base.assign_planes = NULL;
- output->base.set_backlight = NULL;
- output->base.set_dpms = NULL;
- output->base.switch_mode = rdp_switch_mode;
-
- return 0;
-}
-
-static int
-rdp_output_enable(struct weston_output *base)
-{
- struct rdp_output *output = to_rdp_output(base);
- struct rdp_backend *b = to_rdp_backend(base->compositor);
- struct wl_event_loop *loop;
-
- output->shadow_surface = pixman_image_create_bits(PIXMAN_x8r8g8b8,
- output->base.current_mode->width,
- output->base.current_mode->height,
- NULL,
- output->base.current_mode->width * 4);
- if (output->shadow_surface == NULL) {
- weston_log("Failed to create surface for frame buffer.\n");
- return -1;
- }
-
- if (pixman_renderer_output_create(&output->base,
- PIXMAN_RENDERER_OUTPUT_USE_SHADOW) < 0) {
- pixman_image_unref(output->shadow_surface);
- return -1;
- }
-
- loop = wl_display_get_event_loop(b->compositor->wl_display);
- output->finish_frame_timer = wl_event_loop_add_timer(loop, finish_frame_handler, output);
-
- b->output = output;
-
- return 0;
-}
-
-static int
-rdp_output_disable(struct weston_output *base)
-{
- struct rdp_output *output = to_rdp_output(base);
- struct rdp_backend *b = to_rdp_backend(base->compositor);
-
- if (!output->base.enabled)
- return 0;
-
- pixman_image_unref(output->shadow_surface);
- pixman_renderer_output_destroy(&output->base);
-
- wl_event_source_remove(output->finish_frame_timer);
- b->output = NULL;
-
- return 0;
-}
-
-static void
-rdp_output_destroy(struct weston_output *base)
-{
- struct rdp_output *output = to_rdp_output(base);
-
- rdp_output_disable(&output->base);
- weston_output_release(&output->base);
-
- free(output);
-}
-
-static struct weston_output *
-rdp_output_create(struct weston_compositor *compositor, const char *name)
-{
- struct rdp_output *output;
-
- output = zalloc(sizeof *output);
- if (output == NULL)
- return NULL;
-
- weston_output_init(&output->base, compositor, name);
-
- output->base.destroy = rdp_output_destroy;
- output->base.disable = rdp_output_disable;
- output->base.enable = rdp_output_enable;
- output->base.attach_head = NULL;
-
- weston_compositor_add_pending_output(&output->base, compositor);
-
- return &output->base;
-}
-
-static int
-rdp_head_create(struct weston_compositor *compositor, const char *name)
-{
- struct rdp_head *head;
-
- head = zalloc(sizeof *head);
- if (!head)
- return -1;
-
- weston_head_init(&head->base, name);
- weston_head_set_connection_status(&head->base, true);
- weston_compositor_add_head(compositor, &head->base);
-
- return 0;
-}
-
-static void
-rdp_head_destroy(struct rdp_head *head)
-{
- weston_head_release(&head->base);
- free(head);
-}
-
-static void
-rdp_destroy(struct weston_compositor *ec)
-{
- struct rdp_backend *b = to_rdp_backend(ec);
- struct weston_head *base, *next;
- struct rdp_peers_item *rdp_peer, *tmp;
- int i;
-
- wl_list_for_each_safe(rdp_peer, tmp, &b->output->peers, link) {
- freerdp_peer* client = rdp_peer->peer;
-
- client->Disconnect(client);
- freerdp_peer_context_free(client);
- freerdp_peer_free(client);
- }
-
- for (i = 0; i < MAX_FREERDP_FDS; i++)
- if (b->listener_events[i])
- wl_event_source_remove(b->listener_events[i]);
-
- weston_compositor_shutdown(ec);
-
- wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
- rdp_head_destroy(to_rdp_head(base));
-
- freerdp_listener_free(b->listener);
-
- free(b->server_cert);
- free(b->server_key);
- free(b->rdp_key);
- free(b);
-}
-
-static
-int rdp_listener_activity(int fd, uint32_t mask, void *data)
-{
- freerdp_listener* instance = (freerdp_listener *)data;
-
- if (!(mask & WL_EVENT_READABLE))
- return 0;
- if (!instance->CheckFileDescriptor(instance)) {
- weston_log("failed to check FreeRDP file descriptor\n");
- return -1;
- }
- return 0;
-}
-
-static
-int rdp_implant_listener(struct rdp_backend *b, freerdp_listener* instance)
-{
- int i, fd;
- int rcount = 0;
- void* rfds[MAX_FREERDP_FDS];
- struct wl_event_loop *loop;
-
- if (!instance->GetFileDescriptor(instance, rfds, &rcount)) {
- weston_log("Failed to get FreeRDP file descriptor\n");
- return -1;
- }
-
- loop = wl_display_get_event_loop(b->compositor->wl_display);
- for (i = 0; i < rcount; i++) {
- fd = (int)(long)(rfds[i]);
- b->listener_events[i] = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
- rdp_listener_activity, instance);
- }
-
- for ( ; i < MAX_FREERDP_FDS; i++)
- b->listener_events[i] = 0;
- return 0;
-}
-
-
-static FREERDP_CB_RET_TYPE
-rdp_peer_context_new(freerdp_peer* client, RdpPeerContext* context)
-{
- context->item.peer = client;
- context->item.flags = RDP_PEER_OUTPUT_ENABLED;
-
-#if FREERDP_VERSION_MAJOR == 1 && FREERDP_VERSION_MINOR == 1
- context->rfx_context = rfx_context_new();
-#else
- context->rfx_context = rfx_context_new(TRUE);
-#endif
- if (!context->rfx_context) {
- FREERDP_CB_RETURN(FALSE);
- }
-
- context->rfx_context->mode = RLGR3;
- context->rfx_context->width = client->settings->DesktopWidth;
- context->rfx_context->height = client->settings->DesktopHeight;
- rfx_context_set_pixel_format(context->rfx_context, DEFAULT_PIXEL_FORMAT);
-
- context->nsc_context = nsc_context_new();
- if (!context->nsc_context)
- goto out_error_nsc;
-
- nsc_context_set_pixel_format(context->nsc_context, DEFAULT_PIXEL_FORMAT);
-
- context->encode_stream = Stream_New(NULL, 65536);
- if (!context->encode_stream)
- goto out_error_stream;
-
- FREERDP_CB_RETURN(TRUE);
-
-out_error_nsc:
- rfx_context_free(context->rfx_context);
-out_error_stream:
- nsc_context_free(context->nsc_context);
- FREERDP_CB_RETURN(FALSE);
-}
-
-static void
-rdp_peer_context_free(freerdp_peer* client, RdpPeerContext* context)
-{
- int i;
- if (!context)
- return;
-
- wl_list_remove(&context->item.link);
- for (i = 0; i < MAX_FREERDP_FDS; i++) {
- if (context->events[i])
- wl_event_source_remove(context->events[i]);
- }
-
- if (context->item.flags & RDP_PEER_ACTIVATED) {
- weston_seat_release_keyboard(context->item.seat);
- weston_seat_release_pointer(context->item.seat);
- /* XXX we should weston_seat_release(context->item.seat); here
- * but it would crash on reconnect */
- }
-
- Stream_Free(context->encode_stream, TRUE);
- nsc_context_free(context->nsc_context);
- rfx_context_free(context->rfx_context);
- free(context->rfx_rects);
-}
-
-
-static int
-rdp_client_activity(int fd, uint32_t mask, void *data)
-{
- freerdp_peer* client = (freerdp_peer *)data;
-
- if (!client->CheckFileDescriptor(client)) {
- weston_log("unable to checkDescriptor for %p\n", client);
- goto out_clean;
- }
- return 0;
-
-out_clean:
- freerdp_peer_context_free(client);
- freerdp_peer_free(client);
- return 0;
-}
-
-static BOOL
-xf_peer_capabilities(freerdp_peer* client)
-{
- return TRUE;
-}
-
-struct rdp_to_xkb_keyboard_layout {
- UINT32 rdpLayoutCode;
- const char *xkbLayout;
- const char *xkbVariant;
-};
-
-/* table reversed from
- https://github.com/awakecoding/FreeRDP/blob/master/libfreerdp/locale/xkb_layout_ids.c#L811 */
-static const
-struct rdp_to_xkb_keyboard_layout rdp_keyboards[] = {
- {KBD_ARABIC_101, "ara", 0},
- {KBD_BULGARIAN, 0, 0},
- {KBD_CHINESE_TRADITIONAL_US, 0},
- {KBD_CZECH, "cz", 0},
- {KBD_CZECH_PROGRAMMERS, "cz", "bksl"},
- {KBD_CZECH_QWERTY, "cz", "qwerty"},
- {KBD_DANISH, "dk", 0},
- {KBD_GERMAN, "de", 0},
- {KBD_GERMAN_NEO, "de", "neo"},
- {KBD_GERMAN_IBM, "de", "qwerty"},
- {KBD_GREEK, "gr", 0},
- {KBD_GREEK_220, "gr", "simple"},
- {KBD_GREEK_319, "gr", "extended"},
- {KBD_GREEK_POLYTONIC, "gr", "polytonic"},
- {KBD_US, "us", 0},
- {KBD_US_ENGLISH_TABLE_FOR_IBM_ARABIC_238_L, "ara", "buckwalter"},
- {KBD_SPANISH, "es", 0},
- {KBD_SPANISH_VARIATION, "es", "nodeadkeys"},
- {KBD_FINNISH, "fi", 0},
- {KBD_FRENCH, "fr", 0},
- {KBD_HEBREW, "il", 0},
- {KBD_HUNGARIAN, "hu", 0},
- {KBD_HUNGARIAN_101_KEY, "hu", "standard"},
- {KBD_ICELANDIC, "is", 0},
- {KBD_ITALIAN, "it", 0},
- {KBD_ITALIAN_142, "it", "nodeadkeys"},
- {KBD_JAPANESE, "jp", 0},
- {KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002, "jp", "kana"},
- {KBD_KOREAN, "kr", 0},
- {KBD_KOREAN_INPUT_SYSTEM_IME_2000, "kr", "kr104"},
- {KBD_DUTCH, "nl", 0},
- {KBD_NORWEGIAN, "no", 0},
- {KBD_POLISH_PROGRAMMERS, "pl", 0},
- {KBD_POLISH_214, "pl", "qwertz"},
- {KBD_ROMANIAN, "ro", 0},
- {KBD_RUSSIAN, "ru", 0},
- {KBD_RUSSIAN_TYPEWRITER, "ru", "typewriter"},
- {KBD_CROATIAN, "hr", 0},
- {KBD_SLOVAK, "sk", 0},
- {KBD_SLOVAK_QWERTY, "sk", "qwerty"},
- {KBD_ALBANIAN, 0, 0},
- {KBD_SWEDISH, "se", 0},
- {KBD_THAI_KEDMANEE, "th", 0},
- {KBD_THAI_KEDMANEE_NON_SHIFTLOCK, "th", "tis"},
- {KBD_TURKISH_Q, "tr", 0},
- {KBD_TURKISH_F, "tr", "f"},
- {KBD_URDU, "in", "urd-phonetic3"},
- {KBD_UKRAINIAN, "ua", 0},
- {KBD_BELARUSIAN, "by", 0},
- {KBD_SLOVENIAN, "si", 0},
- {KBD_ESTONIAN, "ee", 0},
- {KBD_LATVIAN, "lv", 0},
- {KBD_LITHUANIAN_IBM, "lt", "ibm"},
- {KBD_FARSI, "af", 0},
- {KBD_VIETNAMESE, "vn", 0},
- {KBD_ARMENIAN_EASTERN, "am", 0},
- {KBD_AZERI_LATIN, 0, 0},
- {KBD_FYRO_MACEDONIAN, "mk", 0},
- {KBD_GEORGIAN, "ge", 0},
- {KBD_FAEROESE, 0, 0},
- {KBD_DEVANAGARI_INSCRIPT, 0, 0},
- {KBD_MALTESE_47_KEY, 0, 0},
- {KBD_NORWEGIAN_WITH_SAMI, "no", "smi"},
- {KBD_KAZAKH, "kz", 0},
- {KBD_KYRGYZ_CYRILLIC, "kg", "phonetic"},
- {KBD_TATAR, "ru", "tt"},
- {KBD_BENGALI, "bd", 0},
- {KBD_BENGALI_INSCRIPT, "bd", "probhat"},
- {KBD_PUNJABI, 0, 0},
- {KBD_GUJARATI, "in", "guj"},
- {KBD_TAMIL, "in", "tam"},
- {KBD_TELUGU, "in", "tel"},
- {KBD_KANNADA, "in", "kan"},
- {KBD_MALAYALAM, "in", "mal"},
- {KBD_HINDI_TRADITIONAL, "in", 0},
- {KBD_MARATHI, 0, 0},
- {KBD_MONGOLIAN_CYRILLIC, "mn", 0},
- {KBD_UNITED_KINGDOM_EXTENDED, "gb", "intl"},
- {KBD_SYRIAC, "syc", 0},
- {KBD_SYRIAC_PHONETIC, "syc", "syc_phonetic"},
- {KBD_NEPALI, "np", 0},
- {KBD_PASHTO, "af", "ps"},
- {KBD_DIVEHI_PHONETIC, 0, 0},
- {KBD_LUXEMBOURGISH, 0, 0},
- {KBD_MAORI, "mao", 0},
- {KBD_CHINESE_SIMPLIFIED_US, 0, 0},
- {KBD_SWISS_GERMAN, "ch", "de_nodeadkeys"},
- {KBD_UNITED_KINGDOM, "gb", 0},
- {KBD_LATIN_AMERICAN, "latam", 0},
- {KBD_BELGIAN_FRENCH, "be", 0},
- {KBD_BELGIAN_PERIOD, "be", "oss_sundeadkeys"},
- {KBD_PORTUGUESE, "pt", 0},
- {KBD_SERBIAN_LATIN, "rs", 0},
- {KBD_AZERI_CYRILLIC, "az", "cyrillic"},
- {KBD_SWEDISH_WITH_SAMI, "se", "smi"},
- {KBD_UZBEK_CYRILLIC, "af", "uz"},
- {KBD_INUKTITUT_LATIN, "ca", "ike"},
- {KBD_CANADIAN_FRENCH_LEGACY, "ca", "fr-legacy"},
- {KBD_SERBIAN_CYRILLIC, "rs", 0},
- {KBD_CANADIAN_FRENCH, "ca", "fr-legacy"},
- {KBD_SWISS_FRENCH, "ch", "fr"},
- {KBD_BOSNIAN, "ba", 0},
- {KBD_IRISH, 0, 0},
- {KBD_BOSNIAN_CYRILLIC, "ba", "us"},
- {KBD_UNITED_STATES_DVORAK, "us", "dvorak"},
- {KBD_PORTUGUESE_BRAZILIAN_ABNT2, "br", "nativo"},
- {KBD_CANADIAN_MULTILINGUAL_STANDARD, "ca", "multix"},
- {KBD_GAELIC, "ie", "CloGaelach"},
-
- {0x00000000, 0, 0},
-};
-
-/* taken from 2.2.7.1.6 Input Capability Set (TS_INPUT_CAPABILITYSET) */
-static const char *rdp_keyboard_types[] = {
- "", /* 0: unused */
- "", /* 1: IBM PC/XT or compatible (83-key) keyboard */
- "", /* 2: Olivetti "ICO" (102-key) keyboard */
- "", /* 3: IBM PC/AT (84-key) or similar keyboard */
- "pc102",/* 4: IBM enhanced (101- or 102-key) keyboard */
- "", /* 5: Nokia 1050 and similar keyboards */
- "", /* 6: Nokia 9140 and similar keyboards */
- "" /* 7: Japanese keyboard */
-};
-
-static BOOL
-xf_peer_activate(freerdp_peer* client)
-{
- RdpPeerContext *peerCtx;
- struct rdp_backend *b;
- struct rdp_output *output;
- rdpSettings *settings;
- rdpPointerUpdate *pointer;
- struct rdp_peers_item *peersItem;
- struct xkb_rule_names xkbRuleNames;
- struct xkb_keymap *keymap;
- struct weston_output *weston_output;
- int i;
- pixman_box32_t box;
- pixman_region32_t damage;
- char seat_name[50];
- POINTER_SYSTEM_UPDATE pointer_system;
-
- peerCtx = (RdpPeerContext *)client->context;
- b = peerCtx->rdpBackend;
- peersItem = &peerCtx->item;
- output = b->output;
- settings = client->settings;
-
- if (!settings->SurfaceCommandsEnabled) {
- weston_log("client doesn't support required SurfaceCommands\n");
- return FALSE;
- }
-
- if (b->force_no_compression && settings->CompressionEnabled) {
- weston_log("Forcing compression off\n");
- settings->CompressionEnabled = FALSE;
- }
-
- if (output->base.width != (int)settings->DesktopWidth ||
- output->base.height != (int)settings->DesktopHeight)
- {
- if (b->no_clients_resize) {
- /* RDP peers don't dictate their resolution to weston */
- if (!settings->DesktopResize) {
- /* peer does not support desktop resize */
- weston_log("%s: client doesn't support resizing, closing connection\n", __FUNCTION__);
- return FALSE;
- } else {
- settings->DesktopWidth = output->base.width;
- settings->DesktopHeight = output->base.height;
- client->update->DesktopResize(client->context);
- }
- } else {
- /* ask weston to adjust size */
- struct weston_mode new_mode;
- struct weston_mode *target_mode;
- new_mode.width = (int)settings->DesktopWidth;
- new_mode.height = (int)settings->DesktopHeight;
- target_mode = ensure_matching_mode(&output->base, &new_mode);
- if (!target_mode) {
- weston_log("client mode not found\n");
- return FALSE;
- }
- weston_output_mode_set_native(&output->base, target_mode, 1);
- output->base.width = new_mode.width;
- output->base.height = new_mode.height;
- }
- }
-
- weston_output = &output->base;
- RFX_RESET(peerCtx->rfx_context, weston_output->width, weston_output->height);
- NSC_RESET(peerCtx->nsc_context, weston_output->width, weston_output->height);
-
- if (peersItem->flags & RDP_PEER_ACTIVATED)
- return TRUE;
-
- /* when here it's the first reactivation, we need to setup a little more */
- weston_log("kbd_layout:0x%x kbd_type:0x%x kbd_subType:0x%x kbd_functionKeys:0x%x\n",
- settings->KeyboardLayout, settings->KeyboardType, settings->KeyboardSubType,
- settings->KeyboardFunctionKey);
-
- memset(&xkbRuleNames, 0, sizeof(xkbRuleNames));
- if (settings->KeyboardType <= 7)
- xkbRuleNames.model = rdp_keyboard_types[settings->KeyboardType];
- for (i = 0; rdp_keyboards[i].rdpLayoutCode; i++) {
- if (rdp_keyboards[i].rdpLayoutCode == settings->KeyboardLayout) {
- xkbRuleNames.layout = rdp_keyboards[i].xkbLayout;
- xkbRuleNames.variant = rdp_keyboards[i].xkbVariant;
- weston_log("%s: matching layout=%s variant=%s\n", __FUNCTION__,
- xkbRuleNames.layout, xkbRuleNames.variant);
- break;
- }
- }
-
- keymap = NULL;
- if (xkbRuleNames.layout) {
- keymap = xkb_keymap_new_from_names(b->compositor->xkb_context,
- &xkbRuleNames, 0);
- }
-
- if (settings->ClientHostname)
- snprintf(seat_name, sizeof(seat_name), "RDP %s", settings->ClientHostname);
- else
- snprintf(seat_name, sizeof(seat_name), "RDP peer @%s", settings->ClientAddress);
-
- peersItem->seat = zalloc(sizeof(*peersItem->seat));
- if (!peersItem->seat) {
- xkb_keymap_unref(keymap);
- weston_log("unable to create a weston_seat\n");
- return FALSE;
- }
-
- weston_seat_init(peersItem->seat, b->compositor, seat_name);
- weston_seat_init_keyboard(peersItem->seat, keymap);
- xkb_keymap_unref(keymap);
- weston_seat_init_pointer(peersItem->seat);
-
- peersItem->flags |= RDP_PEER_ACTIVATED;
-
- /* disable pointer on the client side */
- pointer = client->update->pointer;
- pointer_system.type = SYSPTR_NULL;
- pointer->PointerSystem(client->context, &pointer_system);
-
- /* sends a full refresh */
- box.x1 = 0;
- box.y1 = 0;
- box.x2 = output->base.width;
- box.y2 = output->base.height;
- pixman_region32_init_with_extents(&damage, &box);
-
- rdp_peer_refresh_region(&damage, client);
-
- pixman_region32_fini(&damage);
-
- return TRUE;
-}
-
-static BOOL
-xf_peer_post_connect(freerdp_peer *client)
-{
- return TRUE;
-}
-
-static FREERDP_CB_RET_TYPE
-xf_mouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y)
-{
- RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
- struct rdp_output *output;
- uint32_t button = 0;
- bool need_frame = false;
- struct timespec time;
-
- if (flags & PTR_FLAGS_MOVE) {
- output = peerContext->rdpBackend->output;
- if (x < output->base.width && y < output->base.height) {
- weston_compositor_get_time(&time);
- notify_motion_absolute(peerContext->item.seat, &time,
- x, y);
- need_frame = true;
- }
- }
-
- if (flags & PTR_FLAGS_BUTTON1)
- button = BTN_LEFT;
- else if (flags & PTR_FLAGS_BUTTON2)
- button = BTN_RIGHT;
- else if (flags & PTR_FLAGS_BUTTON3)
- button = BTN_MIDDLE;
-
- if (button) {
- weston_compositor_get_time(&time);
- notify_button(peerContext->item.seat, &time, button,
- (flags & PTR_FLAGS_DOWN) ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED
- );
- need_frame = true;
- }
-
- if (flags & PTR_FLAGS_WHEEL) {
- struct weston_pointer_axis_event weston_event;
- double value;
-
- /* DEFAULT_AXIS_STEP_DISTANCE is stolen from compositor-x11.c
- * The RDP specs says the lower bits of flags contains the "the number of rotation
- * units the mouse wheel was rotated".
- *
- * https://blogs.msdn.microsoft.com/oldnewthing/20130123-00/?p=5473 explains the 120 value
- */
- value = -(flags & 0xff) / 120.0;
- if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
- value = -value;
-
- weston_event.axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
- weston_event.value = DEFAULT_AXIS_STEP_DISTANCE * value;
- weston_event.discrete = (int)value;
- weston_event.has_discrete = true;
-
- weston_compositor_get_time(&time);
-
- notify_axis(peerContext->item.seat, &time, &weston_event);
- need_frame = true;
- }
-
- if (need_frame)
- notify_pointer_frame(peerContext->item.seat);
-
- FREERDP_CB_RETURN(TRUE);
-}
-
-static FREERDP_CB_RET_TYPE
-xf_extendedMouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y)
-{
- RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
- struct rdp_output *output;
- struct timespec time;
-
- output = peerContext->rdpBackend->output;
- if (x < output->base.width && y < output->base.height) {
- weston_compositor_get_time(&time);
- notify_motion_absolute(peerContext->item.seat, &time, x, y);
- }
-
- FREERDP_CB_RETURN(TRUE);
-}
-
-
-static FREERDP_CB_RET_TYPE
-xf_input_synchronize_event(rdpInput *input, UINT32 flags)
-{
- freerdp_peer *client = input->context->peer;
- RdpPeerContext *peerCtx = (RdpPeerContext *)input->context;
- struct rdp_output *output = peerCtx->rdpBackend->output;
- pixman_box32_t box;
- pixman_region32_t damage;
-
- /* sends a full refresh */
- box.x1 = 0;
- box.y1 = 0;
- box.x2 = output->base.width;
- box.y2 = output->base.height;
- pixman_region32_init_with_extents(&damage, &box);
-
- rdp_peer_refresh_region(&damage, client);
-
- pixman_region32_fini(&damage);
- FREERDP_CB_RETURN(TRUE);
-}
-
-
-static FREERDP_CB_RET_TYPE
-xf_input_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code)
-{
- uint32_t scan_code, vk_code, full_code;
- enum wl_keyboard_key_state keyState;
- RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
- int notify = 0;
- struct timespec time;
-
- if (!(peerContext->item.flags & RDP_PEER_ACTIVATED))
- FREERDP_CB_RETURN(TRUE);
-
- if (flags & KBD_FLAGS_DOWN) {
- keyState = WL_KEYBOARD_KEY_STATE_PRESSED;
- notify = 1;
- } else if (flags & KBD_FLAGS_RELEASE) {
- keyState = WL_KEYBOARD_KEY_STATE_RELEASED;
- notify = 1;
- }
-
- if (notify) {
- full_code = code;
- if (flags & KBD_FLAGS_EXTENDED)
- full_code |= KBD_FLAGS_EXTENDED;
-
- vk_code = GetVirtualKeyCodeFromVirtualScanCode(full_code, 4);
- if (flags & KBD_FLAGS_EXTENDED)
- vk_code |= KBDEXT;
-
- scan_code = GetKeycodeFromVirtualKeyCode(vk_code, KEYCODE_TYPE_EVDEV);
-
- /*weston_log("code=%x ext=%d vk_code=%x scan_code=%x\n", code, (flags & KBD_FLAGS_EXTENDED) ? 1 : 0,
- vk_code, scan_code);*/
- weston_compositor_get_time(&time);
- notify_key(peerContext->item.seat, &time,
- scan_code - 8, keyState, STATE_UPDATE_AUTOMATIC);
- }
-
- FREERDP_CB_RETURN(TRUE);
-}
-
-static FREERDP_CB_RET_TYPE
-xf_input_unicode_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code)
-{
- weston_log("Client sent a unicode keyboard event (flags:0x%X code:0x%X)\n", flags, code);
- FREERDP_CB_RETURN(TRUE);
-}
-
-
-static FREERDP_CB_RET_TYPE
-xf_suppress_output(rdpContext *context, BYTE allow, const RECTANGLE_16 *area)
-{
- RdpPeerContext *peerContext = (RdpPeerContext *)context;
-
- if (allow)
- peerContext->item.flags |= RDP_PEER_OUTPUT_ENABLED;
- else
- peerContext->item.flags &= (~RDP_PEER_OUTPUT_ENABLED);
-
- FREERDP_CB_RETURN(TRUE);
-}
-
-static int
-rdp_peer_init(freerdp_peer *client, struct rdp_backend *b)
-{
- int rcount = 0;
- void *rfds[MAX_FREERDP_FDS];
- int i, fd;
- struct wl_event_loop *loop;
- rdpSettings *settings;
- rdpInput *input;
- RdpPeerContext *peerCtx;
-
- client->ContextSize = sizeof(RdpPeerContext);
- client->ContextNew = (psPeerContextNew)rdp_peer_context_new;
- client->ContextFree = (psPeerContextFree)rdp_peer_context_free;
- freerdp_peer_context_new(client);
-
- peerCtx = (RdpPeerContext *) client->context;
- peerCtx->rdpBackend = b;
-
- settings = client->settings;
- /* configure security settings */
- if (b->rdp_key)
- settings->RdpKeyFile = strdup(b->rdp_key);
- if (b->tls_enabled) {
- settings->CertificateFile = strdup(b->server_cert);
- settings->PrivateKeyFile = strdup(b->server_key);
- } else {
- settings->TlsSecurity = FALSE;
- }
- settings->NlaSecurity = FALSE;
-
- if (!client->Initialize(client)) {
- weston_log("peer initialization failed\n");
- goto error_initialize;
- }
-
- settings->OsMajorType = OSMAJORTYPE_UNIX;
- settings->OsMinorType = OSMINORTYPE_PSEUDO_XSERVER;
- settings->ColorDepth = 32;
- settings->RefreshRect = TRUE;
- settings->RemoteFxCodec = TRUE;
- settings->NSCodec = TRUE;
- settings->FrameMarkerCommandEnabled = TRUE;
- settings->SurfaceFrameMarkerEnabled = TRUE;
-
- client->Capabilities = xf_peer_capabilities;
- client->PostConnect = xf_peer_post_connect;
- client->Activate = xf_peer_activate;
-
- client->update->SuppressOutput = (pSuppressOutput)xf_suppress_output;
-
- input = client->input;
- input->SynchronizeEvent = xf_input_synchronize_event;
- input->MouseEvent = xf_mouseEvent;
- input->ExtendedMouseEvent = xf_extendedMouseEvent;
- input->KeyboardEvent = xf_input_keyboard_event;
- input->UnicodeKeyboardEvent = xf_input_unicode_keyboard_event;
-
- if (!client->GetFileDescriptor(client, rfds, &rcount)) {
- weston_log("unable to retrieve client fds\n");
- goto error_initialize;
- }
-
- loop = wl_display_get_event_loop(b->compositor->wl_display);
- for (i = 0; i < rcount; i++) {
- fd = (int)(long)(rfds[i]);
-
- peerCtx->events[i] = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
- rdp_client_activity, client);
- }
- for ( ; i < MAX_FREERDP_FDS; i++)
- peerCtx->events[i] = 0;
-
- wl_list_insert(&b->output->peers, &peerCtx->item.link);
- return 0;
-
-error_initialize:
- client->Close(client);
- return -1;
-}
-
-
-static FREERDP_CB_RET_TYPE
-rdp_incoming_peer(freerdp_listener *instance, freerdp_peer *client)
-{
- struct rdp_backend *b = (struct rdp_backend *)instance->param4;
- if (rdp_peer_init(client, b) < 0) {
- weston_log("error when treating incoming peer\n");
- FREERDP_CB_RETURN(FALSE);
- }
-
- FREERDP_CB_RETURN(TRUE);
-}
-
-static const struct weston_rdp_output_api api = {
- rdp_output_set_size,
-};
-
-static struct rdp_backend *
-rdp_backend_create(struct weston_compositor *compositor,
- struct weston_rdp_backend_config *config)
-{
- struct rdp_backend *b;
- char *fd_str;
- char *fd_tail;
- int fd, ret;
-
- b = zalloc(sizeof *b);
- if (b == NULL)
- return NULL;
-
- b->compositor = compositor;
- b->base.destroy = rdp_destroy;
- b->base.create_output = rdp_output_create;
- b->rdp_key = config->rdp_key ? strdup(config->rdp_key) : NULL;
- b->no_clients_resize = config->no_clients_resize;
- b->force_no_compression = config->force_no_compression;
-
- compositor->backend = &b->base;
-
- /* activate TLS only if certificate/key are available */
- if (config->server_cert && config->server_key) {
- weston_log("TLS support activated\n");
- b->server_cert = strdup(config->server_cert);
- b->server_key = strdup(config->server_key);
- if (!b->server_cert || !b->server_key)
- goto err_free_strings;
- b->tls_enabled = 1;
- }
-
- if (weston_compositor_set_presentation_clock_software(compositor) < 0)
- goto err_compositor;
-
- if (pixman_renderer_init(compositor) < 0)
- goto err_compositor;
-
- if (rdp_head_create(compositor, "rdp") < 0)
- goto err_compositor;
-
- compositor->capabilities |= WESTON_CAP_ARBITRARY_MODES;
-
- if (!config->env_socket) {
- b->listener = freerdp_listener_new();
- b->listener->PeerAccepted = rdp_incoming_peer;
- b->listener->param4 = b;
- if (!b->listener->Open(b->listener, config->bind_address, config->port)) {
- weston_log("unable to bind rdp socket\n");
- goto err_listener;
- }
-
- if (rdp_implant_listener(b, b->listener) < 0)
- goto err_compositor;
- } else {
- /* get the socket from RDP_FD var */
- fd_str = getenv("RDP_FD");
- if (!fd_str) {
- weston_log("RDP_FD env variable not set\n");
- goto err_output;
- }
-
- fd = strtoul(fd_str, &fd_tail, 10);
- if (errno != 0 || fd_tail == fd_str || *fd_tail != '\0'
- || rdp_peer_init(freerdp_peer_new(fd), b))
- goto err_output;
- }
-
- ret = weston_plugin_api_register(compositor, WESTON_RDP_OUTPUT_API_NAME,
- &api, sizeof(api));
-
- if (ret < 0) {
- weston_log("Failed to register output API.\n");
- goto err_output;
- }
-
- return b;
-
-err_listener:
- freerdp_listener_free(b->listener);
-err_output:
- weston_output_release(&b->output->base);
-err_compositor:
- weston_compositor_shutdown(compositor);
-err_free_strings:
- free(b->rdp_key);
- free(b->server_cert);
- free(b->server_key);
- free(b);
- return NULL;
-}
-
-static void
-config_init_to_defaults(struct weston_rdp_backend_config *config)
-{
- config->bind_address = NULL;
- config->port = 3389;
- config->rdp_key = NULL;
- config->server_cert = NULL;
- config->server_key = NULL;
- config->env_socket = 0;
- config->no_clients_resize = 0;
- config->force_no_compression = 0;
-}
-
-WL_EXPORT int
-weston_backend_init(struct weston_compositor *compositor,
- struct weston_backend_config *config_base)
-{
- struct rdp_backend *b;
- struct weston_rdp_backend_config config = {{ 0, }};
- int major, minor, revision;
-
-#if FREERDP_VERSION_MAJOR >= 2
- winpr_InitializeSSL(0);
-#endif
- freerdp_get_version(&major, &minor, &revision);
- weston_log("using FreeRDP version %d.%d.%d\n", major, minor, revision);
-
- if (config_base == NULL ||
- config_base->struct_version != WESTON_RDP_BACKEND_CONFIG_VERSION ||
- config_base->struct_size > sizeof(struct weston_rdp_backend_config)) {
- weston_log("RDP backend config structure is invalid\n");
- return -1;
- }
-
- config_init_to_defaults(&config);
- memcpy(&config, config_base, config_base->struct_size);
-
- if (!config.rdp_key && (!config.server_cert || !config.server_key)) {
- weston_log("the RDP compositor requires keys and an optional certificate for RDP or TLS security ("
- "--rdp4-key or --rdp-tls-cert/--rdp-tls-key)\n");
- return -1;
- }
-
- b = rdp_backend_create(compositor, &config);
- if (b == NULL)
- return -1;
- return 0;
-}
diff --git a/libweston/backend-tdm/meson.build b/libweston/backend-tdm/meson.build
deleted file mode 100644
index bec333da..00000000
--- a/libweston/backend-tdm/meson.build
+++ /dev/null
@@ -1,35 +0,0 @@
-if not get_option('backend-tdm')
- subdir_done()
-endif
-
-config_h.set('BUILD_TDM_COMPOSITOR', '1')
-
-srcs_tdm = [
- 'tdm.c',
- linux_dmabuf_unstable_v1_protocol_c,
- linux_dmabuf_unstable_v1_server_protocol_h,
- presentation_time_server_protocol_h,
-]
-
-deps_tdm = [
- dep_libdl,
- dep_libweston_private,
- dep_session_helper,
- dep_libinput_backend,
- dependency('libtbm'),
- dependency('libtdm'),
- dependency('libudev', version: '>= 136'),
-]
-
-plugin_tdm = shared_library(
- 'tdm-backend',
- srcs_tdm,
- include_directories: common_inc,
- dependencies: deps_tdm,
- name_prefix: '',
- install: true,
- install_dir: dir_module_libweston
-)
-env_modmap += 'tdm-backend.so=@0@;'.format(plugin_tdm.full_path())
-
-install_headers(backend_drm_h, subdir: dir_include_libweston_install)
diff --git a/libweston/backend-tdm/tdm-internal.h b/libweston/backend-tdm/tdm-internal.h
deleted file mode 100644
index 6fb8818d..00000000
--- a/libweston/backend-tdm/tdm-internal.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2011 Intel Corporation
- * Copyright © 2017, 2018 Collabora, Ltd.
- * Copyright © 2017, 2018 General Electric Company
- * Copyright (c) 2018 DisplayLink (UK) Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <linux/input.h>
-#include <linux/vt.h>
-#include <assert.h>
-#include <sys/mman.h>
-#include <time.h>
-
-#include <libudev.h>
-
-#include <libweston/libweston.h>
-#include <libweston/backend-drm.h>
-#include <libweston/weston-log.h>
-#include <tdm.h>
-#include <tbm_bufmgr.h>
-#include <tbm_surface_internal.h>
-#include <tbm_dummy_display.h>
-#include "shared/helpers.h"
-#include "libinput-seat.h"
-#include "backend.h"
-#include "libweston-internal.h"
-
-#define tdm_debug(b, ...) \
- weston_log_scope_printf((b)->debug, __VA_ARGS__)
-
-/**
- * Possible values for the WTDM_PLANE_TYPE property.
- */
-enum wtdm_backend_plane_type {
- WTDM_PLANE_TYPE_PRIMARY = 0,
- WTDM_PLANE_TYPE_OVERLAY,
-};
-
-struct tdm_backend {
- struct weston_backend base;
- struct weston_compositor *compositor;
-
- struct udev *udev;
- struct wl_event_source *tdm_source;
-
- struct wl_listener session_listener;
- uint32_t gbm_format;
-
- struct udev_input input;
-
- bool use_pixman;
- bool use_pixman_shadow;
-
- uint32_t pageflip_timeout;
-
- struct weston_log_scope *debug;
-
- tbm_bufmgr tbufmgr;
- tbm_dummy_display *tbm_display;
- tdm_display *tdisplay;
-
- int tdm_fd;
-
- struct wl_list plane_list;
-};
-
-struct tdm_backend_mode {
- struct weston_mode base;
-
- struct wl_list head_link;
- const tdm_output_mode *tmode;
-};
-
-struct tdm_backend_plane {
- struct weston_plane base;
- struct tdm_backend *backend;
- enum wtdm_backend_plane_type type;
- struct wl_list link;
-};
-
-struct tdm_backend_hwc {
- struct tdm_backend *backend;
-
- tdm_hwc *thwc;
- tbm_surface_queue_h target_buffer_queue;
-
- tbm_surface_h commit_fb;
- tbm_surface_h display_fb;
-};
-
-struct tdm_backend_head {
- struct weston_head base;
- struct tdm_backend *backend;
-
- int index;
- unsigned int pipe;
-
- tdm_output *toutput;
- tdm_output_type toutput_type;
- struct tdm_backend_hwc *hwc;
-
- struct wl_list mode_list;
-
- tdm_output_dpms dpms;
- tdm_output_conn_status conn_status;
-};
-
-struct tdm_backend_output {
- struct weston_output base;
- struct tdm_backend *backend;
-
- tbm_surface_h pending_fb;
- tbm_surface_h current_fb;
-
- tbm_surface_h pixman_tsurfaces[2];
- pixman_image_t *image[2];
- int current_image;
- pixman_region32_t previous_damage;
-};
-
-struct tdm_pending_state {
- struct tdm_backend *backend;
- struct wl_list output_list;
-};
-
-static inline struct tdm_backend_head *
-to_tdm_head(struct weston_head *base)
-{
- return container_of(base, struct tdm_backend_head, base);
-}
-
-static inline struct tdm_backend_output *
-to_tdm_output(struct weston_output *base)
-{
- return container_of(base, struct tdm_backend_output, base);
-}
-
-static inline struct tdm_backend *
-to_tdm_backend(struct weston_compositor *base)
-{
- return container_of(base->backend, struct tdm_backend, base);
-}
-
-static inline struct tdm_backend_mode *
-to_tdm_mode(struct weston_mode *base)
-{
- return container_of(base, struct tdm_backend_mode, base);
-}
diff --git a/libweston/backend-tdm/tdm.c b/libweston/backend-tdm/tdm.c
deleted file mode 100644
index 3140ca35..00000000
--- a/libweston/backend-tdm/tdm.c
+++ /dev/null
@@ -1,1280 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2011 Intel Corporation
- * Copyright © 2017, 2018 Collabora, Ltd.
- * Copyright © 2017, 2018 General Electric Company
- * Copyright (c) 2018 DisplayLink (UK) Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <linux/input.h>
-#include <linux/vt.h>
-#include <assert.h>
-#include <sys/mman.h>
-#include <time.h>
-
-#include <libudev.h>
-
-#include <libweston/weston-log.h>
-#include "tdm-internal.h"
-#include "launcher-util.h"
-#include "renderer-gl/gl-renderer.h"
-#include "pixman-renderer.h"
-#include "presentation-time-server-protocol.h"
-#include "linux-dmabuf.h"
-
-struct gl_renderer_interface *gl_renderer;
-
-static const char default_seat[] = "seat0";
-
-static struct tdm_backend_head *
-tdm_backend_output_get_primary_head(struct tdm_backend_output *output)
-{
- struct weston_head *base;
- struct tdm_backend_head *head, *primary_head = NULL;
-
- wl_list_for_each(base, &output->base.head_list, output_link) {
- head = to_tdm_head(base);
- if (head->pipe == 0) {
- primary_head = head;
- break;
- }
- }
-
- return primary_head;
-}
-
-static void
-tdm_backend_hwc_destroy(struct tdm_backend_hwc *hwc)
-{
- if (!hwc) return;
-
- free(hwc);
-}
-
-static struct tdm_backend_hwc *
-tdm_backend_hwc_create(struct tdm_backend_head *head)
-{
- struct tdm_backend_hwc *hwc;
- tdm_hwc *thwc;
- tdm_error terror;
-
- hwc = zalloc(sizeof *hwc);
- if (!hwc)
- return NULL;
-
- thwc = tdm_output_get_hwc(head->toutput, &terror);
- if (terror != TDM_ERROR_NONE) goto err_alloc;
-
- hwc->thwc = thwc;
-
- hwc->target_buffer_queue = tdm_hwc_get_client_target_buffer_queue(thwc, &terror);
- if (terror != TDM_ERROR_NONE) goto err_alloc;
-
- return hwc;
-
-err_alloc:
- free(hwc);
-
- return NULL;
-}
-
-static int
-tdm_backend_hwc_target_acquire_buffer(struct tdm_backend_hwc *hwc, tbm_surface_h *tsurface)
-{
- tbm_surface_queue_error_e tsq_err;
-
- if (!tbm_surface_queue_can_acquire(hwc->target_buffer_queue, 1))
- return 0;
-
- tsq_err = tbm_surface_queue_acquire(hwc->target_buffer_queue, tsurface);
- if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) {
- weston_log("failed to tbm_surface_queue_acquire\n");
- return tsq_err;
- }
-
- return 0;
-}
-
-static int
-tdm_backend_hwc_target_release_buffer(struct tdm_backend_hwc *hwc, tbm_surface_h tsurface)
-{
- tbm_surface_queue_error_e tsq_err;
-
- tsq_err = tbm_surface_queue_release(hwc->target_buffer_queue, tsurface);
- if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) {
- weston_log("failed to tbm_surface_queue_release\n");
- return tsq_err;
- }
-
- return 0;
-}
-
-static void
-tdm_backend_hwc_commit_handler(tdm_hwc *thwc, unsigned int sequence,
- unsigned int tv_sec, unsigned int tv_usec,
- void *user_data)
-{
- struct tdm_backend_output *output = (struct tdm_backend_output *)user_data;
- struct tdm_backend_head *head = tdm_backend_output_get_primary_head(output);
- struct tdm_backend *b = output->backend;;
- struct tdm_backend_hwc *hwc = head->hwc;
- struct timespec ts;
- uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
- WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
- WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
-
- if (output->current_fb) {
- tbm_surface_internal_unref(output->current_fb);
-
- if (!b->use_pixman)
- tdm_backend_hwc_target_release_buffer(hwc, output->current_fb);
- }
-
- output->current_fb = output->pending_fb;
- output->pending_fb = NULL;
-
- ts.tv_sec = tv_sec;
- ts.tv_nsec = tv_usec * 1000;
-
- weston_output_finish_frame(&output->base, &ts, flags);
-}
-
-static tbm_surface_h
-tdm_backend_output_render_gl(struct tdm_backend_output *output,
- pixman_region32_t *damage)
-{
- struct weston_compositor *ec = output->base.compositor;
- struct tdm_backend_head *head = tdm_backend_output_get_primary_head(output);
- tbm_surface_h tsurface;
-
- ec->renderer->repaint_output(&output->base, damage);
-
- if (tdm_backend_hwc_target_acquire_buffer(head->hwc, &tsurface) < 0)
- return NULL;
-
- tbm_surface_internal_ref(tsurface);
-
- return tsurface;
-}
-
-static tbm_surface_h
-tdm_backend_output_render_pixman(struct tdm_backend_output *output,
- pixman_region32_t *damage)
-{
- struct weston_compositor *ec = output->base.compositor;
-
- output->current_image ^= 1;
-
- pixman_renderer_output_set_buffer(&output->base,
- output->image[output->current_image]);
- pixman_renderer_output_set_hw_extra_damage(&output->base,
- &output->previous_damage);
-
- ec->renderer->repaint_output(&output->base, damage);
-
- pixman_region32_copy(&output->previous_damage, damage);
-
- tbm_surface_internal_ref(output->pixman_tsurfaces[output->current_image]);
-
- return output->pixman_tsurfaces[output->current_image];
-}
-
-static void
-tdm_backend_output_render(struct tdm_backend_output *output, pixman_region32_t *damage)
-{
- struct weston_compositor *c = output->base.compositor;
- struct tdm_backend *b = to_tdm_backend(c);
- tbm_surface_h fb;
-
- if (b->use_pixman) {
- fb = tdm_backend_output_render_pixman(output, damage);
- } else {
- fb = tdm_backend_output_render_gl(output, damage);
- }
-
- if (!fb) return;
-
- if (output->pending_fb)
- tbm_surface_internal_unref(output->pending_fb);
-
- output->pending_fb = fb;
-
- pixman_region32_subtract(&c->primary_plane.damage,
- &c->primary_plane.damage, damage);
-}
-
-static int
-tdm_backend_output_repaint(struct weston_output *output_base,
- pixman_region32_t *damage,
- void *repaint_data)
-{
- struct tdm_backend_output *output = to_tdm_output(output_base);
-
- tdm_backend_output_render(output, damage);
-
- return 0;
-}
-
-static int
-tdm_backend_output_start_repaint_loop(struct weston_output *output_base)
-{
- weston_output_finish_frame(output_base, NULL,
- WP_PRESENTATION_FEEDBACK_INVALID);
- return 0;
-}
-
-/**
- * Begin a new repaint cycle
- */
-static void *
-tdm_repaint_begin(struct weston_compositor *compositor)
-{
- struct tdm_backend *b = to_tdm_backend(compositor);
-
- if (weston_log_scope_is_enabled(b->debug)) {
- char *dbg = weston_compositor_print_scene_graph(compositor);
- tdm_debug(b, "[repaint] Beginning repaint\n");
- tdm_debug(b, "%s", dbg);
- free(dbg);
- }
-
- return NULL;
-}
-
-/**
- * Flush a repaint set
- */
-static int
-tdm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
-{
- struct weston_output *output_base = NULL;
- uint32_t num_types;
- tdm_region tdamage;
-
- wl_list_for_each(output_base, &compositor->output_list, link) {
- struct tdm_backend_output *output = to_tdm_output(output_base);
- struct tdm_backend_head *head = tdm_backend_output_get_primary_head(output);
-
- if (!output->pending_fb)
- continue;
-
- memset(&tdamage, 0, sizeof(tdamage));
-
- tdm_hwc_set_client_target_buffer(head->hwc->thwc, output->pending_fb, tdamage);
- tdm_hwc_validate(head->hwc->thwc, NULL, 0, &num_types);
- tdm_hwc_accept_validation(head->hwc->thwc);
- tdm_hwc_commit(head->hwc->thwc, 0, tdm_backend_hwc_commit_handler, output);
- }
-
- return 0;
-}
-
-/**
- * Cancel a repaint set
- */
-static void
-tdm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
-{
- struct tdm_backend *b = to_tdm_backend(compositor);
- struct weston_output *output_base = NULL;
-
- wl_list_for_each(output_base, &compositor->output_list, link) {
- struct tdm_backend_output *output = to_tdm_output(output_base);
- struct tdm_backend_head *head = tdm_backend_output_get_primary_head(output);
-
- if (!output->pending_fb)
- continue;
-
- if (!b->use_pixman) {
- tdm_backend_hwc_target_release_buffer(head->hwc, output->pending_fb);
- }
-
- tbm_surface_internal_unref(output->pending_fb);
- output->pending_fb = NULL;
- }
-}
-
-static int
-tdm_backend_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
-{
- return 0;
-}
-
-static struct tdm_backend_plane *
-tdm_backend_plane_create(struct tdm_backend *b, struct tdm_backend_output *output,
- enum wtdm_backend_plane_type type)
-{
- struct tdm_backend_plane *plane;
-
- plane = zalloc(sizeof(*plane));
- if (!plane) {
- weston_log("%s: out of memory\n", __func__);
- return NULL;
- }
-
- plane->backend = b;
- plane->type = type;
-
- weston_plane_init(&plane->base, b->compositor, 0, 0);
- wl_list_insert(&b->plane_list, &plane->link);
-
- return plane;
-}
-
-/**
- * Destroy one TDM plane
- *
- * Destroy a TDM plane, removing it from screen and releasing its retained
- * buffers in the process. The counterpart to tdm_backend_plane_create.
- *
- * @param plane Plane to deallocate (will be freed)
- */
-static void
-tdm_backend_plane_destroy(struct tdm_backend_plane *plane)
-{
- weston_plane_release(&plane->base);
- wl_list_remove(&plane->link);
- free(plane);
-}
-
-/**
- * Initialise sprites (overlay planes)
- *
- * Walk the list of provided TDM planes, and add overlay planes.
- *
- * Call destroy_sprites to free these planes.
- *
- * @param b TDM compositor backend
- */
-static void
-create_sprites(struct tdm_backend *b)
-{
- struct tdm_backend_plane *primary_plane, *overlay_plane;
-
- primary_plane = tdm_backend_plane_create(b, NULL, WTDM_PLANE_TYPE_PRIMARY);
- if (!primary_plane) {
- weston_log("failed to tdm_backend_plane_create\n");
- return;
- }
-
- overlay_plane = tdm_backend_plane_create(b, NULL, WTDM_PLANE_TYPE_OVERLAY);
- if (!overlay_plane) {
- weston_log("failed to tdm_backend_plane_create\n");
- tdm_backend_plane_destroy(primary_plane);
- return;
- }
-
- weston_compositor_stack_plane(b->compositor,
- &primary_plane->base,
- &b->compositor->primary_plane);
-}
-
-/**
- * Clean up sprites (overlay planes)
- *
- * The counterpart to create_sprites.
- *
- * @param b TDM compositor backend
- */
-static void
-destroy_sprites(struct tdm_backend *b)
-{
- struct tdm_backend_plane *plane, *next;
-
- wl_list_for_each_safe(plane, next, &b->plane_list, link)
- tdm_backend_plane_destroy(plane);
-}
-
-/**
- * Power output on or off
- *
- * The DPMS/power level of an output is used to switch it on or off. This
- * is TDM's hook for doing so, which can called either as part of repaint,
- * or independently of the repaint loop.
- *
- * If we are called as part of repaint, we simply set the relevant bit in
- * state and return.
- *
- * This function is never called on a virtual output.
- */
-static void
-tdm_backend_output_set_dpms(struct weston_output *output_base, enum dpms_enum level)
-{
- tdm_error terror;
- struct tdm_backend_output *output = to_tdm_output(output_base);
- struct tdm_backend_head *head = tdm_backend_output_get_primary_head(output);
-
- terror = tdm_output_set_dpms(head->toutput, level);
- if (terror != TDM_ERROR_NONE)
- weston_log("fail to tdm_output_set_dpms\n");
-}
-
-static int
-tdm_backend_output_init_egl(struct tdm_backend_output *output, struct tdm_backend *b)
-{
- struct tdm_backend_head *head;
- struct tdm_backend_hwc *hwc;
- tbm_format format;
-
- head = tdm_backend_output_get_primary_head(output);
- if (!head) {
- weston_log("fail to get primary head\n");
- return -1;
- }
-
- hwc = head->hwc;
- if (!hwc) {
- weston_log("fail to get hwc\n");
- return -1;
- }
-
- if (!hwc->target_buffer_queue) {
- weston_log("fail to get target buffer queue\n");
- return -1;
- }
-
- format = tbm_surface_queue_get_format(hwc->target_buffer_queue);
-
- if (gl_renderer->output_window_create(&output->base,
- (EGLNativeWindowType)hwc->target_buffer_queue,
- hwc->target_buffer_queue,
- &format,
- 0) < 0) {
- weston_log("failed to create gl renderer output state\n");
- return -1;
- }
-
- return 1;
-}
-
-static void
-tdm_backend_output_fini_egl(struct tdm_backend_output *output)
-{
-}
-
-static int
-tdm_backend_output_init_pixman(struct tdm_backend_output *output, struct tdm_backend *b)
-{
- int w = output->base.current_mode->width;
- int h = output->base.current_mode->height;
- /* only support xrgb8888 */
- uint32_t pixman_format = PIXMAN_x8r8g8b8;
- unsigned int i;
- uint32_t flags = 0;
-
- /* FIXME error checking */
- for (i = 0; i < ARRAY_LENGTH(output->pixman_tsurfaces); i++) {
- tbm_surface_info_s info;
-
- output->pixman_tsurfaces[i] = tbm_surface_create(w, h, TBM_FORMAT_XRGB8888);
- if (!output->pixman_tsurfaces[i])
- goto err;
-
- tbm_surface_get_info(output->pixman_tsurfaces[i], &info);
-
- output->image[i] =
- pixman_image_create_bits(pixman_format, w, h,
- (uint32_t *)info.planes[0].ptr,
- info.planes[0].stride);
- if (!output->image[i])
- goto err;
- }
-
- if (b->use_pixman_shadow)
- flags |= PIXMAN_RENDERER_OUTPUT_USE_SHADOW;
-
- if (pixman_renderer_output_create(&output->base, flags) < 0)
- goto err;
-
- weston_log("TDM: output %s %s shadow framebuffer.\n", output->base.name,
- b->use_pixman_shadow ? "uses" : "does not use");
-
- pixman_region32_init_rect(&output->previous_damage,
- output->base.x, output->base.y, output->base.width, output->base.height);
-
- return 0;
-
-err:
- for (i = 0; i < ARRAY_LENGTH(output->pixman_tsurfaces); i++) {
- if (output->pixman_tsurfaces[i])
- tbm_surface_internal_unref(output->pixman_tsurfaces[i]);
- if (output->image[i])
- pixman_image_unref(output->image[i]);
-
- output->pixman_tsurfaces[i] = NULL;
- output->image[i] = NULL;
- }
-
- return -1;
-}
-
-static void
-tdm_backend_output_fini_pixman(struct tdm_backend_output *output)
-{
- unsigned int i;
-
- pixman_renderer_output_destroy(&output->base);
- pixman_region32_fini(&output->previous_damage);
-
- for (i = 0; i < ARRAY_LENGTH(output->pixman_tsurfaces); i++) {
- pixman_image_unref(output->image[i]);
- tbm_surface_internal_unref(output->pixman_tsurfaces[i]);
- output->pixman_tsurfaces[i] = NULL;
- output->image[i] = NULL;
- }
-}
-
-static void
-setup_output_seat_constraint(struct tdm_backend *b,
- struct weston_output *output,
- const char *s)
-{
- if (strcmp(s, "") != 0) {
- struct weston_pointer *pointer;
- struct udev_seat *seat;
-
- seat = udev_seat_get_named(&b->input, s);
- if (!seat)
- return;
-
- seat->base.output = output;
-
- pointer = weston_seat_get_pointer(&seat->base);
- if (pointer)
- weston_pointer_clamp(pointer,
- &pointer->x,
- &pointer->y);
- }
-}
-
-static int
-tdm_backend_output_attach_head(struct weston_output *output_base,
- struct weston_head *head_base)
-{
- if (!output_base->enabled)
- return 0;
-
- weston_output_schedule_repaint(output_base);
-
- return 0;
-}
-
-static void
-tdm_backend_output_detach_head(struct weston_output *output_base,
- struct weston_head *head_base)
-{
- if (!output_base->enabled)
- return;
-
- weston_output_schedule_repaint(output_base);
-}
-
-static void
-tdm_backend_output_set_seat(struct weston_output *base,
- const char *seat)
-{
- struct tdm_backend_output *output = to_tdm_output(base);
- struct tdm_backend *b = to_tdm_backend(base->compositor);
-
- setup_output_seat_constraint(b, &output->base,
- seat ? seat : "");
-}
-
-static int
-tdm_backend_output_enable(struct weston_output *base)
-{
- struct tdm_backend_output *output = to_tdm_output(base);
- struct tdm_backend *b = to_tdm_backend(base->compositor);
- struct tdm_backend_head *head = tdm_backend_output_get_primary_head(output);
-
- head->hwc = tdm_backend_hwc_create(head);
- if (!head->hwc) goto err;
-
- if (b->use_pixman) {
- if (tdm_backend_output_init_pixman(output, b) < 0) {
- weston_log("Failed to init output pixman state\n");
- goto err;
- }
- } else if (tdm_backend_output_init_egl(output, b) < 0) {
- weston_log("Failed to init output gl state\n");
- goto err;
- }
-
- output->base.start_repaint_loop = tdm_backend_output_start_repaint_loop;
- output->base.repaint = tdm_backend_output_repaint;
- output->base.assign_planes = NULL;// todo
- output->base.set_dpms = tdm_backend_output_set_dpms;
- output->base.switch_mode = tdm_backend_output_switch_mode;
- output->base.set_gamma = NULL;
-
- weston_log("Output %s (crtc %d) video modes:\n",
- output->base.name, /*output->crtc_id*/ 0);
-
- return 0;
-
-err:
- return -1;
-}
-
-static void
-tdm_backend_output_deinit(struct weston_output *base)
-{
- struct tdm_backend_output *output = to_tdm_output(base);
- struct tdm_backend *b = to_tdm_backend(base->compositor);
-
- if (b->use_pixman)
- tdm_backend_output_fini_pixman(output);
- else
- tdm_backend_output_fini_egl(output);
-}
-
-static void
-tdm_backend_output_destroy(struct weston_output *base)
-{
- struct tdm_backend_output *output = to_tdm_output(base);
-
- if (output->base.enabled)
- tdm_backend_output_deinit(&output->base);
-
- weston_output_release(&output->base);
-
- free(output);
-}
-
-static int
-tdm_backend_output_disable(struct weston_output *base)
-{
- struct tdm_backend_output *output = to_tdm_output(base);
-
- weston_log("Disabling output %s\n", output->base.name);
-
- if (output->base.enabled)
- tdm_backend_output_deinit(&output->base);
-
- return 0;
-}
-
-static char *
-_output_type_to_str(tdm_output_type output_type)
-{
- if (output_type == TDM_OUTPUT_TYPE_Unknown) return "Unknown";
- else if (output_type == TDM_OUTPUT_TYPE_VGA) return "VGA";
- else if (output_type == TDM_OUTPUT_TYPE_DVII) return "DVII";
- else if (output_type == TDM_OUTPUT_TYPE_DVID) return "DVID";
- else if (output_type == TDM_OUTPUT_TYPE_DVIA) return "DVIA";
- else if (output_type == TDM_OUTPUT_TYPE_SVIDEO) return "SVIDEO";
- else if (output_type == TDM_OUTPUT_TYPE_LVDS) return "LVDS";
- else if (output_type == TDM_OUTPUT_TYPE_Component) return "Component";
- else if (output_type == TDM_OUTPUT_TYPE_9PinDIN) return "9PinDIN";
- else if (output_type == TDM_OUTPUT_TYPE_DisplayPort) return "DisplayPort";
- else if (output_type == TDM_OUTPUT_TYPE_HDMIA) return "HDMIA";
- else if (output_type == TDM_OUTPUT_TYPE_HDMIB) return "HDMIB";
- else if (output_type == TDM_OUTPUT_TYPE_TV) return "TV";
- else if (output_type == TDM_OUTPUT_TYPE_eDP) return "eDP";
- else if (output_type == TDM_OUTPUT_TYPE_DSI) return "DSI";
- else return "Unknown";
-}
-
-static int
-tdm_backend_head_update(struct tdm_backend_head *head)
-{
- tdm_error terror;
- tdm_output_conn_status status;
- int i;
-
- terror = tdm_output_get_conn_status(head->toutput, &status);
- if (terror != TDM_ERROR_NONE) {
- weston_log("fail to tdm_backend_output_get_conn_status\n");
- return terror;
- }
-
- if ((head->conn_status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) &&
- (status == TDM_OUTPUT_CONN_STATUS_CONNECTED)) {
- const tdm_output_mode *tmodes = NULL;
- int num_tmodes = 0;
- const char *maker, *model;
- unsigned int phy_w, phy_h;
-
- terror = tdm_output_get_model_info(head->toutput, &maker, &model, NULL);
- if (terror != TDM_ERROR_NONE) {
- weston_log("fail to get model info\n");
- return terror;
- }
-
- terror = tdm_output_get_physical_size(head->toutput, &phy_w, &phy_h);
- if (terror != TDM_ERROR_NONE) {
- weston_log("fail to get physical size\n");
- return terror;
- }
-
- weston_head_set_monitor_strings(&head->base, maker, model, NULL);
- weston_head_set_physical_size(&head->base, phy_w, phy_h);
- weston_head_set_connection_status(&head->base, status == TDM_OUTPUT_CONN_STATUS_CONNECTED);
-
- terror = tdm_output_get_available_modes(head->toutput, &tmodes, &num_tmodes);
- if (terror != TDM_ERROR_NONE || num_tmodes == 0) {
- weston_log("fail to get tmodes\n");
- return terror;
- }
-
- for (i = 0; i < num_tmodes; i++) {
- struct tdm_backend_mode *mode;
-
- mode = zalloc(sizeof *mode);
- if (!mode) {
- weston_log("fail to alloc tmode\n");
- return -1;
- }
-
- mode->tmode = &tmodes[i];
- mode->base.flags = 0;
- mode->base.width = tmodes[i].hdisplay;
- mode->base.height = tmodes[i].vdisplay;;
- mode->base.refresh = tmodes[i].clock;
-
- wl_list_insert(&head->mode_list, &mode->head_link);
- }
- }
-
- head->conn_status = status;
-
- return 0;
-}
-
-static void
-_tdm_backend_head_cb_toutput_change(tdm_output *toutput, tdm_output_change_type type,
- tdm_value value, void *user_data)
-{
- struct tdm_backend_head *head = NULL;
- tdm_output_dpms tdpms;
- tdm_output_conn_status status;
-
- head = (struct tdm_backend_head *)user_data;
-
- switch (type) {
- case TDM_OUTPUT_CHANGE_CONNECTION:
- status = (tdm_output_conn_status)value.u32;
- head->conn_status = status;
- if ((status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) ||
- (status == TDM_OUTPUT_CONN_STATUS_CONNECTED))
- tdm_backend_head_update(head);
- break;
- case TDM_OUTPUT_CHANGE_DPMS:
- tdpms = (tdm_output_dpms)value.u32;
- head->dpms = tdpms;
- default:
- break;
- }
-}
-
-/**
- * Create a Weston head for a connector
- *
- * Given a TDM connector, create a matching tdm_backend_head structure and add it
- * to Weston's head list.
- *
- * @param backend Weston backend structure
- * @param index tdm_output index
- * @returns The new head, or NULL on failure.
- */
-static struct tdm_backend_head *
-tdm_backend_head_create(struct tdm_backend *backend, int index)
-{
- struct tdm_backend_head *head;
- tdm_output *toutput = NULL;
- tdm_output_type output_type;
- tdm_error terror;
- const char *name;
-
- head = zalloc(sizeof *head);
- if (!head)
- return NULL;
-
- head->index = index;
-
- toutput = tdm_display_get_output(backend->tdisplay, index, NULL);
- if (!toutput) goto err_alloc;
-
- terror = tdm_output_get_output_type(toutput, &output_type);
- if (terror != TDM_ERROR_NONE) goto err_alloc;
-
- terror = tdm_output_get_pipe(toutput, &head->pipe);
- if (terror != TDM_ERROR_NONE) goto err_alloc;
-
- terror = tdm_output_add_change_handler(toutput, _tdm_backend_head_cb_toutput_change, head);
- if (terror != TDM_ERROR_NONE) {
- weston_log("failed to tdm_backend_output_add_change_handler\n");
- goto err_alloc;
- }
-
- head->index = index;
- head->toutput = toutput;
- head->toutput_type = output_type;
- head->toutput = toutput;
- head->backend = backend;
- wl_list_init(&head->mode_list);
-
- name = _output_type_to_str(output_type);
-
- if ((output_type == TDM_OUTPUT_TYPE_LVDS) ||
- (output_type == TDM_OUTPUT_TYPE_eDP) ||
- (output_type == TDM_OUTPUT_TYPE_DSI))
- weston_head_set_internal(&head->base);
-
- weston_head_init(&head->base, name);
- head->backend = backend;
-
- tdm_backend_head_update(head);
- weston_compositor_add_head(backend->compositor, &head->base);
-
- return head;
-
-err_alloc:
- free(head);
-
- return NULL;
-}
-
-static void
-tdm_backend_head_destroy(struct tdm_backend_head *head)
-{
- weston_head_release(&head->base);
-
- if (head->hwc)
- tdm_backend_hwc_destroy(head->hwc);
-
- tdm_output_remove_change_handler(head->toutput, _tdm_backend_head_cb_toutput_change, head);
-
- free(head);
-}
-
-/**
- * Create a Weston output structure
- *
- * Create an "empty" tdm_output. This is the implementation of
- * weston_backend::create_output.
- *
- * Creating an output is usually followed by tdm_backend_output_attach_head()
- * and tdm_backend_output_enable() to make use of it.
- *
- * @param compositor The compositor instance.
- * @param name Name for the new output.
- * @returns The output, or NULL on failure.
- */
-static struct weston_output *
-tdm_backend_output_create(struct weston_compositor *compositor, const char *name)
-{
- struct tdm_backend *b = to_tdm_backend(compositor);
- struct tdm_backend_output *output;
-
- output = zalloc(sizeof *output);
- if (output == NULL)
- return NULL;
-
- output->backend = b;
-
- weston_output_init(&output->base, compositor, name);
-
- output->base.enable = tdm_backend_output_enable;
- output->base.destroy = tdm_backend_output_destroy;
- output->base.disable = tdm_backend_output_disable;
- output->base.attach_head = tdm_backend_output_attach_head;
- output->base.detach_head = tdm_backend_output_detach_head;
-
- weston_compositor_add_pending_output(&output->base, b->compositor);
-
- return &output->base;
-}
-
-static int
-tdm_backend_create_heads(struct tdm_backend *b)
-{
- struct tdm_backend_head *head;
- tdm_error terror;
- int num_outputs;
- int i;
-
- terror = tdm_display_get_output_count(b->tdisplay, &num_outputs);
- if ((terror != TDM_ERROR_NONE) || (num_outputs < 1)) {
- weston_log("fail to get tdm_display_get_output_count\n");
- return -1;
- }
-
- for (i = 0; i < num_outputs; i++) {
- head = tdm_backend_head_create(b, i);
- if (!head)
- weston_log("TDM: failed to create head index:%d.\n", i);
- }
-
- return 0;
-}
-
-static void
-tdm_destroy(struct weston_compositor *ec)
-{
- struct tdm_backend *b = to_tdm_backend(ec);
- struct weston_head *base, *next;
-
- udev_input_destroy(&b->input);
-
- wl_event_source_remove(b->tdm_source);
-
- destroy_sprites(b);
-
- weston_compositor_log_scope_destroy(b->debug);
- b->debug = NULL;
- weston_compositor_shutdown(ec);
-
- wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
- tdm_backend_head_destroy(to_tdm_head(base));
-
- udev_unref(b->udev);
-
- weston_launcher_destroy(ec->launcher);
-
- tbm_dummy_display_destroy(b->tbm_display);
- tbm_bufmgr_deinit(b->tbufmgr);
- tdm_display_deinit(b->tdisplay);
-
- close(b->tdm_fd);
- free(b);
-}
-
-static void
-session_notify(struct wl_listener *listener, void *data)
-{
- struct weston_compositor *compositor = data;
- struct tdm_backend *b = to_tdm_backend(compositor);
-
- if (compositor->session_active) {
- weston_log("activating session\n");
- weston_compositor_wake(compositor);
- weston_compositor_damage_all(compositor);
- udev_input_enable(&b->input);
- } else {
- weston_log("deactivating session\n");
- udev_input_disable(&b->input);
-
- weston_compositor_offscreen(compositor);
-
- /* If we have a repaint scheduled (either from a
- * pending pageflip or the idle handler), make sure we
- * cancel that so we don't try to pageflip when we're
- * vt switched away. The OFFSCREEN state will prevent
- * further attempts at repainting. When we switch
- * back, we schedule a repaint, which will process
- * pending frame callbacks. */
-
- // unset all plane?
- }
-}
-
-static int
-init_pixman(struct tdm_backend *b)
-{
- return pixman_renderer_init(b->compositor);
-}
-
-static int
-tdm_backend_create_gl_renderer(struct tdm_backend *b)
-{
- if (gl_renderer->display_create(b->compositor,
- 0,
- b->tbm_display,
- EGL_WINDOW_BIT,
- NULL,
- 0) < 0)
- return -1;
-
- return 0;
-}
-
-static int
-init_egl(struct tdm_backend *b)
-{
- gl_renderer = weston_load_module("gl-renderer.so",
- "gl_renderer_interface");
- if (!gl_renderer)
- return -1;
-
- b->tbm_display = tbm_dummy_display_create();
- if (!b->tbm_display) {
- weston_log("Failed to tbm_dummy_display_create\n");
- return -1;
- }
-
- if (tdm_backend_create_gl_renderer(b) < 0) {
- tbm_dummy_display_destroy(b->tbm_display);
- return -1;
- }
-
- return 0;
-}
-
-static int
-on_tdm_input(int fd, uint32_t mask, void *data)
-{
- struct tdm_backend *b = data;
- tdm_error terror;
-
- terror = tdm_display_handle_events(b->tdisplay);
- if (terror != TDM_ERROR_NONE)
- weston_log("tdm_display_handle_events failed\n");
-
- return 1;
-}
-
-static int
-tdm_backend_output_set_mode(struct weston_output *base,
- enum weston_drm_backend_output_mode mode,
- const char *modeline)
-{
- struct tdm_backend_output *output = to_tdm_output(base);
- struct tdm_backend_head *head = tdm_backend_output_get_primary_head(output);
- struct tdm_backend_mode *backend_mode;
- tdm_error terror;
-
- if (!head) return -1;
-
- /* temporary use only preferred */
- wl_list_for_each(backend_mode, &head->mode_list, head_link) {
- if (backend_mode->tmode->type & TDM_OUTPUT_MODE_TYPE_PREFERRED) {
- output->base.current_mode = &backend_mode->base;
- output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
-
- output->base.native_mode = output->base.current_mode;
- output->base.native_scale = output->base.current_scale;
-
- wl_list_insert(output->base.mode_list.prev, &backend_mode->base.link);
- break;
- }
-
- }
-
- terror = tdm_output_set_mode(head->toutput, backend_mode->tmode);
- if (terror != TDM_ERROR_NONE) {
- weston_log("fail to set tmode.\n");
- return terror;
- }
-
- return 0;
-}
-
-static void
-tdm_backend_output_set_gbm_format(struct weston_output *base,
- const char *gbm_format)
-{
- /* not support */
-}
-
-static const struct weston_drm_output_api api = {
- tdm_backend_output_set_mode,
- tdm_backend_output_set_gbm_format,
- tdm_backend_output_set_seat,
-};
-
-static struct tdm_backend *
-tdm_backend_create(struct weston_compositor *compositor,
- struct weston_drm_backend_config *config)
-{
- struct tdm_backend *b;
- struct wl_event_loop *loop;
- const char *seat_id = default_seat;
- const char *session_seat;
- int ret;
- tdm_error terror;
- int tdm_fd;
-
- session_seat = getenv("XDG_SEAT");
- if (session_seat)
- seat_id = session_seat;
-
- if (config->seat_id)
- seat_id = config->seat_id;
-
- weston_log("initializing tdm backend\n");
-
- b = zalloc(sizeof *b);
- if (b == NULL)
- return NULL;
-
- b->compositor = compositor;
- b->use_pixman = config->use_pixman;
- b->pageflip_timeout = config->pageflip_timeout;
- b->use_pixman_shadow = config->use_pixman_shadow;
-
- b->debug = weston_compositor_add_log_scope(compositor->weston_log_ctx, "tdm-backend",
- "Debug messages from TDM backend\n",
- NULL, NULL, NULL);
-
- compositor->backend = &b->base;
-
- /* Check if we run tdm-backend using weston-launch */
- compositor->launcher = weston_launcher_connect(compositor, config->tty,
- seat_id, true);
- if (compositor->launcher == NULL) {
- weston_log("fatal: tdm backend should be run using "
- "weston-launch binary, or your system should "
- "provide the logind D-Bus API.\n");
- goto err_compositor;
- }
-
- b->udev = udev_new();
- if (b->udev == NULL) {
- weston_log("failed to initialize udev context\n");
- goto err_launcher;
- }
-
- b->session_listener.notify = session_notify;
- wl_signal_add(&compositor->session_signal, &b->session_listener);
-
- b->tbufmgr = tbm_bufmgr_server_init();
- if (!b->tbufmgr) {
- weston_log("failed to initialize tbm_bufmgr\n");
- goto err_udev;
- }
-
- b->tdisplay = tdm_display_init(&terror);
- if (!b->tdisplay) {
- weston_log("failed to initialize tdm_display\n");
- goto err_tbm;
- }
-
- if (b->use_pixman) {
- if (init_pixman(b) < 0) {
- weston_log("failed to initialize pixman renderer\n");
- goto err_tdm;
- }
- }
- else {
- if (init_egl(b) < 0) {
- weston_log("failed to initialize egl\n");
- goto err_tdm;
- }
- }
-
- if (tdm_backend_create_heads(b) < 0) {
- weston_log("Failed to create heads for\n");
- goto err_tdm;
- }
-
- b->base.destroy = tdm_destroy;
- b->base.repaint_begin = tdm_repaint_begin;
- b->base.repaint_flush = tdm_repaint_flush;
- b->base.repaint_cancel = tdm_repaint_cancel;
- b->base.create_output = tdm_backend_output_create;
- b->base.device_changed = NULL;
- b->base.can_scanout_dmabuf = NULL;
-
- weston_setup_vt_switch_bindings(compositor);
-
- wl_list_init(&b->plane_list);
- create_sprites(b);
-
- if (udev_input_init(&b->input,
- compositor, b->udev, seat_id,
- config->configure_device) < 0) {
- weston_log("failed to create input devices\n");
- goto err_tdm;
- }
-
- tdm_display_get_fd(b->tdisplay, &tdm_fd);
- b->tdm_fd = dup(tdm_fd);
-
- loop = wl_display_get_event_loop(compositor->wl_display);
- b->tdm_source =
- wl_event_loop_add_fd(loop, b->tdm_fd,
- WL_EVENT_READABLE, on_tdm_input, b);
-
- if (compositor->renderer->import_dmabuf) {
- if (linux_dmabuf_setup(compositor) < 0)
- weston_log("Error: initializing dmabuf "
- "support failed.\n");
- }
-
- ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
- &api, sizeof(api));
-
- if (ret < 0) {
- weston_log("Failed to register output API.\n");
- goto err_tdm_source;
- }
-
- return b;
-
-err_tdm_source:
- wl_event_source_remove(b->tdm_source);
- udev_input_destroy(&b->input);
-err_tdm:
- tdm_display_deinit(b->tdisplay);
-err_tbm:
- tbm_bufmgr_deinit(b->tbufmgr);
-err_udev:
- udev_unref(b->udev);
-err_launcher:
- weston_launcher_destroy(compositor->launcher);
-err_compositor:
- weston_compositor_shutdown(compositor);
- free(b);
- return NULL;
-}
-
-static void
-config_init_to_defaults(struct weston_drm_backend_config *config)
-{
- config->use_pixman_shadow = true;
-}
-
-WL_EXPORT int
-weston_backend_init(struct weston_compositor *compositor,
- struct weston_backend_config *config_base)
-{
- struct tdm_backend *b;
- struct weston_drm_backend_config config = {{ 0, }};
-
- if (config_base == NULL ||
- config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
- config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
- weston_log("tdm backend config structure is invalid\n");
- return -1;
- }
-
- config_init_to_defaults(&config);
- memcpy(&config, config_base, config_base->struct_size);
-
- b = tdm_backend_create(compositor, &config);
- if (b == NULL)
- return -1;
-
- return 0;
-}
diff --git a/libweston/backend-wayland/meson.build b/libweston/backend-wayland/meson.build
deleted file mode 100644
index 7e82513a..00000000
--- a/libweston/backend-wayland/meson.build
+++ /dev/null
@@ -1,44 +0,0 @@
-if not get_option('backend-wayland')
- subdir_done()
-endif
-
-config_h.set('BUILD_WAYLAND_COMPOSITOR', '1')
-
-srcs_wlwl = [
- 'wayland.c',
- fullscreen_shell_unstable_v1_client_protocol_h,
- fullscreen_shell_unstable_v1_protocol_c,
- presentation_time_protocol_c,
- presentation_time_server_protocol_h,
- xdg_shell_server_protocol_h,
- xdg_shell_protocol_c,
-]
-
-deps_wlwl = [
- dependency('wayland-client'),
- dependency('wayland-cursor'),
- dep_pixman,
- dep_libweston_private,
- dep_libdrm_headers,
- dep_lib_cairo_shared,
-]
-
-if get_option('renderer-gl')
- d = dependency('wayland-egl', required: false)
- if not d.found()
- error('wayland-backend + gl-renderer requires wayland-egl which was not found. Or, you can use \'-Dbackend-wayland=false\' or \'-Drenderer-gl=false\'.')
- endif
- deps_wlwl += d
-endif
-
-plugin_wlwl = shared_library(
- 'wayland-backend',
- srcs_wlwl,
- include_directories: common_inc,
- dependencies: deps_wlwl,
- name_prefix: '',
- install: true,
- install_dir: dir_module_libweston
-)
-env_modmap += 'wayland-backend.so=@0@;'.format(plugin_wlwl.full_path())
-install_headers(backend_wayland_h, subdir: dir_include_libweston_install)
diff --git a/libweston/backend-wayland/wayland.c b/libweston/backend-wayland/wayland.c
deleted file mode 100644
index 42af0c80..00000000
--- a/libweston/backend-wayland/wayland.c
+++ /dev/null
@@ -1,2906 +0,0 @@
-/*
- * Copyright © 2010-2011 Benjamin Franzke
- * Copyright © 2013 Jason Ekstrand
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/mman.h>
-#include <linux/input.h>
-
-#include <drm_fourcc.h>
-#include <wayland-client.h>
-#include <wayland-cursor.h>
-
-#ifdef ENABLE_EGL
-#include <wayland-egl.h>
-#endif
-
-#include <libweston/libweston.h>
-#include <libweston/backend-wayland.h>
-#include "renderer-gl/gl-renderer.h"
-#include "shared/weston-egl-ext.h"
-#include "pixman-renderer.h"
-#include "shared/helpers.h"
-#include "shared/image-loader.h"
-#include "shared/os-compatibility.h"
-#include "shared/cairo-util.h"
-#include "shared/timespec-util.h"
-#include "fullscreen-shell-unstable-v1-client-protocol.h"
-#include "xdg-shell-client-protocol.h"
-#include "presentation-time-server-protocol.h"
-#include "linux-dmabuf.h"
-#include <libweston/windowed-output-api.h>
-
-#define WINDOW_TITLE "Weston Compositor"
-
-static const uint32_t wayland_formats[] = {
- DRM_FORMAT_ARGB8888,
-};
-
-struct wayland_backend {
- struct weston_backend base;
- struct weston_compositor *compositor;
-
- struct {
- struct wl_display *wl_display;
- struct wl_registry *registry;
- struct wl_compositor *compositor;
- struct wl_shell *shell;
- struct xdg_wm_base *xdg_wm_base;
- struct zwp_fullscreen_shell_v1 *fshell;
- struct wl_shm *shm;
-
- struct wl_list output_list;
-
- struct wl_event_source *wl_source;
- uint32_t event_mask;
- } parent;
-
- bool use_pixman;
- bool sprawl_across_outputs;
- bool fullscreen;
-
- struct theme *theme;
- cairo_device_t *frame_device;
- struct wl_cursor_theme *cursor_theme;
- struct wl_cursor *cursor;
-
- struct wl_list input_list;
-};
-
-struct wayland_output {
- struct weston_output base;
-
- struct {
- bool draw_initial_frame;
- struct wl_surface *surface;
-
- struct wl_output *output;
- uint32_t global_id;
-
- struct wl_shell_surface *shell_surface;
- struct xdg_surface *xdg_surface;
- struct xdg_toplevel *xdg_toplevel;
- int configure_width, configure_height;
- bool wait_for_configure;
- } parent;
-
- int keyboard_count;
-
- char *title;
- struct frame *frame;
-
- struct {
- struct wl_egl_window *egl_window;
- struct {
- cairo_surface_t *top;
- cairo_surface_t *left;
- cairo_surface_t *right;
- cairo_surface_t *bottom;
- } border;
- } gl;
-
- struct {
- struct wl_list buffers;
- struct wl_list free_buffers;
- } shm;
-
- struct weston_mode mode;
-
- struct wl_callback *frame_cb;
-};
-
-struct wayland_parent_output {
- struct wayland_backend *backend; /**< convenience */
- struct wayland_head *head;
- struct wl_list link;
-
- struct wl_output *global;
- uint32_t id;
-
- struct {
- char *make;
- char *model;
- int32_t width, height;
- uint32_t subpixel;
- } physical;
-
- int32_t x, y;
- uint32_t transform;
- uint32_t scale;
-
- struct wl_callback *sync_cb; /**< wl_output < 2 done replacement */
-
- struct wl_list mode_list;
- struct weston_mode *preferred_mode;
- struct weston_mode *current_mode;
-};
-
-struct wayland_head {
- struct weston_head base;
- struct wayland_parent_output *parent_output;
-};
-
-struct wayland_shm_buffer {
- struct wayland_output *output;
- struct wl_list link;
- struct wl_list free_link;
-
- struct wl_buffer *buffer;
- void *data;
- size_t size;
- pixman_region32_t damage; /**< in global coords */
- int frame_damaged;
-
- pixman_image_t *pm_image;
- cairo_surface_t *c_surface;
-};
-
-struct wayland_input {
- struct weston_seat base;
- struct wayland_backend *backend;
- struct wl_list link;
-
- struct {
- struct wl_seat *seat;
- struct wl_pointer *pointer;
- struct wl_keyboard *keyboard;
- struct wl_touch *touch;
-
- struct {
- struct wl_surface *surface;
- int32_t hx, hy;
- } cursor;
- } parent;
-
- struct weston_touch_device *touch_device;
-
- enum weston_key_state_update keyboard_state_update;
- uint32_t key_serial;
- uint32_t enter_serial;
- uint32_t touch_points;
- bool touch_active;
- bool has_focus;
- int seat_version;
-
- struct wayland_output *output;
- struct wayland_output *touch_focus;
- struct wayland_output *keyboard_focus;
-
- struct weston_pointer_axis_event vert, horiz;
-};
-
-struct gl_renderer_interface *gl_renderer;
-
-static inline struct wayland_head *
-to_wayland_head(struct weston_head *base)
-{
- return container_of(base, struct wayland_head, base);
-}
-
-static inline struct wayland_output *
-to_wayland_output(struct weston_output *base)
-{
- return container_of(base, struct wayland_output, base);
-}
-
-static inline struct wayland_backend *
-to_wayland_backend(struct weston_compositor *base)
-{
- return container_of(base->backend, struct wayland_backend, base);
-}
-
-static void
-wayland_shm_buffer_destroy(struct wayland_shm_buffer *buffer)
-{
- cairo_surface_destroy(buffer->c_surface);
- pixman_image_unref(buffer->pm_image);
-
- wl_buffer_destroy(buffer->buffer);
- munmap(buffer->data, buffer->size);
-
- pixman_region32_fini(&buffer->damage);
-
- wl_list_remove(&buffer->link);
- wl_list_remove(&buffer->free_link);
- free(buffer);
-}
-
-static void
-buffer_release(void *data, struct wl_buffer *buffer)
-{
- struct wayland_shm_buffer *sb = data;
-
- if (sb->output) {
- wl_list_insert(&sb->output->shm.free_buffers, &sb->free_link);
- } else {
- wayland_shm_buffer_destroy(sb);
- }
-}
-
-static const struct wl_buffer_listener buffer_listener = {
- buffer_release
-};
-
-static struct wayland_shm_buffer *
-wayland_output_get_shm_buffer(struct wayland_output *output)
-{
- struct wayland_backend *b =
- to_wayland_backend(output->base.compositor);
- struct wl_shm *shm = b->parent.shm;
- struct wayland_shm_buffer *sb;
-
- struct wl_shm_pool *pool;
- int width, height, stride;
- int32_t fx, fy;
- int fd;
- unsigned char *data;
-
- if (!wl_list_empty(&output->shm.free_buffers)) {
- sb = container_of(output->shm.free_buffers.next,
- struct wayland_shm_buffer, free_link);
- wl_list_remove(&sb->free_link);
- wl_list_init(&sb->free_link);
-
- return sb;
- }
-
- if (output->frame) {
- width = frame_width(output->frame);
- height = frame_height(output->frame);
- } else {
- width = output->base.current_mode->width;
- height = output->base.current_mode->height;
- }
-
- stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
-
- fd = os_create_anonymous_file(height * stride);
- if (fd < 0) {
- weston_log("could not create an anonymous file buffer: %s\n",
- strerror(errno));
- return NULL;
- }
-
- data = mmap(NULL, height * stride, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if (data == MAP_FAILED) {
- weston_log("could not mmap %d memory for data: %s\n", height * stride,
- strerror(errno));
- close(fd);
- return NULL;
- }
-
- sb = zalloc(sizeof *sb);
- if (sb == NULL) {
- weston_log("could not zalloc %zu memory for sb: %s\n", sizeof *sb,
- strerror(errno));
- close(fd);
- munmap(data, height * stride);
- return NULL;
- }
-
- sb->output = output;
- wl_list_init(&sb->free_link);
- wl_list_insert(&output->shm.buffers, &sb->link);
-
- pixman_region32_init(&sb->damage);
- pixman_region32_copy(&sb->damage, &output->base.region);
- sb->frame_damaged = 1;
-
- sb->data = data;
- sb->size = height * stride;
-
- pool = wl_shm_create_pool(shm, fd, sb->size);
-
- sb->buffer = wl_shm_pool_create_buffer(pool, 0,
- width, height,
- stride,
- WL_SHM_FORMAT_ARGB8888);
- wl_buffer_add_listener(sb->buffer, &buffer_listener, sb);
- wl_shm_pool_destroy(pool);
- close(fd);
-
- memset(data, 0, sb->size);
-
- sb->c_surface =
- cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32,
- width, height, stride);
-
- fx = 0;
- fy = 0;
- if (output->frame)
- frame_interior(output->frame, &fx, &fy, 0, 0);
- sb->pm_image =
- pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height,
- (uint32_t *)(data + fy * stride) + fx,
- stride);
-
- return sb;
-}
-
-static void
-frame_done(void *data, struct wl_callback *callback, uint32_t time)
-{
- struct wayland_output *output = data;
- struct timespec ts;
-
- assert(callback == output->frame_cb);
- wl_callback_destroy(callback);
- output->frame_cb = NULL;
-
- /* XXX: use the presentation extension for proper timings */
-
- /*
- * This is the fallback case, where Presentation extension is not
- * available from the parent compositor. We do not know the base for
- * 'time', so we cannot feed it to finish_frame(). Do the only thing
- * we can, and pretend finish_frame time is when we process this
- * event.
- */
- weston_compositor_read_presentation_clock(output->base.compositor, &ts);
- weston_output_finish_frame(&output->base, &ts, 0);
-}
-
-static const struct wl_callback_listener frame_listener = {
- frame_done
-};
-
-static void
-draw_initial_frame(struct wayland_output *output)
-{
- struct wayland_shm_buffer *sb;
-
- sb = wayland_output_get_shm_buffer(output);
-
- /* If we are rendering with GL, then orphan it so that it gets
- * destroyed immediately */
- if (output->gl.egl_window)
- sb->output = NULL;
-
- wl_surface_attach(output->parent.surface, sb->buffer, 0, 0);
- wl_surface_damage(output->parent.surface, 0, 0,
- output->base.current_mode->width,
- output->base.current_mode->height);
-}
-
-#ifdef ENABLE_EGL
-static void
-wayland_output_update_gl_border(struct wayland_output *output)
-{
- int32_t ix, iy, iwidth, iheight, fwidth, fheight;
- cairo_t *cr;
-
- if (!output->frame)
- return;
- if (!(frame_status(output->frame) & FRAME_STATUS_REPAINT))
- return;
-
- fwidth = frame_width(output->frame);
- fheight = frame_height(output->frame);
- frame_interior(output->frame, &ix, &iy, &iwidth, &iheight);
-
- if (!output->gl.border.top)
- output->gl.border.top =
- cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
- fwidth, iy);
- cr = cairo_create(output->gl.border.top);
- frame_repaint(output->frame, cr);
- cairo_destroy(cr);
- gl_renderer->output_set_border(&output->base, GL_RENDERER_BORDER_TOP,
- fwidth, iy,
- cairo_image_surface_get_stride(output->gl.border.top) / 4,
- cairo_image_surface_get_data(output->gl.border.top));
-
-
- if (!output->gl.border.left)
- output->gl.border.left =
- cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
- ix, 1);
- cr = cairo_create(output->gl.border.left);
- cairo_translate(cr, 0, -iy);
- frame_repaint(output->frame, cr);
- cairo_destroy(cr);
- gl_renderer->output_set_border(&output->base, GL_RENDERER_BORDER_LEFT,
- ix, 1,
- cairo_image_surface_get_stride(output->gl.border.left) / 4,
- cairo_image_surface_get_data(output->gl.border.left));
-
-
- if (!output->gl.border.right)
- output->gl.border.right =
- cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
- fwidth - (ix + iwidth), 1);
- cr = cairo_create(output->gl.border.right);
- cairo_translate(cr, -(iwidth + ix), -iy);
- frame_repaint(output->frame, cr);
- cairo_destroy(cr);
- gl_renderer->output_set_border(&output->base, GL_RENDERER_BORDER_RIGHT,
- fwidth - (ix + iwidth), 1,
- cairo_image_surface_get_stride(output->gl.border.right) / 4,
- cairo_image_surface_get_data(output->gl.border.right));
-
-
- if (!output->gl.border.bottom)
- output->gl.border.bottom =
- cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
- fwidth, fheight - (iy + iheight));
- cr = cairo_create(output->gl.border.bottom);
- cairo_translate(cr, 0, -(iy + iheight));
- frame_repaint(output->frame, cr);
- cairo_destroy(cr);
- gl_renderer->output_set_border(&output->base, GL_RENDERER_BORDER_BOTTOM,
- fwidth, fheight - (iy + iheight),
- cairo_image_surface_get_stride(output->gl.border.bottom) / 4,
- cairo_image_surface_get_data(output->gl.border.bottom));
-}
-#endif
-
-static int
-wayland_output_start_repaint_loop(struct weston_output *output_base)
-{
- struct wayland_output *output = to_wayland_output(output_base);
- struct wayland_backend *wb =
- to_wayland_backend(output->base.compositor);
-
- /* If this is the initial frame, we need to attach a buffer so that
- * the compositor can map the surface and include it in its render
- * loop. If the surface doesn't end up in the render loop, the frame
- * callback won't be invoked. The buffer is transparent and of the
- * same size as the future real output buffer. */
- if (output->parent.draw_initial_frame) {
- output->parent.draw_initial_frame = false;
-
- draw_initial_frame(output);
- }
-
- output->frame_cb = wl_surface_frame(output->parent.surface);
- wl_callback_add_listener(output->frame_cb, &frame_listener, output);
- wl_surface_commit(output->parent.surface);
- wl_display_flush(wb->parent.wl_display);
-
- return 0;
-}
-
-#ifdef ENABLE_EGL
-static int
-wayland_output_repaint_gl(struct weston_output *output_base,
- pixman_region32_t *damage,
- void *repaint_data)
-{
- struct wayland_output *output = to_wayland_output(output_base);
- struct weston_compositor *ec = output->base.compositor;
-
- output->frame_cb = wl_surface_frame(output->parent.surface);
- wl_callback_add_listener(output->frame_cb, &frame_listener, output);
-
- wayland_output_update_gl_border(output);
-
- ec->renderer->repaint_output(&output->base, damage);
-
- pixman_region32_subtract(&ec->primary_plane.damage,
- &ec->primary_plane.damage, damage);
- return 0;
-}
-#endif
-
-static void
-wayland_output_update_shm_border(struct wayland_shm_buffer *buffer)
-{
- int32_t ix, iy, iwidth, iheight, fwidth, fheight;
- cairo_t *cr;
-
- if (!buffer->output->frame || !buffer->frame_damaged)
- return;
-
- cr = cairo_create(buffer->c_surface);
-
- frame_interior(buffer->output->frame, &ix, &iy, &iwidth, &iheight);
- fwidth = frame_width(buffer->output->frame);
- fheight = frame_height(buffer->output->frame);
-
- /* Set the clip so we don't unnecisaraly damage the surface */
- cairo_move_to(cr, ix, iy);
- cairo_rel_line_to(cr, iwidth, 0);
- cairo_rel_line_to(cr, 0, iheight);
- cairo_rel_line_to(cr, -iwidth, 0);
- cairo_line_to(cr, ix, iy);
- cairo_line_to(cr, 0, iy);
- cairo_line_to(cr, 0, fheight);
- cairo_line_to(cr, fwidth, fheight);
- cairo_line_to(cr, fwidth, 0);
- cairo_line_to(cr, 0, 0);
- cairo_line_to(cr, 0, iy);
- cairo_close_path(cr);
- cairo_clip(cr);
-
- /* Draw using a pattern so that the final result gets clipped */
- cairo_push_group(cr);
- frame_repaint(buffer->output->frame, cr);
- cairo_pop_group_to_source(cr);
- cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
- cairo_paint(cr);
-
- cairo_destroy(cr);
-}
-
-static void
-wayland_shm_buffer_attach(struct wayland_shm_buffer *sb)
-{
- pixman_region32_t damage;
- pixman_box32_t *rects;
- int32_t ix, iy, iwidth, iheight, fwidth, fheight;
- int i, n;
-
- pixman_region32_init(&damage);
- pixman_region32_copy(&damage, &sb->damage);
- pixman_region32_translate(&damage, -sb->output->base.x,
- -sb->output->base.y);
-
- weston_transformed_region(sb->output->base.width,
- sb->output->base.height,
- sb->output->base.transform,
- sb->output->base.current_scale,
- &damage, &damage);
-
- if (sb->output->frame) {
- frame_interior(sb->output->frame, &ix, &iy, &iwidth, &iheight);
- fwidth = frame_width(sb->output->frame);
- fheight = frame_height(sb->output->frame);
-
- pixman_region32_translate(&damage, ix, iy);
-
- if (sb->frame_damaged) {
- pixman_region32_union_rect(&damage, &damage,
- 0, 0, fwidth, iy);
- pixman_region32_union_rect(&damage, &damage,
- 0, iy, ix, iheight);
- pixman_region32_union_rect(&damage, &damage,
- ix + iwidth, iy,
- fwidth - (ix + iwidth), iheight);
- pixman_region32_union_rect(&damage, &damage,
- 0, iy + iheight,
- fwidth, fheight - (iy + iheight));
- }
- }
-
- rects = pixman_region32_rectangles(&damage, &n);
- wl_surface_attach(sb->output->parent.surface, sb->buffer, 0, 0);
- for (i = 0; i < n; ++i)
- wl_surface_damage(sb->output->parent.surface, rects[i].x1,
- rects[i].y1, rects[i].x2 - rects[i].x1,
- rects[i].y2 - rects[i].y1);
-
- if (sb->output->frame)
- pixman_region32_fini(&damage);
-}
-
-static int
-wayland_output_repaint_pixman(struct weston_output *output_base,
- pixman_region32_t *damage,
- void *repaint_data)
-{
- struct wayland_output *output = to_wayland_output(output_base);
- struct wayland_backend *b =
- to_wayland_backend(output->base.compositor);
- struct wayland_shm_buffer *sb;
-
- if (output->frame) {
- if (frame_status(output->frame) & FRAME_STATUS_REPAINT)
- wl_list_for_each(sb, &output->shm.buffers, link)
- sb->frame_damaged = 1;
- }
-
- wl_list_for_each(sb, &output->shm.buffers, link)
- pixman_region32_union(&sb->damage, &sb->damage, damage);
-
- sb = wayland_output_get_shm_buffer(output);
-
- wayland_output_update_shm_border(sb);
- pixman_renderer_output_set_buffer(output_base, sb->pm_image);
- b->compositor->renderer->repaint_output(output_base, &sb->damage);
-
- wayland_shm_buffer_attach(sb);
-
- output->frame_cb = wl_surface_frame(output->parent.surface);
- wl_callback_add_listener(output->frame_cb, &frame_listener, output);
- wl_surface_commit(output->parent.surface);
- wl_display_flush(b->parent.wl_display);
-
- pixman_region32_fini(&sb->damage);
- pixman_region32_init(&sb->damage);
- sb->frame_damaged = 0;
-
- pixman_region32_subtract(&b->compositor->primary_plane.damage,
- &b->compositor->primary_plane.damage, damage);
- return 0;
-}
-
-static void
-wayland_backend_destroy_output_surface(struct wayland_output *output)
-{
- assert(output->parent.surface);
-
- if (output->parent.xdg_toplevel) {
- xdg_toplevel_destroy(output->parent.xdg_toplevel);
- output->parent.xdg_toplevel = NULL;
- }
-
- if (output->parent.xdg_surface) {
- xdg_surface_destroy(output->parent.xdg_surface);
- output->parent.xdg_surface = NULL;
- }
-
- if (output->parent.shell_surface) {
- wl_shell_surface_destroy(output->parent.shell_surface);
- output->parent.shell_surface = NULL;
- }
-
- wl_surface_destroy(output->parent.surface);
- output->parent.surface = NULL;
-}
-
-static void
-wayland_output_destroy_shm_buffers(struct wayland_output *output)
-{
- struct wayland_shm_buffer *buffer, *next;
-
- /* Throw away any remaining SHM buffers */
- wl_list_for_each_safe(buffer, next, &output->shm.free_buffers, free_link)
- wayland_shm_buffer_destroy(buffer);
- /* These will get thrown away when they get released */
- wl_list_for_each(buffer, &output->shm.buffers, link)
- buffer->output = NULL;
-}
-
-static int
-wayland_output_disable(struct weston_output *base)
-{
- struct wayland_output *output = to_wayland_output(base);
- struct wayland_backend *b = to_wayland_backend(base->compositor);
-
- if (!output->base.enabled)
- return 0;
-
- if (b->use_pixman) {
- pixman_renderer_output_destroy(&output->base);
-#ifdef ENABLE_EGL
- } else {
- gl_renderer->output_destroy(&output->base);
- wl_egl_window_destroy(output->gl.egl_window);
-#endif
- }
-
- wayland_output_destroy_shm_buffers(output);
-
- wayland_backend_destroy_output_surface(output);
-
- if (output->frame)
- frame_destroy(output->frame);
-
- cairo_surface_destroy(output->gl.border.top);
- cairo_surface_destroy(output->gl.border.left);
- cairo_surface_destroy(output->gl.border.right);
- cairo_surface_destroy(output->gl.border.bottom);
-
- return 0;
-}
-
-static void
-wayland_output_destroy(struct weston_output *base)
-{
- struct wayland_output *output = to_wayland_output(base);
-
- wayland_output_disable(&output->base);
-
- weston_output_release(&output->base);
-
- if (output->frame_cb)
- wl_callback_destroy(output->frame_cb);
-
- free(output->title);
- free(output);
-}
-
-static const struct wl_shell_surface_listener shell_surface_listener;
-
-#ifdef ENABLE_EGL
-static int
-wayland_output_init_gl_renderer(struct wayland_output *output)
-{
- int32_t fwidth = 0, fheight = 0;
-
- if (output->frame) {
- fwidth = frame_width(output->frame);
- fheight = frame_height(output->frame);
- } else {
- fwidth = output->base.current_mode->width;
- fheight = output->base.current_mode->height;
- }
-
- output->gl.egl_window =
- wl_egl_window_create(output->parent.surface,
- fwidth, fheight);
- if (!output->gl.egl_window) {
- weston_log("failure to create wl_egl_window\n");
- return -1;
- }
-
- if (gl_renderer->output_window_create(&output->base,
- output->gl.egl_window,
- output->gl.egl_window,
- wayland_formats,
- ARRAY_LENGTH(wayland_formats)) < 0)
- goto cleanup_window;
-
- return 0;
-
-cleanup_window:
- wl_egl_window_destroy(output->gl.egl_window);
- return -1;
-}
-#endif
-
-static int
-wayland_output_init_pixman_renderer(struct wayland_output *output)
-{
- return pixman_renderer_output_create(&output->base,
- PIXMAN_RENDERER_OUTPUT_USE_SHADOW);
-}
-
-static void
-wayland_output_resize_surface(struct wayland_output *output)
-{
- struct wayland_backend *b =
- to_wayland_backend(output->base.compositor);
- int32_t ix, iy, iwidth, iheight;
- int32_t width, height;
- struct wl_region *region;
-
- width = output->base.current_mode->width;
- height = output->base.current_mode->height;
-
- if (output->frame) {
- frame_resize_inside(output->frame, width, height);
-
- frame_input_rect(output->frame, &ix, &iy, &iwidth, &iheight);
- region = wl_compositor_create_region(b->parent.compositor);
- wl_region_add(region, ix, iy, iwidth, iheight);
- wl_surface_set_input_region(output->parent.surface, region);
- wl_region_destroy(region);
-
- if (output->parent.xdg_surface) {
- xdg_surface_set_window_geometry(output->parent.xdg_surface,
- ix,
- iy,
- iwidth,
- iheight);
- }
-
- frame_opaque_rect(output->frame, &ix, &iy, &iwidth, &iheight);
- region = wl_compositor_create_region(b->parent.compositor);
- wl_region_add(region, ix, iy, iwidth, iheight);
- wl_surface_set_opaque_region(output->parent.surface, region);
- wl_region_destroy(region);
-
- width = frame_width(output->frame);
- height = frame_height(output->frame);
- } else {
- region = wl_compositor_create_region(b->parent.compositor);
- wl_region_add(region, 0, 0, width, height);
- wl_surface_set_input_region(output->parent.surface, region);
- wl_region_destroy(region);
-
- region = wl_compositor_create_region(b->parent.compositor);
- wl_region_add(region, 0, 0, width, height);
- wl_surface_set_opaque_region(output->parent.surface, region);
- wl_region_destroy(region);
-
- if (output->parent.xdg_surface) {
- xdg_surface_set_window_geometry(output->parent.xdg_surface,
- 0,
- 0,
- width,
- height);
- }
- }
-
-#ifdef ENABLE_EGL
- if (output->gl.egl_window) {
- wl_egl_window_resize(output->gl.egl_window,
- width, height, 0, 0);
-
- /* These will need to be re-created due to the resize */
- gl_renderer->output_set_border(&output->base,
- GL_RENDERER_BORDER_TOP,
- 0, 0, 0, NULL);
- cairo_surface_destroy(output->gl.border.top);
- output->gl.border.top = NULL;
- gl_renderer->output_set_border(&output->base,
- GL_RENDERER_BORDER_LEFT,
- 0, 0, 0, NULL);
- cairo_surface_destroy(output->gl.border.left);
- output->gl.border.left = NULL;
- gl_renderer->output_set_border(&output->base,
- GL_RENDERER_BORDER_RIGHT,
- 0, 0, 0, NULL);
- cairo_surface_destroy(output->gl.border.right);
- output->gl.border.right = NULL;
- gl_renderer->output_set_border(&output->base,
- GL_RENDERER_BORDER_BOTTOM,
- 0, 0, 0, NULL);
- cairo_surface_destroy(output->gl.border.bottom);
- output->gl.border.bottom = NULL;
- }
-#endif
-
- wayland_output_destroy_shm_buffers(output);
-}
-
-static int
-wayland_output_set_windowed(struct wayland_output *output)
-{
- struct wayland_backend *b =
- to_wayland_backend(output->base.compositor);
-
- if (output->frame)
- return 0;
-
- if (!b->theme) {
- b->theme = theme_create();
- if (!b->theme)
- return -1;
- }
- output->frame = frame_create(b->theme, 100, 100,
- FRAME_BUTTON_CLOSE, output->title, NULL);
- if (!output->frame)
- return -1;
-
- if (output->keyboard_count)
- frame_set_flag(output->frame, FRAME_FLAG_ACTIVE);
-
- wayland_output_resize_surface(output);
-
- if (output->parent.xdg_toplevel) {
- xdg_toplevel_unset_fullscreen(output->parent.xdg_toplevel);
- } else if (output->parent.shell_surface) {
- wl_shell_surface_set_toplevel(output->parent.shell_surface);
- } else {
- abort();
- }
-
- return 0;
-}
-
-static void
-wayland_output_set_fullscreen(struct wayland_output *output,
- enum wl_shell_surface_fullscreen_method method,
- uint32_t framerate, struct wl_output *target)
-{
- if (output->frame) {
- frame_destroy(output->frame);
- output->frame = NULL;
- }
-
- wayland_output_resize_surface(output);
-
- if (output->parent.xdg_toplevel) {
- xdg_toplevel_set_fullscreen(output->parent.xdg_toplevel, target);
- } else if (output->parent.shell_surface) {
- wl_shell_surface_set_fullscreen(output->parent.shell_surface,
- method, framerate, target);
- } else {
- abort();
- }
-}
-
-static struct weston_mode *
-wayland_output_choose_mode(struct wayland_output *output,
- struct weston_mode *ref_mode)
-{
- struct weston_mode *mode;
-
- /* First look for an exact match */
- wl_list_for_each(mode, &output->base.mode_list, link)
- if (mode->width == ref_mode->width &&
- mode->height == ref_mode->height &&
- mode->refresh == ref_mode->refresh)
- return mode;
-
- /* If we can't find an exact match, ignore refresh and try again */
- wl_list_for_each(mode, &output->base.mode_list, link)
- if (mode->width == ref_mode->width &&
- mode->height == ref_mode->height)
- return mode;
-
- /* Yeah, we failed */
- return NULL;
-}
-
-enum mode_status {
- MODE_STATUS_UNKNOWN,
- MODE_STATUS_SUCCESS,
- MODE_STATUS_FAIL,
- MODE_STATUS_CANCEL,
-};
-
-static void
-mode_feedback_successful(void *data,
- struct zwp_fullscreen_shell_mode_feedback_v1 *fb)
-{
- enum mode_status *value = data;
-
- printf("Mode switch successful\n");
-
- *value = MODE_STATUS_SUCCESS;
-}
-
-static void
-mode_feedback_failed(void *data, struct zwp_fullscreen_shell_mode_feedback_v1 *fb)
-{
- enum mode_status *value = data;
-
- printf("Mode switch failed\n");
-
- *value = MODE_STATUS_FAIL;
-}
-
-static void
-mode_feedback_cancelled(void *data, struct zwp_fullscreen_shell_mode_feedback_v1 *fb)
-{
- enum mode_status *value = data;
-
- printf("Mode switch cancelled\n");
-
- *value = MODE_STATUS_CANCEL;
-}
-
-struct zwp_fullscreen_shell_mode_feedback_v1_listener mode_feedback_listener = {
- mode_feedback_successful,
- mode_feedback_failed,
- mode_feedback_cancelled,
-};
-
-static enum mode_status
-wayland_output_fullscreen_shell_mode_feedback(struct wayland_output *output,
- struct weston_mode *mode)
-{
- struct wayland_backend *b = to_wayland_backend(output->base.compositor);
- struct zwp_fullscreen_shell_mode_feedback_v1 *mode_feedback;
- enum mode_status mode_status;
- int ret = 0;
-
- mode_feedback =
- zwp_fullscreen_shell_v1_present_surface_for_mode(b->parent.fshell,
- output->parent.surface,
- output->parent.output,
- mode->refresh);
-
- zwp_fullscreen_shell_mode_feedback_v1_add_listener(mode_feedback,
- &mode_feedback_listener,
- &mode_status);
-
- output->parent.draw_initial_frame = false;
- draw_initial_frame(output);
- wl_surface_commit(output->parent.surface);
-
- mode_status = MODE_STATUS_UNKNOWN;
- while (mode_status == MODE_STATUS_UNKNOWN && ret >= 0)
- ret = wl_display_dispatch(b->parent.wl_display);
-
- zwp_fullscreen_shell_mode_feedback_v1_destroy(mode_feedback);
-
- return mode_status;
-}
-
-static int
-wayland_output_switch_mode(struct weston_output *output_base,
- struct weston_mode *mode)
-{
- struct wayland_output *output = to_wayland_output(output_base);
- struct wayland_backend *b;
- struct wl_surface *old_surface;
- struct weston_mode *old_mode;
- enum mode_status mode_status;
-
- if (output_base == NULL) {
- weston_log("output is NULL.\n");
- return -1;
- }
-
- if (mode == NULL) {
- weston_log("mode is NULL.\n");
- return -1;
- }
-
- b = to_wayland_backend(output_base->compositor);
-
- if (output->parent.xdg_surface || output->parent.shell_surface || !b->parent.fshell)
- return -1;
-
- mode = wayland_output_choose_mode(output, mode);
- if (mode == NULL)
- return -1;
-
- if (output->base.current_mode == mode)
- return 0;
-
- old_mode = output->base.current_mode;
- old_surface = output->parent.surface;
- output->base.current_mode = mode;
- output->parent.surface =
- wl_compositor_create_surface(b->parent.compositor);
- wl_surface_set_user_data(output->parent.surface, output);
-
- /* Blow the old buffers because we changed size/surfaces */
- wayland_output_resize_surface(output);
-
- mode_status = wayland_output_fullscreen_shell_mode_feedback(output, mode);
-
- /* This should kick-start things again */
- wayland_output_start_repaint_loop(&output->base);
-
- if (mode_status == MODE_STATUS_FAIL) {
- output->base.current_mode = old_mode;
- wl_surface_destroy(output->parent.surface);
- output->parent.surface = old_surface;
- wayland_output_resize_surface(output);
-
- return -1;
- }
-
- old_mode->flags &= ~WL_OUTPUT_MODE_CURRENT;
- output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
-
- if (b->use_pixman) {
- pixman_renderer_output_destroy(output_base);
- if (wayland_output_init_pixman_renderer(output) < 0)
- goto err_output;
-#ifdef ENABLE_EGL
- } else {
- gl_renderer->output_destroy(output_base);
- wl_egl_window_destroy(output->gl.egl_window);
- if (wayland_output_init_gl_renderer(output) < 0)
- goto err_output;
-#endif
- }
- wl_surface_destroy(old_surface);
-
- weston_output_schedule_repaint(&output->base);
-
- return 0;
-
-err_output:
- /* XXX */
- return -1;
-}
-
-static void
-handle_xdg_surface_configure(void *data, struct xdg_surface *surface,
- uint32_t serial)
-{
- xdg_surface_ack_configure(surface, serial);
-}
-
-static const struct xdg_surface_listener xdg_surface_listener = {
- handle_xdg_surface_configure
-};
-
-static void
-handle_xdg_toplevel_configure(void *data, struct xdg_toplevel *toplevel,
- int32_t width, int32_t height,
- struct wl_array *states)
-{
- struct wayland_output *output = data;
-
- output->parent.configure_width = width;
- output->parent.configure_height = height;
-
- output->parent.wait_for_configure = false;
- /* FIXME: implement resizing */
-}
-
-static void
-handle_xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
-{
- struct wayland_output *output = data;
- struct weston_compositor *compositor = output->base.compositor;
-
- wayland_output_destroy(&output->base);
-
- if (wl_list_empty(&compositor->output_list))
- weston_compositor_exit(compositor);
-}
-
-static const struct xdg_toplevel_listener xdg_toplevel_listener = {
- handle_xdg_toplevel_configure,
- handle_xdg_toplevel_close,
-};
-
-static int
-wayland_backend_create_output_surface(struct wayland_output *output)
-{
- struct wayland_backend *b = to_wayland_backend(output->base.compositor);
-
- assert(!output->parent.surface);
-
- output->parent.surface =
- wl_compositor_create_surface(b->parent.compositor);
- if (!output->parent.surface)
- return -1;
-
- wl_surface_set_user_data(output->parent.surface, output);
-
- output->parent.draw_initial_frame = true;
-
- if (b->parent.xdg_wm_base) {
- output->parent.xdg_surface =
- xdg_wm_base_get_xdg_surface(b->parent.xdg_wm_base,
- output->parent.surface);
- xdg_surface_add_listener(output->parent.xdg_surface,
- &xdg_surface_listener, output);
-
- output->parent.xdg_toplevel =
- xdg_surface_get_toplevel(output->parent.xdg_surface);
- xdg_toplevel_add_listener(output->parent.xdg_toplevel,
- &xdg_toplevel_listener, output);
-
- xdg_toplevel_set_title(output->parent.xdg_toplevel, output->title);
-
- wl_surface_commit(output->parent.surface);
-
- output->parent.wait_for_configure = true;
-
- while (output->parent.wait_for_configure)
- wl_display_dispatch(b->parent.wl_display);
-
- weston_log("wayland-backend: Using xdg_wm_base\n");
- }
- else if (b->parent.shell) {
- output->parent.shell_surface =
- wl_shell_get_shell_surface(b->parent.shell,
- output->parent.surface);
- if (!output->parent.shell_surface) {
- wl_surface_destroy(output->parent.surface);
- return -1;
- }
-
- wl_shell_surface_add_listener(output->parent.shell_surface,
- &shell_surface_listener, output);
-
- weston_log("wayland-backend: Using wl_shell\n");
- }
-
- return 0;
-}
-
-static int
-wayland_output_enable(struct weston_output *base)
-{
- struct wayland_output *output = to_wayland_output(base);
- struct wayland_backend *b = to_wayland_backend(base->compositor);
- enum mode_status mode_status;
- int ret = 0;
-
- weston_log("Creating %dx%d wayland output at (%d, %d)\n",
- output->base.current_mode->width,
- output->base.current_mode->height,
- output->base.x, output->base.y);
-
- if (!output->parent.surface)
- ret = wayland_backend_create_output_surface(output);
-
- if (ret < 0)
- return -1;
-
- wl_list_init(&output->shm.buffers);
- wl_list_init(&output->shm.free_buffers);
-
- if (b->use_pixman) {
- if (wayland_output_init_pixman_renderer(output) < 0)
- goto err_output;
-
- output->base.repaint = wayland_output_repaint_pixman;
-#ifdef ENABLE_EGL
- } else {
- if (wayland_output_init_gl_renderer(output) < 0)
- goto err_output;
-
- output->base.repaint = wayland_output_repaint_gl;
-#endif
- }
-
- output->base.start_repaint_loop = wayland_output_start_repaint_loop;
- output->base.assign_planes = NULL;
- output->base.set_backlight = NULL;
- output->base.set_dpms = NULL;
- output->base.switch_mode = wayland_output_switch_mode;
-
- if (b->sprawl_across_outputs) {
- if (b->parent.fshell) {
- wayland_output_resize_surface(output);
-
- mode_status = wayland_output_fullscreen_shell_mode_feedback(output, &output->mode);
-
- if (mode_status == MODE_STATUS_FAIL) {
- zwp_fullscreen_shell_v1_present_surface(b->parent.fshell,
- output->parent.surface,
- ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER,
- output->parent.output);
-
- output->parent.draw_initial_frame = true;
- }
- } else {
- wayland_output_set_fullscreen(output,
- WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER,
- output->mode.refresh, output->parent.output);
- }
- } else if (b->fullscreen) {
- wayland_output_set_fullscreen(output, 0, 0, NULL);
- } else {
- wayland_output_set_windowed(output);
- }
-
- return 0;
-
-err_output:
- wayland_backend_destroy_output_surface(output);
-
- return -1;
-}
-
-static int
-wayland_output_setup_for_parent_output(struct wayland_output *output,
- struct wayland_parent_output *poutput);
-
-static int
-wayland_output_setup_fullscreen(struct wayland_output *output,
- struct wayland_head *head);
-
-static int
-wayland_output_attach_head(struct weston_output *output_base,
- struct weston_head *head_base)
-{
- struct wayland_backend *b = to_wayland_backend(output_base->compositor);
- struct wayland_output *output = to_wayland_output(output_base);
- struct wayland_head *head = to_wayland_head(head_base);
-
- if (!wl_list_empty(&output->base.head_list))
- return -1;
-
- if (head->parent_output) {
- if (wayland_output_setup_for_parent_output(output,
- head->parent_output) < 0)
- return -1;
- } else if (b->fullscreen) {
- if (wayland_output_setup_fullscreen(output, head) < 0)
- return -1;
- } else {
- /* A floating window, nothing to do. */
- }
-
- return 0;
-}
-
-static void
-wayland_output_detach_head(struct weston_output *output_base,
- struct weston_head *head)
-{
- struct wayland_output *output = to_wayland_output(output_base);
-
- /* Rely on the disable hook if the output was enabled. We do not
- * support cloned heads, so detaching is guaranteed to disable the
- * output.
- */
- if (output->base.enabled)
- return;
-
- /* undo setup fullscreen */
- if (output->parent.surface)
- wayland_backend_destroy_output_surface(output);
-}
-
-static struct weston_output *
-wayland_output_create(struct weston_compositor *compositor, const char *name)
-{
- struct wayland_output *output;
- char *title;
-
- /* name can't be NULL. */
- assert(name);
-
- output = zalloc(sizeof *output);
- if (output == NULL) {
- perror("zalloc");
- return NULL;
- }
-
- if (asprintf(&title, "%s - %s", WINDOW_TITLE, name) < 0) {
- free(output);
- return NULL;
- }
- output->title = title;
-
- weston_output_init(&output->base, compositor, name);
-
- output->base.destroy = wayland_output_destroy;
- output->base.disable = wayland_output_disable;
- output->base.enable = wayland_output_enable;
- output->base.attach_head = wayland_output_attach_head;
- output->base.detach_head = wayland_output_detach_head;
-
- weston_compositor_add_pending_output(&output->base, compositor);
-
- return &output->base;
-}
-
-static struct wayland_head *
-wayland_head_create(struct weston_compositor *compositor, const char *name)
-{
- struct wayland_head *head;
-
- assert(name);
-
- head = zalloc(sizeof *head);
- if (!head)
- return NULL;
-
- weston_head_init(&head->base, name);
- weston_head_set_connection_status(&head->base, true);
- weston_compositor_add_head(compositor, &head->base);
-
- return head;
-}
-
-static int
-wayland_head_create_windowed(struct weston_compositor *compositor,
- const char *name)
-{
- if (!wayland_head_create(compositor, name))
- return -1;
-
- return 0;
-}
-
-static int
-wayland_head_create_for_parent_output(struct weston_compositor *compositor,
- struct wayland_parent_output *poutput)
-{
- struct wayland_head *head;
- char name[100];
- int ret;
-
- ret = snprintf(name, sizeof(name), "wlparent-%d", poutput->id);
- if (ret < 1 || (unsigned)ret >= sizeof(name))
- return -1;
-
- head = wayland_head_create(compositor, name);
- if (!head)
- return -1;
-
- assert(!poutput->head);
- head->parent_output = poutput;
- poutput->head = head;
-
- weston_head_set_monitor_strings(&head->base,
- poutput->physical.make,
- poutput->physical.model, NULL);
- weston_head_set_physical_size(&head->base,
- poutput->physical.width,
- poutput->physical.height);
-
- return 0;
-}
-
-static void
-wayland_head_destroy(struct wayland_head *head)
-{
- if (head->parent_output)
- head->parent_output->head = NULL;
-
- weston_head_release(&head->base);
- free(head);
-}
-
-static int
-wayland_output_set_size(struct weston_output *base, int width, int height)
-{
- struct wayland_output *output = to_wayland_output(base);
- struct weston_head *head;
- int output_width, output_height;
-
- /* We can only be called once. */
- assert(!output->base.current_mode);
-
- /* Make sure we have scale set. */
- assert(output->base.scale);
-
- if (width < 1) {
- weston_log("Invalid width \"%d\" for output %s\n",
- width, output->base.name);
- return -1;
- }
-
- if (height < 1) {
- weston_log("Invalid height \"%d\" for output %s\n",
- height, output->base.name);
- return -1;
- }
-
- wl_list_for_each(head, &output->base.head_list, output_link) {
- weston_head_set_monitor_strings(head, "wayland", "none", NULL);
-
- /* XXX: Calculate proper size. */
- weston_head_set_physical_size(head, width, height);
- }
-
- output_width = width * output->base.scale;
- output_height = height * output->base.scale;
-
- output->mode.flags =
- WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
-
- output->mode.width = output_width;
- output->mode.height = output_height;
- output->mode.refresh = 60000;
- wl_list_insert(&output->base.mode_list, &output->mode.link);
-
- output->base.current_mode = &output->mode;
-
- return 0;
-}
-
-static int
-wayland_output_setup_for_parent_output(struct wayland_output *output,
- struct wayland_parent_output *poutput)
-{
- struct weston_mode *mode;
-
- if (poutput->current_mode) {
- mode = poutput->current_mode;
- } else if (poutput->preferred_mode) {
- mode = poutput->preferred_mode;
- } else if (!wl_list_empty(&poutput->mode_list)) {
- mode = container_of(poutput->mode_list.next,
- struct weston_mode, link);
- } else {
- weston_log("No valid modes found. Skipping output.\n");
- return -1;
- }
-
- output->base.scale = 1;
- output->base.transform = WL_OUTPUT_TRANSFORM_NORMAL;
-
- output->parent.output = poutput->global;
-
- wl_list_insert_list(&output->base.mode_list, &poutput->mode_list);
- wl_list_init(&poutput->mode_list);
-
- /* No other mode should have CURRENT already. */
- mode->flags |= WL_OUTPUT_MODE_CURRENT;
- output->base.current_mode = mode;
-
- /* output->mode is unused in this path. */
-
- return 0;
-}
-
-static int
-wayland_output_setup_fullscreen(struct wayland_output *output,
- struct wayland_head *head)
-{
- struct wayland_backend *b = to_wayland_backend(output->base.compositor);
- int width = 0, height = 0;
-
- output->base.scale = 1;
- output->base.transform = WL_OUTPUT_TRANSFORM_NORMAL;
-
- if (wayland_backend_create_output_surface(output) < 0)
- return -1;
-
- /* What should size be set if conditional is false? */
- if (b->parent.xdg_wm_base || b->parent.shell) {
- if (output->parent.xdg_toplevel)
- xdg_toplevel_set_fullscreen(output->parent.xdg_toplevel,
- output->parent.output);
- else if (output->parent.shell_surface)
- wl_shell_surface_set_fullscreen(output->parent.shell_surface,
- 0, 0, NULL);
-
- wl_display_roundtrip(b->parent.wl_display);
-
- width = output->parent.configure_width;
- height = output->parent.configure_height;
- }
-
- if (wayland_output_set_size(&output->base, width, height) < 0)
- goto err_set_size;
-
- /* The head is not attached yet, so set_size did not set these. */
- weston_head_set_monitor_strings(&head->base, "wayland", "none", NULL);
- /* XXX: Calculate proper size. */
- weston_head_set_physical_size(&head->base, width, height);
-
- return 0;
-
-err_set_size:
- wayland_backend_destroy_output_surface(output);
-
- return -1;
-}
-
-static void
-shell_surface_ping(void *data, struct wl_shell_surface *shell_surface,
- uint32_t serial)
-{
- wl_shell_surface_pong(shell_surface, serial);
-}
-
-static void
-shell_surface_configure(void *data, struct wl_shell_surface *shell_surface,
- uint32_t edges, int32_t width, int32_t height)
-{
- struct wayland_output *output = data;
-
- output->parent.configure_width = width;
- output->parent.configure_height = height;
-
- /* FIXME: implement resizing */
-}
-
-static void
-shell_surface_popup_done(void *data, struct wl_shell_surface *shell_surface)
-{
-}
-
-static const struct wl_shell_surface_listener shell_surface_listener = {
- shell_surface_ping,
- shell_surface_configure,
- shell_surface_popup_done
-};
-
-/* Events received from the wayland-server this compositor is client of: */
-
-/* parent input interface */
-static void
-input_set_cursor(struct wayland_input *input)
-{
-
- struct wl_buffer *buffer;
- struct wl_cursor_image *image;
-
- if (!input->backend->cursor)
- return; /* Couldn't load the cursor. Can't set it */
-
- image = input->backend->cursor->images[0];
- buffer = wl_cursor_image_get_buffer(image);
- if (!buffer)
- return;
-
- wl_pointer_set_cursor(input->parent.pointer, input->enter_serial,
- input->parent.cursor.surface,
- image->hotspot_x, image->hotspot_y);
-
- wl_surface_attach(input->parent.cursor.surface, buffer, 0, 0);
- wl_surface_damage(input->parent.cursor.surface, 0, 0,
- image->width, image->height);
- wl_surface_commit(input->parent.cursor.surface);
-}
-
-static void
-input_handle_pointer_enter(void *data, struct wl_pointer *pointer,
- uint32_t serial, struct wl_surface *surface,
- wl_fixed_t fixed_x, wl_fixed_t fixed_y)
-{
- struct wayland_input *input = data;
- int32_t fx, fy;
- enum theme_location location;
- double x, y;
-
- if (!surface) {
- input->output = NULL;
- input->has_focus = false;
- notify_pointer_focus(&input->base, NULL, 0, 0);
- return;
- }
-
- x = wl_fixed_to_double(fixed_x);
- y = wl_fixed_to_double(fixed_y);
-
- /* XXX: If we get a modifier event immediately before the focus,
- * we should try to keep the same serial. */
- input->enter_serial = serial;
- input->output = wl_surface_get_user_data(surface);
-
- if (input->output->frame) {
- location = frame_pointer_enter(input->output->frame, input,
- x, y);
- frame_interior(input->output->frame, &fx, &fy, NULL, NULL);
- x -= fx;
- y -= fy;
-
- if (frame_status(input->output->frame) & FRAME_STATUS_REPAINT)
- weston_output_schedule_repaint(&input->output->base);
- } else {
- location = THEME_LOCATION_CLIENT_AREA;
- }
-
- weston_output_transform_coordinate(&input->output->base, x, y, &x, &y);
-
- if (location == THEME_LOCATION_CLIENT_AREA) {
- input->has_focus = true;
- notify_pointer_focus(&input->base, &input->output->base, x, y);
- wl_pointer_set_cursor(input->parent.pointer,
- input->enter_serial, NULL, 0, 0);
- } else {
- input->has_focus = false;
- notify_pointer_focus(&input->base, NULL, 0, 0);
- input_set_cursor(input);
- }
-}
-
-static void
-input_handle_pointer_leave(void *data, struct wl_pointer *pointer,
- uint32_t serial, struct wl_surface *surface)
-{
- struct wayland_input *input = data;
-
- if (!input->output)
- return;
-
- if (input->output->frame) {
- frame_pointer_leave(input->output->frame, input);
-
- if (frame_status(input->output->frame) & FRAME_STATUS_REPAINT)
- weston_output_schedule_repaint(&input->output->base);
- }
-
- notify_pointer_focus(&input->base, NULL, 0, 0);
- input->output = NULL;
- input->has_focus = false;
-}
-
-static void
-input_handle_motion(void *data, struct wl_pointer *pointer,
- uint32_t time, wl_fixed_t fixed_x, wl_fixed_t fixed_y)
-{
- struct wayland_input *input = data;
- int32_t fx, fy;
- enum theme_location location;
- bool want_frame = false;
- double x, y;
- struct timespec ts;
-
- if (!input->output)
- return;
-
- x = wl_fixed_to_double(fixed_x);
- y = wl_fixed_to_double(fixed_y);
-
- if (input->output->frame) {
- location = frame_pointer_motion(input->output->frame, input,
- x, y);
- frame_interior(input->output->frame, &fx, &fy, NULL, NULL);
- x -= fx;
- y -= fy;
-
- if (frame_status(input->output->frame) & FRAME_STATUS_REPAINT)
- weston_output_schedule_repaint(&input->output->base);
- } else {
- location = THEME_LOCATION_CLIENT_AREA;
- }
-
- weston_output_transform_coordinate(&input->output->base, x, y, &x, &y);
-
- if (input->has_focus && location != THEME_LOCATION_CLIENT_AREA) {
- input_set_cursor(input);
- notify_pointer_focus(&input->base, NULL, 0, 0);
- input->has_focus = false;
- want_frame = true;
- } else if (!input->has_focus &&
- location == THEME_LOCATION_CLIENT_AREA) {
- wl_pointer_set_cursor(input->parent.pointer,
- input->enter_serial, NULL, 0, 0);
- notify_pointer_focus(&input->base, &input->output->base, x, y);
- input->has_focus = true;
- want_frame = true;
- }
-
- if (location == THEME_LOCATION_CLIENT_AREA) {
- timespec_from_msec(&ts, time);
- notify_motion_absolute(&input->base, &ts, x, y);
- want_frame = true;
- }
-
- if (want_frame && input->seat_version < WL_POINTER_FRAME_SINCE_VERSION)
- notify_pointer_frame(&input->base);
-}
-
-static void
-input_handle_button(void *data, struct wl_pointer *pointer,
- uint32_t serial, uint32_t time, uint32_t button,
- enum wl_pointer_button_state state)
-{
- struct wayland_input *input = data;
- enum theme_location location;
- struct timespec ts;
-
- if (!input->output)
- return;
-
- if (input->output->frame) {
- location = frame_pointer_button(input->output->frame, input,
- button, state);
-
- if (frame_status(input->output->frame) & FRAME_STATUS_MOVE) {
- if (input->output->parent.xdg_toplevel)
- xdg_toplevel_move(input->output->parent.xdg_toplevel,
- input->parent.seat, serial);
- else if (input->output->parent.shell_surface)
- wl_shell_surface_move(input->output->parent.shell_surface,
- input->parent.seat, serial);
- frame_status_clear(input->output->frame,
- FRAME_STATUS_MOVE);
- return;
- }
-
- if (frame_status(input->output->frame) & FRAME_STATUS_CLOSE) {
- wayland_output_destroy(&input->output->base);
- input->output = NULL;
- input->keyboard_focus = NULL;
-
- if (wl_list_empty(&input->backend->compositor->output_list))
- weston_compositor_exit(input->backend->compositor);
-
- return;
- }
-
- if (frame_status(input->output->frame) & FRAME_STATUS_REPAINT)
- weston_output_schedule_repaint(&input->output->base);
- } else {
- location = THEME_LOCATION_CLIENT_AREA;
- }
-
- if (location == THEME_LOCATION_CLIENT_AREA) {
- timespec_from_msec(&ts, time);
- notify_button(&input->base, &ts, button, state);
- if (input->seat_version < WL_POINTER_FRAME_SINCE_VERSION)
- notify_pointer_frame(&input->base);
- }
-}
-
-static void
-input_handle_axis(void *data, struct wl_pointer *pointer,
- uint32_t time, uint32_t axis, wl_fixed_t value)
-{
- struct wayland_input *input = data;
- struct weston_pointer_axis_event weston_event;
- struct timespec ts;
-
- weston_event.axis = axis;
- weston_event.value = wl_fixed_to_double(value);
- weston_event.has_discrete = false;
-
- if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL &&
- input->vert.has_discrete) {
- weston_event.has_discrete = true;
- weston_event.discrete = input->vert.discrete;
- input->vert.has_discrete = false;
- } else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL &&
- input->horiz.has_discrete) {
- weston_event.has_discrete = true;
- weston_event.discrete = input->horiz.discrete;
- input->horiz.has_discrete = false;
- }
-
- timespec_from_msec(&ts, time);
-
- notify_axis(&input->base, &ts, &weston_event);
-
- if (input->seat_version < WL_POINTER_FRAME_SINCE_VERSION)
- notify_pointer_frame(&input->base);
-}
-
-static void
-input_handle_frame(void *data, struct wl_pointer *pointer)
-{
- struct wayland_input *input = data;
-
- notify_pointer_frame(&input->base);
-}
-
-static void
-input_handle_axis_source(void *data, struct wl_pointer *pointer,
- uint32_t source)
-{
- struct wayland_input *input = data;
-
- notify_axis_source(&input->base, source);
-}
-
-static void
-input_handle_axis_stop(void *data, struct wl_pointer *pointer,
- uint32_t time, uint32_t axis)
-{
- struct wayland_input *input = data;
- struct weston_pointer_axis_event weston_event;
- struct timespec ts;
-
- weston_event.axis = axis;
- weston_event.value = 0;
-
- timespec_from_msec(&ts, time);
-
- notify_axis(&input->base, &ts, &weston_event);
-}
-
-static void
-input_handle_axis_discrete(void *data, struct wl_pointer *pointer,
- uint32_t axis, int32_t discrete)
-{
- struct wayland_input *input = data;
-
- if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
- input->vert.has_discrete = true;
- input->vert.discrete = discrete;
- } else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
- input->horiz.has_discrete = true;
- input->horiz.discrete = discrete;
- }
-}
-
-static const struct wl_pointer_listener pointer_listener = {
- input_handle_pointer_enter,
- input_handle_pointer_leave,
- input_handle_motion,
- input_handle_button,
- input_handle_axis,
- input_handle_frame,
- input_handle_axis_source,
- input_handle_axis_stop,
- input_handle_axis_discrete,
-};
-
-static void
-input_handle_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format,
- int fd, uint32_t size)
-{
- struct wayland_input *input = data;
- struct xkb_keymap *keymap;
- char *map_str;
-
- if (!data) {
- close(fd);
- return;
- }
-
- if (format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
- map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
- if (map_str == MAP_FAILED) {
- weston_log("mmap failed: %s\n", strerror(errno));
- goto error;
- }
-
- keymap = xkb_keymap_new_from_string(input->backend->compositor->xkb_context,
- map_str,
- XKB_KEYMAP_FORMAT_TEXT_V1,
- 0);
- munmap(map_str, size);
-
- if (!keymap) {
- weston_log("failed to compile keymap\n");
- goto error;
- }
-
- input->keyboard_state_update = STATE_UPDATE_NONE;
- } else if (format == WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP) {
- weston_log("No keymap provided; falling back to default\n");
- keymap = NULL;
- input->keyboard_state_update = STATE_UPDATE_AUTOMATIC;
- } else {
- weston_log("Invalid keymap\n");
- goto error;
- }
-
- close(fd);
-
- if (weston_seat_get_keyboard(&input->base))
- weston_seat_update_keymap(&input->base, keymap);
- else
- weston_seat_init_keyboard(&input->base, keymap);
-
- xkb_keymap_unref(keymap);
-
- return;
-
-error:
- wl_keyboard_release(input->parent.keyboard);
- close(fd);
-}
-
-static void
-input_handle_keyboard_enter(void *data,
- struct wl_keyboard *keyboard,
- uint32_t serial,
- struct wl_surface *surface,
- struct wl_array *keys)
-{
- struct wayland_input *input = data;
- struct wayland_output *focus;
-
- focus = input->keyboard_focus;
- if (focus) {
- /* This shouldn't happen */
- focus->keyboard_count--;
- if (!focus->keyboard_count && focus->frame)
- frame_unset_flag(focus->frame, FRAME_FLAG_ACTIVE);
- if (frame_status(focus->frame) & FRAME_STATUS_REPAINT)
- weston_output_schedule_repaint(&focus->base);
- }
-
- if (!surface) {
- input->keyboard_focus = NULL;
- return;
- }
-
- input->keyboard_focus = wl_surface_get_user_data(surface);
- input->keyboard_focus->keyboard_count++;
-
- focus = input->keyboard_focus;
- if (focus->frame) {
- frame_set_flag(focus->frame, FRAME_FLAG_ACTIVE);
- if (frame_status(focus->frame) & FRAME_STATUS_REPAINT)
- weston_output_schedule_repaint(&focus->base);
- }
-
-
- /* XXX: If we get a modifier event immediately before the focus,
- * we should try to keep the same serial. */
- notify_keyboard_focus_in(&input->base, keys,
- STATE_UPDATE_AUTOMATIC);
-}
-
-static void
-input_handle_keyboard_leave(void *data,
- struct wl_keyboard *keyboard,
- uint32_t serial,
- struct wl_surface *surface)
-{
- struct wayland_input *input = data;
- struct wayland_output *focus;
-
- notify_keyboard_focus_out(&input->base);
-
- focus = input->keyboard_focus;
- if (!focus)
- return;
-
- focus->keyboard_count--;
- if (!focus->keyboard_count && focus->frame) {
- frame_unset_flag(focus->frame, FRAME_FLAG_ACTIVE);
- if (frame_status(focus->frame) & FRAME_STATUS_REPAINT)
- weston_output_schedule_repaint(&focus->base);
- }
-
- input->keyboard_focus = NULL;
-}
-
-static void
-input_handle_key(void *data, struct wl_keyboard *keyboard,
- uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
-{
- struct wayland_input *input = data;
- struct timespec ts;
-
- if (!input->keyboard_focus)
- return;
-
- timespec_from_msec(&ts, time);
-
- input->key_serial = serial;
- notify_key(&input->base, &ts, key,
- state ? WL_KEYBOARD_KEY_STATE_PRESSED :
- WL_KEYBOARD_KEY_STATE_RELEASED,
- input->keyboard_state_update);
-}
-
-static void
-input_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard,
- uint32_t serial_in, uint32_t mods_depressed,
- uint32_t mods_latched, uint32_t mods_locked,
- uint32_t group)
-{
- struct weston_keyboard *keyboard;
- struct wayland_input *input = data;
- struct wayland_backend *b = input->backend;
- uint32_t serial_out;
-
- /* If we get a key event followed by a modifier event with the
- * same serial number, then we try to preserve those semantics by
- * reusing the same serial number on the way out too. */
- if (serial_in == input->key_serial)
- serial_out = wl_display_get_serial(b->compositor->wl_display);
- else
- serial_out = wl_display_next_serial(b->compositor->wl_display);
-
- keyboard = weston_seat_get_keyboard(&input->base);
- xkb_state_update_mask(keyboard->xkb_state.state,
- mods_depressed, mods_latched,
- mods_locked, 0, 0, group);
- notify_modifiers(&input->base, serial_out);
-}
-
-static void
-input_handle_repeat_info(void *data, struct wl_keyboard *keyboard,
- int32_t rate, int32_t delay)
-{
- struct wayland_input *input = data;
- struct wayland_backend *b = input->backend;
-
- b->compositor->kb_repeat_rate = rate;
- b->compositor->kb_repeat_delay = delay;
-}
-
-static const struct wl_keyboard_listener keyboard_listener = {
- input_handle_keymap,
- input_handle_keyboard_enter,
- input_handle_keyboard_leave,
- input_handle_key,
- input_handle_modifiers,
- input_handle_repeat_info,
-};
-
-static void
-input_handle_touch_down(void *data, struct wl_touch *wl_touch,
- uint32_t serial, uint32_t time,
- struct wl_surface *surface, int32_t id,
- wl_fixed_t fixed_x, wl_fixed_t fixed_y)
-{
- struct wayland_input *input = data;
- struct wayland_output *output;
- enum theme_location location;
- bool first_touch;
- int32_t fx, fy;
- double x, y;
- struct timespec ts;
-
- x = wl_fixed_to_double(fixed_x);
- y = wl_fixed_to_double(fixed_y);
-
- timespec_from_msec(&ts, time);
-
- first_touch = (input->touch_points == 0);
- input->touch_points++;
-
- input->touch_focus = wl_surface_get_user_data(surface);
- output = input->touch_focus;
- if (!first_touch && !input->touch_active)
- return;
-
- if (output->frame) {
- location = frame_touch_down(output->frame, input, id, x, y);
-
- frame_interior(output->frame, &fx, &fy, NULL, NULL);
- x -= fx;
- y -= fy;
-
- if (frame_status(output->frame) & FRAME_STATUS_REPAINT)
- weston_output_schedule_repaint(&output->base);
-
- if (first_touch && (frame_status(output->frame) & FRAME_STATUS_MOVE)) {
- input->touch_points--;
- if (output->parent.xdg_toplevel)
- xdg_toplevel_move(output->parent.xdg_toplevel,
- input->parent.seat, serial);
- else if (output->parent.shell_surface)
- wl_shell_surface_move(output->parent.shell_surface,
- input->parent.seat, serial);
- frame_status_clear(output->frame,
- FRAME_STATUS_MOVE);
- return;
- }
-
- if (first_touch && location != THEME_LOCATION_CLIENT_AREA)
- return;
- }
-
- weston_output_transform_coordinate(&output->base, x, y, &x, &y);
-
- notify_touch(input->touch_device, &ts, id, x, y, WL_TOUCH_DOWN);
- input->touch_active = true;
-}
-
-static void
-input_handle_touch_up(void *data, struct wl_touch *wl_touch,
- uint32_t serial, uint32_t time, int32_t id)
-{
- struct wayland_input *input = data;
- struct wayland_output *output = input->touch_focus;
- bool active = input->touch_active;
- struct timespec ts;
-
- timespec_from_msec(&ts, time);
-
- input->touch_points--;
- if (input->touch_points == 0) {
- input->touch_focus = NULL;
- input->touch_active = false;
- }
-
- if (!output)
- return;
-
- if (output->frame) {
- frame_touch_up(output->frame, input, id);
-
- if (frame_status(output->frame) & FRAME_STATUS_CLOSE) {
- wayland_output_destroy(&output->base);
- input->touch_focus = NULL;
- input->keyboard_focus = NULL;
- if (wl_list_empty(&input->backend->compositor->output_list))
- weston_compositor_exit(input->backend->compositor);
-
- return;
- }
- if (frame_status(output->frame) & FRAME_STATUS_REPAINT)
- weston_output_schedule_repaint(&output->base);
- }
-
- if (active)
- notify_touch(input->touch_device, &ts, id, 0, 0, WL_TOUCH_UP);
-}
-
-static void
-input_handle_touch_motion(void *data, struct wl_touch *wl_touch,
- uint32_t time, int32_t id,
- wl_fixed_t fixed_x, wl_fixed_t fixed_y)
-{
- struct wayland_input *input = data;
- struct wayland_output *output = input->touch_focus;
- int32_t fx, fy;
- double x, y;
- struct timespec ts;
-
- x = wl_fixed_to_double(fixed_x);
- y = wl_fixed_to_double(fixed_y);
- timespec_from_msec(&ts, time);
-
- if (!output || !input->touch_active)
- return;
-
- if (output->frame) {
- frame_interior(output->frame, &fx, &fy, NULL, NULL);
- x -= fx;
- y -= fy;
- }
-
- weston_output_transform_coordinate(&output->base, x, y, &x, &y);
-
- notify_touch(input->touch_device, &ts, id, x, y, WL_TOUCH_MOTION);
-}
-
-static void
-input_handle_touch_frame(void *data, struct wl_touch *wl_touch)
-{
- struct wayland_input *input = data;
-
- if (!input->touch_focus || !input->touch_active)
- return;
-
- notify_touch_frame(input->touch_device);
-}
-
-static void
-input_handle_touch_cancel(void *data, struct wl_touch *wl_touch)
-{
- struct wayland_input *input = data;
-
- if (!input->touch_focus || !input->touch_active)
- return;
-
- notify_touch_cancel(input->touch_device);
-}
-
-static const struct wl_touch_listener touch_listener = {
- input_handle_touch_down,
- input_handle_touch_up,
- input_handle_touch_motion,
- input_handle_touch_frame,
- input_handle_touch_cancel,
-};
-
-
-static struct weston_touch_device *
-create_touch_device(struct wayland_input *input)
-{
- struct weston_touch_device *touch_device;
- char str[128];
-
- /* manufacture a unique'ish name */
- snprintf(str, sizeof str, "wayland-touch[%u]",
- wl_proxy_get_id((struct wl_proxy *)input->parent.seat));
-
- touch_device = weston_touch_create_touch_device(input->base.touch_state,
- str, NULL, NULL);
-
- return touch_device;
-}
-
-static void
-input_handle_capabilities(void *data, struct wl_seat *seat,
- enum wl_seat_capability caps)
-{
- struct wayland_input *input = data;
-
- if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->parent.pointer) {
- input->parent.pointer = wl_seat_get_pointer(seat);
- wl_pointer_set_user_data(input->parent.pointer, input);
- wl_pointer_add_listener(input->parent.pointer,
- &pointer_listener, input);
- weston_seat_init_pointer(&input->base);
- } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->parent.pointer) {
- if (input->seat_version >= WL_POINTER_RELEASE_SINCE_VERSION)
- wl_pointer_release(input->parent.pointer);
- else
- wl_pointer_destroy(input->parent.pointer);
- input->parent.pointer = NULL;
- weston_seat_release_pointer(&input->base);
- }
-
- if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->parent.keyboard) {
- input->parent.keyboard = wl_seat_get_keyboard(seat);
- wl_keyboard_set_user_data(input->parent.keyboard, input);
- wl_keyboard_add_listener(input->parent.keyboard,
- &keyboard_listener, input);
- } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->parent.keyboard) {
- if (input->seat_version >= WL_KEYBOARD_RELEASE_SINCE_VERSION)
- wl_keyboard_release(input->parent.keyboard);
- else
- wl_keyboard_destroy(input->parent.keyboard);
- input->parent.keyboard = NULL;
- weston_seat_release_keyboard(&input->base);
- }
-
- if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->parent.touch) {
- input->parent.touch = wl_seat_get_touch(seat);
- wl_touch_set_user_data(input->parent.touch, input);
- wl_touch_add_listener(input->parent.touch,
- &touch_listener, input);
- weston_seat_init_touch(&input->base);
- input->touch_device = create_touch_device(input);
- } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->parent.touch) {
- weston_touch_device_destroy(input->touch_device);
- input->touch_device = NULL;
- if (input->seat_version >= WL_TOUCH_RELEASE_SINCE_VERSION)
- wl_touch_release(input->parent.touch);
- else
- wl_touch_destroy(input->parent.touch);
- input->parent.touch = NULL;
- weston_seat_release_touch(&input->base);
- }
-}
-
-static void
-input_handle_name(void *data, struct wl_seat *seat,
- const char *name)
-{
-}
-
-static const struct wl_seat_listener seat_listener = {
- input_handle_capabilities,
- input_handle_name,
-};
-
-static void
-display_add_seat(struct wayland_backend *b, uint32_t id, uint32_t available_version)
-{
- struct wayland_input *input;
- uint32_t version = MIN(available_version, 4);
-
- input = zalloc(sizeof *input);
- if (input == NULL)
- return;
-
- weston_seat_init(&input->base, b->compositor, "default");
- input->backend = b;
- input->parent.seat = wl_registry_bind(b->parent.registry, id,
- &wl_seat_interface, version);
- input->seat_version = version;
- wl_list_insert(b->input_list.prev, &input->link);
-
- wl_seat_add_listener(input->parent.seat, &seat_listener, input);
- wl_seat_set_user_data(input->parent.seat, input);
-
- input->parent.cursor.surface =
- wl_compositor_create_surface(b->parent.compositor);
-
- input->vert.axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
- input->horiz.axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
-}
-
-static void
-wayland_parent_output_geometry(void *data, struct wl_output *output_proxy,
- int32_t x, int32_t y,
- int32_t physical_width, int32_t physical_height,
- int32_t subpixel, const char *make,
- const char *model, int32_t transform)
-{
- struct wayland_parent_output *output = data;
-
- output->x = x;
- output->y = y;
- output->physical.width = physical_width;
- output->physical.height = physical_height;
- output->physical.subpixel = subpixel;
-
- free(output->physical.make);
- output->physical.make = strdup(make);
- free(output->physical.model);
- output->physical.model = strdup(model);
-
- output->transform = transform;
-}
-
-static struct weston_mode *
-find_mode(struct wl_list *list, int32_t width, int32_t height, uint32_t refresh)
-{
- struct weston_mode *mode;
-
- wl_list_for_each(mode, list, link) {
- if (mode->width == width && mode->height == height &&
- mode->refresh == refresh)
- return mode;
- }
-
- mode = zalloc(sizeof *mode);
- if (!mode)
- return NULL;
-
- mode->width = width;
- mode->height = height;
- mode->refresh = refresh;
- wl_list_insert(list, &mode->link);
-
- return mode;
-}
-
-static struct weston_output *
-wayland_parent_output_get_enabled_output(struct wayland_parent_output *poutput)
-{
- struct wayland_head *head = poutput->head;
-
- if (!head)
- return NULL;
-
- if (!weston_head_is_enabled(&head->base))
- return NULL;
-
- return weston_head_get_output(&head->base);
-}
-
-static void
-wayland_parent_output_mode(void *data, struct wl_output *wl_output_proxy,
- uint32_t flags, int32_t width, int32_t height,
- int32_t refresh)
-{
- struct wayland_parent_output *output = data;
- struct weston_output *enabled_output;
- struct weston_mode *mode;
-
- enabled_output = wayland_parent_output_get_enabled_output(output);
- if (enabled_output) {
- mode = find_mode(&enabled_output->mode_list,
- width, height, refresh);
- if (!mode)
- return;
- mode->flags = flags;
- /* Do a mode-switch on current mode change? */
- } else {
- mode = find_mode(&output->mode_list, width, height, refresh);
- if (!mode)
- return;
- mode->flags = flags;
- if (flags & WL_OUTPUT_MODE_CURRENT)
- output->current_mode = mode;
- if (flags & WL_OUTPUT_MODE_PREFERRED)
- output->preferred_mode = mode;
- }
-}
-
-static const struct wl_output_listener output_listener = {
- wayland_parent_output_geometry,
- wayland_parent_output_mode
-};
-
-static void
-output_sync_callback(void *data, struct wl_callback *callback, uint32_t unused)
-{
- struct wayland_parent_output *output = data;
-
- assert(output->sync_cb == callback);
- wl_callback_destroy(callback);
- output->sync_cb = NULL;
-
- assert(output->backend->sprawl_across_outputs);
-
- wayland_head_create_for_parent_output(output->backend->compositor, output);
-}
-
-static const struct wl_callback_listener output_sync_listener = {
- output_sync_callback
-};
-
-static void
-wayland_backend_register_output(struct wayland_backend *b, uint32_t id)
-{
- struct wayland_parent_output *output;
-
- output = zalloc(sizeof *output);
- if (!output)
- return;
-
- output->backend = b;
- output->id = id;
- output->global = wl_registry_bind(b->parent.registry, id,
- &wl_output_interface, 1);
- if (!output->global) {
- free(output);
- return;
- }
-
- wl_output_add_listener(output->global, &output_listener, output);
-
- output->scale = 0;
- output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
- output->physical.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
- wl_list_init(&output->mode_list);
- wl_list_insert(&b->parent.output_list, &output->link);
-
- if (b->sprawl_across_outputs) {
- output->sync_cb = wl_display_sync(b->parent.wl_display);
- wl_callback_add_listener(output->sync_cb,
- &output_sync_listener, output);
- }
-}
-
-static void
-wayland_parent_output_destroy(struct wayland_parent_output *output)
-{
- struct weston_mode *mode, *next;
-
- if (output->sync_cb)
- wl_callback_destroy(output->sync_cb);
-
- if (output->head)
- wayland_head_destroy(output->head);
-
- wl_output_destroy(output->global);
- free(output->physical.make);
- free(output->physical.model);
-
- wl_list_for_each_safe(mode, next, &output->mode_list, link) {
- wl_list_remove(&mode->link);
- free(mode);
- }
-
- wl_list_remove(&output->link);
- free(output);
-}
-
-static void
-xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial)
-{
- xdg_wm_base_pong(shell, serial);
-}
-
-static const struct xdg_wm_base_listener wm_base_listener = {
- xdg_wm_base_ping,
-};
-
-static void
-registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
- const char *interface, uint32_t version)
-{
- struct wayland_backend *b = data;
-
- if (strcmp(interface, "wl_compositor") == 0) {
- b->parent.compositor =
- wl_registry_bind(registry, name,
- &wl_compositor_interface,
- MIN(version, 4));
- } else if (strcmp(interface, "xdg_wm_base") == 0) {
- b->parent.xdg_wm_base =
- wl_registry_bind(registry, name,
- &xdg_wm_base_interface, 1);
- xdg_wm_base_add_listener(b->parent.xdg_wm_base,
- &wm_base_listener, b);
- } else if (strcmp(interface, "wl_shell") == 0) {
- b->parent.shell =
- wl_registry_bind(registry, name,
- &wl_shell_interface, 1);
- } else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0) {
- b->parent.fshell =
- wl_registry_bind(registry, name,
- &zwp_fullscreen_shell_v1_interface, 1);
- } else if (strcmp(interface, "wl_seat") == 0) {
- display_add_seat(b, name, version);
- } else if (strcmp(interface, "wl_output") == 0) {
- wayland_backend_register_output(b, name);
- } else if (strcmp(interface, "wl_shm") == 0) {
- b->parent.shm =
- wl_registry_bind(registry, name, &wl_shm_interface, 1);
- }
-}
-
-static void
-registry_handle_global_remove(void *data, struct wl_registry *registry,
- uint32_t name)
-{
- struct wayland_backend *b = data;
- struct wayland_parent_output *output, *next;
-
- wl_list_for_each_safe(output, next, &b->parent.output_list, link)
- if (output->id == name)
- wayland_parent_output_destroy(output);
-}
-
-static const struct wl_registry_listener registry_listener = {
- registry_handle_global,
- registry_handle_global_remove
-};
-
-static int
-wayland_backend_handle_event(int fd, uint32_t mask, void *data)
-{
- struct wayland_backend *b = data;
- int count = 0;
-
- if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) {
- weston_compositor_exit(b->compositor);
- return 0;
- }
-
- if (mask & WL_EVENT_READABLE)
- count = wl_display_dispatch(b->parent.wl_display);
- if (mask & WL_EVENT_WRITABLE)
- wl_display_flush(b->parent.wl_display);
-
- if (mask == 0) {
- count = wl_display_dispatch_pending(b->parent.wl_display);
- wl_display_flush(b->parent.wl_display);
- }
-
- return count;
-}
-
-static void
-wayland_destroy(struct weston_compositor *ec)
-{
- struct wayland_backend *b = to_wayland_backend(ec);
- struct weston_head *base, *next;
-
- wl_event_source_remove(b->parent.wl_source);
-
- weston_compositor_shutdown(ec);
-
- wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
- wayland_head_destroy(to_wayland_head(base));
-
- if (b->parent.shm)
- wl_shm_destroy(b->parent.shm);
-
- if (b->parent.xdg_wm_base)
- xdg_wm_base_destroy(b->parent.xdg_wm_base);
-
- if (b->parent.shell)
- wl_shell_destroy(b->parent.shell);
-
- if (b->parent.fshell)
- zwp_fullscreen_shell_v1_release(b->parent.fshell);
-
- if (b->parent.compositor)
- wl_compositor_destroy(b->parent.compositor);
-
- if (b->theme)
- theme_destroy(b->theme);
-
- if (b->frame_device)
- cairo_device_destroy(b->frame_device);
-
- wl_cursor_theme_destroy(b->cursor_theme);
-
- wl_registry_destroy(b->parent.registry);
- wl_display_flush(b->parent.wl_display);
- wl_display_disconnect(b->parent.wl_display);
-
- free(b);
-}
-
-static const char *left_ptrs[] = {
- "left_ptr",
- "default",
- "top_left_arrow",
- "left-arrow"
-};
-
-static void
-create_cursor(struct wayland_backend *b,
- struct weston_wayland_backend_config *config)
-{
- unsigned int i;
-
- b->cursor_theme = wl_cursor_theme_load(config->cursor_theme,
- config->cursor_size,
- b->parent.shm);
- if (!b->cursor_theme) {
- fprintf(stderr, "could not load cursor theme\n");
- return;
- }
-
- b->cursor = NULL;
- for (i = 0; !b->cursor && i < ARRAY_LENGTH(left_ptrs); ++i)
- b->cursor = wl_cursor_theme_get_cursor(b->cursor_theme,
- left_ptrs[i]);
- if (!b->cursor) {
- fprintf(stderr, "could not load left cursor\n");
- return;
- }
-}
-
-static void
-fullscreen_binding(struct weston_keyboard *keyboard,
- const struct timespec *time, uint32_t key, void *data)
-{
- struct wayland_backend *b = data;
- struct wayland_input *input = NULL;
-
- wl_list_for_each(input, &b->input_list, link)
- if (&input->base == keyboard->seat)
- break;
-
- if (!input || !input->output)
- return;
-
- if (input->output->frame)
- wayland_output_set_fullscreen(input->output, 0, 0, NULL);
- else
- wayland_output_set_windowed(input->output);
-
- weston_output_schedule_repaint(&input->output->base);
-}
-
-static struct wayland_backend *
-wayland_backend_create(struct weston_compositor *compositor,
- struct weston_wayland_backend_config *new_config)
-{
- struct wayland_backend *b;
- struct wl_event_loop *loop;
- int fd;
-
- b = zalloc(sizeof *b);
- if (b == NULL)
- return NULL;
-
- b->compositor = compositor;
- compositor->backend = &b->base;
-
- if (weston_compositor_set_presentation_clock_software(compositor) < 0)
- goto err_compositor;
-
- b->parent.wl_display = wl_display_connect(new_config->display_name);
- if (b->parent.wl_display == NULL) {
- weston_log("Error: Failed to connect to parent Wayland compositor: %s\n",
- strerror(errno));
- weston_log_continue(STAMP_SPACE "display option: %s, WAYLAND_DISPLAY=%s\n",
- new_config->display_name ?: "(none)",
- getenv("WAYLAND_DISPLAY") ?: "(not set)");
- goto err_compositor;
- }
-
- wl_list_init(&b->parent.output_list);
- wl_list_init(&b->input_list);
- b->parent.registry = wl_display_get_registry(b->parent.wl_display);
- wl_registry_add_listener(b->parent.registry, &registry_listener, b);
- wl_display_roundtrip(b->parent.wl_display);
-
- create_cursor(b, new_config);
-
-#ifdef ENABLE_EGL
- b->use_pixman = new_config->use_pixman;
-#else
- b->use_pixman = true;
-#endif
- b->fullscreen = new_config->fullscreen;
-
- if (!b->use_pixman) {
- gl_renderer = weston_load_module("gl-renderer.so",
- "gl_renderer_interface");
- if (!gl_renderer)
- b->use_pixman = true;
- }
-
- if (!b->use_pixman) {
- if (gl_renderer->display_create(compositor,
- EGL_PLATFORM_WAYLAND_KHR,
- b->parent.wl_display,
- EGL_WINDOW_BIT,
- wayland_formats,
- ARRAY_LENGTH(wayland_formats)) < 0) {
- weston_log("Failed to initialize the GL renderer; "
- "falling back to pixman.\n");
- b->use_pixman = true;
- }
- }
-
- if (b->use_pixman) {
- if (pixman_renderer_init(compositor) < 0) {
- weston_log("Failed to initialize pixman renderer\n");
- goto err_display;
- }
- }
-
- b->base.destroy = wayland_destroy;
- b->base.create_output = wayland_output_create;
-
- loop = wl_display_get_event_loop(compositor->wl_display);
-
- fd = wl_display_get_fd(b->parent.wl_display);
- b->parent.wl_source =
- wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
- wayland_backend_handle_event, b);
- if (b->parent.wl_source == NULL)
- goto err_display;
-
- wl_event_source_check(b->parent.wl_source);
-
- if (compositor->renderer->import_dmabuf) {
- if (linux_dmabuf_setup(compositor) < 0)
- weston_log("Error: initializing dmabuf "
- "support failed.\n");
- }
-
- return b;
-err_display:
- wl_display_disconnect(b->parent.wl_display);
-err_compositor:
- weston_compositor_shutdown(compositor);
- free(b);
- return NULL;
-}
-
-static void
-wayland_backend_destroy(struct wayland_backend *b)
-{
- wl_display_disconnect(b->parent.wl_display);
-
- if (b->theme)
- theme_destroy(b->theme);
- if (b->frame_device)
- cairo_device_destroy(b->frame_device);
- wl_cursor_theme_destroy(b->cursor_theme);
-
- weston_compositor_shutdown(b->compositor);
- free(b);
-}
-
-static const struct weston_windowed_output_api windowed_api = {
- wayland_output_set_size,
- wayland_head_create_windowed,
-};
-
-static void
-config_init_to_defaults(struct weston_wayland_backend_config *config)
-{
-}
-
-WL_EXPORT int
-weston_backend_init(struct weston_compositor *compositor,
- struct weston_backend_config *config_base)
-{
- struct wayland_backend *b;
- struct wayland_parent_output *poutput;
- struct weston_wayland_backend_config new_config;
- int ret;
-
- if (config_base == NULL ||
- config_base->struct_version != WESTON_WAYLAND_BACKEND_CONFIG_VERSION ||
- config_base->struct_size > sizeof(struct weston_wayland_backend_config)) {
- weston_log("wayland backend config structure is invalid\n");
- return -1;
- }
-
- config_init_to_defaults(&new_config);
- memcpy(&new_config, config_base, config_base->struct_size);
-
- b = wayland_backend_create(compositor, &new_config);
-
- if (!b)
- return -1;
-
- if (new_config.sprawl || b->parent.fshell) {
- b->sprawl_across_outputs = true;
- wl_display_roundtrip(b->parent.wl_display);
-
- wl_list_for_each(poutput, &b->parent.output_list, link)
- wayland_head_create_for_parent_output(compositor, poutput);
-
- return 0;
- }
-
- if (new_config.fullscreen) {
- if (!wayland_head_create(compositor, "wayland-fullscreen")) {
- weston_log("Unable to create a fullscreen head.\n");
- goto err_outputs;
- }
-
- return 0;
- }
-
- ret = weston_plugin_api_register(compositor, WESTON_WINDOWED_OUTPUT_API_NAME,
- &windowed_api, sizeof(windowed_api));
-
- if (ret < 0) {
- weston_log("Failed to register output API.\n");
- wayland_backend_destroy(b);
- return -1;
- }
-
- weston_compositor_add_key_binding(compositor, KEY_F,
- MODIFIER_CTRL | MODIFIER_ALT,
- fullscreen_binding, b);
- return 0;
-
-err_outputs:
- wayland_backend_destroy(b);
- return -1;
-}
diff --git a/libweston/backend-x11/meson.build b/libweston/backend-x11/meson.build
deleted file mode 100644
index 3e6ca54f..00000000
--- a/libweston/backend-x11/meson.build
+++ /dev/null
@@ -1,58 +0,0 @@
-
-if not get_option('backend-x11')
- subdir_done()
-endif
-
-config_h.set('BUILD_X11_COMPOSITOR', '1')
-
-srcs_x11 = [
- 'x11.c',
- presentation_time_server_protocol_h,
-]
-
-dep_x11_xcb = dependency('xcb', version: '>= 1.8', required: false)
-if not dep_x11_xcb.found()
- error('x11-backend requires xcb >= 1.8 which was not found. Or, you can use \'-Dbackend-x11=false\'.')
-endif
-
-deps_x11 = [
- dep_libweston_private,
- dep_libdrm_headers,
- dep_x11_xcb,
- dep_lib_cairo_shared,
- dep_pixman,
-]
-
-foreach name : [ 'xcb-shm', 'x11', 'x11-xcb' ]
- d = dependency(name, required: false)
- if not d.found()
- error('x11-backend requires @0@ which was not found. Or, you can use \'-Dbackend-x11=false\'.'.format(name))
- endif
- deps_x11 += d
-endforeach
-
-dep_xcb_xkb = dependency('xcb-xkb', version: '>= 1.9', required: false)
-if dep_xcb_xkb.found()
- deps_x11 += dep_xcb_xkb
- config_h.set('HAVE_XCB_XKB', '1')
-endif
-
-if get_option('renderer-gl')
- if not dep_egl.found()
- error('x11-backend + gl-renderer requires egl which was not found. Or, you can use \'-Dbackend-x11=false\' or \'-Drenderer-gl=false\'.')
- endif
- deps_x11 += dep_egl
-endif
-
-plugin_x11 = shared_library(
- 'x11-backend',
- srcs_x11,
- include_directories: common_inc,
- dependencies: deps_x11,
- name_prefix: '',
- install: true,
- install_dir: dir_module_libweston
-)
-env_modmap += 'x11-backend.so=@0@;'.format(plugin_x11.full_path())
-
-install_headers(backend_x11_h, subdir: dir_include_libweston_install)
diff --git a/libweston/backend-x11/x11.c b/libweston/backend-x11/x11.c
deleted file mode 100644
index 5fda0568..00000000
--- a/libweston/backend-x11/x11.c
+++ /dev/null
@@ -1,1959 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2010-2011 Intel Corporation
- * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <sys/shm.h>
-#include <linux/input.h>
-
-#include <drm_fourcc.h>
-#include <xcb/xcb.h>
-#include <xcb/shm.h>
-#ifdef HAVE_XCB_XKB
-#include <xcb/xkb.h>
-#endif
-
-#include <X11/Xlib.h>
-#include <X11/Xlib-xcb.h>
-
-#include <xkbcommon/xkbcommon.h>
-
-#include <libweston/libweston.h>
-#include <libweston/backend-x11.h>
-#include "shared/helpers.h"
-#include "shared/image-loader.h"
-#include "shared/timespec-util.h"
-#include "shared/file-util.h"
-#include "renderer-gl/gl-renderer.h"
-#include "shared/weston-egl-ext.h"
-#include "pixman-renderer.h"
-#include "presentation-time-server-protocol.h"
-#include "linux-dmabuf.h"
-#include "linux-explicit-synchronization.h"
-#include <libweston/windowed-output-api.h>
-
-#define DEFAULT_AXIS_STEP_DISTANCE 10
-
-#define WINDOW_MIN_WIDTH 128
-#define WINDOW_MIN_HEIGHT 128
-
-#define WINDOW_MAX_WIDTH 8192
-#define WINDOW_MAX_HEIGHT 8192
-
-static const uint32_t x11_formats[] = {
- DRM_FORMAT_XRGB8888,
-};
-
-struct x11_backend {
- struct weston_backend base;
- struct weston_compositor *compositor;
-
- Display *dpy;
- xcb_connection_t *conn;
- xcb_screen_t *screen;
- xcb_cursor_t null_cursor;
- struct wl_array keys;
- struct wl_event_source *xcb_source;
- struct xkb_keymap *xkb_keymap;
- unsigned int has_xkb;
- uint8_t xkb_event_base;
- int fullscreen;
- int no_input;
- int use_pixman;
-
- int has_net_wm_state_fullscreen;
-
- /* We could map multi-pointer X to multiple wayland seats, but
- * for now we only support core X input. */
- struct weston_seat core_seat;
- double prev_x;
- double prev_y;
-
- struct {
- xcb_atom_t wm_protocols;
- xcb_atom_t wm_normal_hints;
- xcb_atom_t wm_size_hints;
- xcb_atom_t wm_delete_window;
- xcb_atom_t wm_class;
- xcb_atom_t net_wm_name;
- xcb_atom_t net_supporting_wm_check;
- xcb_atom_t net_supported;
- xcb_atom_t net_wm_icon;
- xcb_atom_t net_wm_state;
- xcb_atom_t net_wm_state_fullscreen;
- xcb_atom_t string;
- xcb_atom_t utf8_string;
- xcb_atom_t cardinal;
- xcb_atom_t xkb_names;
- } atom;
-};
-
-struct x11_head {
- struct weston_head base;
-};
-
-struct x11_output {
- struct weston_output base;
-
- xcb_window_t window;
- struct weston_mode mode;
- struct weston_mode native;
- struct wl_event_source *finish_frame_timer;
-
- xcb_gc_t gc;
- xcb_shm_seg_t segment;
- pixman_image_t *hw_surface;
- int shm_id;
- void *buf;
- uint8_t depth;
- int32_t scale;
- bool resize_pending;
- bool window_resized;
-};
-
-struct window_delete_data {
- struct x11_backend *backend;
- xcb_window_t window;
-};
-
-struct gl_renderer_interface *gl_renderer;
-
-static inline struct x11_head *
-to_x11_head(struct weston_head *base)
-{
- return container_of(base, struct x11_head, base);
-}
-
-static inline struct x11_output *
-to_x11_output(struct weston_output *base)
-{
- return container_of(base, struct x11_output, base);
-}
-
-static inline struct x11_backend *
-to_x11_backend(struct weston_compositor *base)
-{
- return container_of(base->backend, struct x11_backend, base);
-}
-
-static xcb_screen_t *
-x11_compositor_get_default_screen(struct x11_backend *b)
-{
- xcb_screen_iterator_t iter;
- int i, screen_nbr = XDefaultScreen(b->dpy);
-
- iter = xcb_setup_roots_iterator(xcb_get_setup(b->conn));
- for (i = 0; iter.rem; xcb_screen_next(&iter), i++)
- if (i == screen_nbr)
- return iter.data;
-
- return xcb_setup_roots_iterator(xcb_get_setup(b->conn)).data;
-}
-
-static struct xkb_keymap *
-x11_backend_get_keymap(struct x11_backend *b)
-{
- xcb_get_property_cookie_t cookie;
- xcb_get_property_reply_t *reply;
- struct xkb_rule_names names;
- struct xkb_keymap *ret;
- const char *value_all, *value_part;
- int length_all, length_part;
-
- memset(&names, 0, sizeof(names));
-
- cookie = xcb_get_property(b->conn, 0, b->screen->root,
- b->atom.xkb_names, b->atom.string, 0, 1024);
- reply = xcb_get_property_reply(b->conn, cookie, NULL);
- if (reply == NULL)
- return NULL;
-
- value_all = xcb_get_property_value(reply);
- length_all = xcb_get_property_value_length(reply);
- value_part = value_all;
-
-#define copy_prop_value(to) \
- length_part = strlen(value_part); \
- if (value_part + length_part < (value_all + length_all) && \
- length_part > 0) \
- names.to = value_part; \
- value_part += length_part + 1;
-
- copy_prop_value(rules);
- copy_prop_value(model);
- copy_prop_value(layout);
- copy_prop_value(variant);
- copy_prop_value(options);
-#undef copy_prop_value
-
- ret = xkb_keymap_new_from_names(b->compositor->xkb_context, &names, 0);
-
- free(reply);
- return ret;
-}
-
-static uint32_t
-get_xkb_mod_mask(struct x11_backend *b, uint32_t in)
-{
- struct weston_keyboard *keyboard =
- weston_seat_get_keyboard(&b->core_seat);
- struct weston_xkb_info *info = keyboard->xkb_info;
- uint32_t ret = 0;
-
- if ((in & ShiftMask) && info->shift_mod != XKB_MOD_INVALID)
- ret |= (1 << info->shift_mod);
- if ((in & LockMask) && info->caps_mod != XKB_MOD_INVALID)
- ret |= (1 << info->caps_mod);
- if ((in & ControlMask) && info->ctrl_mod != XKB_MOD_INVALID)
- ret |= (1 << info->ctrl_mod);
- if ((in & Mod1Mask) && info->alt_mod != XKB_MOD_INVALID)
- ret |= (1 << info->alt_mod);
- if ((in & Mod2Mask) && info->mod2_mod != XKB_MOD_INVALID)
- ret |= (1 << info->mod2_mod);
- if ((in & Mod3Mask) && info->mod3_mod != XKB_MOD_INVALID)
- ret |= (1 << info->mod3_mod);
- if ((in & Mod4Mask) && info->super_mod != XKB_MOD_INVALID)
- ret |= (1 << info->super_mod);
- if ((in & Mod5Mask) && info->mod5_mod != XKB_MOD_INVALID)
- ret |= (1 << info->mod5_mod);
-
- return ret;
-}
-
-static void
-x11_backend_setup_xkb(struct x11_backend *b)
-{
-#ifndef HAVE_XCB_XKB
- weston_log("XCB-XKB not available during build\n");
- b->has_xkb = 0;
- b->xkb_event_base = 0;
- return;
-#else
- struct weston_keyboard *keyboard;
- const xcb_query_extension_reply_t *ext;
- xcb_generic_error_t *error;
- xcb_void_cookie_t select;
- xcb_xkb_use_extension_cookie_t use_ext;
- xcb_xkb_use_extension_reply_t *use_ext_reply;
- xcb_xkb_per_client_flags_cookie_t pcf;
- xcb_xkb_per_client_flags_reply_t *pcf_reply;
- xcb_xkb_get_state_cookie_t state;
- xcb_xkb_get_state_reply_t *state_reply;
- uint32_t values[1] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
-
- b->has_xkb = 0;
- b->xkb_event_base = 0;
-
- ext = xcb_get_extension_data(b->conn, &xcb_xkb_id);
- if (!ext) {
- weston_log("XKB extension not available on host X11 server\n");
- return;
- }
- b->xkb_event_base = ext->first_event;
-
- select = xcb_xkb_select_events_checked(b->conn,
- XCB_XKB_ID_USE_CORE_KBD,
- XCB_XKB_EVENT_TYPE_STATE_NOTIFY,
- 0,
- XCB_XKB_EVENT_TYPE_STATE_NOTIFY,
- 0,
- 0,
- NULL);
- error = xcb_request_check(b->conn, select);
- if (error) {
- weston_log("error: failed to select for XKB state events\n");
- free(error);
- return;
- }
-
- use_ext = xcb_xkb_use_extension(b->conn,
- XCB_XKB_MAJOR_VERSION,
- XCB_XKB_MINOR_VERSION);
- use_ext_reply = xcb_xkb_use_extension_reply(b->conn, use_ext, NULL);
- if (!use_ext_reply) {
- weston_log("couldn't start using XKB extension\n");
- return;
- }
-
- if (!use_ext_reply->supported) {
- weston_log("XKB extension version on the server is too old "
- "(want %d.%d, has %d.%d)\n",
- XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION,
- use_ext_reply->serverMajor, use_ext_reply->serverMinor);
- free(use_ext_reply);
- return;
- }
- free(use_ext_reply);
-
- pcf = xcb_xkb_per_client_flags(b->conn,
- XCB_XKB_ID_USE_CORE_KBD,
- XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
- XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
- 0,
- 0,
- 0);
- pcf_reply = xcb_xkb_per_client_flags_reply(b->conn, pcf, NULL);
- if (!pcf_reply ||
- !(pcf_reply->value & XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT)) {
- weston_log("failed to set XKB per-client flags, not using "
- "detectable repeat\n");
- free(pcf_reply);
- return;
- }
- free(pcf_reply);
-
- state = xcb_xkb_get_state(b->conn, XCB_XKB_ID_USE_CORE_KBD);
- state_reply = xcb_xkb_get_state_reply(b->conn, state, NULL);
- if (!state_reply) {
- weston_log("failed to get initial XKB state\n");
- return;
- }
-
- keyboard = weston_seat_get_keyboard(&b->core_seat);
- xkb_state_update_mask(keyboard->xkb_state.state,
- get_xkb_mod_mask(b, state_reply->baseMods),
- get_xkb_mod_mask(b, state_reply->latchedMods),
- get_xkb_mod_mask(b, state_reply->lockedMods),
- 0,
- 0,
- state_reply->group);
-
- free(state_reply);
-
- xcb_change_window_attributes(b->conn, b->screen->root,
- XCB_CW_EVENT_MASK, values);
-
- b->has_xkb = 1;
-#endif
-}
-
-#ifdef HAVE_XCB_XKB
-static void
-update_xkb_keymap(struct x11_backend *b)
-{
- struct xkb_keymap *keymap;
-
- keymap = x11_backend_get_keymap(b);
- if (!keymap) {
- weston_log("failed to get XKB keymap\n");
- return;
- }
- weston_seat_update_keymap(&b->core_seat, keymap);
- xkb_keymap_unref(keymap);
-}
-#endif
-
-static int
-x11_input_create(struct x11_backend *b, int no_input)
-{
- struct xkb_keymap *keymap;
-
- weston_seat_init(&b->core_seat, b->compositor, "default");
-
- if (no_input)
- return 0;
-
- weston_seat_init_pointer(&b->core_seat);
-
- keymap = x11_backend_get_keymap(b);
- if (weston_seat_init_keyboard(&b->core_seat, keymap) < 0)
- return -1;
- xkb_keymap_unref(keymap);
-
- x11_backend_setup_xkb(b);
-
- return 0;
-}
-
-static void
-x11_input_destroy(struct x11_backend *b)
-{
- weston_seat_release(&b->core_seat);
-}
-
-static int
-x11_output_start_repaint_loop(struct weston_output *output)
-{
- struct timespec ts;
-
- weston_compositor_read_presentation_clock(output->compositor, &ts);
- weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
-
- return 0;
-}
-
-static int
-x11_output_repaint_gl(struct weston_output *output_base,
- pixman_region32_t *damage,
- void *repaint_data)
-{
- struct x11_output *output = to_x11_output(output_base);
- struct weston_compositor *ec = output->base.compositor;
-
- ec->renderer->repaint_output(output_base, damage);
-
- pixman_region32_subtract(&ec->primary_plane.damage,
- &ec->primary_plane.damage, damage);
-
- wl_event_source_timer_update(output->finish_frame_timer, 10);
- return 0;
-}
-
-static void
-set_clip_for_output(struct weston_output *output_base, pixman_region32_t *region)
-{
- struct x11_output *output = to_x11_output(output_base);
- struct weston_compositor *ec = output->base.compositor;
- struct x11_backend *b = to_x11_backend(ec);
- pixman_region32_t transformed_region;
- pixman_box32_t *rects;
- xcb_rectangle_t *output_rects;
- xcb_void_cookie_t cookie;
- int nrects, i;
- xcb_generic_error_t *err;
-
- pixman_region32_init(&transformed_region);
- pixman_region32_copy(&transformed_region, region);
- pixman_region32_translate(&transformed_region,
- -output_base->x, -output_base->y);
- weston_transformed_region(output_base->width, output_base->height,
- output_base->transform,
- output_base->current_scale,
- &transformed_region, &transformed_region);
-
- rects = pixman_region32_rectangles(&transformed_region, &nrects);
- output_rects = calloc(nrects, sizeof(xcb_rectangle_t));
-
- if (output_rects == NULL) {
- pixman_region32_fini(&transformed_region);
- return;
- }
-
- for (i = 0; i < nrects; i++) {
- output_rects[i].x = rects[i].x1;
- output_rects[i].y = rects[i].y1;
- output_rects[i].width = rects[i].x2 - rects[i].x1;
- output_rects[i].height = rects[i].y2 - rects[i].y1;
- }
-
- pixman_region32_fini(&transformed_region);
-
- cookie = xcb_set_clip_rectangles_checked(b->conn, XCB_CLIP_ORDERING_UNSORTED,
- output->gc,
- 0, 0, nrects,
- output_rects);
- err = xcb_request_check(b->conn, cookie);
- if (err != NULL) {
- weston_log("Failed to set clip rects, err: %d\n", err->error_code);
- free(err);
- }
- free(output_rects);
-}
-
-
-static int
-x11_output_repaint_shm(struct weston_output *output_base,
- pixman_region32_t *damage,
- void *repaint_data)
-{
- struct x11_output *output = to_x11_output(output_base);
- struct weston_compositor *ec = output->base.compositor;
- struct x11_backend *b = to_x11_backend(ec);
- xcb_void_cookie_t cookie;
- xcb_generic_error_t *err;
-
- pixman_renderer_output_set_buffer(output_base, output->hw_surface);
- ec->renderer->repaint_output(output_base, damage);
-
- pixman_region32_subtract(&ec->primary_plane.damage,
- &ec->primary_plane.damage, damage);
- set_clip_for_output(output_base, damage);
- cookie = xcb_shm_put_image_checked(b->conn, output->window, output->gc,
- pixman_image_get_width(output->hw_surface),
- pixman_image_get_height(output->hw_surface),
- 0, 0,
- pixman_image_get_width(output->hw_surface),
- pixman_image_get_height(output->hw_surface),
- 0, 0, output->depth, XCB_IMAGE_FORMAT_Z_PIXMAP,
- 0, output->segment, 0);
- err = xcb_request_check(b->conn, cookie);
- if (err != NULL) {
- weston_log("Failed to put shm image, err: %d\n", err->error_code);
- free(err);
- }
-
- wl_event_source_timer_update(output->finish_frame_timer, 10);
- return 0;
-}
-
-static int
-finish_frame_handler(void *data)
-{
- struct x11_output *output = data;
- struct timespec ts;
-
- weston_compositor_read_presentation_clock(output->base.compositor, &ts);
- weston_output_finish_frame(&output->base, &ts, 0);
-
- return 1;
-}
-
-static void
-x11_output_deinit_shm(struct x11_backend *b, struct x11_output *output)
-{
- xcb_void_cookie_t cookie;
- xcb_generic_error_t *err;
- xcb_free_gc(b->conn, output->gc);
-
- pixman_image_unref(output->hw_surface);
- output->hw_surface = NULL;
- cookie = xcb_shm_detach_checked(b->conn, output->segment);
- err = xcb_request_check(b->conn, cookie);
- if (err) {
- weston_log("xcb_shm_detach failed, error %d\n", err->error_code);
- free(err);
- }
- shmdt(output->buf);
-}
-
-static void
-x11_output_set_wm_protocols(struct x11_backend *b,
- struct x11_output *output)
-{
- xcb_atom_t list[1];
-
- list[0] = b->atom.wm_delete_window;
- xcb_change_property (b->conn,
- XCB_PROP_MODE_REPLACE,
- output->window,
- b->atom.wm_protocols,
- XCB_ATOM_ATOM,
- 32,
- ARRAY_LENGTH(list),
- list);
-}
-
-struct wm_normal_hints {
- uint32_t flags;
- uint32_t pad[4];
- int32_t min_width, min_height;
- int32_t max_width, max_height;
- int32_t width_inc, height_inc;
- int32_t min_aspect_x, min_aspect_y;
- int32_t max_aspect_x, max_aspect_y;
- int32_t base_width, base_height;
- int32_t win_gravity;
-};
-
-#define WM_NORMAL_HINTS_MIN_SIZE 16
-#define WM_NORMAL_HINTS_MAX_SIZE 32
-
-static void
-x11_output_set_icon(struct x11_backend *b,
- struct x11_output *output, const char *filename)
-{
- uint32_t *icon;
- int32_t width, height;
- pixman_image_t *image;
-
- image = load_image(filename);
- if (!image)
- return;
- width = pixman_image_get_width(image);
- height = pixman_image_get_height(image);
- icon = malloc(width * height * 4 + 8);
- if (!icon) {
- pixman_image_unref(image);
- return;
- }
-
- icon[0] = width;
- icon[1] = height;
- memcpy(icon + 2, pixman_image_get_data(image), width * height * 4);
- xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window,
- b->atom.net_wm_icon, b->atom.cardinal, 32,
- width * height + 2, icon);
- free(icon);
- pixman_image_unref(image);
-}
-
-static void
-x11_output_wait_for_map(struct x11_backend *b, struct x11_output *output)
-{
- xcb_map_notify_event_t *map_notify;
- xcb_configure_notify_event_t *configure_notify;
- xcb_generic_event_t *event;
- int mapped = 0, configured = 0;
- uint8_t response_type;
-
- /* This isn't the nicest way to do this. Ideally, we could
- * just go back to the main loop and once we get the configure
- * notify, we add the output to the compositor. While we do
- * support output hotplug, we can't start up with no outputs.
- * We could add the output and then resize once we get the
- * configure notify, but we don't want to start up and
- * immediately resize the output.
- *
- * Also, some window managers don't give us our final
- * fullscreen size before map_notify, so if we don't get a
- * configure_notify before map_notify, we just wait for the
- * first one and hope that's our size. */
-
- xcb_flush(b->conn);
-
- while (!mapped || !configured) {
- event = xcb_wait_for_event(b->conn);
- response_type = event->response_type & ~0x80;
-
- switch (response_type) {
- case XCB_MAP_NOTIFY:
- map_notify = (xcb_map_notify_event_t *) event;
- if (map_notify->window == output->window)
- mapped = 1;
- break;
-
- case XCB_CONFIGURE_NOTIFY:
- configure_notify =
- (xcb_configure_notify_event_t *) event;
-
-
- if (configure_notify->width % output->scale != 0 ||
- configure_notify->height % output->scale != 0)
- weston_log("Resolution is not a multiple of screen size, rounding\n");
- output->mode.width = configure_notify->width;
- output->mode.height = configure_notify->height;
- configured = 1;
- break;
- }
- }
-}
-
-static xcb_visualtype_t *
-find_visual_by_id(xcb_screen_t *screen,
- xcb_visualid_t id)
-{
- xcb_depth_iterator_t i;
- xcb_visualtype_iterator_t j;
- for (i = xcb_screen_allowed_depths_iterator(screen);
- i.rem;
- xcb_depth_next(&i)) {
- for (j = xcb_depth_visuals_iterator(i.data);
- j.rem;
- xcb_visualtype_next(&j)) {
- if (j.data->visual_id == id)
- return j.data;
- }
- }
- return 0;
-}
-
-static uint8_t
-get_depth_of_visual(xcb_screen_t *screen,
- xcb_visualid_t id)
-{
- xcb_depth_iterator_t i;
- xcb_visualtype_iterator_t j;
- for (i = xcb_screen_allowed_depths_iterator(screen);
- i.rem;
- xcb_depth_next(&i)) {
- for (j = xcb_depth_visuals_iterator(i.data);
- j.rem;
- xcb_visualtype_next(&j)) {
- if (j.data->visual_id == id)
- return i.data->depth;
- }
- }
- return 0;
-}
-
-static int
-x11_output_init_shm(struct x11_backend *b, struct x11_output *output,
- int width, int height)
-{
- xcb_visualtype_t *visual_type;
- xcb_screen_t *screen;
- xcb_format_iterator_t fmt;
- xcb_void_cookie_t cookie;
- xcb_generic_error_t *err;
- const xcb_query_extension_reply_t *ext;
- int bitsperpixel = 0;
- pixman_format_code_t pixman_format;
-
- /* Check if SHM is available */
- ext = xcb_get_extension_data(b->conn, &xcb_shm_id);
- if (ext == NULL || !ext->present) {
- /* SHM is missing */
- weston_log("SHM extension is not available\n");
- errno = ENOENT;
- return -1;
- }
-
- screen = x11_compositor_get_default_screen(b);
- visual_type = find_visual_by_id(screen, screen->root_visual);
- if (!visual_type) {
- weston_log("Failed to lookup visual for root window\n");
- errno = ENOENT;
- return -1;
- }
- weston_log("Found visual, bits per value: %d, red_mask: %.8x, green_mask: %.8x, blue_mask: %.8x\n",
- visual_type->bits_per_rgb_value,
- visual_type->red_mask,
- visual_type->green_mask,
- visual_type->blue_mask);
- output->depth = get_depth_of_visual(screen, screen->root_visual);
- weston_log("Visual depth is %d\n", output->depth);
-
- for (fmt = xcb_setup_pixmap_formats_iterator(xcb_get_setup(b->conn));
- fmt.rem;
- xcb_format_next(&fmt)) {
- if (fmt.data->depth == output->depth) {
- bitsperpixel = fmt.data->bits_per_pixel;
- break;
- }
- }
- weston_log("Found format for depth %d, bpp: %d\n",
- output->depth, bitsperpixel);
-
- if (bitsperpixel == 32 &&
- visual_type->red_mask == 0xff0000 &&
- visual_type->green_mask == 0x00ff00 &&
- visual_type->blue_mask == 0x0000ff) {
- weston_log("Will use x8r8g8b8 format for SHM surfaces\n");
- pixman_format = PIXMAN_x8r8g8b8;
- } else if (bitsperpixel == 16 &&
- visual_type->red_mask == 0x00f800 &&
- visual_type->green_mask == 0x0007e0 &&
- visual_type->blue_mask == 0x00001f) {
- weston_log("Will use r5g6b5 format for SHM surfaces\n");
- pixman_format = PIXMAN_r5g6b5;
- } else {
- weston_log("Can't find appropriate format for SHM pixmap\n");
- errno = ENOTSUP;
- return -1;
- }
-
-
- /* Create SHM segment and attach it */
- output->shm_id = shmget(IPC_PRIVATE, width * height * (bitsperpixel / 8), IPC_CREAT | S_IRWXU);
- if (output->shm_id == -1) {
- weston_log("x11shm: failed to allocate SHM segment\n");
- return -1;
- }
- output->buf = shmat(output->shm_id, NULL, 0 /* read/write */);
- if (-1 == (long)output->buf) {
- weston_log("x11shm: failed to attach SHM segment\n");
- return -1;
- }
- output->segment = xcb_generate_id(b->conn);
- cookie = xcb_shm_attach_checked(b->conn, output->segment, output->shm_id, 1);
- err = xcb_request_check(b->conn, cookie);
- if (err) {
- weston_log("x11shm: xcb_shm_attach error %d, op code %d, resource id %d\n",
- err->error_code, err->major_code, err->minor_code);
- free(err);
- return -1;
- }
-
- shmctl(output->shm_id, IPC_RMID, NULL);
-
- /* Now create pixman image */
- output->hw_surface = pixman_image_create_bits(pixman_format, width, height, output->buf,
- width * (bitsperpixel / 8));
-
- output->gc = xcb_generate_id(b->conn);
- xcb_create_gc(b->conn, output->gc, output->window, 0, NULL);
-
- return 0;
-}
-
-static int
-x11_output_switch_mode(struct weston_output *base, struct weston_mode *mode)
-{
- struct x11_backend *b;
- struct x11_output *output;
- static uint32_t values[2];
- int ret;
-
- if (base == NULL) {
- weston_log("output is NULL.\n");
- return -1;
- }
-
- if (mode == NULL) {
- weston_log("mode is NULL.\n");
- return -1;
- }
-
- b = to_x11_backend(base->compositor);
- output = to_x11_output(base);
-
- if (mode->width == output->mode.width &&
- mode->height == output->mode.height)
- return 0;
-
- if (mode->width < WINDOW_MIN_WIDTH || mode->width > WINDOW_MAX_WIDTH)
- return -1;
-
- if (mode->height < WINDOW_MIN_HEIGHT || mode->height > WINDOW_MAX_HEIGHT)
- return -1;
-
- /* xcb_configure_window will create an event, and we could end up
- being called twice */
- output->resize_pending = true;
-
- /* window could've been resized by the user, so don't do it twice */
- if (!output->window_resized) {
- values[0] = mode->width;
- values[1] = mode->height;
- xcb_configure_window(b->conn, output->window, XCB_CONFIG_WINDOW_WIDTH |
- XCB_CONFIG_WINDOW_HEIGHT, values);
- }
-
- output->mode.width = mode->width;
- output->mode.height = mode->height;
-
- if (b->use_pixman) {
- pixman_renderer_output_destroy(&output->base);
- x11_output_deinit_shm(b, output);
-
- if (x11_output_init_shm(b, output,
- output->base.current_mode->width,
- output->base.current_mode->height) < 0) {
- weston_log("Failed to initialize SHM for the X11 output\n");
- return -1;
- }
-
- if (pixman_renderer_output_create(&output->base,
- PIXMAN_RENDERER_OUTPUT_USE_SHADOW) < 0) {
- weston_log("Failed to create pixman renderer for output\n");
- x11_output_deinit_shm(b, output);
- return -1;
- }
- } else {
- Window xid = (Window) output->window;
-
- gl_renderer->output_destroy(&output->base);
-
- ret = gl_renderer->output_window_create(&output->base,
- (EGLNativeWindowType) output->window,
- &xid,
- x11_formats,
- ARRAY_LENGTH(x11_formats));
- if (ret < 0)
- return -1;
- }
-
- output->resize_pending = false;
- output->window_resized = false;
-
- return 0;
-}
-
-static int
-x11_output_disable(struct weston_output *base)
-{
- struct x11_output *output = to_x11_output(base);
- struct x11_backend *backend = to_x11_backend(base->compositor);
-
- if (!output->base.enabled)
- return 0;
-
- wl_event_source_remove(output->finish_frame_timer);
-
- if (backend->use_pixman) {
- pixman_renderer_output_destroy(&output->base);
- x11_output_deinit_shm(backend, output);
- } else {
- gl_renderer->output_destroy(&output->base);
- }
-
- xcb_destroy_window(backend->conn, output->window);
- xcb_flush(backend->conn);
-
- return 0;
-}
-
-static void
-x11_output_destroy(struct weston_output *base)
-{
- struct x11_output *output = to_x11_output(base);
-
- x11_output_disable(&output->base);
- weston_output_release(&output->base);
-
- free(output);
-}
-
-static int
-x11_output_enable(struct weston_output *base)
-{
- struct x11_output *output = to_x11_output(base);
- struct x11_backend *b = to_x11_backend(base->compositor);
-
- static const char name[] = "Weston Compositor";
- static const char class[] = "weston-1\0Weston Compositor";
- char *title = NULL;
- xcb_screen_t *screen;
- struct wm_normal_hints normal_hints;
- struct wl_event_loop *loop;
- char *icon_filename;
-
- int ret;
- uint32_t mask = XCB_CW_EVENT_MASK | XCB_CW_CURSOR;
- xcb_atom_t atom_list[1];
- uint32_t values[2] = {
- XCB_EVENT_MASK_EXPOSURE |
- XCB_EVENT_MASK_STRUCTURE_NOTIFY,
- 0
- };
-
- if (!b->no_input)
- values[0] |=
- XCB_EVENT_MASK_KEY_PRESS |
- XCB_EVENT_MASK_KEY_RELEASE |
- XCB_EVENT_MASK_BUTTON_PRESS |
- XCB_EVENT_MASK_BUTTON_RELEASE |
- XCB_EVENT_MASK_POINTER_MOTION |
- XCB_EVENT_MASK_ENTER_WINDOW |
- XCB_EVENT_MASK_LEAVE_WINDOW |
- XCB_EVENT_MASK_KEYMAP_STATE |
- XCB_EVENT_MASK_FOCUS_CHANGE;
-
- values[1] = b->null_cursor;
- output->window = xcb_generate_id(b->conn);
- screen = x11_compositor_get_default_screen(b);
- xcb_create_window(b->conn,
- XCB_COPY_FROM_PARENT,
- output->window,
- screen->root,
- 0, 0,
- output->base.current_mode->width,
- output->base.current_mode->height,
- 0,
- XCB_WINDOW_CLASS_INPUT_OUTPUT,
- screen->root_visual,
- mask, values);
-
- if (b->fullscreen) {
- atom_list[0] = b->atom.net_wm_state_fullscreen;
- xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE,
- output->window,
- b->atom.net_wm_state,
- XCB_ATOM_ATOM, 32,
- ARRAY_LENGTH(atom_list), atom_list);
- } else {
- memset(&normal_hints, 0, sizeof normal_hints);
- normal_hints.flags =
- WM_NORMAL_HINTS_MAX_SIZE | WM_NORMAL_HINTS_MIN_SIZE;
- normal_hints.min_width = WINDOW_MIN_WIDTH;
- normal_hints.min_height = WINDOW_MIN_HEIGHT;
- normal_hints.max_width = WINDOW_MAX_WIDTH;
- normal_hints.max_height = WINDOW_MAX_HEIGHT;
- xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window,
- b->atom.wm_normal_hints,
- b->atom.wm_size_hints, 32,
- sizeof normal_hints / 4,
- (uint8_t *) &normal_hints);
- }
-
- /* Set window name. Don't bother with non-EWMH WMs. */
- if (output->base.name) {
- if (asprintf(&title, "%s - %s", name, output->base.name) < 0)
- title = NULL;
- } else {
- title = strdup(name);
- }
-
- if (title) {
- xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window,
- b->atom.net_wm_name, b->atom.utf8_string, 8,
- strlen(title), title);
- free(title);
- } else {
- goto err;
- }
-
- xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window,
- b->atom.wm_class, b->atom.string, 8,
- sizeof class, class);
-
- icon_filename = file_name_with_datadir("wayland.png");
- x11_output_set_icon(b, output, icon_filename);
- free(icon_filename);
-
- x11_output_set_wm_protocols(b, output);
-
- xcb_map_window(b->conn, output->window);
-
- if (b->fullscreen)
- x11_output_wait_for_map(b, output);
-
- if (b->use_pixman) {
- if (x11_output_init_shm(b, output,
- output->base.current_mode->width,
- output->base.current_mode->height) < 0) {
- weston_log("Failed to initialize SHM for the X11 output\n");
- goto err;
- }
- if (pixman_renderer_output_create(&output->base,
- PIXMAN_RENDERER_OUTPUT_USE_SHADOW) < 0) {
- weston_log("Failed to create pixman renderer for output\n");
- x11_output_deinit_shm(b, output);
- goto err;
- }
-
- output->base.repaint = x11_output_repaint_shm;
- } else {
- /* eglCreatePlatformWindowSurfaceEXT takes a Window*
- * but eglCreateWindowSurface takes a Window. */
- Window xid = (Window) output->window;
-
- ret = gl_renderer->output_window_create(
- &output->base,
- (EGLNativeWindowType) output->window,
- &xid,
- x11_formats,
- ARRAY_LENGTH(x11_formats));
- if (ret < 0)
- goto err;
-
- output->base.repaint = x11_output_repaint_gl;
- }
-
- output->base.start_repaint_loop = x11_output_start_repaint_loop;
- output->base.assign_planes = NULL;
- output->base.set_backlight = NULL;
- output->base.set_dpms = NULL;
- output->base.switch_mode = x11_output_switch_mode;
-
- loop = wl_display_get_event_loop(b->compositor->wl_display);
- output->finish_frame_timer =
- wl_event_loop_add_timer(loop, finish_frame_handler, output);
-
- weston_log("x11 output %dx%d, window id %d\n",
- output->base.current_mode->width,
- output->base.current_mode->height,
- output->window);
-
- return 0;
-
-err:
- xcb_destroy_window(b->conn, output->window);
- xcb_flush(b->conn);
-
- return -1;
-}
-
-static int
-x11_output_set_size(struct weston_output *base, int width, int height)
-{
- struct x11_output *output = to_x11_output(base);
- struct x11_backend *b = to_x11_backend(base->compositor);
- struct weston_head *head;
- xcb_screen_t *scrn = b->screen;
- int output_width, output_height;
-
- /* We can only be called once. */
- assert(!output->base.current_mode);
-
- /* Make sure we have scale set. */
- assert(output->base.scale);
-
- if (width < WINDOW_MIN_WIDTH) {
- weston_log("Invalid width \"%d\" for output %s\n",
- width, output->base.name);
- return -1;
- }
-
- if (height < WINDOW_MIN_HEIGHT) {
- weston_log("Invalid height \"%d\" for output %s\n",
- height, output->base.name);
- return -1;
- }
-
- wl_list_for_each(head, &output->base.head_list, output_link) {
- weston_head_set_monitor_strings(head, "weston-X11", "none", NULL);
- weston_head_set_physical_size(head,
- width * scrn->width_in_millimeters / scrn->width_in_pixels,
- height * scrn->height_in_millimeters / scrn->height_in_pixels);
- }
-
- output_width = width * output->base.scale;
- output_height = height * output->base.scale;
-
- output->mode.flags =
- WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
-
- output->mode.width = output_width;
- output->mode.height = output_height;
- output->mode.refresh = 60000;
- output->native = output->mode;
- output->scale = output->base.scale;
- wl_list_insert(&output->base.mode_list, &output->mode.link);
-
- output->base.current_mode = &output->mode;
- output->base.native_mode = &output->native;
- output->base.native_scale = output->base.scale;
-
- return 0;
-}
-
-static struct weston_output *
-x11_output_create(struct weston_compositor *compositor, const char *name)
-{
- struct x11_output *output;
-
- /* name can't be NULL. */
- assert(name);
-
- output = zalloc(sizeof *output);
- if (!output)
- return NULL;
-
- weston_output_init(&output->base, compositor, name);
-
- output->base.destroy = x11_output_destroy;
- output->base.disable = x11_output_disable;
- output->base.enable = x11_output_enable;
- output->base.attach_head = NULL;
-
- weston_compositor_add_pending_output(&output->base, compositor);
-
- return &output->base;
-}
-
-static int
-x11_head_create(struct weston_compositor *compositor, const char *name)
-{
- struct x11_head *head;
-
- assert(name);
-
- head = zalloc(sizeof *head);
- if (!head)
- return -1;
-
- weston_head_init(&head->base, name);
- weston_head_set_connection_status(&head->base, true);
- weston_compositor_add_head(compositor, &head->base);
-
- return 0;
-}
-
-static void
-x11_head_destroy(struct x11_head *head)
-{
- weston_head_release(&head->base);
- free(head);
-}
-
-static struct x11_output *
-x11_backend_find_output(struct x11_backend *b, xcb_window_t window)
-{
- struct x11_output *output;
-
- wl_list_for_each(output, &b->compositor->output_list, base.link) {
- if (output->window == window)
- return output;
- }
-
- return NULL;
-}
-
-static void
-x11_backend_delete_window(struct x11_backend *b, xcb_window_t window)
-{
- struct x11_output *output;
-
- output = x11_backend_find_output(b, window);
- if (output)
- x11_output_destroy(&output->base);
-
- if (wl_list_empty(&b->compositor->output_list))
- weston_compositor_exit(b->compositor);
-}
-
-static void delete_cb(void *data)
-{
- struct window_delete_data *wd = data;
-
- x11_backend_delete_window(wd->backend, wd->window);
- free(wd);
-}
-
-#ifdef HAVE_XCB_XKB
-static void
-update_xkb_state(struct x11_backend *b, xcb_xkb_state_notify_event_t *state)
-{
- struct weston_keyboard *keyboard =
- weston_seat_get_keyboard(&b->core_seat);
-
- xkb_state_update_mask(keyboard->xkb_state.state,
- get_xkb_mod_mask(b, state->baseMods),
- get_xkb_mod_mask(b, state->latchedMods),
- get_xkb_mod_mask(b, state->lockedMods),
- 0,
- 0,
- state->group);
-
- notify_modifiers(&b->core_seat,
- wl_display_next_serial(b->compositor->wl_display));
-}
-#endif
-
-/**
- * This is monumentally unpleasant. If we don't have XCB-XKB bindings,
- * the best we can do (given that XCB also lacks XI2 support), is to take
- * the state from the core key events. Unfortunately that only gives us
- * the effective (i.e. union of depressed/latched/locked) state, and we
- * need the granularity.
- *
- * So we still update the state with every key event we see, but also use
- * the state field from X11 events as a mask so we don't get any stuck
- * modifiers.
- */
-static void
-update_xkb_state_from_core(struct x11_backend *b, uint16_t x11_mask)
-{
- uint32_t mask = get_xkb_mod_mask(b, x11_mask);
- struct weston_keyboard *keyboard
- = weston_seat_get_keyboard(&b->core_seat);
-
- xkb_state_update_mask(keyboard->xkb_state.state,
- keyboard->modifiers.mods_depressed & mask,
- keyboard->modifiers.mods_latched & mask,
- keyboard->modifiers.mods_locked & mask,
- 0,
- 0,
- (x11_mask >> 13) & 3);
- notify_modifiers(&b->core_seat,
- wl_display_next_serial(b->compositor->wl_display));
-}
-
-static void
-x11_backend_deliver_button_event(struct x11_backend *b,
- xcb_generic_event_t *event)
-{
- xcb_button_press_event_t *button_event =
- (xcb_button_press_event_t *) event;
- uint32_t button;
- struct x11_output *output;
- struct weston_pointer_axis_event weston_event;
- bool is_button_pressed = event->response_type == XCB_BUTTON_PRESS;
- struct timespec time = { 0 };
-
- assert(event->response_type == XCB_BUTTON_PRESS ||
- event->response_type == XCB_BUTTON_RELEASE);
-
- output = x11_backend_find_output(b, button_event->event);
- if (!output)
- return;
-
- if (is_button_pressed)
- xcb_grab_pointer(b->conn, 0, output->window,
- XCB_EVENT_MASK_BUTTON_PRESS |
- XCB_EVENT_MASK_BUTTON_RELEASE |
- XCB_EVENT_MASK_POINTER_MOTION |
- XCB_EVENT_MASK_ENTER_WINDOW |
- XCB_EVENT_MASK_LEAVE_WINDOW,
- XCB_GRAB_MODE_ASYNC,
- XCB_GRAB_MODE_ASYNC,
- output->window, XCB_CURSOR_NONE,
- button_event->time);
- else
- xcb_ungrab_pointer(b->conn, button_event->time);
-
- if (!b->has_xkb)
- update_xkb_state_from_core(b, button_event->state);
-
- switch (button_event->detail) {
- case 1:
- button = BTN_LEFT;
- break;
- case 2:
- button = BTN_MIDDLE;
- break;
- case 3:
- button = BTN_RIGHT;
- break;
- case 4:
- /* Axis are measured in pixels, but the xcb events are discrete
- * steps. Therefore move the axis by some pixels every step. */
- if (is_button_pressed) {
- weston_event.value = -DEFAULT_AXIS_STEP_DISTANCE;
- weston_event.discrete = -1;
- weston_event.has_discrete = true;
- weston_event.axis =
- WL_POINTER_AXIS_VERTICAL_SCROLL;
- weston_compositor_get_time(&time);
- notify_axis(&b->core_seat, &time, &weston_event);
- notify_pointer_frame(&b->core_seat);
- }
- return;
- case 5:
- if (is_button_pressed) {
- weston_event.value = DEFAULT_AXIS_STEP_DISTANCE;
- weston_event.discrete = 1;
- weston_event.has_discrete = true;
- weston_event.axis =
- WL_POINTER_AXIS_VERTICAL_SCROLL;
- weston_compositor_get_time(&time);
- notify_axis(&b->core_seat, &time, &weston_event);
- notify_pointer_frame(&b->core_seat);
- }
- return;
- case 6:
- if (is_button_pressed) {
- weston_event.value = -DEFAULT_AXIS_STEP_DISTANCE;
- weston_event.discrete = -1;
- weston_event.has_discrete = true;
- weston_event.axis =
- WL_POINTER_AXIS_HORIZONTAL_SCROLL;
- weston_compositor_get_time(&time);
- notify_axis(&b->core_seat, &time, &weston_event);
- notify_pointer_frame(&b->core_seat);
- }
- return;
- case 7:
- if (is_button_pressed) {
- weston_event.value = DEFAULT_AXIS_STEP_DISTANCE;
- weston_event.discrete = 1;
- weston_event.has_discrete = true;
- weston_event.axis =
- WL_POINTER_AXIS_HORIZONTAL_SCROLL;
- weston_compositor_get_time(&time);
- notify_axis(&b->core_seat, &time, &weston_event);
- notify_pointer_frame(&b->core_seat);
- }
- return;
- default:
- button = button_event->detail + BTN_SIDE - 8;
- break;
- }
-
- weston_compositor_get_time(&time);
-
- notify_button(&b->core_seat, &time, button,
- is_button_pressed ? WL_POINTER_BUTTON_STATE_PRESSED :
- WL_POINTER_BUTTON_STATE_RELEASED);
- notify_pointer_frame(&b->core_seat);
-}
-
-static void
-x11_backend_deliver_motion_event(struct x11_backend *b,
- xcb_generic_event_t *event)
-{
- struct x11_output *output;
- double x, y;
- struct weston_pointer_motion_event motion_event = { 0 };
- xcb_motion_notify_event_t *motion_notify =
- (xcb_motion_notify_event_t *) event;
- struct timespec time;
-
- if (!b->has_xkb)
- update_xkb_state_from_core(b, motion_notify->state);
- output = x11_backend_find_output(b, motion_notify->event);
- if (!output)
- return;
-
- weston_output_transform_coordinate(&output->base,
- motion_notify->event_x,
- motion_notify->event_y,
- &x, &y);
-
- motion_event = (struct weston_pointer_motion_event) {
- .mask = WESTON_POINTER_MOTION_REL,
- .dx = x - b->prev_x,
- .dy = y - b->prev_y
- };
-
- weston_compositor_get_time(&time);
- notify_motion(&b->core_seat, &time, &motion_event);
- notify_pointer_frame(&b->core_seat);
-
- b->prev_x = x;
- b->prev_y = y;
-}
-
-static void
-x11_backend_deliver_enter_event(struct x11_backend *b,
- xcb_generic_event_t *event)
-{
- struct x11_output *output;
- double x, y;
-
- xcb_enter_notify_event_t *enter_notify =
- (xcb_enter_notify_event_t *) event;
- if (enter_notify->state >= Button1Mask)
- return;
- if (!b->has_xkb)
- update_xkb_state_from_core(b, enter_notify->state);
- output = x11_backend_find_output(b, enter_notify->event);
- if (!output)
- return;
-
- weston_output_transform_coordinate(&output->base,
- enter_notify->event_x,
- enter_notify->event_y, &x, &y);
-
- notify_pointer_focus(&b->core_seat, &output->base, x, y);
-
- b->prev_x = x;
- b->prev_y = y;
-}
-
-static int
-x11_backend_next_event(struct x11_backend *b,
- xcb_generic_event_t **event, uint32_t mask)
-{
- if (mask & WL_EVENT_READABLE)
- *event = xcb_poll_for_event(b->conn);
- else
- *event = xcb_poll_for_queued_event(b->conn);
-
- return *event != NULL;
-}
-
-static int
-x11_backend_handle_event(int fd, uint32_t mask, void *data)
-{
- struct x11_backend *b = data;
- struct x11_output *output;
- xcb_generic_event_t *event, *prev;
- xcb_client_message_event_t *client_message;
- xcb_enter_notify_event_t *enter_notify;
- xcb_key_press_event_t *key_press, *key_release;
- xcb_keymap_notify_event_t *keymap_notify;
- xcb_focus_in_event_t *focus_in;
- xcb_expose_event_t *expose;
- xcb_configure_notify_event_t *configure;
- xcb_atom_t atom;
- xcb_window_t window;
- uint32_t *k;
- uint32_t i, set;
- uint8_t response_type;
- int count;
- struct timespec time;
-
- prev = NULL;
- count = 0;
- while (x11_backend_next_event(b, &event, mask)) {
- response_type = event->response_type & ~0x80;
-
- switch (prev ? prev->response_type & ~0x80 : 0x80) {
- case XCB_KEY_RELEASE:
- /* Suppress key repeat events; this is only used if we
- * don't have XCB XKB support. */
- key_release = (xcb_key_press_event_t *) prev;
- key_press = (xcb_key_press_event_t *) event;
- if (response_type == XCB_KEY_PRESS &&
- key_release->time == key_press->time &&
- key_release->detail == key_press->detail) {
- /* Don't deliver the held key release
- * event or the new key press event. */
- free(event);
- free(prev);
- prev = NULL;
- continue;
- } else {
- /* Deliver the held key release now
- * and fall through and handle the new
- * event below. */
- update_xkb_state_from_core(b, key_release->state);
- weston_compositor_get_time(&time);
- notify_key(&b->core_seat,
- &time,
- key_release->detail - 8,
- WL_KEYBOARD_KEY_STATE_RELEASED,
- STATE_UPDATE_AUTOMATIC);
- free(prev);
- prev = NULL;
- break;
- }
-
- case XCB_FOCUS_IN:
- assert(response_type == XCB_KEYMAP_NOTIFY);
- keymap_notify = (xcb_keymap_notify_event_t *) event;
- b->keys.size = 0;
- for (i = 0; i < ARRAY_LENGTH(keymap_notify->keys) * 8; i++) {
- set = keymap_notify->keys[i >> 3] &
- (1 << (i & 7));
- if (set) {
- k = wl_array_add(&b->keys, sizeof *k);
- *k = i;
- }
- }
-
- /* Unfortunately the state only comes with the enter
- * event, rather than with the focus event. I'm not
- * sure of the exact semantics around it and whether
- * we can ensure that we get both? */
- notify_keyboard_focus_in(&b->core_seat, &b->keys,
- STATE_UPDATE_AUTOMATIC);
-
- free(prev);
- prev = NULL;
- break;
-
- default:
- /* No previous event held */
- break;
- }
-
- switch (response_type) {
- case XCB_KEY_PRESS:
- key_press = (xcb_key_press_event_t *) event;
- if (!b->has_xkb)
- update_xkb_state_from_core(b, key_press->state);
- weston_compositor_get_time(&time);
- notify_key(&b->core_seat,
- &time,
- key_press->detail - 8,
- WL_KEYBOARD_KEY_STATE_PRESSED,
- b->has_xkb ? STATE_UPDATE_NONE :
- STATE_UPDATE_AUTOMATIC);
- break;
- case XCB_KEY_RELEASE:
- /* If we don't have XKB, we need to use the lame
- * autorepeat detection above. */
- if (!b->has_xkb) {
- prev = event;
- break;
- }
- key_release = (xcb_key_press_event_t *) event;
- weston_compositor_get_time(&time);
- notify_key(&b->core_seat,
- &time,
- key_release->detail - 8,
- WL_KEYBOARD_KEY_STATE_RELEASED,
- STATE_UPDATE_NONE);
- break;
- case XCB_BUTTON_PRESS:
- case XCB_BUTTON_RELEASE:
- x11_backend_deliver_button_event(b, event);
- break;
- case XCB_MOTION_NOTIFY:
- x11_backend_deliver_motion_event(b, event);
- break;
-
- case XCB_EXPOSE:
- expose = (xcb_expose_event_t *) event;
- output = x11_backend_find_output(b, expose->window);
- if (!output)
- break;
-
- weston_output_damage(&output->base);
- weston_output_schedule_repaint(&output->base);
- break;
-
- case XCB_ENTER_NOTIFY:
- x11_backend_deliver_enter_event(b, event);
- break;
-
- case XCB_LEAVE_NOTIFY:
- enter_notify = (xcb_enter_notify_event_t *) event;
- if (enter_notify->state >= Button1Mask)
- break;
- if (!b->has_xkb)
- update_xkb_state_from_core(b, enter_notify->state);
- notify_pointer_focus(&b->core_seat, NULL, 0, 0);
- break;
-
- case XCB_CLIENT_MESSAGE:
- client_message = (xcb_client_message_event_t *) event;
- atom = client_message->data.data32[0];
- window = client_message->window;
- if (atom == b->atom.wm_delete_window) {
- struct wl_event_loop *loop;
- struct window_delete_data *data = malloc(sizeof *data);
-
- /* if malloc failed we should at least try to
- * delete the window, even if it may result in
- * a crash.
- */
- if (!data) {
- x11_backend_delete_window(b, window);
- break;
- }
- data->backend = b;
- data->window = window;
- loop = wl_display_get_event_loop(b->compositor->wl_display);
- wl_event_loop_add_idle(loop, delete_cb, data);
- }
- break;
-
- case XCB_CONFIGURE_NOTIFY:
- configure = (struct xcb_configure_notify_event_t *) event;
- struct x11_output *output =
- x11_backend_find_output(b, configure->window);
-
- if (!output || output->resize_pending)
- break;
-
- struct weston_mode mode = output->mode;
-
- if (mode.width == configure->width &&
- mode.height == configure->height)
- break;
-
- output->window_resized = true;
-
- mode.width = configure->width;
- mode.height = configure->height;
-
- if (weston_output_mode_set_native(&output->base,
- &mode, output->scale) < 0)
- weston_log("Mode switch failed\n");
-
- break;
-
- case XCB_FOCUS_IN:
- focus_in = (xcb_focus_in_event_t *) event;
- if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED)
- break;
-
- prev = event;
- break;
-
- case XCB_FOCUS_OUT:
- focus_in = (xcb_focus_in_event_t *) event;
- if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED ||
- focus_in->mode == XCB_NOTIFY_MODE_UNGRAB)
- break;
- notify_keyboard_focus_out(&b->core_seat);
- break;
-
- default:
- break;
- }
-
-#ifdef HAVE_XCB_XKB
- if (b->has_xkb) {
- if (response_type == b->xkb_event_base) {
- xcb_xkb_state_notify_event_t *state =
- (xcb_xkb_state_notify_event_t *) event;
- if (state->xkbType == XCB_XKB_STATE_NOTIFY)
- update_xkb_state(b, state);
- } else if (response_type == XCB_PROPERTY_NOTIFY) {
- xcb_property_notify_event_t *prop_notify =
- (xcb_property_notify_event_t *) event;
- if (prop_notify->window == b->screen->root &&
- prop_notify->atom == b->atom.xkb_names &&
- prop_notify->state == XCB_PROPERTY_NEW_VALUE)
- update_xkb_keymap(b);
- }
- }
-#endif
-
- count++;
- if (prev != event)
- free (event);
- }
-
- switch (prev ? prev->response_type & ~0x80 : 0x80) {
- case XCB_KEY_RELEASE:
- key_release = (xcb_key_press_event_t *) prev;
- update_xkb_state_from_core(b, key_release->state);
- weston_compositor_get_time(&time);
- notify_key(&b->core_seat,
- &time,
- key_release->detail - 8,
- WL_KEYBOARD_KEY_STATE_RELEASED,
- STATE_UPDATE_AUTOMATIC);
- free(prev);
- prev = NULL;
- break;
- default:
- break;
- }
-
- return count;
-}
-
-#define F(field) offsetof(struct x11_backend, field)
-
-static void
-x11_backend_get_resources(struct x11_backend *b)
-{
- static const struct { const char *name; int offset; } atoms[] = {
- { "WM_PROTOCOLS", F(atom.wm_protocols) },
- { "WM_NORMAL_HINTS", F(atom.wm_normal_hints) },
- { "WM_SIZE_HINTS", F(atom.wm_size_hints) },
- { "WM_DELETE_WINDOW", F(atom.wm_delete_window) },
- { "WM_CLASS", F(atom.wm_class) },
- { "_NET_WM_NAME", F(atom.net_wm_name) },
- { "_NET_WM_ICON", F(atom.net_wm_icon) },
- { "_NET_WM_STATE", F(atom.net_wm_state) },
- { "_NET_WM_STATE_FULLSCREEN", F(atom.net_wm_state_fullscreen) },
- { "_NET_SUPPORTING_WM_CHECK",
- F(atom.net_supporting_wm_check) },
- { "_NET_SUPPORTED", F(atom.net_supported) },
- { "STRING", F(atom.string) },
- { "UTF8_STRING", F(atom.utf8_string) },
- { "CARDINAL", F(atom.cardinal) },
- { "_XKB_RULES_NAMES", F(atom.xkb_names) },
- };
-
- xcb_intern_atom_cookie_t cookies[ARRAY_LENGTH(atoms)];
- xcb_intern_atom_reply_t *reply;
- xcb_pixmap_t pixmap;
- xcb_gc_t gc;
- unsigned int i;
- uint8_t data[] = { 0, 0, 0, 0 };
-
- for (i = 0; i < ARRAY_LENGTH(atoms); i++)
- cookies[i] = xcb_intern_atom (b->conn, 0,
- strlen(atoms[i].name),
- atoms[i].name);
-
- for (i = 0; i < ARRAY_LENGTH(atoms); i++) {
- reply = xcb_intern_atom_reply (b->conn, cookies[i], NULL);
- *(xcb_atom_t *) ((char *) b + atoms[i].offset) = reply->atom;
- free(reply);
- }
-
- pixmap = xcb_generate_id(b->conn);
- gc = xcb_generate_id(b->conn);
- xcb_create_pixmap(b->conn, 1, pixmap, b->screen->root, 1, 1);
- xcb_create_gc(b->conn, gc, pixmap, 0, NULL);
- xcb_put_image(b->conn, XCB_IMAGE_FORMAT_XY_PIXMAP,
- pixmap, gc, 1, 1, 0, 0, 0, 32, sizeof data, data);
- b->null_cursor = xcb_generate_id(b->conn);
- xcb_create_cursor (b->conn, b->null_cursor,
- pixmap, pixmap, 0, 0, 0, 0, 0, 0, 1, 1);
- xcb_free_gc(b->conn, gc);
- xcb_free_pixmap(b->conn, pixmap);
-}
-
-static void
-x11_backend_get_wm_info(struct x11_backend *c)
-{
- xcb_get_property_cookie_t cookie;
- xcb_get_property_reply_t *reply;
- xcb_atom_t *atom;
- unsigned int i;
-
- cookie = xcb_get_property(c->conn, 0, c->screen->root,
- c->atom.net_supported,
- XCB_ATOM_ATOM, 0, 1024);
- reply = xcb_get_property_reply(c->conn, cookie, NULL);
- if (reply == NULL)
- return;
-
- atom = (xcb_atom_t *) xcb_get_property_value(reply);
-
- for (i = 0; i < reply->value_len; i++) {
- if (atom[i] == c->atom.net_wm_state_fullscreen)
- c->has_net_wm_state_fullscreen = 1;
- }
-
- free(reply);
-}
-
-static void
-x11_destroy(struct weston_compositor *ec)
-{
- struct x11_backend *backend = to_x11_backend(ec);
- struct weston_head *base, *next;
-
- wl_event_source_remove(backend->xcb_source);
- x11_input_destroy(backend);
-
- weston_compositor_shutdown(ec); /* destroys outputs, too */
-
- wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
- x11_head_destroy(to_x11_head(base));
-
- XCloseDisplay(backend->dpy);
- free(backend);
-}
-
-static int
-init_gl_renderer(struct x11_backend *b)
-{
- int ret;
-
- gl_renderer = weston_load_module("gl-renderer.so",
- "gl_renderer_interface");
- if (!gl_renderer)
- return -1;
-
- ret = gl_renderer->display_create(b->compositor, EGL_PLATFORM_X11_KHR,
- (void *) b->dpy,
- EGL_WINDOW_BIT,
- x11_formats,
- ARRAY_LENGTH(x11_formats));
-
- return ret;
-}
-
-static const struct weston_windowed_output_api api = {
- x11_output_set_size,
- x11_head_create,
-};
-
-static struct x11_backend *
-x11_backend_create(struct weston_compositor *compositor,
- struct weston_x11_backend_config *config)
-{
- struct x11_backend *b;
- struct wl_event_loop *loop;
- int ret;
-
- b = zalloc(sizeof *b);
- if (b == NULL)
- return NULL;
-
- b->compositor = compositor;
- b->fullscreen = config->fullscreen;
- b->no_input = config->no_input;
-
- compositor->backend = &b->base;
-
- if (weston_compositor_set_presentation_clock_software(compositor) < 0)
- goto err_free;
-
- b->dpy = XOpenDisplay(NULL);
- if (b->dpy == NULL)
- goto err_free;
-
- b->conn = XGetXCBConnection(b->dpy);
- XSetEventQueueOwner(b->dpy, XCBOwnsEventQueue);
-
- if (xcb_connection_has_error(b->conn))
- goto err_xdisplay;
-
- b->screen = x11_compositor_get_default_screen(b);
- wl_array_init(&b->keys);
-
- x11_backend_get_resources(b);
- x11_backend_get_wm_info(b);
-
- if (!b->has_net_wm_state_fullscreen && config->fullscreen) {
- weston_log("Can not fullscreen without window manager support"
- "(need _NET_WM_STATE_FULLSCREEN)\n");
- config->fullscreen = 0;
- }
-
- b->use_pixman = config->use_pixman;
- if (b->use_pixman) {
- if (pixman_renderer_init(compositor) < 0) {
- weston_log("Failed to initialize pixman renderer for X11 backend\n");
- goto err_xdisplay;
- }
- }
- else if (init_gl_renderer(b) < 0) {
- goto err_xdisplay;
- }
- weston_log("Using %s renderer\n", config->use_pixman ? "pixman" : "gl");
-
- b->base.destroy = x11_destroy;
- b->base.create_output = x11_output_create;
-
- if (x11_input_create(b, config->no_input) < 0) {
- weston_log("Failed to create X11 input\n");
- goto err_renderer;
- }
-
- loop = wl_display_get_event_loop(compositor->wl_display);
- b->xcb_source =
- wl_event_loop_add_fd(loop,
- xcb_get_file_descriptor(b->conn),
- WL_EVENT_READABLE,
- x11_backend_handle_event, b);
- wl_event_source_check(b->xcb_source);
-
- if (compositor->renderer->import_dmabuf) {
- if (linux_dmabuf_setup(compositor) < 0)
- weston_log("Error: initializing dmabuf "
- "support failed.\n");
- }
-
- if (compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC) {
- if (linux_explicit_synchronization_setup(compositor) < 0)
- weston_log("Error: initializing explicit "
- " synchronization support failed.\n");
- }
-
- ret = weston_plugin_api_register(compositor, WESTON_WINDOWED_OUTPUT_API_NAME,
- &api, sizeof(api));
-
- if (ret < 0) {
- weston_log("Failed to register output API.\n");
- goto err_x11_input;
- }
-
- return b;
-
-err_x11_input:
- x11_input_destroy(b);
-err_renderer:
- compositor->renderer->destroy(compositor);
-err_xdisplay:
- XCloseDisplay(b->dpy);
-err_free:
- free(b);
- return NULL;
-}
-
-static void
-config_init_to_defaults(struct weston_x11_backend_config *config)
-{
-}
-
-WL_EXPORT int
-weston_backend_init(struct weston_compositor *compositor,
- struct weston_backend_config *config_base)
-{
- struct x11_backend *b;
- struct weston_x11_backend_config config = {{ 0, }};
-
- if (config_base == NULL ||
- config_base->struct_version != WESTON_X11_BACKEND_CONFIG_VERSION ||
- config_base->struct_size > sizeof(struct weston_x11_backend_config)) {
- weston_log("X11 backend config structure is invalid\n");
- return -1;
- }
-
- config_init_to_defaults(&config);
- memcpy(&config, config_base, config_base->struct_size);
-
- b = x11_backend_create(compositor, &config);
- if (b == NULL)
- return -1;
-
- return 0;
-}
diff --git a/libweston/backend.h b/libweston/backend.h
deleted file mode 100644
index ff10b363..00000000
--- a/libweston/backend.h
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2017, 2018 General Electric Company
- * Copyright © 2012, 2017-2019 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * This header contains the libweston ABI exported only for internal backends.
- */
-
-#ifndef LIBWESTON_BACKEND_INTERNAL_H
-#define LIBWESTON_BACKEND_INTERNAL_H
-
-struct weston_backend {
- void (*destroy)(struct weston_compositor *compositor);
-
- /** Begin a repaint sequence
- *
- * Provides the backend with explicit markers around repaint
- * sequences, which may allow the backend to aggregate state
- * application. This call will be bracketed by the repaint_flush (on
- * success), or repaint_cancel (when any output in the grouping fails
- * repaint).
- *
- * Returns an opaque pointer, which the backend may use as private
- * data referring to the repaint cycle.
- */
- void * (*repaint_begin)(struct weston_compositor *compositor);
-
- /** Cancel a repaint sequence
- *
- * Cancels a repaint sequence, when an error has occurred during
- * one output's repaint; see repaint_begin.
- *
- * @param repaint_data Data returned by repaint_begin
- */
- void (*repaint_cancel)(struct weston_compositor *compositor,
- void *repaint_data);
-
- /** Conclude a repaint sequence
- *
- * Called on successful completion of a repaint sequence; see
- * repaint_begin.
- *
- * @param repaint_data Data returned by repaint_begin
- */
- int (*repaint_flush)(struct weston_compositor *compositor,
- void *repaint_data);
-
- /** Allocate a new output
- *
- * @param compositor The compositor.
- * @param name Name for the new output.
- *
- * Allocates a new output structure that embeds a weston_output,
- * initializes it, and returns the pointer to the weston_output
- * member.
- *
- * Must set weston_output members @c destroy, @c enable and @c disable.
- */
- struct weston_output *
- (*create_output)(struct weston_compositor *compositor,
- const char *name);
-
- /** Notify of device addition/removal
- *
- * @param compositor The compositor.
- * @param device The device that has changed.
- * @param added Where it was added (or removed)
- *
- * Called when a device has been added/removed from the session.
- * The backend can decide what to do based on whether it is a
- * device that it is controlling or not.
- */
- void (*device_changed)(struct weston_compositor *compositor,
- dev_t device, bool added);
-
- /** Verifies if the dmabuf can be used directly/scanned-out by the HW.
- *
- * @param compositor The compositor.
- * @param buffer The dmabuf to verify.
- *
- * Determines if the buffer can be imported directly by the display
- * controller/HW. Back-ends can use this to check if the supplied
- * buffer can be scanned-out, as to void importing it into the GPU.
- */
- bool (*can_scanout_dmabuf)(struct weston_compositor *compositor,
- struct linux_dmabuf_buffer *buffer);
-};
-
-/* weston_head */
-
-void
-weston_head_init(struct weston_head *head, const char *name);
-
-void
-weston_head_release(struct weston_head *head);
-
-void
-weston_head_set_connection_status(struct weston_head *head, bool connected);
-
-void
-weston_head_set_internal(struct weston_head *head);
-
-void
-weston_head_set_monitor_strings(struct weston_head *head,
- const char *make,
- const char *model,
- const char *serialno);
-void
-weston_head_set_non_desktop(struct weston_head *head, bool non_desktop);
-
-void
-weston_head_set_physical_size(struct weston_head *head,
- int32_t mm_width, int32_t mm_height);
-
-void
-weston_head_set_subpixel(struct weston_head *head,
- enum wl_output_subpixel sp);
-/* weston_output */
-
-void
-weston_output_init(struct weston_output *output,
- struct weston_compositor *compositor,
- const char *name);
-void
-weston_output_damage(struct weston_output *output);
-
-void
-weston_output_release(struct weston_output *output);
-
-void
-weston_output_init_zoom(struct weston_output *output);
-
-void
-weston_output_finish_frame(struct weston_output *output,
- const struct timespec *stamp,
- uint32_t presented_flags);
-int
-weston_output_mode_set_native(struct weston_output *output,
- struct weston_mode *mode,
- int32_t scale);
-void
-weston_output_transform_coordinate(struct weston_output *output,
- double device_x, double device_y,
- double *x, double *y);
-
-/* weston_seat */
-
-void
-notify_axis(struct weston_seat *seat, const struct timespec *time,
- struct weston_pointer_axis_event *event);
-void
-notify_axis_source(struct weston_seat *seat, uint32_t source);
-
-void
-notify_button(struct weston_seat *seat, const struct timespec *time,
- int32_t button, enum wl_pointer_button_state state);
-
-void
-notify_key(struct weston_seat *seat, const struct timespec *time, uint32_t key,
- enum wl_keyboard_key_state state,
- enum weston_key_state_update update_state);
-void
-notify_keyboard_focus_in(struct weston_seat *seat, struct wl_array *keys,
- enum weston_key_state_update update_state);
-void
-notify_keyboard_focus_out(struct weston_seat *seat);
-
-void
-notify_motion(struct weston_seat *seat, const struct timespec *time,
- struct weston_pointer_motion_event *event);
-void
-notify_motion_absolute(struct weston_seat *seat, const struct timespec *time,
- double x, double y);
-void
-notify_modifiers(struct weston_seat *seat, uint32_t serial);
-
-void
-notify_pointer_frame(struct weston_seat *seat);
-
-void
-notify_pointer_focus(struct weston_seat *seat, struct weston_output *output,
- double x, double y);
-
-/* weston_touch_device */
-
-void
-notify_touch_normalized(struct weston_touch_device *device,
- const struct timespec *time,
- int touch_id,
- double x, double y,
- const struct weston_point2d_device_normalized *norm,
- int touch_type);
-
-/** Feed in touch down, motion, and up events, non-calibratable device.
- *
- * @sa notify_touch_cal
- */
-static inline void
-notify_touch(struct weston_touch_device *device, const struct timespec *time,
- int touch_id, double x, double y, int touch_type)
-{
- notify_touch_normalized(device, time, touch_id, x, y, NULL, touch_type);
-}
-
-void
-notify_touch_frame(struct weston_touch_device *device);
-
-void
-notify_touch_cancel(struct weston_touch_device *device);
-
-void
-notify_touch_calibrator(struct weston_touch_device *device,
- const struct timespec *time, int32_t slot,
- const struct weston_point2d_device_normalized *norm,
- int touch_type);
-void
-notify_touch_calibrator_cancel(struct weston_touch_device *device);
-void
-notify_touch_calibrator_frame(struct weston_touch_device *device);
-
-#endif
diff --git a/libweston/bindings.c b/libweston/bindings.c
deleted file mode 100644
index 68c07a22..00000000
--- a/libweston/bindings.c
+++ /dev/null
@@ -1,588 +0,0 @@
-/*
- * Copyright © 2011-2012 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <linux/input.h>
-
-#include <libweston/libweston.h>
-#include "shared/helpers.h"
-#include "shared/timespec-util.h"
-
-struct weston_binding {
- uint32_t key;
- uint32_t button;
- uint32_t axis;
- uint32_t modifier;
- void *handler;
- void *data;
- struct wl_list link;
-};
-
-static struct weston_binding *
-weston_compositor_add_binding(struct weston_compositor *compositor,
- uint32_t key, uint32_t button, uint32_t axis,
- uint32_t modifier, void *handler, void *data)
-{
- struct weston_binding *binding;
-
- binding = malloc(sizeof *binding);
- if (binding == NULL)
- return NULL;
-
- binding->key = key;
- binding->button = button;
- binding->axis = axis;
- binding->modifier = modifier;
- binding->handler = handler;
- binding->data = data;
-
- return binding;
-}
-
-WL_EXPORT struct weston_binding *
-weston_compositor_add_key_binding(struct weston_compositor *compositor,
- uint32_t key, uint32_t modifier,
- weston_key_binding_handler_t handler,
- void *data)
-{
- struct weston_binding *binding;
-
- binding = weston_compositor_add_binding(compositor, key, 0, 0,
- modifier, handler, data);
- if (binding == NULL)
- return NULL;
-
- wl_list_insert(compositor->key_binding_list.prev, &binding->link);
-
- return binding;
-}
-
-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,
- void *data)
-{
- struct weston_binding *binding;
-
- binding = weston_compositor_add_binding(compositor, 0, button, 0,
- modifier, handler, data);
- if (binding == NULL)
- return NULL;
-
- wl_list_insert(compositor->button_binding_list.prev, &binding->link);
-
- return binding;
-}
-
-WL_EXPORT struct weston_binding *
-weston_compositor_add_touch_binding(struct weston_compositor *compositor,
- uint32_t modifier,
- weston_touch_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->touch_binding_list.prev, &binding->link);
-
- return binding;
-}
-
-WL_EXPORT struct weston_binding *
-weston_compositor_add_axis_binding(struct weston_compositor *compositor,
- uint32_t axis, uint32_t modifier,
- weston_axis_binding_handler_t handler,
- void *data)
-{
- struct weston_binding *binding;
-
- binding = weston_compositor_add_binding(compositor, 0, 0, axis,
- modifier, handler, data);
- if (binding == NULL)
- return NULL;
-
- wl_list_insert(compositor->axis_binding_list.prev, &binding->link);
-
- return binding;
-}
-
-WL_EXPORT struct weston_binding *
-weston_compositor_add_debug_binding(struct weston_compositor *compositor,
- uint32_t key,
- weston_key_binding_handler_t handler,
- void *data)
-{
- struct weston_binding *binding;
-
- binding = weston_compositor_add_binding(compositor, key, 0, 0, 0,
- handler, data);
-
- wl_list_insert(compositor->debug_binding_list.prev, &binding->link);
-
- return binding;
-}
-
-WL_EXPORT void
-weston_binding_destroy(struct weston_binding *binding)
-{
- wl_list_remove(&binding->link);
- free(binding);
-}
-
-void
-weston_binding_list_destroy_all(struct wl_list *list)
-{
- struct weston_binding *binding, *tmp;
-
- wl_list_for_each_safe(binding, tmp, list, link)
- weston_binding_destroy(binding);
-}
-
-struct binding_keyboard_grab {
- uint32_t key;
- struct weston_keyboard_grab grab;
-};
-
-static void
-binding_key(struct weston_keyboard_grab *grab,
- const struct timespec *time, uint32_t key, uint32_t state_w)
-{
- struct binding_keyboard_grab *b =
- container_of(grab, struct binding_keyboard_grab, grab);
- struct wl_resource *resource;
- enum wl_keyboard_key_state state = state_w;
- uint32_t serial;
- struct weston_keyboard *keyboard = grab->keyboard;
- struct wl_display *display = keyboard->seat->compositor->wl_display;
- uint32_t msecs;
-
- if (key == b->key) {
- if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
- weston_keyboard_end_grab(grab->keyboard);
- if (keyboard->input_method_resource)
- keyboard->grab = &keyboard->input_method_grab;
- free(b);
- } else {
- /* Don't send the key press event for the binding key */
- return;
- }
- }
- if (!wl_list_empty(&keyboard->focus_resource_list)) {
- serial = wl_display_next_serial(display);
- msecs = timespec_to_msec(time);
- wl_resource_for_each(resource, &keyboard->focus_resource_list) {
- wl_keyboard_send_key(resource,
- serial,
- msecs,
- key,
- state);
- }
- }
-}
-
-static void
-binding_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
- uint32_t mods_depressed, uint32_t mods_latched,
- uint32_t mods_locked, uint32_t group)
-{
- struct wl_resource *resource;
-
- wl_resource_for_each(resource, &grab->keyboard->focus_resource_list) {
- wl_keyboard_send_modifiers(resource, serial, mods_depressed,
- mods_latched, mods_locked, group);
- }
-}
-
-static void
-binding_cancel(struct weston_keyboard_grab *grab)
-{
- struct binding_keyboard_grab *binding_grab =
- container_of(grab, struct binding_keyboard_grab, grab);
-
- weston_keyboard_end_grab(grab->keyboard);
- free(binding_grab);
-}
-
-static const struct weston_keyboard_grab_interface binding_grab = {
- binding_key,
- binding_modifiers,
- binding_cancel,
-};
-
-static void
-install_binding_grab(struct weston_keyboard *keyboard,
- const struct timespec *time, uint32_t key,
- struct weston_surface *focus)
-{
- struct binding_keyboard_grab *grab;
-
- grab = malloc(sizeof *grab);
- grab->key = key;
- grab->grab.interface = &binding_grab;
- weston_keyboard_start_grab(keyboard, &grab->grab);
-
- /* Notify the surface which had the focus before this binding
- * triggered that we stole a keypress from under it, by forcing
- * a wl_keyboard leave/enter pair. The enter event will contain
- * the pressed key in the keys array, so the client will know
- * the exact state of the keyboard.
- * If the old focus surface is different than the new one it
- * means it was changed in the binding handler, so it received
- * the enter event already. */
- if (focus && keyboard->focus == focus) {
- weston_keyboard_set_focus(keyboard, NULL);
- weston_keyboard_set_focus(keyboard, focus);
- }
-}
-
-void
-weston_compositor_run_key_binding(struct weston_compositor *compositor,
- struct weston_keyboard *keyboard,
- const struct timespec *time, uint32_t key,
- enum wl_keyboard_key_state state)
-{
- struct weston_binding *b, *tmp;
- struct weston_surface *focus;
- struct weston_seat *seat = keyboard->seat;
-
- 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_safe(b, tmp, &compositor->key_binding_list, link) {
- if (b->key == key && b->modifier == seat->modifier_state) {
- weston_key_binding_handler_t handler = b->handler;
- focus = keyboard->focus;
- handler(keyboard, time, key, b->data);
-
- /* If this was a key binding and it didn't
- * install a keyboard grab, install one now to
- * swallow the key press. */
- if (keyboard->grab ==
- &keyboard->default_grab)
- install_binding_grab(keyboard,
- time,
- key,
- focus);
- }
- }
-}
-
-void
-weston_compositor_run_modifier_binding(struct weston_compositor *compositor,
- struct weston_keyboard *keyboard,
- enum weston_keyboard_modifier modifier,
- enum wl_keyboard_key_state state)
-{
- struct weston_binding *b, *tmp;
-
- if (keyboard->grab != &keyboard->default_grab)
- return;
-
- wl_list_for_each_safe(b, tmp, &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(keyboard, modifier, b->data);
- }
-}
-
-void
-weston_compositor_run_button_binding(struct weston_compositor *compositor,
- struct weston_pointer *pointer,
- const struct timespec *time,
- uint32_t button,
- enum wl_pointer_button_state state)
-{
- struct weston_binding *b, *tmp;
-
- 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_safe(b, tmp, &compositor->button_binding_list, link) {
- if (b->button == button &&
- b->modifier == pointer->seat->modifier_state) {
- weston_button_binding_handler_t handler = b->handler;
- handler(pointer, time, button, b->data);
- }
- }
-}
-
-void
-weston_compositor_run_touch_binding(struct weston_compositor *compositor,
- struct weston_touch *touch,
- const struct timespec *time,
- int touch_type)
-{
- struct weston_binding *b, *tmp;
-
- if (touch->num_tp != 1 || touch_type != WL_TOUCH_DOWN)
- return;
-
- wl_list_for_each_safe(b, tmp, &compositor->touch_binding_list, link) {
- if (b->modifier == touch->seat->modifier_state) {
- weston_touch_binding_handler_t handler = b->handler;
- handler(touch, time, b->data);
- }
- }
-}
-
-int
-weston_compositor_run_axis_binding(struct weston_compositor *compositor,
- struct weston_pointer *pointer,
- const struct timespec *time,
- struct weston_pointer_axis_event *event)
-{
- struct weston_binding *b, *tmp;
-
- /* Invalidate all active modifier bindings. */
- wl_list_for_each(b, &compositor->modifier_binding_list, link)
- b->key = event->axis;
-
- wl_list_for_each_safe(b, tmp, &compositor->axis_binding_list, link) {
- if (b->axis == event->axis &&
- b->modifier == pointer->seat->modifier_state) {
- weston_axis_binding_handler_t handler = b->handler;
- handler(pointer, time, event, b->data);
- return 1;
- }
- }
-
- return 0;
-}
-
-int
-weston_compositor_run_debug_binding(struct weston_compositor *compositor,
- struct weston_keyboard *keyboard,
- const struct timespec *time, uint32_t key,
- enum wl_keyboard_key_state state)
-{
- weston_key_binding_handler_t handler;
- struct weston_binding *binding, *tmp;
- int count = 0;
-
- wl_list_for_each_safe(binding, tmp, &compositor->debug_binding_list, link) {
- if (key != binding->key)
- continue;
-
- count++;
- handler = binding->handler;
- handler(keyboard, time, key, binding->data);
- }
-
- return count;
-}
-
-struct debug_binding_grab {
- struct weston_keyboard_grab grab;
- struct weston_seat *seat;
- uint32_t key[2];
- int key_released[2];
-};
-
-static void
-debug_binding_key(struct weston_keyboard_grab *grab, const struct timespec *time,
- uint32_t key, uint32_t state)
-{
- struct debug_binding_grab *db = (struct debug_binding_grab *) grab;
- struct weston_compositor *ec = db->seat->compositor;
- struct wl_display *display = ec->wl_display;
- struct wl_resource *resource;
- uint32_t serial;
- int send = 0, terminate = 0;
- int check_binding = 1;
- int i;
- struct wl_list *resource_list;
- uint32_t msecs;
-
- if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
- /* Do not run bindings on key releases */
- check_binding = 0;
-
- for (i = 0; i < 2; i++)
- if (key == db->key[i])
- db->key_released[i] = 1;
-
- if (db->key_released[0] && db->key_released[1]) {
- /* All key releases been swalled so end the grab */
- terminate = 1;
- } else if (key != db->key[0] && key != db->key[1]) {
- /* Should not swallow release of other keys */
- send = 1;
- }
- } else if (key == db->key[0] && !db->key_released[0]) {
- /* Do not check bindings for the first press of the binding
- * key. This allows it to be used as a debug shortcut.
- * We still need to swallow this event. */
- check_binding = 0;
- } else if (db->key[1]) {
- /* If we already ran a binding don't process another one since
- * we can't keep track of all the binding keys that were
- * pressed in order to swallow the release events. */
- send = 1;
- check_binding = 0;
- }
-
- if (check_binding) {
- if (weston_compositor_run_debug_binding(ec, grab->keyboard,
- time, key, state)) {
- /* We ran a binding so swallow the press and keep the
- * grab to swallow the released too. */
- send = 0;
- terminate = 0;
- db->key[1] = key;
- } else {
- /* Terminate the grab since the key pressed is not a
- * debug binding key. */
- send = 1;
- terminate = 1;
- }
- }
-
- if (send) {
- serial = wl_display_next_serial(display);
- resource_list = &grab->keyboard->focus_resource_list;
- msecs = timespec_to_msec(time);
- wl_resource_for_each(resource, resource_list) {
- wl_keyboard_send_key(resource, serial, msecs, key, state);
- }
- }
-
- if (terminate) {
- weston_keyboard_end_grab(grab->keyboard);
- if (grab->keyboard->input_method_resource)
- grab->keyboard->grab = &grab->keyboard->input_method_grab;
- free(db);
- }
-}
-
-static void
-debug_binding_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
- uint32_t mods_depressed, uint32_t mods_latched,
- uint32_t mods_locked, uint32_t group)
-{
- struct wl_resource *resource;
- struct wl_list *resource_list;
-
- resource_list = &grab->keyboard->focus_resource_list;
-
- wl_resource_for_each(resource, resource_list) {
- wl_keyboard_send_modifiers(resource, serial, mods_depressed,
- mods_latched, mods_locked, group);
- }
-}
-
-static void
-debug_binding_cancel(struct weston_keyboard_grab *grab)
-{
- struct debug_binding_grab *db = (struct debug_binding_grab *) grab;
-
- weston_keyboard_end_grab(grab->keyboard);
- free(db);
-}
-
-struct weston_keyboard_grab_interface debug_binding_keyboard_grab = {
- debug_binding_key,
- debug_binding_modifiers,
- debug_binding_cancel,
-};
-
-static void
-debug_binding(struct weston_keyboard *keyboard, const struct timespec *time,
- uint32_t key, void *data)
-{
- struct debug_binding_grab *grab;
-
- grab = calloc(1, sizeof *grab);
- if (!grab)
- return;
-
- grab->seat = keyboard->seat;
- grab->key[0] = key;
- grab->grab.interface = &debug_binding_keyboard_grab;
- weston_keyboard_start_grab(keyboard, &grab->grab);
-}
-
-/** Install the trigger binding for debug bindings.
- *
- * \param compositor The compositor.
- * \param mod The modifier.
- *
- * This will add a key binding for modifier+SHIFT+SPACE that will trigger
- * debug key bindings.
- */
-WL_EXPORT void
-weston_install_debug_key_binding(struct weston_compositor *compositor,
- uint32_t mod)
-{
- weston_compositor_add_key_binding(compositor, KEY_SPACE,
- mod | MODIFIER_SHIFT,
- debug_binding, NULL);
-}
diff --git a/libweston/clipboard.c b/libweston/clipboard.c
deleted file mode 100644
index c8296b01..00000000
--- a/libweston/clipboard.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * Copyright © 2012 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <linux/input.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/uio.h>
-
-#include <libweston/libweston.h>
-#include "shared/helpers.h"
-
-struct clipboard_source {
- struct weston_data_source base;
- struct wl_array contents;
- struct clipboard *clipboard;
- struct wl_event_source *event_source;
- uint32_t serial;
- int refcount;
- int fd;
-};
-
-struct clipboard {
- struct weston_seat *seat;
- struct wl_listener selection_listener;
- struct wl_listener destroy_listener;
- struct clipboard_source *source;
-};
-
-static void clipboard_client_create(struct clipboard_source *source, int fd);
-
-static void
-clipboard_source_unref(struct clipboard_source *source)
-{
- char **s;
-
- source->refcount--;
- if (source->refcount > 0)
- return;
-
- if (source->event_source) {
- wl_event_source_remove(source->event_source);
- close(source->fd);
- }
- wl_signal_emit(&source->base.destroy_signal,
- &source->base);
- s = source->base.mime_types.data;
- free(*s);
- wl_array_release(&source->base.mime_types);
- wl_array_release(&source->contents);
- free(source);
-}
-
-static int
-clipboard_source_data(int fd, uint32_t mask, void *data)
-{
- struct clipboard_source *source = data;
- struct clipboard *clipboard = source->clipboard;
- char *p;
- int len, size;
-
- if (source->contents.alloc - source->contents.size < 1024) {
- wl_array_add(&source->contents, 1024);
- source->contents.size -= 1024;
- }
-
- p = source->contents.data + source->contents.size;
- size = source->contents.alloc - source->contents.size;
- len = read(fd, p, size);
- if (len == 0) {
- wl_event_source_remove(source->event_source);
- close(fd);
- source->event_source = NULL;
- } else if (len < 0) {
- clipboard_source_unref(source);
- clipboard->source = NULL;
- } else {
- source->contents.size += len;
- }
-
- return 1;
-}
-
-static void
-clipboard_source_accept(struct weston_data_source *source,
- uint32_t time, const char *mime_type)
-{
-}
-
-static void
-clipboard_source_send(struct weston_data_source *base,
- const char *mime_type, int32_t fd)
-{
- struct clipboard_source *source =
- container_of(base, struct clipboard_source, base);
- char **s;
-
- s = source->base.mime_types.data;
- if (strcmp(mime_type, s[0]) == 0)
- clipboard_client_create(source, fd);
- else
- close(fd);
-}
-
-static void
-clipboard_source_cancel(struct weston_data_source *source)
-{
-}
-
-static struct clipboard_source *
-clipboard_source_create(struct clipboard *clipboard,
- const char *mime_type, uint32_t serial, int fd)
-{
- struct wl_display *display = clipboard->seat->compositor->wl_display;
- struct wl_event_loop *loop = wl_display_get_event_loop(display);
- struct clipboard_source *source;
- char **s;
-
- source = zalloc(sizeof *source);
- if (source == NULL)
- return NULL;
-
- wl_array_init(&source->contents);
- wl_array_init(&source->base.mime_types);
- source->base.resource = NULL;
- source->base.accept = clipboard_source_accept;
- source->base.send = clipboard_source_send;
- source->base.cancel = clipboard_source_cancel;
- wl_signal_init(&source->base.destroy_signal);
- source->refcount = 1;
- source->clipboard = clipboard;
- source->serial = serial;
- source->fd = fd;
-
- s = wl_array_add(&source->base.mime_types, sizeof *s);
- if (s == NULL)
- goto err_add;
- *s = strdup(mime_type);
- if (*s == NULL)
- goto err_strdup;
- source->event_source =
- wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
- clipboard_source_data, source);
- if (source->event_source == NULL)
- goto err_source;
-
- return source;
-
- err_source:
- free(*s);
- err_strdup:
- wl_array_release(&source->base.mime_types);
- err_add:
- free(source);
-
- return NULL;
-}
-
-struct clipboard_client {
- struct wl_event_source *event_source;
- size_t offset;
- struct clipboard_source *source;
-};
-
-static int
-clipboard_client_data(int fd, uint32_t mask, void *data)
-{
- struct clipboard_client *client = data;
- char *p;
- size_t size;
- int len;
-
- size = client->source->contents.size;
- p = client->source->contents.data;
- len = write(fd, p + client->offset, size - client->offset);
- if (len > 0)
- client->offset += len;
-
- if (client->offset == size || len <= 0) {
- close(fd);
- wl_event_source_remove(client->event_source);
- clipboard_source_unref(client->source);
- free(client);
- }
-
- return 1;
-}
-
-static void
-clipboard_client_create(struct clipboard_source *source, int fd)
-{
- struct weston_seat *seat = source->clipboard->seat;
- struct clipboard_client *client;
- struct wl_event_loop *loop =
- wl_display_get_event_loop(seat->compositor->wl_display);
-
- client = zalloc(sizeof *client);
- if (client == NULL)
- return;
-
- client->source = source;
- source->refcount++;
- client->event_source =
- wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE,
- clipboard_client_data, client);
-}
-
-static void
-clipboard_set_selection(struct wl_listener *listener, void *data)
-{
- struct clipboard *clipboard =
- container_of(listener, struct clipboard, selection_listener);
- struct weston_seat *seat = data;
- struct weston_data_source *source = seat->selection_data_source;
- const char **mime_types;
- int p[2];
-
- if (source == NULL) {
- if (clipboard->source)
- weston_seat_set_selection(seat,
- &clipboard->source->base,
- clipboard->source->serial);
- return;
- } else if (source->accept == clipboard_source_accept) {
- /* Callback for our data source. */
- return;
- }
-
- if (clipboard->source)
- clipboard_source_unref(clipboard->source);
-
- clipboard->source = NULL;
-
- mime_types = source->mime_types.data;
-
- if (!mime_types || pipe2(p, O_CLOEXEC) == -1)
- return;
-
- source->send(source, mime_types[0], p[1]);
-
- clipboard->source =
- clipboard_source_create(clipboard, mime_types[0],
- seat->selection_serial, p[0]);
- if (clipboard->source == NULL) {
- close(p[0]);
- return;
- }
-}
-
-static void
-clipboard_destroy(struct wl_listener *listener, void *data)
-{
- struct clipboard *clipboard =
- container_of(listener, struct clipboard, destroy_listener);
-
- wl_list_remove(&clipboard->selection_listener.link);
- wl_list_remove(&clipboard->destroy_listener.link);
-
- free(clipboard);
-}
-
-struct clipboard *
-clipboard_create(struct weston_seat *seat)
-{
- struct clipboard *clipboard;
-
- clipboard = zalloc(sizeof *clipboard);
- if (clipboard == NULL)
- return NULL;
-
- clipboard->seat = seat;
- clipboard->selection_listener.notify = clipboard_set_selection;
- clipboard->destroy_listener.notify = clipboard_destroy;
-
- wl_signal_add(&seat->selection_signal,
- &clipboard->selection_listener);
- wl_signal_add(&seat->destroy_signal,
- &clipboard->destroy_listener);
-
- return clipboard;
-}
diff --git a/libweston/compositor.c b/libweston/compositor.c
deleted file mode 100644
index 1e7c2b94..00000000
--- a/libweston/compositor.c
+++ /dev/null
@@ -1,7882 +0,0 @@
-/*
- * Copyright © 2010-2011 Intel Corporation
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2012-2018 Collabora, Ltd.
- * Copyright © 2017, 2018 General Electric Company
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <assert.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/wait.h>
-#include <sys/socket.h>
-#include <sys/utsname.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <math.h>
-#include <linux/input.h>
-#include <dlfcn.h>
-#include <signal.h>
-#include <setjmp.h>
-#include <sys/time.h>
-#include <time.h>
-#include <errno.h>
-#include <inttypes.h>
-
-#include "timeline.h"
-
-#include <libweston/libweston.h>
-#include <libweston/weston-log.h>
-#include "linux-dmabuf.h"
-#include "viewporter-server-protocol.h"
-#include "presentation-time-server-protocol.h"
-#include "xdg-output-unstable-v1-server-protocol.h"
-#include "linux-explicit-synchronization-unstable-v1-server-protocol.h"
-#include "linux-explicit-synchronization.h"
-#include "shared/fd-util.h"
-#include "shared/helpers.h"
-#include "shared/os-compatibility.h"
-#include "shared/string-helpers.h"
-#include "shared/timespec-util.h"
-#include "git-version.h"
-#include <libweston/version.h>
-#include <libweston/plugin-registry.h>
-#include "pixel-formats.h"
-#include "backend.h"
-#include "libweston-internal.h"
-
-#include "weston-log-internal.h"
-
-/**
- * \defgroup head Head
- * \defgroup output Output
- * \defgroup compositor Compositor
- */
-
-#define DEFAULT_REPAINT_WINDOW 7 /* milliseconds */
-
-static void
-weston_output_update_matrix(struct weston_output *output);
-
-static void
-weston_output_transform_scale_init(struct weston_output *output,
- uint32_t transform, uint32_t scale);
-
-static void
-weston_compositor_build_view_list(struct weston_compositor *compositor);
-
-static char *
-weston_output_create_heads_string(struct weston_output *output);
-
-/** Send wl_output events for mode and scale changes
- *
- * \param head Send on all resources bound to this head.
- * \param mode_changed If true, send the current mode.
- * \param scale_changed If true, send the current scale.
- */
-static void
-weston_mode_switch_send_events(struct weston_head *head,
- bool mode_changed, bool scale_changed)
-{
- struct weston_output *output = head->output;
- struct wl_resource *resource;
- int version;
-
- wl_resource_for_each(resource, &head->resource_list) {
- if (mode_changed) {
- wl_output_send_mode(resource,
- output->current_mode->flags,
- output->current_mode->width,
- output->current_mode->height,
- output->current_mode->refresh);
- }
-
- version = wl_resource_get_version(resource);
- if (version >= WL_OUTPUT_SCALE_SINCE_VERSION && scale_changed)
- wl_output_send_scale(resource, output->current_scale);
-
- if (version >= WL_OUTPUT_DONE_SINCE_VERSION)
- wl_output_send_done(resource);
- }
- wl_resource_for_each(resource, &head->xdg_output_resource_list) {
- zxdg_output_v1_send_logical_position(resource,
- output->x,
- output->y);
- zxdg_output_v1_send_logical_size(resource,
- output->width,
- output->height);
- zxdg_output_v1_send_done(resource);
- }
-}
-
-static void
-weston_mode_switch_finish(struct weston_output *output,
- int mode_changed, int scale_changed)
-{
- struct weston_seat *seat;
- struct weston_head *head;
- pixman_region32_t old_output_region;
-
- pixman_region32_init(&old_output_region);
- pixman_region32_copy(&old_output_region, &output->region);
-
- /* Update output region and transformation matrix */
- weston_output_transform_scale_init(output, output->transform, output->current_scale);
-
- pixman_region32_init_rect(&output->region, output->x, output->y,
- output->width, output->height);
-
- weston_output_update_matrix(output);
-
- /* If a pointer falls outside the outputs new geometry, move it to its
- * lower-right corner */
- wl_list_for_each(seat, &output->compositor->seat_list, link) {
- struct weston_pointer *pointer = weston_seat_get_pointer(seat);
- int32_t x, y;
-
- if (!pointer)
- continue;
-
- x = wl_fixed_to_int(pointer->x);
- y = wl_fixed_to_int(pointer->y);
-
- if (!pixman_region32_contains_point(&old_output_region,
- x, y, NULL) ||
- pixman_region32_contains_point(&output->region,
- x, y, NULL))
- continue;
-
- if (x >= output->x + output->width)
- x = output->x + output->width - 1;
- if (y >= output->y + output->height)
- y = output->y + output->height - 1;
-
- pointer->x = wl_fixed_from_int(x);
- pointer->y = wl_fixed_from_int(y);
- }
-
- pixman_region32_fini(&old_output_region);
-
- if (!mode_changed && !scale_changed)
- return;
-
- /* notify clients of the changes */
- wl_list_for_each(head, &output->head_list, output_link)
- weston_mode_switch_send_events(head,
- mode_changed, scale_changed);
-}
-
-static void
-weston_compositor_reflow_outputs(struct weston_compositor *compositor,
- struct weston_output *resized_output, int delta_width);
-
-/**
- * \ingroup output
- */
-WL_EXPORT int
-weston_output_mode_set_native(struct weston_output *output,
- struct weston_mode *mode,
- int32_t scale)
-{
- int ret;
- int mode_changed = 0, scale_changed = 0;
- int32_t old_width;
-
- if (!output->switch_mode)
- return -1;
-
- if (!output->original_mode) {
- mode_changed = 1;
- ret = output->switch_mode(output, mode);
- if (ret < 0)
- return ret;
- if (output->current_scale != scale) {
- scale_changed = 1;
- output->current_scale = scale;
- }
- }
-
- old_width = output->width;
- output->native_mode = mode;
- output->native_scale = scale;
-
- weston_mode_switch_finish(output, mode_changed, scale_changed);
-
- if (mode_changed || scale_changed) {
- weston_compositor_reflow_outputs(output->compositor, output, output->width - old_width);
-
- wl_signal_emit(&output->compositor->output_resized_signal, output);
- }
- return 0;
-}
-
-/**
- * \ingroup output
- */
-WL_EXPORT int
-weston_output_mode_switch_to_native(struct weston_output *output)
-{
- int ret;
- int mode_changed = 0, scale_changed = 0;
-
- if (!output->switch_mode)
- return -1;
-
- if (!output->original_mode) {
- weston_log("already in the native mode\n");
- return -1;
- }
- /* the non fullscreen clients haven't seen a mode set since we
- * switched into a temporary, so we need to notify them if the
- * mode at that time is different from the native mode now.
- */
- mode_changed = (output->original_mode != output->native_mode);
- scale_changed = (output->original_scale != output->native_scale);
-
- ret = output->switch_mode(output, output->native_mode);
- if (ret < 0)
- return ret;
-
- output->current_scale = output->native_scale;
-
- output->original_mode = NULL;
- output->original_scale = 0;
-
- weston_mode_switch_finish(output, mode_changed, scale_changed);
-
- return 0;
-}
-
-/**
- * \ingroup output
- */
-WL_EXPORT int
-weston_output_mode_switch_to_temporary(struct weston_output *output,
- struct weston_mode *mode,
- int32_t scale)
-{
- int ret;
-
- if (!output->switch_mode)
- return -1;
-
- /* original_mode is the last mode non full screen clients have seen,
- * so we shouldn't change it if we already have one set.
- */
- if (!output->original_mode) {
- output->original_mode = output->native_mode;
- output->original_scale = output->native_scale;
- }
- ret = output->switch_mode(output, mode);
- if (ret < 0)
- return ret;
-
- output->current_scale = scale;
-
- weston_mode_switch_finish(output, 0, 0);
-
- return 0;
-}
-
-static void
-region_init_infinite(pixman_region32_t *region)
-{
- pixman_region32_init_rect(region, INT32_MIN, INT32_MIN,
- UINT32_MAX, UINT32_MAX);
-}
-
-static struct weston_subsurface *
-weston_surface_to_subsurface(struct weston_surface *surface);
-
-WL_EXPORT struct weston_view *
-weston_view_create(struct weston_surface *surface)
-{
- struct weston_view *view;
-
- view = zalloc(sizeof *view);
- if (view == NULL)
- return NULL;
-
- view->surface = surface;
- view->plane = &surface->compositor->primary_plane;
-
- /* Assign to surface */
- wl_list_insert(&surface->views, &view->surface_link);
-
- wl_signal_init(&view->destroy_signal);
- wl_list_init(&view->link);
- wl_list_init(&view->layer_link.link);
-
- pixman_region32_init(&view->clip);
-
- view->alpha = 1.0;
- pixman_region32_init(&view->transform.opaque);
-
- wl_list_init(&view->geometry.transformation_list);
- wl_list_insert(&view->geometry.transformation_list,
- &view->transform.position.link);
- weston_matrix_init(&view->transform.position.matrix);
- wl_list_init(&view->geometry.child_list);
- pixman_region32_init(&view->geometry.scissor);
- pixman_region32_init(&view->transform.boundingbox);
- view->transform.dirty = 1;
-
- return view;
-}
-
-struct weston_frame_callback {
- struct wl_resource *resource;
- struct wl_list link;
-};
-
-struct weston_presentation_feedback {
- struct wl_resource *resource;
-
- /* XXX: could use just wl_resource_get_link() instead */
- struct wl_list link;
-
- /* The per-surface feedback flags */
- uint32_t psf_flags;
-};
-
-static void
-weston_presentation_feedback_discard(
- struct weston_presentation_feedback *feedback)
-{
- wp_presentation_feedback_send_discarded(feedback->resource);
- wl_resource_destroy(feedback->resource);
-}
-
-static void
-weston_presentation_feedback_discard_list(struct wl_list *list)
-{
- struct weston_presentation_feedback *feedback, *tmp;
-
- wl_list_for_each_safe(feedback, tmp, list, link)
- weston_presentation_feedback_discard(feedback);
-}
-
-static void
-weston_presentation_feedback_present(
- struct weston_presentation_feedback *feedback,
- struct weston_output *output,
- uint32_t refresh_nsec,
- const struct timespec *ts,
- uint64_t seq,
- uint32_t flags)
-{
- struct wl_client *client = wl_resource_get_client(feedback->resource);
- struct weston_head *head;
- struct wl_resource *o;
- uint32_t tv_sec_hi;
- uint32_t tv_sec_lo;
- uint32_t tv_nsec;
- bool done = false;
-
- wl_list_for_each(head, &output->head_list, output_link) {
- wl_resource_for_each(o, &head->resource_list) {
- if (wl_resource_get_client(o) != client)
- continue;
-
- wp_presentation_feedback_send_sync_output(feedback->resource, o);
- done = true;
- }
-
- /* For clone mode, send it for just one wl_output global,
- * they are all equivalent anyway.
- */
- if (done)
- break;
- }
-
- timespec_to_proto(ts, &tv_sec_hi, &tv_sec_lo, &tv_nsec);
- wp_presentation_feedback_send_presented(feedback->resource,
- tv_sec_hi, tv_sec_lo, tv_nsec,
- refresh_nsec,
- seq >> 32, seq & 0xffffffff,
- flags | feedback->psf_flags);
- wl_resource_destroy(feedback->resource);
-}
-
-static void
-weston_presentation_feedback_present_list(struct wl_list *list,
- struct weston_output *output,
- uint32_t refresh_nsec,
- const struct timespec *ts,
- uint64_t seq,
- uint32_t flags)
-{
- struct weston_presentation_feedback *feedback, *tmp;
-
- assert(!(flags & WP_PRESENTATION_FEEDBACK_INVALID) ||
- wl_list_empty(list));
-
- wl_list_for_each_safe(feedback, tmp, list, link)
- weston_presentation_feedback_present(feedback, output,
- refresh_nsec, ts, seq,
- flags);
-}
-
-static void
-surface_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
-{
- struct weston_surface_state *state =
- container_of(listener, struct weston_surface_state,
- buffer_destroy_listener);
-
- state->buffer = NULL;
-}
-
-static void
-weston_surface_state_init(struct weston_surface_state *state)
-{
- state->newly_attached = 0;
- state->buffer = NULL;
- state->buffer_destroy_listener.notify =
- surface_state_handle_buffer_destroy;
- state->sx = 0;
- state->sy = 0;
-
- pixman_region32_init(&state->damage_surface);
- pixman_region32_init(&state->damage_buffer);
- pixman_region32_init(&state->opaque);
- region_init_infinite(&state->input);
-
- wl_list_init(&state->frame_callback_list);
- wl_list_init(&state->feedback_list);
-
- state->buffer_viewport.buffer.transform = WL_OUTPUT_TRANSFORM_NORMAL;
- state->buffer_viewport.buffer.scale = 1;
- state->buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
- state->buffer_viewport.surface.width = -1;
- state->buffer_viewport.changed = 0;
-
- state->acquire_fence_fd = -1;
-
- state->desired_protection = WESTON_HDCP_DISABLE;
- state->protection_mode = WESTON_SURFACE_PROTECTION_MODE_RELAXED;
-}
-
-static void
-weston_surface_state_fini(struct weston_surface_state *state)
-{
- struct weston_frame_callback *cb, *next;
-
- wl_list_for_each_safe(cb, next,
- &state->frame_callback_list, link)
- wl_resource_destroy(cb->resource);
-
- weston_presentation_feedback_discard_list(&state->feedback_list);
-
- pixman_region32_fini(&state->input);
- pixman_region32_fini(&state->opaque);
- pixman_region32_fini(&state->damage_surface);
- pixman_region32_fini(&state->damage_buffer);
-
- if (state->buffer)
- wl_list_remove(&state->buffer_destroy_listener.link);
- state->buffer = NULL;
-
- fd_clear(&state->acquire_fence_fd);
- weston_buffer_release_reference(&state->buffer_release_ref, NULL);
-}
-
-static void
-weston_surface_state_set_buffer(struct weston_surface_state *state,
- struct weston_buffer *buffer)
-{
- if (state->buffer == buffer)
- return;
-
- if (state->buffer)
- wl_list_remove(&state->buffer_destroy_listener.link);
- state->buffer = buffer;
- if (state->buffer)
- wl_signal_add(&state->buffer->destroy_signal,
- &state->buffer_destroy_listener);
-}
-
-WL_EXPORT struct weston_surface *
-weston_surface_create(struct weston_compositor *compositor)
-{
- struct weston_surface *surface;
-
- surface = zalloc(sizeof *surface);
- if (surface == NULL)
- return NULL;
-
- wl_signal_init(&surface->destroy_signal);
- wl_signal_init(&surface->commit_signal);
-
- surface->compositor = compositor;
- surface->ref_count = 1;
-
- surface->buffer_viewport.buffer.transform = WL_OUTPUT_TRANSFORM_NORMAL;
- surface->buffer_viewport.buffer.scale = 1;
- surface->buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
- surface->buffer_viewport.surface.width = -1;
-
- weston_surface_state_init(&surface->pending);
-
- pixman_region32_init(&surface->damage);
- pixman_region32_init(&surface->opaque);
- region_init_infinite(&surface->input);
-
- wl_list_init(&surface->views);
-
- wl_list_init(&surface->frame_callback_list);
- wl_list_init(&surface->feedback_list);
-
- wl_list_init(&surface->subsurface_list);
- wl_list_init(&surface->subsurface_list_pending);
-
- weston_matrix_init(&surface->buffer_to_surface_matrix);
- weston_matrix_init(&surface->surface_to_buffer_matrix);
-
- wl_list_init(&surface->pointer_constraints);
-
- surface->acquire_fence_fd = -1;
-
- surface->desired_protection = WESTON_HDCP_DISABLE;
- surface->current_protection = WESTON_HDCP_DISABLE;
- surface->protection_mode = WESTON_SURFACE_PROTECTION_MODE_RELAXED;
-
- return surface;
-}
-
-WL_EXPORT void
-weston_surface_set_color(struct weston_surface *surface,
- float red, float green, float blue, float alpha)
-{
- surface->compositor->renderer->surface_set_color(surface, red, green, blue, alpha);
- surface->is_opaque = !(alpha < 1.0);
-}
-
-WL_EXPORT void
-weston_view_to_global_float(struct weston_view *view,
- float sx, float sy, float *x, float *y)
-{
- if (view->transform.enabled) {
- struct weston_vector v = { { sx, sy, 0.0f, 1.0f } };
-
- weston_matrix_transform(&view->transform.matrix, &v);
-
- if (fabsf(v.f[3]) < 1e-6) {
- weston_log("warning: numerical instability in "
- "%s(), divisor = %g\n", __func__,
- v.f[3]);
- *x = 0;
- *y = 0;
- return;
- }
-
- *x = v.f[0] / v.f[3];
- *y = v.f[1] / v.f[3];
- } else {
- *x = sx + view->geometry.x;
- *y = sy + view->geometry.y;
- }
-}
-
-WL_EXPORT void
-weston_transformed_coord(int width, int height,
- enum wl_output_transform transform,
- int32_t scale,
- float sx, float sy, float *bx, float *by)
-{
- switch (transform) {
- case WL_OUTPUT_TRANSFORM_NORMAL:
- default:
- *bx = sx;
- *by = sy;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED:
- *bx = width - sx;
- *by = sy;
- break;
- case WL_OUTPUT_TRANSFORM_90:
- *bx = height - sy;
- *by = sx;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- *bx = height - sy;
- *by = width - sx;
- break;
- case WL_OUTPUT_TRANSFORM_180:
- *bx = width - sx;
- *by = height - sy;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_180:
- *bx = sx;
- *by = height - sy;
- break;
- case WL_OUTPUT_TRANSFORM_270:
- *bx = sy;
- *by = width - sx;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- *bx = sy;
- *by = sx;
- break;
- }
-
- *bx *= scale;
- *by *= scale;
-}
-
-WL_EXPORT pixman_box32_t
-weston_transformed_rect(int width, int height,
- enum wl_output_transform transform,
- int32_t scale,
- pixman_box32_t rect)
-{
- float x1, x2, y1, y2;
-
- pixman_box32_t ret;
-
- weston_transformed_coord(width, height, transform, scale,
- rect.x1, rect.y1, &x1, &y1);
- weston_transformed_coord(width, height, transform, scale,
- rect.x2, rect.y2, &x2, &y2);
-
- if (x1 <= x2) {
- ret.x1 = x1;
- ret.x2 = x2;
- } else {
- ret.x1 = x2;
- ret.x2 = x1;
- }
-
- if (y1 <= y2) {
- ret.y1 = y1;
- ret.y2 = y2;
- } else {
- ret.y1 = y2;
- ret.y2 = y1;
- }
-
- return ret;
-}
-
-/** Transform a region by a matrix, restricted to axis-aligned transformations
- *
- * Warning: This function does not work for projective, affine, or matrices
- * that encode arbitrary rotations. Only 90-degree step rotations are
- * supported.
- */
-WL_EXPORT void
-weston_matrix_transform_region(pixman_region32_t *dest,
- struct weston_matrix *matrix,
- pixman_region32_t *src)
-{
- pixman_box32_t *src_rects, *dest_rects;
- int nrects, i;
-
- src_rects = pixman_region32_rectangles(src, &nrects);
- dest_rects = malloc(nrects * sizeof(*dest_rects));
- if (!dest_rects)
- return;
-
- for (i = 0; i < nrects; i++) {
- struct weston_vector vec1 = {{
- src_rects[i].x1, src_rects[i].y1, 0, 1
- }};
- weston_matrix_transform(matrix, &vec1);
- vec1.f[0] /= vec1.f[3];
- vec1.f[1] /= vec1.f[3];
-
- struct weston_vector vec2 = {{
- src_rects[i].x2, src_rects[i].y2, 0, 1
- }};
- weston_matrix_transform(matrix, &vec2);
- vec2.f[0] /= vec2.f[3];
- vec2.f[1] /= vec2.f[3];
-
- if (vec1.f[0] < vec2.f[0]) {
- dest_rects[i].x1 = floor(vec1.f[0]);
- dest_rects[i].x2 = ceil(vec2.f[0]);
- } else {
- dest_rects[i].x1 = floor(vec2.f[0]);
- dest_rects[i].x2 = ceil(vec1.f[0]);
- }
-
- if (vec1.f[1] < vec2.f[1]) {
- dest_rects[i].y1 = floor(vec1.f[1]);
- dest_rects[i].y2 = ceil(vec2.f[1]);
- } else {
- dest_rects[i].y1 = floor(vec2.f[1]);
- dest_rects[i].y2 = ceil(vec1.f[1]);
- }
- }
-
- pixman_region32_clear(dest);
- pixman_region32_init_rects(dest, dest_rects, nrects);
- free(dest_rects);
-}
-
-WL_EXPORT void
-weston_transformed_region(int width, int height,
- enum wl_output_transform transform,
- int32_t scale,
- pixman_region32_t *src, pixman_region32_t *dest)
-{
- pixman_box32_t *src_rects, *dest_rects;
- int nrects, i;
-
- if (transform == WL_OUTPUT_TRANSFORM_NORMAL && scale == 1) {
- if (src != dest)
- pixman_region32_copy(dest, src);
- return;
- }
-
- src_rects = pixman_region32_rectangles(src, &nrects);
- dest_rects = malloc(nrects * sizeof(*dest_rects));
- if (!dest_rects)
- return;
-
- if (transform == WL_OUTPUT_TRANSFORM_NORMAL) {
- memcpy(dest_rects, src_rects, nrects * sizeof(*dest_rects));
- } else {
- for (i = 0; i < nrects; i++) {
- switch (transform) {
- default:
- case WL_OUTPUT_TRANSFORM_NORMAL:
- dest_rects[i].x1 = src_rects[i].x1;
- dest_rects[i].y1 = src_rects[i].y1;
- dest_rects[i].x2 = src_rects[i].x2;
- dest_rects[i].y2 = src_rects[i].y2;
- break;
- case WL_OUTPUT_TRANSFORM_90:
- dest_rects[i].x1 = height - src_rects[i].y2;
- dest_rects[i].y1 = src_rects[i].x1;
- dest_rects[i].x2 = height - src_rects[i].y1;
- dest_rects[i].y2 = src_rects[i].x2;
- break;
- case WL_OUTPUT_TRANSFORM_180:
- dest_rects[i].x1 = width - src_rects[i].x2;
- dest_rects[i].y1 = height - src_rects[i].y2;
- dest_rects[i].x2 = width - src_rects[i].x1;
- dest_rects[i].y2 = height - src_rects[i].y1;
- break;
- case WL_OUTPUT_TRANSFORM_270:
- dest_rects[i].x1 = src_rects[i].y1;
- dest_rects[i].y1 = width - src_rects[i].x2;
- dest_rects[i].x2 = src_rects[i].y2;
- dest_rects[i].y2 = width - src_rects[i].x1;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED:
- dest_rects[i].x1 = width - src_rects[i].x2;
- dest_rects[i].y1 = src_rects[i].y1;
- dest_rects[i].x2 = width - src_rects[i].x1;
- dest_rects[i].y2 = src_rects[i].y2;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- dest_rects[i].x1 = height - src_rects[i].y2;
- dest_rects[i].y1 = width - src_rects[i].x2;
- dest_rects[i].x2 = height - src_rects[i].y1;
- dest_rects[i].y2 = width - src_rects[i].x1;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_180:
- dest_rects[i].x1 = src_rects[i].x1;
- dest_rects[i].y1 = height - src_rects[i].y2;
- dest_rects[i].x2 = src_rects[i].x2;
- dest_rects[i].y2 = height - src_rects[i].y1;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- dest_rects[i].x1 = src_rects[i].y1;
- dest_rects[i].y1 = src_rects[i].x1;
- dest_rects[i].x2 = src_rects[i].y2;
- dest_rects[i].y2 = src_rects[i].x2;
- break;
- }
- }
- }
-
- if (scale != 1) {
- for (i = 0; i < nrects; i++) {
- dest_rects[i].x1 *= scale;
- dest_rects[i].x2 *= scale;
- dest_rects[i].y1 *= scale;
- dest_rects[i].y2 *= scale;
- }
- }
-
- pixman_region32_clear(dest);
- pixman_region32_init_rects(dest, dest_rects, nrects);
- free(dest_rects);
-}
-
-static void
-viewport_surface_to_buffer(struct weston_surface *surface,
- float sx, float sy, float *bx, float *by)
-{
- struct weston_buffer_viewport *vp = &surface->buffer_viewport;
- double src_width, src_height;
- double src_x, src_y;
-
- if (vp->buffer.src_width == wl_fixed_from_int(-1)) {
- if (vp->surface.width == -1) {
- *bx = sx;
- *by = sy;
- return;
- }
-
- src_x = 0.0;
- src_y = 0.0;
- src_width = surface->width_from_buffer;
- src_height = surface->height_from_buffer;
- } else {
- src_x = wl_fixed_to_double(vp->buffer.src_x);
- src_y = wl_fixed_to_double(vp->buffer.src_y);
- src_width = wl_fixed_to_double(vp->buffer.src_width);
- src_height = wl_fixed_to_double(vp->buffer.src_height);
- }
-
- *bx = sx * src_width / surface->width + src_x;
- *by = sy * src_height / surface->height + src_y;
-}
-
-WL_EXPORT void
-weston_surface_to_buffer_float(struct weston_surface *surface,
- float sx, float sy, float *bx, float *by)
-{
- struct weston_buffer_viewport *vp = &surface->buffer_viewport;
-
- /* first transform coordinates if the viewport is set */
- viewport_surface_to_buffer(surface, sx, sy, bx, by);
-
- weston_transformed_coord(surface->width_from_buffer,
- surface->height_from_buffer,
- vp->buffer.transform, vp->buffer.scale,
- *bx, *by, bx, by);
-}
-
-/** Transform a rectangle from surface coordinates to buffer coordinates
- *
- * \param surface The surface to fetch wp_viewport and buffer transformation
- * from.
- * \param rect The rectangle to transform.
- * \return The transformed rectangle.
- *
- * Viewport and buffer transformations can only do translation, scaling,
- * and rotations in 90-degree steps. Therefore the only loss in the
- * conversion is coordinate rounding.
- *
- * However, some coordinate rounding takes place as an intermediate
- * step before the buffer scale factor is applied, so the rectangle
- * boundary may not be exactly as expected.
- *
- * This is OK for damage tracking since a little extra coverage is
- * not a problem.
- */
-WL_EXPORT pixman_box32_t
-weston_surface_to_buffer_rect(struct weston_surface *surface,
- pixman_box32_t rect)
-{
- struct weston_buffer_viewport *vp = &surface->buffer_viewport;
- float xf, yf;
-
- /* first transform box coordinates if the viewport is set */
- viewport_surface_to_buffer(surface, rect.x1, rect.y1, &xf, &yf);
- rect.x1 = floorf(xf);
- rect.y1 = floorf(yf);
-
- viewport_surface_to_buffer(surface, rect.x2, rect.y2, &xf, &yf);
- rect.x2 = ceilf(xf);
- rect.y2 = ceilf(yf);
-
- return weston_transformed_rect(surface->width_from_buffer,
- surface->height_from_buffer,
- vp->buffer.transform, vp->buffer.scale,
- rect);
-}
-
-/** Transform a region from surface coordinates to buffer coordinates
- *
- * \param surface The surface to fetch wp_viewport and buffer transformation
- * from.
- * \param[in] surface_region The region in surface coordinates.
- * \param[out] buffer_region The region converted to buffer coordinates.
- *
- * Buffer_region must be init'd, but will be completely overwritten.
- *
- * Viewport and buffer transformations can only do translation, scaling,
- * and rotations in 90-degree steps. Therefore the only loss in the
- * conversion is from the coordinate rounding that takes place in
- * \ref weston_surface_to_buffer_rect.
- *
- */
-WL_EXPORT void
-weston_surface_to_buffer_region(struct weston_surface *surface,
- pixman_region32_t *surface_region,
- pixman_region32_t *buffer_region)
-{
- pixman_box32_t *src_rects, *dest_rects;
- int nrects, i;
-
- src_rects = pixman_region32_rectangles(surface_region, &nrects);
- dest_rects = malloc(nrects * sizeof(*dest_rects));
- if (!dest_rects)
- return;
-
- for (i = 0; i < nrects; i++) {
- dest_rects[i] = weston_surface_to_buffer_rect(surface,
- src_rects[i]);
- }
-
- pixman_region32_fini(buffer_region);
- pixman_region32_init_rects(buffer_region, dest_rects, nrects);
- free(dest_rects);
-}
-
-WL_EXPORT void
-weston_view_move_to_plane(struct weston_view *view,
- struct weston_plane *plane)
-{
- if (view->plane == plane)
- return;
-
- weston_view_damage_below(view);
- view->plane = plane;
- weston_surface_damage(view->surface);
-}
-
-/** Inflict damage on the plane where the view is visible.
- *
- * \param view The view that causes the damage.
- *
- * If the view is currently on a plane (including the primary plane),
- * take the view's boundingbox, subtract all the opaque views that cover it,
- * and add the remaining region as damage to the plane. This corresponds
- * to the damage inflicted to the plane if this view disappeared.
- *
- * A repaint is scheduled for this view.
- *
- * The region of all opaque views covering this view is stored in
- * weston_view::clip and updated by view_accumulate_damage() during
- * weston_output_repaint(). Specifically, that region matches the
- * scenegraph as it was last painted.
- */
-WL_EXPORT void
-weston_view_damage_below(struct weston_view *view)
-{
- pixman_region32_t damage;
-
- pixman_region32_init(&damage);
- pixman_region32_subtract(&damage, &view->transform.boundingbox,
- &view->clip);
- if (view->plane)
- pixman_region32_union(&view->plane->damage,
- &view->plane->damage, &damage);
- pixman_region32_fini(&damage);
- weston_view_schedule_repaint(view);
-}
-
-/** Send wl_surface.enter/leave events
- *
- * \param surface The surface.
- * \param head A head of the entered/left output.
- * \param enter True if entered.
- * \param leave True if left.
- *
- * Send the enter/leave events for all protocol objects bound to the given
- * output by the client owning the surface.
- */
-static void
-weston_surface_send_enter_leave(struct weston_surface *surface,
- struct weston_head *head,
- bool enter,
- bool leave)
-{
- struct wl_resource *wloutput;
- struct wl_client *client;
-
- assert(enter != leave);
-
- client = wl_resource_get_client(surface->resource);
- wl_resource_for_each(wloutput, &head->resource_list) {
- if (wl_resource_get_client(wloutput) != client)
- continue;
-
- if (enter)
- wl_surface_send_enter(surface->resource, wloutput);
- if (leave)
- wl_surface_send_leave(surface->resource, wloutput);
- }
-}
-
-static void
-weston_surface_compute_protection(struct protected_surface *psurface)
-{
- enum weston_hdcp_protection min_protection;
- bool min_protection_valid = false;
- struct weston_surface *surface = psurface->surface;
- struct weston_output *output;
-
- wl_list_for_each(output, &surface->compositor->output_list, link)
- if (surface->output_mask & (1u << output->id)) {
- /*
- * If the content-protection is enabled with protection
- * mode as RELAXED for a surface, and if
- * content-recording features like: screen-shooter,
- * recorder, screen-sharing, etc are on, then notify the
- * client, that the protection is disabled.
- *
- * Note: If the protection mode is ENFORCED then there
- * is no need to bother the client as the renderer takes
- * care of censoring the visibility of the protected
- * content.
- */
-
- if (output->disable_planes > 0 &&
- surface->protection_mode == WESTON_SURFACE_PROTECTION_MODE_RELAXED) {
- min_protection = WESTON_HDCP_DISABLE;
- min_protection_valid = true;
- break;
- }
- if (!min_protection_valid) {
- min_protection = output->current_protection;
- min_protection_valid = true;
- }
- if (output->current_protection < min_protection)
- min_protection = output->current_protection;
- }
- if (!min_protection_valid)
- min_protection = WESTON_HDCP_DISABLE;
-
- surface->current_protection = min_protection;
-
- weston_protected_surface_send_event(psurface, surface->current_protection);
-}
-
-static void
-notify_surface_protection_change(void *data)
-{
- struct weston_compositor *compositor = data;
- struct content_protection *cp;
- struct protected_surface *psurface;
-
- cp = compositor->content_protection;
- cp->surface_protection_update = NULL;
-
- /* Notify the clients, whose surfaces are changed */
- wl_list_for_each(psurface, &cp->protected_list, link)
- if (psurface && psurface->surface)
- weston_surface_compute_protection(psurface);
-}
-
-/**
- * \param compositor weston_compositor
- *
- * Schedule an idle task to notify surface about the update in protection,
- * if not already scheduled.
- */
-static void
-weston_schedule_surface_protection_update(struct weston_compositor *compositor)
-{
- struct content_protection *cp = compositor->content_protection;
- struct wl_event_loop *loop;
-
- if (!cp || cp->surface_protection_update)
- return;
- loop = wl_display_get_event_loop(compositor->wl_display);
- cp->surface_protection_update = wl_event_loop_add_idle(loop,
- notify_surface_protection_change,
- compositor);
-}
-
-/**
- * \param es The surface
- * \param mask The new set of outputs for the surface
- *
- * Sets the surface's set of outputs to the ones specified by
- * the new output mask provided. Identifies the outputs that
- * have changed, the posts enter and leave events for these
- * outputs as appropriate.
- */
-static void
-weston_surface_update_output_mask(struct weston_surface *es, uint32_t mask)
-{
- uint32_t different = es->output_mask ^ mask;
- uint32_t entered = mask & different;
- uint32_t left = es->output_mask & different;
- uint32_t output_bit;
- struct weston_output *output;
- struct weston_head *head;
-
- es->output_mask = mask;
- if (es->resource == NULL)
- return;
- if (different == 0)
- return;
-
- wl_list_for_each(output, &es->compositor->output_list, link) {
- output_bit = 1u << output->id;
- if (!(output_bit & different))
- continue;
-
- wl_list_for_each(head, &output->head_list, output_link) {
- weston_surface_send_enter_leave(es, head,
- output_bit & entered,
- output_bit & left);
- }
- }
- /*
- * Change in surfaces' output mask might trigger a change in its
- * protection.
- */
- weston_schedule_surface_protection_update(es->compositor);
-}
-
-static void
-notify_view_output_destroy(struct wl_listener *listener, void *data)
-{
- struct weston_view *view =
- container_of(listener,
- struct weston_view, output_destroy_listener);
-
- view->output = NULL;
- view->output_destroy_listener.notify = NULL;
-}
-
-/** Set the primary output of the view
- *
- * \param view The view whose primary output to set
- * \param output The new primary output for the view
- *
- * Set \a output to be the primary output of the \a view.
- *
- * Notice that the assignment may be temporary; the primary output could be
- * automatically changed. Hence, one cannot rely on the value persisting.
- *
- * Passing NULL as /a output will set the primary output to NULL.
- */
-WL_EXPORT void
-weston_view_set_output(struct weston_view *view, struct weston_output *output)
-{
- if (view->output_destroy_listener.notify) {
- wl_list_remove(&view->output_destroy_listener.link);
- view->output_destroy_listener.notify = NULL;
- }
- view->output = output;
- if (output) {
- view->output_destroy_listener.notify =
- notify_view_output_destroy;
- wl_signal_add(&output->destroy_signal,
- &view->output_destroy_listener);
- }
-}
-
-/** Recalculate which output(s) the surface has views displayed on
- *
- * \param es The surface to remap to outputs
- *
- * Finds the output that is showing the largest amount of one
- * of the surface's various views. This output becomes the
- * surface's primary output for vsync and frame callback purposes.
- *
- * Also notes all outputs of all of the surface's views
- * in the output_mask for the surface.
- */
-static void
-weston_surface_assign_output(struct weston_surface *es)
-{
- struct weston_output *new_output;
- struct weston_view *view;
- pixman_region32_t region;
- uint32_t max, area, mask;
- pixman_box32_t *e;
-
- new_output = NULL;
- max = 0;
- mask = 0;
- pixman_region32_init(&region);
- wl_list_for_each(view, &es->views, surface_link) {
- if (!view->output)
- continue;
-
- pixman_region32_intersect(&region, &view->transform.boundingbox,
- &view->output->region);
-
- e = pixman_region32_extents(&region);
- area = (e->x2 - e->x1) * (e->y2 - e->y1);
-
- mask |= view->output_mask;
-
- if (area >= max) {
- new_output = view->output;
- max = area;
- }
- }
- pixman_region32_fini(&region);
-
- es->output = new_output;
- weston_surface_update_output_mask(es, mask);
-}
-
-/** Recalculate which output(s) the view is displayed on
- *
- * \param ev The view to remap to outputs
- *
- * Identifies the set of outputs that the view is visible on,
- * noting them into the output_mask. The output that the view
- * is most visible on is set as the view's primary output.
- *
- * Also does the same for the view's surface. See
- * weston_surface_assign_output().
- */
-static void
-weston_view_assign_output(struct weston_view *ev)
-{
- struct weston_compositor *ec = ev->surface->compositor;
- struct weston_output *output, *new_output;
- pixman_region32_t region;
- uint32_t max, area, mask;
- pixman_box32_t *e;
-
- new_output = NULL;
- max = 0;
- mask = 0;
- pixman_region32_init(&region);
- wl_list_for_each(output, &ec->output_list, link) {
- if (output->destroying)
- continue;
-
- pixman_region32_intersect(&region, &ev->transform.boundingbox,
- &output->region);
-
- e = pixman_region32_extents(&region);
- area = (e->x2 - e->x1) * (e->y2 - e->y1);
-
- if (area > 0)
- mask |= 1u << output->id;
-
- if (area >= max) {
- new_output = output;
- max = area;
- }
- }
- pixman_region32_fini(&region);
-
- weston_view_set_output(ev, new_output);
- ev->output_mask = mask;
-
- weston_surface_assign_output(ev->surface);
-}
-
-static void
-weston_view_to_view_map(struct weston_view *from, struct weston_view *to,
- int from_x, int from_y, int *to_x, int *to_y)
-{
- float x, y;
-
- weston_view_to_global_float(from, from_x, from_y, &x, &y);
- weston_view_from_global_float(to, x, y, &x, &y);
-
- *to_x = round(x);
- *to_y = round(y);
-}
-
-static void
-weston_view_transfer_scissor(struct weston_view *from, struct weston_view *to)
-{
- pixman_box32_t *a;
- pixman_box32_t b;
-
- a = pixman_region32_extents(&from->geometry.scissor);
-
- weston_view_to_view_map(from, to, a->x1, a->y1, &b.x1, &b.y1);
- weston_view_to_view_map(from, to, a->x2, a->y2, &b.x2, &b.y2);
-
- pixman_region32_fini(&to->geometry.scissor);
- pixman_region32_init_with_extents(&to->geometry.scissor, &b);
-}
-
-static void
-view_compute_bbox(struct weston_view *view, const pixman_box32_t *inbox,
- pixman_region32_t *bbox)
-{
- float min_x = HUGE_VALF, min_y = HUGE_VALF;
- float max_x = -HUGE_VALF, max_y = -HUGE_VALF;
- int32_t s[4][2] = {
- { inbox->x1, inbox->y1 },
- { inbox->x1, inbox->y2 },
- { inbox->x2, inbox->y1 },
- { inbox->x2, inbox->y2 },
- };
- float int_x, int_y;
- int i;
-
- if (inbox->x1 == inbox->x2 || inbox->y1 == inbox->y2) {
- /* avoid rounding empty bbox to 1x1 */
- pixman_region32_init(bbox);
- return;
- }
-
- for (i = 0; i < 4; ++i) {
- float x, y;
- weston_view_to_global_float(view, s[i][0], s[i][1], &x, &y);
- if (x < min_x)
- min_x = x;
- if (x > max_x)
- max_x = x;
- if (y < min_y)
- min_y = y;
- if (y > max_y)
- max_y = y;
- }
-
- int_x = floorf(min_x);
- int_y = floorf(min_y);
- pixman_region32_init_rect(bbox, int_x, int_y,
- ceilf(max_x) - int_x, ceilf(max_y) - int_y);
-}
-
-static void
-weston_view_update_transform_disable(struct weston_view *view)
-{
- view->transform.enabled = 0;
-
- /* round off fractions when not transformed */
- view->geometry.x = roundf(view->geometry.x);
- view->geometry.y = roundf(view->geometry.y);
-
- /* Otherwise identity matrix, but with x and y translation. */
- view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
- view->transform.position.matrix.d[12] = view->geometry.x;
- view->transform.position.matrix.d[13] = view->geometry.y;
-
- view->transform.matrix = view->transform.position.matrix;
-
- view->transform.inverse = view->transform.position.matrix;
- view->transform.inverse.d[12] = -view->geometry.x;
- view->transform.inverse.d[13] = -view->geometry.y;
-
- pixman_region32_init_rect(&view->transform.boundingbox,
- 0, 0,
- view->surface->width,
- view->surface->height);
- if (view->geometry.scissor_enabled)
- pixman_region32_intersect(&view->transform.boundingbox,
- &view->transform.boundingbox,
- &view->geometry.scissor);
-
- pixman_region32_translate(&view->transform.boundingbox,
- view->geometry.x, view->geometry.y);
-
- if (view->alpha == 1.0) {
- pixman_region32_copy(&view->transform.opaque,
- &view->surface->opaque);
- pixman_region32_translate(&view->transform.opaque,
- view->geometry.x,
- view->geometry.y);
- }
-}
-
-static int
-weston_view_update_transform_enable(struct weston_view *view)
-{
- struct weston_view *parent = view->geometry.parent;
- struct weston_matrix *matrix = &view->transform.matrix;
- struct weston_matrix *inverse = &view->transform.inverse;
- struct weston_transform *tform;
- pixman_region32_t surfregion;
- const pixman_box32_t *surfbox;
-
- view->transform.enabled = 1;
-
- /* Otherwise identity matrix, but with x and y translation. */
- view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
- view->transform.position.matrix.d[12] = view->geometry.x;
- view->transform.position.matrix.d[13] = view->geometry.y;
-
- weston_matrix_init(matrix);
- wl_list_for_each(tform, &view->geometry.transformation_list, link)
- weston_matrix_multiply(matrix, &tform->matrix);
-
- if (parent)
- weston_matrix_multiply(matrix, &parent->transform.matrix);
-
- if (weston_matrix_invert(inverse, matrix) < 0) {
- /* Oops, bad total transformation, not invertible */
- weston_log("error: weston_view %p"
- " transformation not invertible.\n", view);
- return -1;
- }
-
- if (view->alpha == 1.0 &&
- matrix->type == WESTON_MATRIX_TRANSFORM_TRANSLATE) {
- pixman_region32_copy(&view->transform.opaque,
- &view->surface->opaque);
- pixman_region32_translate(&view->transform.opaque,
- matrix->d[12],
- matrix->d[13]);
- }
-
- pixman_region32_init_rect(&surfregion, 0, 0,
- view->surface->width, view->surface->height);
- if (view->geometry.scissor_enabled)
- pixman_region32_intersect(&surfregion, &surfregion,
- &view->geometry.scissor);
- surfbox = pixman_region32_extents(&surfregion);
-
- view_compute_bbox(view, surfbox, &view->transform.boundingbox);
- pixman_region32_fini(&surfregion);
-
- return 0;
-}
-
-static struct weston_layer *
-get_view_layer(struct weston_view *view)
-{
- if (view->parent_view)
- return get_view_layer(view->parent_view);
- return view->layer_link.layer;
-}
-
-WL_EXPORT void
-weston_view_update_transform(struct weston_view *view)
-{
- struct weston_view *parent = view->geometry.parent;
- struct weston_layer *layer;
- pixman_region32_t mask;
-
- if (!view->transform.dirty)
- return;
-
- if (parent)
- weston_view_update_transform(parent);
-
- view->transform.dirty = 0;
-
- weston_view_damage_below(view);
-
- pixman_region32_fini(&view->transform.boundingbox);
- pixman_region32_fini(&view->transform.opaque);
- pixman_region32_init(&view->transform.opaque);
-
- /* transform.position is always in transformation_list */
- if (view->geometry.transformation_list.next ==
- &view->transform.position.link &&
- view->geometry.transformation_list.prev ==
- &view->transform.position.link &&
- !parent) {
- weston_view_update_transform_disable(view);
- } else {
- if (weston_view_update_transform_enable(view) < 0)
- weston_view_update_transform_disable(view);
- }
-
- layer = get_view_layer(view);
- if (layer) {
- pixman_region32_init_with_extents(&mask, &layer->mask);
- pixman_region32_intersect(&view->transform.boundingbox,
- &view->transform.boundingbox, &mask);
- pixman_region32_intersect(&view->transform.opaque,
- &view->transform.opaque, &mask);
- pixman_region32_fini(&mask);
- }
-
- if (parent) {
- if (parent->geometry.scissor_enabled) {
- view->geometry.scissor_enabled = true;
- weston_view_transfer_scissor(parent, view);
- } else {
- view->geometry.scissor_enabled = false;
- }
- }
-
- weston_view_damage_below(view);
-
- weston_view_assign_output(view);
-
- wl_signal_emit(&view->surface->compositor->transform_signal,
- view->surface);
-}
-
-WL_EXPORT void
-weston_view_geometry_dirty(struct weston_view *view)
-{
- struct weston_view *child;
-
- /*
- * The invariant: if view->geometry.dirty, then all views
- * in view->geometry.child_list have geometry.dirty too.
- * Corollary: if not parent->geometry.dirty, then all ancestors
- * are not dirty.
- */
-
- if (view->transform.dirty)
- return;
-
- view->transform.dirty = 1;
-
- wl_list_for_each(child, &view->geometry.child_list,
- geometry.parent_link)
- weston_view_geometry_dirty(child);
-}
-
-WL_EXPORT void
-weston_view_to_global_fixed(struct weston_view *view,
- wl_fixed_t vx, wl_fixed_t vy,
- wl_fixed_t *x, wl_fixed_t *y)
-{
- float xf, yf;
-
- weston_view_to_global_float(view,
- wl_fixed_to_double(vx),
- wl_fixed_to_double(vy),
- &xf, &yf);
- *x = wl_fixed_from_double(xf);
- *y = wl_fixed_from_double(yf);
-}
-
-WL_EXPORT void
-weston_view_from_global_float(struct weston_view *view,
- float x, float y, float *vx, float *vy)
-{
- if (view->transform.enabled) {
- struct weston_vector v = { { x, y, 0.0f, 1.0f } };
-
- weston_matrix_transform(&view->transform.inverse, &v);
-
- if (fabsf(v.f[3]) < 1e-6) {
- weston_log("warning: numerical instability in "
- "weston_view_from_global(), divisor = %g\n",
- v.f[3]);
- *vx = 0;
- *vy = 0;
- return;
- }
-
- *vx = v.f[0] / v.f[3];
- *vy = v.f[1] / v.f[3];
- } else {
- *vx = x - view->geometry.x;
- *vy = y - view->geometry.y;
- }
-}
-
-WL_EXPORT void
-weston_view_from_global_fixed(struct weston_view *view,
- wl_fixed_t x, wl_fixed_t y,
- wl_fixed_t *vx, wl_fixed_t *vy)
-{
- float vxf, vyf;
-
- weston_view_from_global_float(view,
- wl_fixed_to_double(x),
- wl_fixed_to_double(y),
- &vxf, &vyf);
- *vx = wl_fixed_from_double(vxf);
- *vy = wl_fixed_from_double(vyf);
-}
-
-WL_EXPORT void
-weston_view_from_global(struct weston_view *view,
- int32_t x, int32_t y, int32_t *vx, int32_t *vy)
-{
- float vxf, vyf;
-
- weston_view_from_global_float(view, x, y, &vxf, &vyf);
- *vx = floorf(vxf);
- *vy = floorf(vyf);
-}
-
-/**
- * \param surface The surface to be repainted
- *
- * Marks the output(s) that the surface is shown on as needing to be
- * repainted. See weston_output_schedule_repaint().
- */
-WL_EXPORT void
-weston_surface_schedule_repaint(struct weston_surface *surface)
-{
- struct weston_output *output;
-
- wl_list_for_each(output, &surface->compositor->output_list, link)
- if (surface->output_mask & (1u << output->id))
- weston_output_schedule_repaint(output);
-}
-
-/**
- * \param view The view to be repainted
- *
- * Marks the output(s) that the view is shown on as needing to be
- * repainted. See weston_output_schedule_repaint().
- */
-WL_EXPORT void
-weston_view_schedule_repaint(struct weston_view *view)
-{
- struct weston_output *output;
-
- wl_list_for_each(output, &view->surface->compositor->output_list, link)
- if (view->output_mask & (1u << output->id))
- weston_output_schedule_repaint(output);
-}
-
-/**
- * XXX: This function does it the wrong way.
- * surface->damage is the damage from the client, and causes
- * surface_flush_damage() to copy pixels. No window management action can
- * cause damage to the client-provided content, warranting re-upload!
- *
- * Instead of surface->damage, this function should record the damage
- * with all the views for this surface to avoid extraneous texture
- * uploads.
- */
-WL_EXPORT void
-weston_surface_damage(struct weston_surface *surface)
-{
- pixman_region32_union_rect(&surface->damage, &surface->damage,
- 0, 0, surface->width,
- surface->height);
-
- weston_surface_schedule_repaint(surface);
-}
-
-WL_EXPORT void
-weston_view_set_position(struct weston_view *view, float x, float y)
-{
- if (view->geometry.x == x && view->geometry.y == y)
- return;
-
- view->geometry.x = x;
- view->geometry.y = y;
- weston_view_geometry_dirty(view);
-}
-
-static void
-transform_parent_handle_parent_destroy(struct wl_listener *listener,
- void *data)
-{
- struct weston_view *view =
- container_of(listener, struct weston_view,
- geometry.parent_destroy_listener);
-
- weston_view_set_transform_parent(view, NULL);
-}
-
-WL_EXPORT void
-weston_view_set_transform_parent(struct weston_view *view,
- struct weston_view *parent)
-{
- if (view->geometry.parent) {
- wl_list_remove(&view->geometry.parent_destroy_listener.link);
- wl_list_remove(&view->geometry.parent_link);
-
- if (!parent)
- view->geometry.scissor_enabled = false;
- }
-
- view->geometry.parent = parent;
-
- view->geometry.parent_destroy_listener.notify =
- transform_parent_handle_parent_destroy;
- if (parent) {
- wl_signal_add(&parent->destroy_signal,
- &view->geometry.parent_destroy_listener);
- wl_list_insert(&parent->geometry.child_list,
- &view->geometry.parent_link);
- }
-
- weston_view_geometry_dirty(view);
-}
-
-/** Set a clip mask rectangle on a view
- *
- * \param view The view to set the clip mask on.
- * \param x Top-left corner X coordinate of the clip rectangle.
- * \param y Top-left corner Y coordinate of the clip rectangle.
- * \param width Width of the clip rectangle, non-negative.
- * \param height Height of the clip rectangle, non-negative.
- *
- * A shell may set a clip mask rectangle on a view. Everything outside
- * the rectangle is cut away for input and output purposes: it is
- * not drawn and cannot be hit by hit-test based input like pointer
- * motion or touch-downs. Everything inside the rectangle will behave
- * normally. Clients are unaware of clipping.
- *
- * The rectangle is set in surface-local coordinates. Setting a clip
- * mask rectangle does not affect the view position, the view is positioned
- * as it would be without a clip. The clip also does not change
- * weston_surface::width,height.
- *
- * The clip mask rectangle is part of transformation inheritance
- * (weston_view_set_transform_parent()). A clip set in the root of the
- * transformation inheritance tree will affect all views in the tree.
- * A clip can be set only on the root view. Attempting to set a clip
- * on view that has a transformation parent will fail. Assigning a parent
- * to a view that has a clip set will cause the clip to be forgotten.
- *
- * Because the clip mask is an axis-aligned rectangle, it poses restrictions
- * on the additional transformations in the child views. These transformations
- * may not rotate the coordinate axes, i.e., only translation and scaling
- * are allowed. Violating this restriction causes the clipping to malfunction.
- * Furthermore, using scaling may cause rounding errors in child clipping.
- *
- * The clip mask rectangle is not automatically adjusted based on
- * wl_surface.attach dx and dy arguments.
- *
- * A clip mask rectangle can be set only if the compositor capability
- * WESTON_CAP_VIEW_CLIP_MASK is present.
- *
- * This function sets the clip mask rectangle and schedules a repaint for
- * the view.
- */
-WL_EXPORT void
-weston_view_set_mask(struct weston_view *view,
- int x, int y, int width, int height)
-{
- struct weston_compositor *compositor = view->surface->compositor;
-
- if (!(compositor->capabilities & WESTON_CAP_VIEW_CLIP_MASK)) {
- weston_log("%s not allowed without capability!\n", __func__);
- return;
- }
-
- if (view->geometry.parent) {
- weston_log("view %p has a parent, clip forbidden!\n", view);
- return;
- }
-
- if (width < 0 || height < 0) {
- weston_log("%s: illegal args %d, %d, %d, %d\n", __func__,
- x, y, width, height);
- return;
- }
-
- pixman_region32_fini(&view->geometry.scissor);
- pixman_region32_init_rect(&view->geometry.scissor, x, y, width, height);
- view->geometry.scissor_enabled = true;
- weston_view_geometry_dirty(view);
- weston_view_schedule_repaint(view);
-}
-
-/** Remove the clip mask from a view
- *
- * \param view The view to remove the clip mask from.
- *
- * Removed the clip mask rectangle and schedules a repaint.
- *
- * \sa weston_view_set_mask
- */
-WL_EXPORT void
-weston_view_set_mask_infinite(struct weston_view *view)
-{
- view->geometry.scissor_enabled = false;
- weston_view_geometry_dirty(view);
- weston_view_schedule_repaint(view);
-}
-
-/* Check if view should be displayed
- *
- * The indicator is set manually when assigning
- * a view to a surface.
- *
- * This needs reworking. See the thread starting at:
- *
- * https://lists.freedesktop.org/archives/wayland-devel/2016-June/029656.html
- */
-WL_EXPORT bool
-weston_view_is_mapped(struct weston_view *view)
-{
- return view->is_mapped;
-}
-
-/* Check if view is opaque in specified region
- *
- * \param view The view to check for opacity.
- * \param region The region to check for opacity, in view coordinates.
- *
- * Returns true if the view is opaque in the specified region, because view
- * alpha is 1.0 and either the opaque region set by the client contains the
- * specified region, or the buffer pixel format or solid color is opaque.
- */
-WL_EXPORT bool
-weston_view_is_opaque(struct weston_view *ev, pixman_region32_t *region)
-{
- pixman_region32_t r;
- bool ret = false;
-
- if (ev->alpha < 1.0)
- return false;
-
- if (ev->surface->is_opaque)
- return true;
-
- if (ev->transform.dirty) {
- weston_log("%s: transform dirty", __func__);
- return false;
- }
-
- pixman_region32_init(&r);
- pixman_region32_subtract(&r, region, &ev->transform.opaque);
-
- if (!pixman_region32_not_empty(&r))
- ret = true;
-
- pixman_region32_fini(&r);
-
- return ret;
-}
-
-/** Check if the view has a valid buffer available
- *
- * @param ev The view to check if it has a valid buffer.
- *
- * Returns true if the view has a valid buffer or false otherwise.
- */
-WL_EXPORT bool
-weston_view_has_valid_buffer(struct weston_view *ev)
-{
- return ev->surface->buffer_ref.buffer != NULL;
-}
-
-/** Check if the view matches the entire output
- *
- * @param ev The view to check.
- * @param output The output to check against.
- *
- * Returns true if the view does indeed matches the entire output.
- */
-WL_EXPORT bool
-weston_view_matches_output_entirely(struct weston_view *ev,
- struct weston_output *output)
-{
- pixman_box32_t *extents =
- pixman_region32_extents(&ev->transform.boundingbox);
-
- if (extents->x1 != output->x ||
- extents->y1 != output->y ||
- extents->x2 != output->x + output->width ||
- extents->y2 != output->y + output->height)
- return false;
-
- return true;
-}
-
-/* Check if a surface has a view assigned to it
- *
- * The indicator is set manually when mapping
- * a surface and creating a view for it.
- *
- * This needs to go. See the thread starting at:
- *
- * https://lists.freedesktop.org/archives/wayland-devel/2016-June/029656.html
- *
- */
-WL_EXPORT bool
-weston_surface_is_mapped(struct weston_surface *surface)
-{
- return surface->is_mapped;
-}
-
-static void
-surface_set_size(struct weston_surface *surface, int32_t width, int32_t height)
-{
- struct weston_view *view;
-
- if (surface->width == width && surface->height == height)
- return;
-
- surface->width = width;
- surface->height = height;
-
- wl_list_for_each(view, &surface->views, surface_link)
- weston_view_geometry_dirty(view);
-}
-
-WL_EXPORT void
-weston_surface_set_size(struct weston_surface *surface,
- int32_t width, int32_t height)
-{
- assert(!surface->resource);
- surface_set_size(surface, width, height);
-}
-
-static int
-fixed_round_up_to_int(wl_fixed_t f)
-{
- return wl_fixed_to_int(wl_fixed_from_int(1) - 1 + f);
-}
-
-static void
-convert_size_by_transform_scale(int32_t *width_out, int32_t *height_out,
- int32_t width, int32_t height,
- uint32_t transform,
- int32_t scale)
-{
- assert(scale > 0);
-
- switch (transform) {
- case WL_OUTPUT_TRANSFORM_NORMAL:
- case WL_OUTPUT_TRANSFORM_180:
- case WL_OUTPUT_TRANSFORM_FLIPPED:
- case WL_OUTPUT_TRANSFORM_FLIPPED_180:
- *width_out = width / scale;
- *height_out = height / scale;
- break;
- case WL_OUTPUT_TRANSFORM_90:
- case WL_OUTPUT_TRANSFORM_270:
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- *width_out = height / scale;
- *height_out = width / scale;
- break;
- default:
- assert(0 && "invalid transform");
- }
-}
-
-static void
-weston_surface_calculate_size_from_buffer(struct weston_surface *surface)
-{
- struct weston_buffer_viewport *vp = &surface->buffer_viewport;
-
- if (!surface->buffer_ref.buffer) {
- surface->width_from_buffer = 0;
- surface->height_from_buffer = 0;
- return;
- }
-
- convert_size_by_transform_scale(&surface->width_from_buffer,
- &surface->height_from_buffer,
- surface->buffer_ref.buffer->width,
- surface->buffer_ref.buffer->height,
- vp->buffer.transform,
- vp->buffer.scale);
-}
-
-static void
-weston_surface_update_size(struct weston_surface *surface)
-{
- struct weston_buffer_viewport *vp = &surface->buffer_viewport;
- int32_t width, height;
-
- width = surface->width_from_buffer;
- height = surface->height_from_buffer;
-
- if (width != 0 && vp->surface.width != -1) {
- surface_set_size(surface,
- vp->surface.width, vp->surface.height);
- return;
- }
-
- if (width != 0 && vp->buffer.src_width != wl_fixed_from_int(-1)) {
- int32_t w = fixed_round_up_to_int(vp->buffer.src_width);
- int32_t h = fixed_round_up_to_int(vp->buffer.src_height);
-
- surface_set_size(surface, w ?: 1, h ?: 1);
- return;
- }
-
- surface_set_size(surface, width, height);
-}
-
-/** weston_compositor_get_time
- * \ingroup compositor
- */
-WL_EXPORT void
-weston_compositor_get_time(struct timespec *time)
-{
- clock_gettime(CLOCK_REALTIME, time);
-}
-
-/** weston_compositor_pick_view
- * \ingroup compositor
- */
-WL_EXPORT struct weston_view *
-weston_compositor_pick_view(struct weston_compositor *compositor,
- wl_fixed_t x, wl_fixed_t y,
- wl_fixed_t *vx, wl_fixed_t *vy)
-{
- struct weston_view *view;
- wl_fixed_t view_x, view_y;
- int view_ix, view_iy;
- int ix = wl_fixed_to_int(x);
- int iy = wl_fixed_to_int(y);
-
- wl_list_for_each(view, &compositor->view_list, link) {
- if (!pixman_region32_contains_point(
- &view->transform.boundingbox, ix, iy, NULL))
- continue;
-
- weston_view_from_global_fixed(view, x, y, &view_x, &view_y);
- view_ix = wl_fixed_to_int(view_x);
- view_iy = wl_fixed_to_int(view_y);
-
- if (!pixman_region32_contains_point(&view->surface->input,
- view_ix, view_iy, NULL))
- continue;
-
- if (view->geometry.scissor_enabled &&
- !pixman_region32_contains_point(&view->geometry.scissor,
- view_ix, view_iy, NULL))
- continue;
-
- *vx = view_x;
- *vy = view_y;
- return view;
- }
-
- *vx = wl_fixed_from_int(-1000000);
- *vy = wl_fixed_from_int(-1000000);
- return NULL;
-}
-
-static void
-weston_compositor_repick(struct weston_compositor *compositor)
-{
- struct weston_seat *seat;
-
- if (!compositor->session_active)
- return;
-
- wl_list_for_each(seat, &compositor->seat_list, link)
- weston_seat_repick(seat);
-}
-
-WL_EXPORT void
-weston_view_unmap(struct weston_view *view)
-{
- struct weston_seat *seat;
-
- if (!weston_view_is_mapped(view))
- return;
-
- weston_view_damage_below(view);
- weston_view_set_output(view, NULL);
- view->plane = NULL;
- view->is_mapped = false;
- weston_layer_entry_remove(&view->layer_link);
- wl_list_remove(&view->link);
- wl_list_init(&view->link);
- 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);
- }
-}
-
-WL_EXPORT void
-weston_surface_unmap(struct weston_surface *surface)
-{
- struct weston_view *view;
-
- surface->is_mapped = false;
- wl_list_for_each(view, &surface->views, surface_link)
- weston_view_unmap(view);
- surface->output = NULL;
-}
-
-static void
-weston_surface_reset_pending_buffer(struct weston_surface *surface)
-{
- weston_surface_state_set_buffer(&surface->pending, NULL);
- surface->pending.sx = 0;
- surface->pending.sy = 0;
- surface->pending.newly_attached = 0;
- surface->pending.buffer_viewport.changed = 0;
-}
-
-WL_EXPORT void
-weston_view_destroy(struct weston_view *view)
-{
- wl_signal_emit(&view->destroy_signal, view);
-
- assert(wl_list_empty(&view->geometry.child_list));
-
- if (weston_view_is_mapped(view)) {
- weston_view_unmap(view);
- weston_compositor_build_view_list(view->surface->compositor);
- }
-
- wl_list_remove(&view->link);
- weston_layer_entry_remove(&view->layer_link);
-
- pixman_region32_fini(&view->clip);
- pixman_region32_fini(&view->geometry.scissor);
- pixman_region32_fini(&view->transform.boundingbox);
- pixman_region32_fini(&view->transform.opaque);
-
- weston_view_set_transform_parent(view, NULL);
- weston_view_set_output(view, NULL);
-
- wl_list_remove(&view->surface_link);
-
- free(view);
-}
-
-WL_EXPORT void
-weston_surface_destroy(struct weston_surface *surface)
-{
- struct weston_frame_callback *cb, *next;
- struct weston_view *ev, *nv;
- struct weston_pointer_constraint *constraint, *next_constraint;
-
- if (--surface->ref_count > 0)
- return;
-
- assert(surface->resource == NULL);
-
- wl_signal_emit(&surface->destroy_signal, surface);
-
- assert(wl_list_empty(&surface->subsurface_list_pending));
- assert(wl_list_empty(&surface->subsurface_list));
-
- wl_list_for_each_safe(ev, nv, &surface->views, surface_link)
- weston_view_destroy(ev);
-
- weston_surface_state_fini(&surface->pending);
-
- weston_buffer_reference(&surface->buffer_ref, NULL);
- weston_buffer_release_reference(&surface->buffer_release_ref, NULL);
-
- pixman_region32_fini(&surface->damage);
- pixman_region32_fini(&surface->opaque);
- pixman_region32_fini(&surface->input);
-
- wl_list_for_each_safe(cb, next, &surface->frame_callback_list, link)
- wl_resource_destroy(cb->resource);
-
- weston_presentation_feedback_discard_list(&surface->feedback_list);
-
- wl_list_for_each_safe(constraint, next_constraint,
- &surface->pointer_constraints,
- link)
- weston_pointer_constraint_destroy(constraint);
-
- fd_clear(&surface->acquire_fence_fd);
-
- free(surface);
-}
-
-static void
-destroy_surface(struct wl_resource *resource)
-{
- struct weston_surface *surface = wl_resource_get_user_data(resource);
-
- assert(surface);
-
- /* Set the resource to NULL, since we don't want to leave a
- * dangling pointer if the surface was refcounted and survives
- * the weston_surface_destroy() call. */
- surface->resource = NULL;
-
- if (surface->viewport_resource)
- wl_resource_set_user_data(surface->viewport_resource, NULL);
-
- if (surface->synchronization_resource) {
- wl_resource_set_user_data(surface->synchronization_resource,
- NULL);
- }
-
- weston_surface_destroy(surface);
-}
-
-static void
-weston_buffer_destroy_handler(struct wl_listener *listener, void *data)
-{
- struct weston_buffer *buffer =
- container_of(listener, struct weston_buffer, destroy_listener);
-
- wl_signal_emit(&buffer->destroy_signal, buffer);
- free(buffer);
-}
-
-WL_EXPORT struct weston_buffer *
-weston_buffer_from_resource(struct wl_resource *resource)
-{
- struct weston_buffer *buffer;
- struct wl_listener *listener;
-
- listener = wl_resource_get_destroy_listener(resource,
- weston_buffer_destroy_handler);
-
- if (listener)
- return container_of(listener, struct weston_buffer,
- destroy_listener);
-
- buffer = zalloc(sizeof *buffer);
- if (buffer == NULL)
- return NULL;
-
- buffer->resource = resource;
- wl_signal_init(&buffer->destroy_signal);
- buffer->destroy_listener.notify = weston_buffer_destroy_handler;
- buffer->y_inverted = 1;
- wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
-
- return buffer;
-}
-
-static void
-weston_buffer_reference_handle_destroy(struct wl_listener *listener,
- void *data)
-{
- struct weston_buffer_reference *ref =
- container_of(listener, struct weston_buffer_reference,
- destroy_listener);
-
- assert((struct weston_buffer *)data == ref->buffer);
- ref->buffer = NULL;
-}
-
-WL_EXPORT void
-weston_buffer_reference(struct weston_buffer_reference *ref,
- struct weston_buffer *buffer)
-{
- if (ref->buffer && buffer != ref->buffer) {
- ref->buffer->busy_count--;
- if (ref->buffer->busy_count == 0) {
- assert(wl_resource_get_client(ref->buffer->resource));
- wl_buffer_send_release(ref->buffer->resource);
- }
- wl_list_remove(&ref->destroy_listener.link);
- }
-
- if (buffer && buffer != ref->buffer) {
- buffer->busy_count++;
- wl_signal_add(&buffer->destroy_signal,
- &ref->destroy_listener);
- }
-
- ref->buffer = buffer;
- ref->destroy_listener.notify = weston_buffer_reference_handle_destroy;
-}
-
-static void
-weston_buffer_release_reference_handle_destroy(struct wl_listener *listener,
- void *data)
-{
- struct weston_buffer_release_reference *ref =
- container_of(listener, struct weston_buffer_release_reference,
- destroy_listener);
-
- assert((struct wl_resource *)data == ref->buffer_release->resource);
- ref->buffer_release = NULL;
-}
-
-static void
-weston_buffer_release_destroy(struct weston_buffer_release *buffer_release)
-{
- struct wl_resource *resource = buffer_release->resource;
- int release_fence_fd = buffer_release->fence_fd;
-
- if (release_fence_fd >= 0) {
- zwp_linux_buffer_release_v1_send_fenced_release(
- resource, release_fence_fd);
- } else {
- zwp_linux_buffer_release_v1_send_immediate_release(
- resource);
- }
-
- wl_resource_destroy(resource);
-}
-
-WL_EXPORT void
-weston_buffer_release_reference(struct weston_buffer_release_reference *ref,
- struct weston_buffer_release *buffer_release)
-{
- if (buffer_release == ref->buffer_release)
- return;
-
- if (ref->buffer_release) {
- ref->buffer_release->ref_count--;
- wl_list_remove(&ref->destroy_listener.link);
- if (ref->buffer_release->ref_count == 0)
- weston_buffer_release_destroy(ref->buffer_release);
- }
-
- if (buffer_release) {
- buffer_release->ref_count++;
- wl_resource_add_destroy_listener(buffer_release->resource,
- &ref->destroy_listener);
- }
-
- ref->buffer_release = buffer_release;
- ref->destroy_listener.notify =
- weston_buffer_release_reference_handle_destroy;
-}
-
-WL_EXPORT void
-weston_buffer_release_move(struct weston_buffer_release_reference *dest,
- struct weston_buffer_release_reference *src)
-{
- weston_buffer_release_reference(dest, src->buffer_release);
- weston_buffer_release_reference(src, NULL);
-}
-
-static void
-weston_surface_attach(struct weston_surface *surface,
- struct weston_buffer *buffer)
-{
- weston_buffer_reference(&surface->buffer_ref, buffer);
-
- if (!buffer) {
- if (weston_surface_is_mapped(surface))
- weston_surface_unmap(surface);
- }
-
- surface->compositor->renderer->attach(surface, buffer);
-
- weston_surface_calculate_size_from_buffer(surface);
- weston_presentation_feedback_discard_list(&surface->feedback_list);
-}
-
-/** weston_compositor_damage_all
- * \ingroup compositor
- */
-WL_EXPORT void
-weston_compositor_damage_all(struct weston_compositor *compositor)
-{
- struct weston_output *output;
-
- wl_list_for_each(output, &compositor->output_list, link)
- weston_output_damage(output);
-}
-
-/**
- * \ingroup output
- */
-WL_EXPORT void
-weston_output_damage(struct weston_output *output)
-{
- struct weston_compositor *compositor = output->compositor;
-
- pixman_region32_union(&compositor->primary_plane.damage,
- &compositor->primary_plane.damage,
- &output->region);
- weston_output_schedule_repaint(output);
-}
-
-static void
-surface_flush_damage(struct weston_surface *surface)
-{
- if (surface->buffer_ref.buffer &&
- wl_shm_buffer_get(surface->buffer_ref.buffer->resource))
- surface->compositor->renderer->flush_damage(surface);
-
- if (pixman_region32_not_empty(&surface->damage))
- TL_POINT(surface->compositor, "core_flush_damage", TLP_SURFACE(surface),
- TLP_OUTPUT(surface->output), TLP_END);
-
- pixman_region32_clear(&surface->damage);
-}
-
-static void
-view_accumulate_damage(struct weston_view *view,
- pixman_region32_t *opaque)
-{
- pixman_region32_t damage;
-
- pixman_region32_init(&damage);
- if (view->transform.enabled) {
- pixman_box32_t *extents;
-
- extents = pixman_region32_extents(&view->surface->damage);
- view_compute_bbox(view, extents, &damage);
- } else {
- pixman_region32_copy(&damage, &view->surface->damage);
- pixman_region32_translate(&damage,
- view->geometry.x, view->geometry.y);
- }
-
- pixman_region32_intersect(&damage, &damage,
- &view->transform.boundingbox);
- pixman_region32_subtract(&damage, &damage, opaque);
- pixman_region32_union(&view->plane->damage,
- &view->plane->damage, &damage);
- pixman_region32_fini(&damage);
- pixman_region32_copy(&view->clip, opaque);
- pixman_region32_union(opaque, opaque, &view->transform.opaque);
-}
-
-static void
-compositor_accumulate_damage(struct weston_compositor *ec)
-{
- struct weston_plane *plane;
- struct weston_view *ev;
- pixman_region32_t opaque, clip;
-
- pixman_region32_init(&clip);
-
- wl_list_for_each(plane, &ec->plane_list, link) {
- pixman_region32_copy(&plane->clip, &clip);
-
- pixman_region32_init(&opaque);
-
- wl_list_for_each(ev, &ec->view_list, link) {
- if (ev->plane != plane)
- continue;
-
- view_accumulate_damage(ev, &opaque);
- }
-
- pixman_region32_union(&clip, &clip, &opaque);
- pixman_region32_fini(&opaque);
- }
-
- pixman_region32_fini(&clip);
-
- wl_list_for_each(ev, &ec->view_list, link)
- ev->surface->touched = false;
-
- wl_list_for_each(ev, &ec->view_list, link) {
- if (ev->surface->touched)
- continue;
- ev->surface->touched = true;
-
- surface_flush_damage(ev->surface);
-
- /* Both the renderer and the backend have seen the buffer
- * by now. If renderer needs the buffer, it has its own
- * reference set. If the backend wants to keep the buffer
- * around for migrating the surface into a non-primary plane
- * later, keep_buffer is true. Otherwise, drop the core
- * reference now, and allow early buffer release. This enables
- * clients to use single-buffering.
- */
- if (!ev->surface->keep_buffer) {
- weston_buffer_reference(&ev->surface->buffer_ref, NULL);
- weston_buffer_release_reference(
- &ev->surface->buffer_release_ref, NULL);
- }
- }
-}
-
-static void
-surface_stash_subsurface_views(struct weston_surface *surface)
-{
- struct weston_subsurface *sub;
-
- wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
- if (sub->surface == surface)
- continue;
-
- wl_list_insert_list(&sub->unused_views, &sub->surface->views);
- wl_list_init(&sub->surface->views);
-
- surface_stash_subsurface_views(sub->surface);
- }
-}
-
-static void
-surface_free_unused_subsurface_views(struct weston_surface *surface)
-{
- struct weston_subsurface *sub;
- struct weston_view *view, *nv;
-
- wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
- if (sub->surface == surface)
- continue;
-
- wl_list_for_each_safe(view, nv, &sub->unused_views, surface_link) {
- weston_view_unmap (view);
- weston_view_destroy(view);
- }
-
- surface_free_unused_subsurface_views(sub->surface);
- }
-}
-
-static void
-view_list_add_subsurface_view(struct weston_compositor *compositor,
- struct weston_subsurface *sub,
- struct weston_view *parent)
-{
- struct weston_subsurface *child;
- struct weston_view *view = NULL, *iv;
-
- if (!weston_surface_is_mapped(sub->surface))
- return;
-
- wl_list_for_each(iv, &sub->unused_views, surface_link) {
- if (iv->geometry.parent == parent) {
- view = iv;
- break;
- }
- }
-
- if (view) {
- /* Put it back in the surface's list of views */
- wl_list_remove(&view->surface_link);
- wl_list_insert(&sub->surface->views, &view->surface_link);
- } else {
- view = weston_view_create(sub->surface);
- weston_view_set_position(view,
- sub->position.x,
- sub->position.y);
- weston_view_set_transform_parent(view, parent);
- }
-
- view->parent_view = parent;
- weston_view_update_transform(view);
- view->is_mapped = true;
-
- if (wl_list_empty(&sub->surface->subsurface_list)) {
- wl_list_insert(compositor->view_list.prev, &view->link);
- return;
- }
-
- wl_list_for_each(child, &sub->surface->subsurface_list, parent_link) {
- if (child->surface == sub->surface)
- wl_list_insert(compositor->view_list.prev, &view->link);
- else
- view_list_add_subsurface_view(compositor, child, view);
- }
-}
-
-/* This recursively adds the sub-surfaces for a view, relying on the
- * sub-surface order. Thus, if a client restacks the sub-surfaces, that
- * change first happens to the sub-surface list, and then automatically
- * propagates here. See weston_surface_damage_subsurfaces() for how the
- * sub-surfaces receive damage when the client changes the state.
- */
-static void
-view_list_add(struct weston_compositor *compositor,
- struct weston_view *view)
-{
- struct weston_subsurface *sub;
-
- weston_view_update_transform(view);
-
- if (wl_list_empty(&view->surface->subsurface_list)) {
- wl_list_insert(compositor->view_list.prev, &view->link);
- return;
- }
-
- wl_list_for_each(sub, &view->surface->subsurface_list, parent_link) {
- if (sub->surface == view->surface)
- wl_list_insert(compositor->view_list.prev, &view->link);
- else
- view_list_add_subsurface_view(compositor, sub, view);
- }
-}
-
-static void
-weston_compositor_build_view_list(struct weston_compositor *compositor)
-{
- struct weston_view *view, *tmp;
- struct weston_layer *layer;
-
- wl_list_for_each(layer, &compositor->layer_list, link)
- wl_list_for_each(view, &layer->view_list.link, layer_link.link)
- surface_stash_subsurface_views(view->surface);
-
- wl_list_for_each_safe(view, tmp, &compositor->view_list, link)
- wl_list_init(&view->link);
- wl_list_init(&compositor->view_list);
-
- wl_list_for_each(layer, &compositor->layer_list, link) {
- wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
- view_list_add(compositor, view);
- }
- }
-
- wl_list_for_each(layer, &compositor->layer_list, link)
- wl_list_for_each(view, &layer->view_list.link, layer_link.link)
- surface_free_unused_subsurface_views(view->surface);
-}
-
-static void
-weston_output_take_feedback_list(struct weston_output *output,
- struct weston_surface *surface)
-{
- struct weston_view *view;
- struct weston_presentation_feedback *feedback;
- uint32_t flags = 0xffffffff;
-
- if (wl_list_empty(&surface->feedback_list))
- return;
-
- /* All views must have the flag for the flag to survive. */
- wl_list_for_each(view, &surface->views, surface_link) {
- /* ignore views that are not on this output at all */
- if (view->output_mask & (1u << output->id))
- flags &= view->psf_flags;
- }
-
- wl_list_for_each(feedback, &surface->feedback_list, link)
- feedback->psf_flags = flags;
-
- wl_list_insert_list(&output->feedback_list, &surface->feedback_list);
- wl_list_init(&surface->feedback_list);
-}
-
-static int
-weston_output_repaint(struct weston_output *output, void *repaint_data)
-{
- struct weston_compositor *ec = output->compositor;
- struct weston_view *ev;
- struct weston_animation *animation, *next;
- struct weston_frame_callback *cb, *cnext;
- struct wl_list frame_callback_list;
- pixman_region32_t output_damage;
- int r;
- uint32_t frame_time_msec;
- enum weston_hdcp_protection highest_requested = WESTON_HDCP_DISABLE;
-
- if (output->destroying)
- return 0;
-
- TL_POINT(ec, "core_repaint_begin", TLP_OUTPUT(output), TLP_END);
-
- /* Rebuild the surface list and update surface transforms up front. */
- weston_compositor_build_view_list(ec);
-
- /* Find the highest protection desired for an output */
- wl_list_for_each(ev, &ec->view_list, link) {
- if (ev->surface->output_mask & (1u << output->id)) {
- /*
- * The desired_protection of the output should be the
- * maximum of the desired_protection of the surfaces,
- * that are displayed on that output, to avoid
- * reducing the protection for existing surfaces.
- */
- if (ev->surface->desired_protection > highest_requested)
- highest_requested =
- ev->surface->desired_protection;
- }
- }
-
- output->desired_protection = highest_requested;
-
- if (output->assign_planes && !output->disable_planes) {
- output->assign_planes(output, repaint_data);
- } else {
- wl_list_for_each(ev, &ec->view_list, link) {
- weston_view_move_to_plane(ev, &ec->primary_plane);
- ev->psf_flags = 0;
- }
- }
-
- wl_list_init(&frame_callback_list);
- wl_list_for_each(ev, &ec->view_list, link) {
- /* Note: This operation is safe to do multiple times on the
- * same surface.
- */
- if (ev->surface->output == output) {
- wl_list_insert_list(&frame_callback_list,
- &ev->surface->frame_callback_list);
- wl_list_init(&ev->surface->frame_callback_list);
-
- weston_output_take_feedback_list(output, ev->surface);
- }
- }
-
- compositor_accumulate_damage(ec);
-
- pixman_region32_init(&output_damage);
- pixman_region32_intersect(&output_damage,
- &ec->primary_plane.damage, &output->region);
- pixman_region32_subtract(&output_damage,
- &output_damage, &ec->primary_plane.clip);
-
- if (output->dirty)
- weston_output_update_matrix(output);
-
- r = output->repaint(output, &output_damage, repaint_data);
-
- pixman_region32_fini(&output_damage);
-
- output->repaint_needed = false;
- if (r == 0)
- output->repaint_status = REPAINT_AWAITING_COMPLETION;
-
- weston_compositor_repick(ec);
-
- frame_time_msec = timespec_to_msec(&output->frame_time);
-
- wl_list_for_each_safe(cb, cnext, &frame_callback_list, link) {
- wl_callback_send_done(cb->resource, frame_time_msec);
- wl_resource_destroy(cb->resource);
- }
-
- wl_list_for_each_safe(animation, next, &output->animation_list, link) {
- animation->frame_counter++;
- animation->frame(animation, output, &output->frame_time);
- }
-
- TL_POINT(ec, "core_repaint_posted", TLP_OUTPUT(output), TLP_END);
-
- return r;
-}
-
-static void
-weston_output_schedule_repaint_reset(struct weston_output *output)
-{
- output->repaint_status = REPAINT_NOT_SCHEDULED;
- TL_POINT(output->compositor, "core_repaint_exit_loop",
- TLP_OUTPUT(output), TLP_END);
-}
-
-static int
-weston_output_maybe_repaint(struct weston_output *output, struct timespec *now,
- void *repaint_data)
-{
- struct weston_compositor *compositor = output->compositor;
- int ret = 0;
- int64_t msec_to_repaint;
-
- /* We're not ready yet; come back to make a decision later. */
- if (output->repaint_status != REPAINT_SCHEDULED)
- return ret;
-
- msec_to_repaint = timespec_sub_to_msec(&output->next_repaint, now);
- if (msec_to_repaint > 1)
- return ret;
-
- /* If we're sleeping, drop the repaint machinery entirely; we will
- * explicitly repaint all outputs when we come back. */
- if (compositor->state == WESTON_COMPOSITOR_SLEEPING ||
- compositor->state == WESTON_COMPOSITOR_OFFSCREEN)
- goto err;
-
- /* We don't actually need to repaint this output; drop it from
- * repaint until something causes damage. */
- if (!output->repaint_needed)
- goto err;
-
- /* If repaint fails, we aren't going to get weston_output_finish_frame
- * to trigger a new repaint, so drop it from repaint and hope
- * something schedules a successful repaint later. As repainting may
- * take some time, re-read our clock as a courtesy to the next
- * output. */
- ret = weston_output_repaint(output, repaint_data);
- weston_compositor_read_presentation_clock(compositor, now);
- if (ret != 0)
- goto err;
-
- output->repainted = true;
- return ret;
-
-err:
- weston_output_schedule_repaint_reset(output);
- return ret;
-}
-
-static void
-output_repaint_timer_arm(struct weston_compositor *compositor)
-{
- struct weston_output *output;
- bool any_should_repaint = false;
- struct timespec now;
- int64_t msec_to_next = INT64_MAX;
-
- weston_compositor_read_presentation_clock(compositor, &now);
-
- wl_list_for_each(output, &compositor->output_list, link) {
- int64_t msec_to_this;
-
- if (output->repaint_status != REPAINT_SCHEDULED)
- continue;
-
- msec_to_this = timespec_sub_to_msec(&output->next_repaint,
- &now);
- if (!any_should_repaint || msec_to_this < msec_to_next)
- msec_to_next = msec_to_this;
-
- any_should_repaint = true;
- }
-
- if (!any_should_repaint)
- return;
-
- /* Even if we should repaint immediately, add the minimum 1 ms delay.
- * This is a workaround to allow coalescing multiple output repaints
- * particularly from weston_output_finish_frame()
- * into the same call, which would not happen if we called
- * output_repaint_timer_handler() directly.
- */
- if (msec_to_next < 1)
- msec_to_next = 1;
-
- wl_event_source_timer_update(compositor->repaint_timer, msec_to_next);
-}
-
-static int
-output_repaint_timer_handler(void *data)
-{
- struct weston_compositor *compositor = data;
- struct weston_output *output;
- struct timespec now;
- void *repaint_data = NULL;
- int ret = 0;
-
- weston_compositor_read_presentation_clock(compositor, &now);
-
- if (compositor->backend->repaint_begin)
- repaint_data = compositor->backend->repaint_begin(compositor);
-
- wl_list_for_each(output, &compositor->output_list, link) {
- ret = weston_output_maybe_repaint(output, &now, repaint_data);
- if (ret)
- break;
- }
-
- if (ret == 0) {
- if (compositor->backend->repaint_flush)
- ret = compositor->backend->repaint_flush(compositor,
- repaint_data);
- } else {
- if (compositor->backend->repaint_cancel)
- compositor->backend->repaint_cancel(compositor,
- repaint_data);
- }
-
- if (ret != 0) {
- wl_list_for_each(output, &compositor->output_list, link) {
- if (output->repainted)
- weston_output_schedule_repaint_reset(output);
- }
- }
-
- wl_list_for_each(output, &compositor->output_list, link)
- output->repainted = false;
-
- output_repaint_timer_arm(compositor);
-
- return 0;
-}
-
-/**
- * \ingroup output
- */
-WL_EXPORT void
-weston_output_finish_frame(struct weston_output *output,
- const struct timespec *stamp,
- uint32_t presented_flags)
-{
- struct weston_compositor *compositor = output->compositor;
- int32_t refresh_nsec;
- struct timespec now;
- int64_t msec_rel;
-
-
- assert(output->repaint_status == REPAINT_AWAITING_COMPLETION);
- assert(stamp || (presented_flags & WP_PRESENTATION_FEEDBACK_INVALID));
-
- weston_compositor_read_presentation_clock(compositor, &now);
-
- /* If we haven't been supplied any timestamp at all, we don't have a
- * timebase to work against, so any delay just wastes time. Push a
- * repaint as soon as possible so we can get on with it. */
- if (!stamp) {
- output->next_repaint = now;
- goto out;
- }
-
- TL_POINT(compositor, "core_repaint_finished", TLP_OUTPUT(output),
- TLP_VBLANK(stamp), TLP_END);
-
- refresh_nsec = millihz_to_nsec(output->current_mode->refresh);
- weston_presentation_feedback_present_list(&output->feedback_list,
- output, refresh_nsec, stamp,
- output->msc,
- presented_flags);
-
- output->frame_time = *stamp;
-
- timespec_add_nsec(&output->next_repaint, stamp, refresh_nsec);
- timespec_add_msec(&output->next_repaint, &output->next_repaint,
- -compositor->repaint_msec);
- msec_rel = timespec_sub_to_msec(&output->next_repaint, &now);
-
- if (msec_rel < -1000 || msec_rel > 1000) {
- static bool warned;
-
- if (!warned)
- weston_log("Warning: computed repaint delay is "
- "insane: %lld msec\n", (long long) msec_rel);
- warned = true;
-
- output->next_repaint = now;
- }
-
- /* Called from restart_repaint_loop and restart happens already after
- * the deadline given by repaint_msec? In that case we delay until
- * the deadline of the next frame, to give clients a more predictable
- * timing of the repaint cycle to lock on. */
- if (presented_flags == WP_PRESENTATION_FEEDBACK_INVALID &&
- msec_rel < 0) {
- while (timespec_sub_to_nsec(&output->next_repaint, &now) < 0) {
- timespec_add_nsec(&output->next_repaint,
- &output->next_repaint,
- refresh_nsec);
- }
- }
-
-out:
- output->repaint_status = REPAINT_SCHEDULED;
- output_repaint_timer_arm(compositor);
-}
-
-static void
-idle_repaint(void *data)
-{
- struct weston_output *output = data;
- int ret;
-
- assert(output->repaint_status == REPAINT_BEGIN_FROM_IDLE);
- output->repaint_status = REPAINT_AWAITING_COMPLETION;
- output->idle_repaint_source = NULL;
- ret = output->start_repaint_loop(output);
- if (ret != 0)
- weston_output_schedule_repaint_reset(output);
-}
-
-WL_EXPORT void
-weston_layer_entry_insert(struct weston_layer_entry *list,
- struct weston_layer_entry *entry)
-{
- wl_list_insert(&list->link, &entry->link);
- entry->layer = list->layer;
-}
-
-WL_EXPORT void
-weston_layer_entry_remove(struct weston_layer_entry *entry)
-{
- wl_list_remove(&entry->link);
- wl_list_init(&entry->link);
- entry->layer = NULL;
-}
-
-
-/** Initialize the weston_layer struct.
- *
- * \param compositor The compositor instance
- * \param layer The layer to initialize
- */
-WL_EXPORT void
-weston_layer_init(struct weston_layer *layer,
- struct weston_compositor *compositor)
-{
- layer->compositor = compositor;
- wl_list_init(&layer->link);
- wl_list_init(&layer->view_list.link);
- layer->view_list.layer = layer;
- weston_layer_set_mask_infinite(layer);
-}
-
-/** Sets the position of the layer in the layer list. The layer will be placed
- * below any layer with the same position value, if any.
- * This function is safe to call if the layer is already on the list, but the
- * layer may be moved below other layers at the same position, if any.
- *
- * \param layer The layer to modify
- * \param position The position the layer will be placed at
- */
-WL_EXPORT void
-weston_layer_set_position(struct weston_layer *layer,
- enum weston_layer_position position)
-{
- struct weston_layer *below;
-
- wl_list_remove(&layer->link);
-
- /* layer_list is ordered from top to bottom, the last layer being the
- * background with the smallest position value */
-
- layer->position = position;
- wl_list_for_each_reverse(below, &layer->compositor->layer_list, link) {
- if (below->position >= layer->position) {
- wl_list_insert(&below->link, &layer->link);
- return;
- }
- }
- wl_list_insert(&layer->compositor->layer_list, &layer->link);
-}
-
-/** Hide a layer by taking it off the layer list.
- * This function is safe to call if the layer is not on the list.
- *
- * \param layer The layer to hide
- */
-WL_EXPORT void
-weston_layer_unset_position(struct weston_layer *layer)
-{
- wl_list_remove(&layer->link);
- wl_list_init(&layer->link);
-}
-
-WL_EXPORT void
-weston_layer_set_mask(struct weston_layer *layer,
- int x, int y, int width, int height)
-{
- struct weston_view *view;
-
- layer->mask.x1 = x;
- layer->mask.x2 = x + width;
- layer->mask.y1 = y;
- layer->mask.y2 = y + height;
-
- wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
- weston_view_geometry_dirty(view);
- }
-}
-
-WL_EXPORT void
-weston_layer_set_mask_infinite(struct weston_layer *layer)
-{
- struct weston_view *view;
-
- layer->mask.x1 = INT32_MIN;
- layer->mask.x2 = INT32_MAX;
- layer->mask.y1 = INT32_MIN;
- layer->mask.y2 = INT32_MAX;
-
- wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
- weston_view_geometry_dirty(view);
- }
-}
-
-WL_EXPORT bool
-weston_layer_mask_is_infinite(struct weston_layer *layer)
-{
- return layer->mask.x1 == INT32_MIN &&
- layer->mask.y1 == INT32_MIN &&
- layer->mask.x2 == INT32_MAX &&
- layer->mask.y2 == INT32_MAX;
-}
-
-/**
- * \ingroup output
- */
-WL_EXPORT void
-weston_output_schedule_repaint(struct weston_output *output)
-{
- struct weston_compositor *compositor = output->compositor;
- struct wl_event_loop *loop;
-
- if (compositor->state == WESTON_COMPOSITOR_SLEEPING ||
- compositor->state == WESTON_COMPOSITOR_OFFSCREEN)
- return;
-
- if (!output->repaint_needed)
- TL_POINT(compositor, "core_repaint_req", TLP_OUTPUT(output), TLP_END);
-
- loop = wl_display_get_event_loop(compositor->wl_display);
- output->repaint_needed = true;
-
- /* If we already have a repaint scheduled for our idle handler,
- * no need to set it again. If the repaint has been called but
- * not finished, then weston_output_finish_frame() will notice
- * that a repaint is needed and schedule one. */
- if (output->repaint_status != REPAINT_NOT_SCHEDULED)
- return;
-
- output->repaint_status = REPAINT_BEGIN_FROM_IDLE;
- assert(!output->idle_repaint_source);
- output->idle_repaint_source = wl_event_loop_add_idle(loop, idle_repaint,
- output);
- TL_POINT(compositor, "core_repaint_enter_loop", TLP_OUTPUT(output), TLP_END);
-}
-
-/** weston_compositor_schedule_repaint
- * \ingroup compositor
- */
-WL_EXPORT void
-weston_compositor_schedule_repaint(struct weston_compositor *compositor)
-{
- struct weston_output *output;
-
- wl_list_for_each(output, &compositor->output_list, link)
- weston_output_schedule_repaint(output);
-}
-
-static void
-surface_destroy(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-surface_attach(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
-{
- struct weston_surface *surface = wl_resource_get_user_data(resource);
- struct weston_buffer *buffer = NULL;
-
- if (buffer_resource) {
- buffer = weston_buffer_from_resource(buffer_resource);
- if (buffer == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
- }
-
- /* Attach, attach, without commit in between does not send
- * wl_buffer.release. */
- weston_surface_state_set_buffer(&surface->pending, buffer);
-
- surface->pending.sx = sx;
- surface->pending.sy = sy;
- surface->pending.newly_attached = 1;
-}
-
-static void
-surface_damage(struct wl_client *client,
- struct wl_resource *resource,
- int32_t x, int32_t y, int32_t width, int32_t height)
-{
- struct weston_surface *surface = wl_resource_get_user_data(resource);
-
- if (width <= 0 || height <= 0)
- return;
-
- pixman_region32_union_rect(&surface->pending.damage_surface,
- &surface->pending.damage_surface,
- x, y, width, height);
-}
-
-static void
-surface_damage_buffer(struct wl_client *client,
- struct wl_resource *resource,
- int32_t x, int32_t y, int32_t width, int32_t height)
-{
- struct weston_surface *surface = wl_resource_get_user_data(resource);
-
- if (width <= 0 || height <= 0)
- return;
-
- pixman_region32_union_rect(&surface->pending.damage_buffer,
- &surface->pending.damage_buffer,
- x, y, width, height);
-}
-
-static void
-destroy_frame_callback(struct wl_resource *resource)
-{
- struct weston_frame_callback *cb = wl_resource_get_user_data(resource);
-
- wl_list_remove(&cb->link);
- free(cb);
-}
-
-static void
-surface_frame(struct wl_client *client,
- struct wl_resource *resource, uint32_t callback)
-{
- struct weston_frame_callback *cb;
- struct weston_surface *surface = wl_resource_get_user_data(resource);
-
- cb = malloc(sizeof *cb);
- if (cb == NULL) {
- wl_resource_post_no_memory(resource);
- return;
- }
-
- cb->resource = wl_resource_create(client, &wl_callback_interface, 1,
- callback);
- if (cb->resource == NULL) {
- free(cb);
- wl_resource_post_no_memory(resource);
- return;
- }
-
- wl_resource_set_implementation(cb->resource, NULL, cb,
- destroy_frame_callback);
-
- wl_list_insert(surface->pending.frame_callback_list.prev, &cb->link);
-}
-
-static void
-surface_set_opaque_region(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *region_resource)
-{
- struct weston_surface *surface = wl_resource_get_user_data(resource);
- struct weston_region *region;
-
- if (region_resource) {
- region = wl_resource_get_user_data(region_resource);
- pixman_region32_copy(&surface->pending.opaque,
- &region->region);
- } else {
- pixman_region32_clear(&surface->pending.opaque);
- }
-}
-
-static void
-surface_set_input_region(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *region_resource)
-{
- struct weston_surface *surface = wl_resource_get_user_data(resource);
- struct weston_region *region;
-
- if (region_resource) {
- region = wl_resource_get_user_data(region_resource);
- pixman_region32_copy(&surface->pending.input,
- &region->region);
- } else {
- pixman_region32_fini(&surface->pending.input);
- region_init_infinite(&surface->pending.input);
- }
-}
-
-/* Cause damage to this sub-surface and all its children.
- *
- * This is useful when there are state changes that need an implicit
- * damage, e.g. a z-order change.
- */
-static void
-weston_surface_damage_subsurfaces(struct weston_subsurface *sub)
-{
- struct weston_subsurface *child;
-
- weston_surface_damage(sub->surface);
- sub->reordered = false;
-
- wl_list_for_each(child, &sub->surface->subsurface_list, parent_link)
- if (child != sub)
- weston_surface_damage_subsurfaces(child);
-}
-
-static void
-weston_surface_commit_subsurface_order(struct weston_surface *surface)
-{
- struct weston_subsurface *sub;
-
- wl_list_for_each_reverse(sub, &surface->subsurface_list_pending,
- parent_link_pending) {
- wl_list_remove(&sub->parent_link);
- wl_list_insert(&surface->subsurface_list, &sub->parent_link);
-
- if (sub->reordered)
- weston_surface_damage_subsurfaces(sub);
- }
-}
-
-static void
-weston_surface_build_buffer_matrix(const struct weston_surface *surface,
- struct weston_matrix *matrix)
-{
- const struct weston_buffer_viewport *vp = &surface->buffer_viewport;
- double src_width, src_height, dest_width, dest_height;
-
- weston_matrix_init(matrix);
-
- if (vp->buffer.src_width == wl_fixed_from_int(-1)) {
- src_width = surface->width_from_buffer;
- src_height = surface->height_from_buffer;
- } else {
- src_width = wl_fixed_to_double(vp->buffer.src_width);
- src_height = wl_fixed_to_double(vp->buffer.src_height);
- }
-
- if (vp->surface.width == -1) {
- dest_width = src_width;
- dest_height = src_height;
- } else {
- dest_width = vp->surface.width;
- dest_height = vp->surface.height;
- }
-
- if (src_width != dest_width || src_height != dest_height)
- weston_matrix_scale(matrix,
- src_width / dest_width,
- src_height / dest_height, 1);
-
- if (vp->buffer.src_width != wl_fixed_from_int(-1))
- weston_matrix_translate(matrix,
- wl_fixed_to_double(vp->buffer.src_x),
- wl_fixed_to_double(vp->buffer.src_y),
- 0);
-
- switch (vp->buffer.transform) {
- case WL_OUTPUT_TRANSFORM_FLIPPED:
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- case WL_OUTPUT_TRANSFORM_FLIPPED_180:
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- weston_matrix_scale(matrix, -1, 1, 1);
- weston_matrix_translate(matrix,
- surface->width_from_buffer, 0, 0);
- break;
- }
-
- switch (vp->buffer.transform) {
- default:
- case WL_OUTPUT_TRANSFORM_NORMAL:
- case WL_OUTPUT_TRANSFORM_FLIPPED:
- break;
- case WL_OUTPUT_TRANSFORM_90:
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- weston_matrix_rotate_xy(matrix, 0, 1);
- weston_matrix_translate(matrix,
- surface->height_from_buffer, 0, 0);
- break;
- case WL_OUTPUT_TRANSFORM_180:
- case WL_OUTPUT_TRANSFORM_FLIPPED_180:
- weston_matrix_rotate_xy(matrix, -1, 0);
- weston_matrix_translate(matrix,
- surface->width_from_buffer,
- surface->height_from_buffer, 0);
- break;
- case WL_OUTPUT_TRANSFORM_270:
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- weston_matrix_rotate_xy(matrix, 0, -1);
- weston_matrix_translate(matrix,
- 0, surface->width_from_buffer, 0);
- break;
- }
-
- weston_matrix_scale(matrix, vp->buffer.scale, vp->buffer.scale, 1);
-}
-
-/**
- * Compute a + b > c while being safe to overflows.
- */
-static bool
-fixed_sum_gt(wl_fixed_t a, wl_fixed_t b, wl_fixed_t c)
-{
- return (int64_t)a + (int64_t)b > (int64_t)c;
-}
-
-static bool
-weston_surface_is_pending_viewport_source_valid(
- const struct weston_surface *surface)
-{
- const struct weston_surface_state *pend = &surface->pending;
- const struct weston_buffer_viewport *vp = &pend->buffer_viewport;
- int width_from_buffer = 0;
- int height_from_buffer = 0;
- wl_fixed_t w;
- wl_fixed_t h;
-
- /* If viewport source rect is not set, it is always ok. */
- if (vp->buffer.src_width == wl_fixed_from_int(-1))
- return true;
-
- if (pend->newly_attached) {
- if (pend->buffer) {
- convert_size_by_transform_scale(&width_from_buffer,
- &height_from_buffer,
- pend->buffer->width,
- pend->buffer->height,
- vp->buffer.transform,
- vp->buffer.scale);
- } else {
- /* No buffer: viewport is irrelevant. */
- return true;
- }
- } else {
- width_from_buffer = surface->width_from_buffer;
- height_from_buffer = surface->height_from_buffer;
- }
-
- assert((width_from_buffer == 0) == (height_from_buffer == 0));
- assert(width_from_buffer >= 0 && height_from_buffer >= 0);
-
- /* No buffer: viewport is irrelevant. */
- if (width_from_buffer == 0 || height_from_buffer == 0)
- return true;
-
- /* overflow checks for wl_fixed_from_int() */
- if (width_from_buffer > wl_fixed_to_int(INT32_MAX))
- return false;
- if (height_from_buffer > wl_fixed_to_int(INT32_MAX))
- return false;
-
- w = wl_fixed_from_int(width_from_buffer);
- h = wl_fixed_from_int(height_from_buffer);
-
- if (fixed_sum_gt(vp->buffer.src_x, vp->buffer.src_width, w))
- return false;
- if (fixed_sum_gt(vp->buffer.src_y, vp->buffer.src_height, h))
- return false;
-
- return true;
-}
-
-static bool
-fixed_is_integer(wl_fixed_t v)
-{
- return (v & 0xff) == 0;
-}
-
-static bool
-weston_surface_is_pending_viewport_dst_size_int(
- const struct weston_surface *surface)
-{
- const struct weston_buffer_viewport *vp =
- &surface->pending.buffer_viewport;
-
- if (vp->surface.width != -1) {
- assert(vp->surface.width > 0 && vp->surface.height > 0);
- return true;
- }
-
- return fixed_is_integer(vp->buffer.src_width) &&
- fixed_is_integer(vp->buffer.src_height);
-}
-
-/* Translate pending damage in buffer co-ordinates to surface
- * co-ordinates and union it with a pixman_region32_t.
- * This should only be called after the buffer is attached.
- */
-static void
-apply_damage_buffer(pixman_region32_t *dest,
- struct weston_surface *surface,
- struct weston_surface_state *state)
-{
- struct weston_buffer *buffer = surface->buffer_ref.buffer;
-
- /* wl_surface.damage_buffer needs to be clipped to the buffer,
- * translated into surface co-ordinates and unioned with
- * any other surface damage.
- * None of this makes sense if there is no buffer though.
- */
- if (buffer && pixman_region32_not_empty(&state->damage_buffer)) {
- pixman_region32_t buffer_damage;
-
- pixman_region32_intersect_rect(&state->damage_buffer,
- &state->damage_buffer,
- 0, 0, buffer->width,
- buffer->height);
- pixman_region32_init(&buffer_damage);
- weston_matrix_transform_region(&buffer_damage,
- &surface->buffer_to_surface_matrix,
- &state->damage_buffer);
- pixman_region32_union(dest, dest, &buffer_damage);
- pixman_region32_fini(&buffer_damage);
- }
- /* We should clear this on commit even if there was no buffer */
- pixman_region32_clear(&state->damage_buffer);
-}
-
-static void
-weston_surface_set_desired_protection(struct weston_surface *surface,
- enum weston_hdcp_protection protection)
-{
- if (surface->desired_protection == protection)
- return;
- surface->desired_protection = protection;
- weston_surface_damage(surface);
-}
-
-static void
-weston_surface_set_protection_mode(struct weston_surface *surface,
- enum weston_surface_protection_mode p_mode)
-{
- struct content_protection *cp = surface->compositor->content_protection;
- struct protected_surface *psurface;
-
- surface->protection_mode = p_mode;
- wl_list_for_each(psurface, &cp->protected_list, link) {
- if (!psurface || psurface->surface != surface)
- continue;
- weston_protected_surface_send_event(psurface,
- surface->current_protection);
- }
-}
-
-static void
-weston_surface_commit_state(struct weston_surface *surface,
- struct weston_surface_state *state)
-{
- struct weston_view *view;
- pixman_region32_t opaque;
-
- /* wl_surface.set_buffer_transform */
- /* wl_surface.set_buffer_scale */
- /* wp_viewport.set_source */
- /* wp_viewport.set_destination */
- surface->buffer_viewport = state->buffer_viewport;
-
- /* wl_surface.attach */
- if (state->newly_attached) {
- /* zwp_surface_synchronization_v1.set_acquire_fence */
- fd_move(&surface->acquire_fence_fd,
- &state->acquire_fence_fd);
- /* zwp_surface_synchronization_v1.get_release */
- weston_buffer_release_move(&surface->buffer_release_ref,
- &state->buffer_release_ref);
- weston_surface_attach(surface, state->buffer);
- }
- weston_surface_state_set_buffer(state, NULL);
- assert(state->acquire_fence_fd == -1);
- assert(state->buffer_release_ref.buffer_release == NULL);
-
- weston_surface_build_buffer_matrix(surface,
- &surface->surface_to_buffer_matrix);
- weston_matrix_invert(&surface->buffer_to_surface_matrix,
- &surface->surface_to_buffer_matrix);
-
- if (state->newly_attached || state->buffer_viewport.changed) {
- weston_surface_update_size(surface);
- if (surface->committed)
- surface->committed(surface, state->sx, state->sy);
- }
-
- state->sx = 0;
- state->sy = 0;
- state->newly_attached = 0;
- state->buffer_viewport.changed = 0;
-
- /* wl_surface.damage and wl_surface.damage_buffer */
- if (pixman_region32_not_empty(&state->damage_surface) ||
- pixman_region32_not_empty(&state->damage_buffer))
- TL_POINT(surface->compositor, "core_commit_damage", TLP_SURFACE(surface), TLP_END);
-
- pixman_region32_union(&surface->damage, &surface->damage,
- &state->damage_surface);
-
- apply_damage_buffer(&surface->damage, surface, state);
-
- pixman_region32_intersect_rect(&surface->damage, &surface->damage,
- 0, 0, surface->width, surface->height);
- pixman_region32_clear(&state->damage_surface);
-
- /* wl_surface.set_opaque_region */
- pixman_region32_init(&opaque);
- pixman_region32_intersect_rect(&opaque, &state->opaque,
- 0, 0, surface->width, surface->height);
-
- if (!pixman_region32_equal(&opaque, &surface->opaque)) {
- pixman_region32_copy(&surface->opaque, &opaque);
- wl_list_for_each(view, &surface->views, surface_link)
- weston_view_geometry_dirty(view);
- }
-
- pixman_region32_fini(&opaque);
-
- /* wl_surface.set_input_region */
- pixman_region32_intersect_rect(&surface->input, &state->input,
- 0, 0, surface->width, surface->height);
-
- /* wl_surface.frame */
- wl_list_insert_list(&surface->frame_callback_list,
- &state->frame_callback_list);
- wl_list_init(&state->frame_callback_list);
-
- /* XXX:
- * What should happen with a feedback request, if there
- * is no wl_buffer attached for this commit?
- */
-
- /* presentation.feedback */
- wl_list_insert_list(&surface->feedback_list,
- &state->feedback_list);
- wl_list_init(&state->feedback_list);
-
- /* weston_protected_surface.enforced/relaxed */
- if (surface->protection_mode != state->protection_mode)
- weston_surface_set_protection_mode(surface,
- state->protection_mode);
-
- /* weston_protected_surface.set_type */
- weston_surface_set_desired_protection(surface, state->desired_protection);
-
- wl_signal_emit(&surface->commit_signal, surface);
-}
-
-static void
-weston_surface_commit(struct weston_surface *surface)
-{
- weston_surface_commit_state(surface, &surface->pending);
-
- weston_surface_commit_subsurface_order(surface);
-
- weston_surface_schedule_repaint(surface);
-}
-
-static void
-weston_subsurface_commit(struct weston_subsurface *sub);
-
-static void
-weston_subsurface_parent_commit(struct weston_subsurface *sub,
- int parent_is_synchronized);
-
-static void
-surface_commit(struct wl_client *client, struct wl_resource *resource)
-{
- struct weston_surface *surface = wl_resource_get_user_data(resource);
- struct weston_subsurface *sub = weston_surface_to_subsurface(surface);
-
- if (!weston_surface_is_pending_viewport_source_valid(surface)) {
- assert(surface->viewport_resource);
-
- wl_resource_post_error(surface->viewport_resource,
- WP_VIEWPORT_ERROR_OUT_OF_BUFFER,
- "wl_surface@%d has viewport source outside buffer",
- wl_resource_get_id(resource));
- return;
- }
-
- if (!weston_surface_is_pending_viewport_dst_size_int(surface)) {
- assert(surface->viewport_resource);
-
- wl_resource_post_error(surface->viewport_resource,
- WP_VIEWPORT_ERROR_BAD_SIZE,
- "wl_surface@%d viewport dst size not integer",
- wl_resource_get_id(resource));
- return;
- }
-
- if (surface->pending.acquire_fence_fd >= 0) {
- assert(surface->synchronization_resource);
-
- if (!surface->pending.buffer) {
- fd_clear(&surface->pending.acquire_fence_fd);
- wl_resource_post_error(surface->synchronization_resource,
- ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_NO_BUFFER,
- "wl_surface@%"PRIu32" no buffer for synchronization",
- wl_resource_get_id(resource));
- return;
- }
-
- /* We support fences for both wp_linux_dmabuf and opaque EGL
- * buffers, as mandated by minor version 2 of the
- * zwp_linux_explicit_synchronization_v1 protocol. Since
- * renderers that support fences currently only support these
- * two buffer types plus SHM buffers, we can just check for the
- * SHM buffer case here.
- */
- if (wl_shm_buffer_get(surface->pending.buffer->resource)) {
- fd_clear(&surface->pending.acquire_fence_fd);
- wl_resource_post_error(surface->synchronization_resource,
- ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_UNSUPPORTED_BUFFER,
- "wl_surface@%"PRIu32" unsupported buffer for synchronization",
- wl_resource_get_id(resource));
- return;
- }
- }
-
- if (surface->pending.buffer_release_ref.buffer_release &&
- !surface->pending.buffer) {
- assert(surface->synchronization_resource);
-
- wl_resource_post_error(surface->synchronization_resource,
- ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_NO_BUFFER,
- "wl_surface@%"PRIu32" no buffer for synchronization",
- wl_resource_get_id(resource));
- return;
- }
-
- if (sub) {
- weston_subsurface_commit(sub);
- return;
- }
-
- weston_surface_commit(surface);
-
- wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
- if (sub->surface != surface)
- weston_subsurface_parent_commit(sub, 0);
- }
-}
-
-static void
-surface_set_buffer_transform(struct wl_client *client,
- struct wl_resource *resource, int transform)
-{
- struct weston_surface *surface = wl_resource_get_user_data(resource);
-
- /* if wl_output.transform grows more members this will need to be updated. */
- if (transform < 0 ||
- transform > WL_OUTPUT_TRANSFORM_FLIPPED_270) {
- wl_resource_post_error(resource,
- WL_SURFACE_ERROR_INVALID_TRANSFORM,
- "buffer transform must be a valid transform "
- "('%d' specified)", transform);
- return;
- }
-
- surface->pending.buffer_viewport.buffer.transform = transform;
- surface->pending.buffer_viewport.changed = 1;
-}
-
-static void
-surface_set_buffer_scale(struct wl_client *client,
- struct wl_resource *resource,
- int32_t scale)
-{
- struct weston_surface *surface = wl_resource_get_user_data(resource);
-
- if (scale < 1) {
- wl_resource_post_error(resource,
- WL_SURFACE_ERROR_INVALID_SCALE,
- "buffer scale must be at least one "
- "('%d' specified)", scale);
- return;
- }
-
- surface->pending.buffer_viewport.buffer.scale = scale;
- surface->pending.buffer_viewport.changed = 1;
-}
-
-static const struct wl_surface_interface surface_interface = {
- surface_destroy,
- surface_attach,
- surface_damage,
- surface_frame,
- surface_set_opaque_region,
- surface_set_input_region,
- surface_commit,
- surface_set_buffer_transform,
- surface_set_buffer_scale,
- surface_damage_buffer
-};
-
-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;
-
- surface = weston_surface_create(ec);
- if (surface == NULL) {
- wl_resource_post_no_memory(resource);
- return;
- }
-
- surface->resource =
- wl_resource_create(client, &wl_surface_interface,
- wl_resource_get_version(resource), id);
- if (surface->resource == NULL) {
- weston_surface_destroy(surface);
- wl_resource_post_no_memory(resource);
- return;
- }
- wl_resource_set_implementation(surface->resource, &surface_interface,
- surface, destroy_surface);
-
- wl_signal_emit(&ec->create_surface_signal, surface);
-}
-
-static void
-destroy_region(struct wl_resource *resource)
-{
- struct weston_region *region = wl_resource_get_user_data(resource);
-
- pixman_region32_fini(&region->region);
- free(region);
-}
-
-static void
-region_destroy(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-region_add(struct wl_client *client, struct wl_resource *resource,
- int32_t x, int32_t y, int32_t width, int32_t height)
-{
- struct weston_region *region = wl_resource_get_user_data(resource);
-
- pixman_region32_union_rect(&region->region, &region->region,
- x, y, width, height);
-}
-
-static void
-region_subtract(struct wl_client *client, struct wl_resource *resource,
- int32_t x, int32_t y, int32_t width, int32_t height)
-{
- struct weston_region *region = wl_resource_get_user_data(resource);
- pixman_region32_t rect;
-
- pixman_region32_init_rect(&rect, x, y, width, height);
- pixman_region32_subtract(&region->region, &region->region, &rect);
- pixman_region32_fini(&rect);
-}
-
-static const struct wl_region_interface region_interface = {
- region_destroy,
- region_add,
- region_subtract
-};
-
-static void
-compositor_create_region(struct wl_client *client,
- struct wl_resource *resource, uint32_t id)
-{
- struct weston_region *region;
-
- region = malloc(sizeof *region);
- if (region == NULL) {
- wl_resource_post_no_memory(resource);
- return;
- }
-
- pixman_region32_init(&region->region);
-
- region->resource =
- wl_resource_create(client, &wl_region_interface, 1, id);
- if (region->resource == NULL) {
- free(region);
- wl_resource_post_no_memory(resource);
- return;
- }
- wl_resource_set_implementation(region->resource, &region_interface,
- region, destroy_region);
-}
-
-static const struct wl_compositor_interface compositor_interface = {
- compositor_create_surface,
- compositor_create_region
-};
-
-static void
-weston_subsurface_commit_from_cache(struct weston_subsurface *sub)
-{
- struct weston_surface *surface = sub->surface;
-
- weston_surface_commit_state(surface, &sub->cached);
- weston_buffer_reference(&sub->cached_buffer_ref, NULL);
-
- weston_surface_commit_subsurface_order(surface);
-
- weston_surface_schedule_repaint(surface);
-
- sub->has_cached_data = 0;
-}
-
-static void
-weston_subsurface_commit_to_cache(struct weston_subsurface *sub)
-{
- struct weston_surface *surface = sub->surface;
-
- /*
- * If this commit would cause the surface to move by the
- * attach(dx, dy) parameters, the old damage region must be
- * translated to correspond to the new surface coordinate system
- * origin.
- */
- pixman_region32_translate(&sub->cached.damage_surface,
- -surface->pending.sx, -surface->pending.sy);
- pixman_region32_union(&sub->cached.damage_surface,
- &sub->cached.damage_surface,
- &surface->pending.damage_surface);
- pixman_region32_clear(&surface->pending.damage_surface);
-
- if (surface->pending.newly_attached) {
- sub->cached.newly_attached = 1;
- weston_surface_state_set_buffer(&sub->cached,
- surface->pending.buffer);
- weston_buffer_reference(&sub->cached_buffer_ref,
- surface->pending.buffer);
- weston_presentation_feedback_discard_list(
- &sub->cached.feedback_list);
- /* zwp_surface_synchronization_v1.set_acquire_fence */
- fd_move(&sub->cached.acquire_fence_fd,
- &surface->pending.acquire_fence_fd);
- /* zwp_surface_synchronization_v1.get_release */
- weston_buffer_release_move(&sub->cached.buffer_release_ref,
- &surface->pending.buffer_release_ref);
- }
- sub->cached.desired_protection = surface->pending.desired_protection;
- sub->cached.protection_mode = surface->pending.protection_mode;
- assert(surface->pending.acquire_fence_fd == -1);
- assert(surface->pending.buffer_release_ref.buffer_release == NULL);
- 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 =
- surface->pending.buffer_viewport.buffer;
- sub->cached.buffer_viewport.surface =
- surface->pending.buffer_viewport.surface;
-
- weston_surface_reset_pending_buffer(surface);
-
- pixman_region32_copy(&sub->cached.opaque, &surface->pending.opaque);
-
- pixman_region32_copy(&sub->cached.input, &surface->pending.input);
-
- wl_list_insert_list(&sub->cached.frame_callback_list,
- &surface->pending.frame_callback_list);
- wl_list_init(&surface->pending.frame_callback_list);
-
- wl_list_insert_list(&sub->cached.feedback_list,
- &surface->pending.feedback_list);
- wl_list_init(&surface->pending.feedback_list);
-
- sub->has_cached_data = 1;
-}
-
-static bool
-weston_subsurface_is_synchronized(struct weston_subsurface *sub)
-{
- while (sub) {
- if (sub->synchronized)
- return true;
-
- if (!sub->parent)
- return false;
-
- sub = weston_surface_to_subsurface(sub->parent);
- }
-
- return false;
-}
-
-static void
-weston_subsurface_commit(struct weston_subsurface *sub)
-{
- struct weston_surface *surface = sub->surface;
- struct weston_subsurface *tmp;
-
- /* Recursive check for effectively synchronized. */
- if (weston_subsurface_is_synchronized(sub)) {
- weston_subsurface_commit_to_cache(sub);
- } else {
- if (sub->has_cached_data) {
- /* flush accumulated state from cache */
- weston_subsurface_commit_to_cache(sub);
- weston_subsurface_commit_from_cache(sub);
- } else {
- weston_surface_commit(surface);
- }
-
- wl_list_for_each(tmp, &surface->subsurface_list, parent_link) {
- if (tmp->surface != surface)
- weston_subsurface_parent_commit(tmp, 0);
- }
- }
-}
-
-static void
-weston_subsurface_synchronized_commit(struct weston_subsurface *sub)
-{
- struct weston_surface *surface = sub->surface;
- struct weston_subsurface *tmp;
-
- /* From now on, commit_from_cache the whole sub-tree, regardless of
- * the synchronized mode of each child. This sub-surface or some
- * of its ancestors were synchronized, so we are synchronized
- * all the way down.
- */
-
- if (sub->has_cached_data)
- weston_subsurface_commit_from_cache(sub);
-
- wl_list_for_each(tmp, &surface->subsurface_list, parent_link) {
- if (tmp->surface != surface)
- weston_subsurface_parent_commit(tmp, 1);
- }
-}
-
-static void
-weston_subsurface_parent_commit(struct weston_subsurface *sub,
- int parent_is_synchronized)
-{
- struct weston_view *view;
- if (sub->position.set) {
- wl_list_for_each(view, &sub->surface->views, surface_link)
- weston_view_set_position(view,
- sub->position.x,
- sub->position.y);
-
- sub->position.set = 0;
- }
-
- if (parent_is_synchronized || sub->synchronized)
- weston_subsurface_synchronized_commit(sub);
-}
-
-static int
-subsurface_get_label(struct weston_surface *surface, char *buf, size_t len)
-{
- return snprintf(buf, len, "sub-surface");
-}
-
-static void
-subsurface_committed(struct weston_surface *surface, int32_t dx, int32_t dy)
-{
- struct weston_view *view;
-
- wl_list_for_each(view, &surface->views, surface_link)
- weston_view_set_position(view,
- view->geometry.x + dx,
- view->geometry.y + dy);
-
- /* No need to check parent mappedness, because if parent is not
- * mapped, parent is not in a visible layer, so this sub-surface
- * will not be drawn either.
- */
-
- if (!weston_surface_is_mapped(surface)) {
- surface->is_mapped = true;
-
- /* Cannot call weston_view_update_transform(),
- * because that would call it also for the parent surface,
- * which might not be mapped yet. That would lead to
- * inconsistent state, where the window could never be
- * mapped.
- *
- * Instead just force the is_mapped flag on, to make
- * weston_surface_is_mapped() return true, so that when the
- * parent surface does get mapped, this one will get
- * included, too. See view_list_add().
- */
- }
-}
-
-static struct weston_subsurface *
-weston_surface_to_subsurface(struct weston_surface *surface)
-{
- if (surface->committed == subsurface_committed)
- return surface->committed_private;
-
- return NULL;
-}
-
-WL_EXPORT struct weston_surface *
-weston_surface_get_main_surface(struct weston_surface *surface)
-{
- struct weston_subsurface *sub;
-
- while (surface && (sub = weston_surface_to_subsurface(surface)))
- surface = sub->parent;
-
- return surface;
-}
-
-WL_EXPORT int
-weston_surface_set_role(struct weston_surface *surface,
- const char *role_name,
- struct wl_resource *error_resource,
- uint32_t error_code)
-{
- assert(role_name);
-
- if (surface->role_name == NULL ||
- surface->role_name == role_name ||
- strcmp(surface->role_name, role_name) == 0) {
- surface->role_name = role_name;
-
- return 0;
- }
-
- wl_resource_post_error(error_resource, error_code,
- "Cannot assign role %s to wl_surface@%d,"
- " already has role %s\n",
- role_name,
- wl_resource_get_id(surface->resource),
- surface->role_name);
- return -1;
-}
-
-WL_EXPORT const char *
-weston_surface_get_role(struct weston_surface *surface)
-{
- return surface->role_name;
-}
-
-WL_EXPORT void
-weston_surface_set_label_func(struct weston_surface *surface,
- int (*desc)(struct weston_surface *,
- char *, size_t))
-{
- surface->get_label = desc;
- weston_timeline_refresh_subscription_objects(surface->compositor,
- surface);
-}
-
-/** Get the size of surface contents
- *
- * \param surface The surface to query.
- * \param width Returns the width of raw contents.
- * \param height Returns the height of raw contents.
- *
- * Retrieves the raw surface content size in pixels for the given surface.
- * This is the whole content size in buffer pixels. If the surface
- * has no content or the renderer does not implement this feature,
- * zeroes are returned.
- *
- * This function is used to determine the buffer size needed for
- * a weston_surface_copy_content() call.
- */
-WL_EXPORT void
-weston_surface_get_content_size(struct weston_surface *surface,
- int *width, int *height)
-{
- struct weston_renderer *rer = surface->compositor->renderer;
-
- if (!rer->surface_get_content_size) {
- *width = 0;
- *height = 0;
- return;
- }
-
- rer->surface_get_content_size(surface, width, height);
-}
-
-/** Get the bounding box of a surface and its subsurfaces
- *
- * \param surface The surface to query.
- * \return The bounding box relative to the surface origin.
- *
- */
-WL_EXPORT struct weston_geometry
-weston_surface_get_bounding_box(struct weston_surface *surface)
-{
- pixman_region32_t region;
- pixman_box32_t *box;
- struct weston_subsurface *subsurface;
-
- pixman_region32_init_rect(&region,
- 0, 0,
- surface->width, surface->height);
-
- wl_list_for_each(subsurface, &surface->subsurface_list, parent_link)
- pixman_region32_union_rect(&region, &region,
- subsurface->position.x,
- subsurface->position.y,
- subsurface->surface->width,
- subsurface->surface->height);
-
- box = pixman_region32_extents(&region);
- struct weston_geometry geometry = {
- .x = box->x1,
- .y = box->y1,
- .width = box->x2 - box->x1,
- .height = box->y2 - box->y1,
- };
-
- pixman_region32_fini(&region);
-
- return geometry;
-}
-
-/** Copy surface contents to system memory.
- *
- * \param surface The surface to copy from.
- * \param target Pointer to the target memory buffer.
- * \param size Size of the target buffer in bytes.
- * \param src_x X location on contents to copy from.
- * \param src_y Y location on contents to copy from.
- * \param width Width in pixels of the area to copy.
- * \param height Height in pixels of the area to copy.
- * \return 0 for success, -1 for failure.
- *
- * Surface contents are maintained by the renderer. They can be in a
- * reserved weston_buffer or as a copy, e.g. a GL texture, or something
- * else.
- *
- * Surface contents are copied into memory pointed to by target,
- * which has size bytes of space available. The target memory
- * may be larger than needed, but being smaller returns an error.
- * The extra bytes in target may or may not be written; their content is
- * unspecified. Size must be large enough to hold the image.
- *
- * The image in the target memory will be arranged in rows from
- * top to bottom, and pixels on a row from left to right. The pixel
- * format is PIXMAN_a8b8g8r8, 4 bytes per pixel, and stride is exactly
- * width * 4.
- *
- * Parameters src_x and src_y define the upper-left corner in buffer
- * coordinates (pixels) to copy from. Parameters width and height
- * define the size of the area to copy in pixels.
- *
- * The rectangle defined by src_x, src_y, width, height must fit in
- * the surface contents. Otherwise an error is returned.
- *
- * Use weston_surface_get_content_size to determine the content size; the
- * needed target buffer size and rectangle limits.
- *
- * CURRENT IMPLEMENTATION RESTRICTIONS:
- * - the machine must be little-endian due to Pixman formats.
- *
- * NOTE: Pixman formats are premultiplied.
- */
-WL_EXPORT int
-weston_surface_copy_content(struct weston_surface *surface,
- void *target, size_t size,
- int src_x, int src_y,
- int width, int height)
-{
- struct weston_renderer *rer = surface->compositor->renderer;
- int cw, ch;
- const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
-
- if (!rer->surface_copy_content)
- return -1;
-
- weston_surface_get_content_size(surface, &cw, &ch);
-
- if (src_x < 0 || src_y < 0)
- return -1;
-
- if (width <= 0 || height <= 0)
- return -1;
-
- if (src_x + width > cw || src_y + height > ch)
- return -1;
-
- if (width * bytespp * height > size)
- return -1;
-
- return rer->surface_copy_content(surface, target, size,
- src_x, src_y, width, height);
-}
-
-static void
-subsurface_set_position(struct wl_client *client,
- struct wl_resource *resource, int32_t x, int32_t y)
-{
- struct weston_subsurface *sub = wl_resource_get_user_data(resource);
-
- if (!sub)
- return;
-
- sub->position.x = x;
- sub->position.y = y;
- sub->position.set = 1;
-}
-
-static struct weston_subsurface *
-subsurface_find_sibling(struct weston_subsurface *sub,
- struct weston_surface *surface)
-{
- struct weston_surface *parent = sub->parent;
- struct weston_subsurface *sibling;
-
- wl_list_for_each(sibling, &parent->subsurface_list, parent_link) {
- if (sibling->surface == surface && sibling != sub)
- return sibling;
- }
-
- return NULL;
-}
-
-static struct weston_subsurface *
-subsurface_sibling_check(struct weston_subsurface *sub,
- struct weston_surface *surface,
- const char *request)
-{
- struct weston_subsurface *sibling;
-
- sibling = subsurface_find_sibling(sub, surface);
- if (!sibling) {
- wl_resource_post_error(sub->resource,
- WL_SUBSURFACE_ERROR_BAD_SURFACE,
- "%s: wl_surface@%d is not a parent or sibling",
- request, wl_resource_get_id(surface->resource));
- return NULL;
- }
-
- assert(sibling->parent == sub->parent);
-
- return sibling;
-}
-
-static void
-subsurface_place_above(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *sibling_resource)
-{
- struct weston_subsurface *sub = wl_resource_get_user_data(resource);
- struct weston_surface *surface =
- wl_resource_get_user_data(sibling_resource);
- struct weston_subsurface *sibling;
-
- if (!sub)
- return;
-
- sibling = subsurface_sibling_check(sub, surface, "place_above");
- if (!sibling)
- return;
-
- wl_list_remove(&sub->parent_link_pending);
- wl_list_insert(sibling->parent_link_pending.prev,
- &sub->parent_link_pending);
-
- sub->reordered = true;
-}
-
-static void
-subsurface_place_below(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *sibling_resource)
-{
- struct weston_subsurface *sub = wl_resource_get_user_data(resource);
- struct weston_surface *surface =
- wl_resource_get_user_data(sibling_resource);
- struct weston_subsurface *sibling;
-
- if (!sub)
- return;
-
- sibling = subsurface_sibling_check(sub, surface, "place_below");
- if (!sibling)
- return;
-
- wl_list_remove(&sub->parent_link_pending);
- wl_list_insert(&sibling->parent_link_pending,
- &sub->parent_link_pending);
-
- sub->reordered = true;
-}
-
-static void
-subsurface_set_sync(struct wl_client *client, struct wl_resource *resource)
-{
- struct weston_subsurface *sub = wl_resource_get_user_data(resource);
-
- if (sub)
- sub->synchronized = 1;
-}
-
-static void
-subsurface_set_desync(struct wl_client *client, struct wl_resource *resource)
-{
- struct weston_subsurface *sub = wl_resource_get_user_data(resource);
-
- if (sub && sub->synchronized) {
- sub->synchronized = 0;
-
- /* If sub became effectively desynchronized, flush. */
- if (!weston_subsurface_is_synchronized(sub))
- weston_subsurface_synchronized_commit(sub);
- }
-}
-
-static void
-weston_subsurface_unlink_parent(struct weston_subsurface *sub)
-{
- wl_list_remove(&sub->parent_link);
- wl_list_remove(&sub->parent_link_pending);
- wl_list_remove(&sub->parent_destroy_listener.link);
- sub->parent = NULL;
-}
-
-static void
-weston_subsurface_destroy(struct weston_subsurface *sub);
-
-static void
-subsurface_handle_surface_destroy(struct wl_listener *listener, void *data)
-{
- struct weston_subsurface *sub =
- container_of(listener, struct weston_subsurface,
- surface_destroy_listener);
- assert(data == sub->surface);
-
- /* The protocol object (wl_resource) is left inert. */
- if (sub->resource)
- wl_resource_set_user_data(sub->resource, NULL);
-
- weston_subsurface_destroy(sub);
-}
-
-static void
-subsurface_handle_parent_destroy(struct wl_listener *listener, void *data)
-{
- struct weston_subsurface *sub =
- container_of(listener, struct weston_subsurface,
- parent_destroy_listener);
- assert(data == sub->parent);
- assert(sub->surface != sub->parent);
-
- if (weston_surface_is_mapped(sub->surface))
- weston_surface_unmap(sub->surface);
-
- weston_subsurface_unlink_parent(sub);
-}
-
-static void
-subsurface_resource_destroy(struct wl_resource *resource)
-{
- struct weston_subsurface *sub = wl_resource_get_user_data(resource);
-
- if (sub)
- weston_subsurface_destroy(sub);
-}
-
-static void
-subsurface_destroy(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-weston_subsurface_link_parent(struct weston_subsurface *sub,
- struct weston_surface *parent)
-{
- sub->parent = parent;
- sub->parent_destroy_listener.notify = subsurface_handle_parent_destroy;
- wl_signal_add(&parent->destroy_signal,
- &sub->parent_destroy_listener);
-
- wl_list_insert(&parent->subsurface_list, &sub->parent_link);
- wl_list_insert(&parent->subsurface_list_pending,
- &sub->parent_link_pending);
-}
-
-static void
-weston_subsurface_link_surface(struct weston_subsurface *sub,
- struct weston_surface *surface)
-{
- sub->surface = surface;
- sub->surface_destroy_listener.notify =
- subsurface_handle_surface_destroy;
- wl_signal_add(&surface->destroy_signal,
- &sub->surface_destroy_listener);
-}
-
-static void
-weston_subsurface_destroy(struct weston_subsurface *sub)
-{
- struct weston_view *view, *next;
-
- assert(sub->surface);
-
- if (sub->resource) {
- assert(weston_surface_to_subsurface(sub->surface) == sub);
- assert(sub->parent_destroy_listener.notify ==
- subsurface_handle_parent_destroy);
-
- wl_list_for_each_safe(view, next, &sub->surface->views, surface_link) {
- weston_view_unmap(view);
- weston_view_destroy(view);
- }
-
- if (sub->parent)
- weston_subsurface_unlink_parent(sub);
-
- weston_surface_state_fini(&sub->cached);
- weston_buffer_reference(&sub->cached_buffer_ref, NULL);
-
- sub->surface->committed = NULL;
- sub->surface->committed_private = NULL;
- weston_surface_set_label_func(sub->surface, NULL);
- } else {
- /* the dummy weston_subsurface for the parent itself */
- assert(sub->parent_destroy_listener.notify == NULL);
- wl_list_remove(&sub->parent_link);
- wl_list_remove(&sub->parent_link_pending);
- }
-
- wl_list_remove(&sub->surface_destroy_listener.link);
- free(sub);
-}
-
-static const struct wl_subsurface_interface subsurface_implementation = {
- subsurface_destroy,
- subsurface_set_position,
- subsurface_place_above,
- subsurface_place_below,
- subsurface_set_sync,
- subsurface_set_desync
-};
-
-static struct weston_subsurface *
-weston_subsurface_create(uint32_t id, struct weston_surface *surface,
- struct weston_surface *parent)
-{
- struct weston_subsurface *sub;
- struct wl_client *client = wl_resource_get_client(surface->resource);
-
- sub = zalloc(sizeof *sub);
- if (sub == NULL)
- return NULL;
-
- wl_list_init(&sub->unused_views);
-
- sub->resource =
- wl_resource_create(client, &wl_subsurface_interface, 1, id);
- if (!sub->resource) {
- free(sub);
- return NULL;
- }
-
- wl_resource_set_implementation(sub->resource,
- &subsurface_implementation,
- sub, subsurface_resource_destroy);
- weston_subsurface_link_surface(sub, surface);
- weston_subsurface_link_parent(sub, parent);
- weston_surface_state_init(&sub->cached);
- sub->cached_buffer_ref.buffer = NULL;
- sub->synchronized = 1;
-
- return sub;
-}
-
-/* Create a dummy subsurface for having the parent itself in its
- * sub-surface lists. Makes stacking order manipulation easy.
- */
-static struct weston_subsurface *
-weston_subsurface_create_for_parent(struct weston_surface *parent)
-{
- struct weston_subsurface *sub;
-
- sub = zalloc(sizeof *sub);
- if (sub == NULL)
- return NULL;
-
- weston_subsurface_link_surface(sub, parent);
- sub->parent = parent;
- wl_list_insert(&parent->subsurface_list, &sub->parent_link);
- wl_list_insert(&parent->subsurface_list_pending,
- &sub->parent_link_pending);
-
- return sub;
-}
-
-static void
-subcompositor_get_subsurface(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t id,
- struct wl_resource *surface_resource,
- struct wl_resource *parent_resource)
-{
- struct weston_surface *surface =
- wl_resource_get_user_data(surface_resource);
- struct weston_surface *parent =
- wl_resource_get_user_data(parent_resource);
- struct weston_subsurface *sub;
- static const char where[] = "get_subsurface: wl_subsurface@";
-
- if (surface == parent) {
- wl_resource_post_error(resource,
- WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
- "%s%d: wl_surface@%d cannot be its own parent",
- where, id, wl_resource_get_id(surface_resource));
- return;
- }
-
- if (weston_surface_to_subsurface(surface)) {
- wl_resource_post_error(resource,
- WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
- "%s%d: wl_surface@%d is already a sub-surface",
- where, id, wl_resource_get_id(surface_resource));
- return;
- }
-
- if (weston_surface_set_role(surface, "wl_subsurface", resource,
- WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE) < 0)
- return;
-
- if (weston_surface_get_main_surface(parent) == surface) {
- wl_resource_post_error(resource,
- WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
- "%s%d: wl_surface@%d is an ancestor of parent",
- where, id, wl_resource_get_id(surface_resource));
- return;
- }
-
- /* make sure the parent is in its own list */
- if (wl_list_empty(&parent->subsurface_list)) {
- if (!weston_subsurface_create_for_parent(parent)) {
- wl_resource_post_no_memory(resource);
- return;
- }
- }
-
- sub = weston_subsurface_create(id, surface, parent);
- if (!sub) {
- wl_resource_post_no_memory(resource);
- return;
- }
-
- surface->committed = subsurface_committed;
- surface->committed_private = sub;
- weston_surface_set_label_func(surface, subsurface_get_label);
-}
-
-static void
-subcompositor_destroy(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static const struct wl_subcompositor_interface subcompositor_interface = {
- subcompositor_destroy,
- subcompositor_get_subsurface
-};
-
-static void
-bind_subcompositor(struct wl_client *client,
- void *data, uint32_t version, uint32_t id)
-{
- struct weston_compositor *compositor = data;
- struct wl_resource *resource;
-
- resource =
- wl_resource_create(client, &wl_subcompositor_interface, 1, id);
- if (resource == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
- wl_resource_set_implementation(resource, &subcompositor_interface,
- compositor, NULL);
-}
-
-/** Set a DPMS mode on all of the compositor's outputs
- *
- * \param compositor The compositor instance
- * \param state The DPMS state the outputs will be set to
- */
-static void
-weston_compositor_dpms(struct weston_compositor *compositor,
- enum dpms_enum state)
-{
- struct weston_output *output;
-
- wl_list_for_each(output, &compositor->output_list, link)
- if (output->set_dpms)
- output->set_dpms(output, state);
-}
-
-/** Restores the compositor to active status
- *
- * \param compositor The compositor instance
- *
- * If the compositor was in a sleeping mode, all outputs are powered
- * back on via DPMS. Otherwise if the compositor was inactive
- * (idle/locked, offscreen, or sleeping) then the compositor's wake
- * signal will fire.
- *
- * Restarts the idle timer.
- * \ingroup compositor
- */
-WL_EXPORT void
-weston_compositor_wake(struct weston_compositor *compositor)
-{
- uint32_t old_state = compositor->state;
-
- /* The state needs to be changed before emitting the wake
- * signal because that may try to schedule a repaint which
- * will not work if the compositor is still sleeping */
- compositor->state = WESTON_COMPOSITOR_ACTIVE;
-
- switch (old_state) {
- case WESTON_COMPOSITOR_SLEEPING:
- case WESTON_COMPOSITOR_IDLE:
- case WESTON_COMPOSITOR_OFFSCREEN:
- weston_compositor_dpms(compositor, WESTON_DPMS_ON);
- wl_signal_emit(&compositor->wake_signal, compositor);
- /* fall through */
- default:
- wl_event_source_timer_update(compositor->idle_source,
- compositor->idle_time * 1000);
- }
-}
-
-/** Turns off rendering and frame events for the compositor.
- *
- * \param compositor The compositor instance
- *
- * This is used for example to prevent further rendering while the
- * compositor is shutting down.
- *
- * Stops the idle timer.
- *
- * \ingroup compositor
- */
-WL_EXPORT void
-weston_compositor_offscreen(struct weston_compositor *compositor)
-{
- switch (compositor->state) {
- case WESTON_COMPOSITOR_OFFSCREEN:
- return;
- case WESTON_COMPOSITOR_SLEEPING:
- default:
- compositor->state = WESTON_COMPOSITOR_OFFSCREEN;
- wl_event_source_timer_update(compositor->idle_source, 0);
- }
-}
-
-/** Powers down all attached output devices
- *
- * \param compositor The compositor instance
- *
- * Causes rendering to the outputs to cease, and no frame events to be
- * sent. Only powers down the outputs if the compositor is not already
- * in sleep mode.
- *
- * Stops the idle timer.
- *
- * \ingroup compositor
- */
-WL_EXPORT void
-weston_compositor_sleep(struct weston_compositor *compositor)
-{
- if (compositor->state == WESTON_COMPOSITOR_SLEEPING)
- return;
-
- wl_event_source_timer_update(compositor->idle_source, 0);
- compositor->state = WESTON_COMPOSITOR_SLEEPING;
- weston_compositor_dpms(compositor, WESTON_DPMS_OFF);
-}
-
-/** Sets compositor to idle mode
- *
- * \param data The compositor instance
- *
- * This is called when the idle timer fires. Once the compositor is in
- * idle mode it requires a wake action (e.g. via
- * weston_compositor_wake()) to restore it. The compositor's
- * idle_signal will be triggered when the idle event occurs.
- *
- * Idleness can be inhibited by setting the compositor's idle_inhibit
- * property.
- */
-static int
-idle_handler(void *data)
-{
- struct weston_compositor *compositor = data;
-
- if (compositor->idle_inhibit)
- return 1;
-
- compositor->state = WESTON_COMPOSITOR_IDLE;
- wl_signal_emit(&compositor->idle_signal, compositor);
-
- return 1;
-}
-
-WL_EXPORT void
-weston_plane_init(struct weston_plane *plane,
- struct weston_compositor *ec,
- int32_t x, int32_t y)
-{
- pixman_region32_init(&plane->damage);
- pixman_region32_init(&plane->clip);
- plane->x = x;
- plane->y = y;
- plane->compositor = ec;
-
- /* Init the link so that the call to wl_list_remove() when releasing
- * the plane without ever stacking doesn't lead to a crash */
- wl_list_init(&plane->link);
-}
-
-WL_EXPORT void
-weston_plane_release(struct weston_plane *plane)
-{
- struct weston_view *view;
-
- pixman_region32_fini(&plane->damage);
- pixman_region32_fini(&plane->clip);
-
- wl_list_for_each(view, &plane->compositor->view_list, link) {
- if (view->plane == plane)
- view->plane = NULL;
- }
-
- wl_list_remove(&plane->link);
-}
-
-/** weston_compositor_stack_plane
- * \ingroup compositor
- */
-WL_EXPORT void
-weston_compositor_stack_plane(struct weston_compositor *ec,
- struct weston_plane *plane,
- struct weston_plane *above)
-{
- if (above)
- wl_list_insert(above->link.prev, &plane->link);
- else
- wl_list_insert(&ec->plane_list, &plane->link);
-}
-
-static void
-output_release(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static const struct wl_output_interface output_interface = {
- output_release,
-};
-
-
-static void unbind_resource(struct wl_resource *resource)
-{
- wl_list_remove(wl_resource_get_link(resource));
-}
-
-static void
-bind_output(struct wl_client *client,
- void *data, uint32_t version, uint32_t id)
-{
- struct weston_head *head = data;
- struct weston_output *output = head->output;
- struct weston_mode *mode;
- struct wl_resource *resource;
-
- resource = wl_resource_create(client, &wl_output_interface,
- version, id);
- if (resource == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_list_insert(&head->resource_list, wl_resource_get_link(resource));
- wl_resource_set_implementation(resource, &output_interface, head,
- unbind_resource);
-
- assert(output);
- wl_output_send_geometry(resource,
- output->x,
- output->y,
- head->mm_width,
- head->mm_height,
- head->subpixel,
- head->make, head->model,
- output->transform);
- if (version >= WL_OUTPUT_SCALE_SINCE_VERSION)
- wl_output_send_scale(resource,
- output->current_scale);
-
- wl_list_for_each (mode, &output->mode_list, link) {
- wl_output_send_mode(resource,
- mode->flags,
- mode->width,
- mode->height,
- mode->refresh);
- }
-
- if (version >= WL_OUTPUT_DONE_SINCE_VERSION)
- wl_output_send_done(resource);
-}
-
-static void
-weston_head_add_global(struct weston_head *head)
-{
- head->global = wl_global_create(head->compositor->wl_display,
- &wl_output_interface, 3,
- head, bind_output);
-}
-
-/** Remove the global wl_output protocol object
- *
- * \param head The head whose global to remove.
- *
- * Also orphans the wl_resources for this head (wl_output).
- */
-static void
-weston_head_remove_global(struct weston_head *head)
-{
- struct wl_resource *resource, *tmp;
-
- if (head->global)
- wl_global_destroy(head->global);
- head->global = NULL;
-
- wl_resource_for_each_safe(resource, tmp, &head->resource_list) {
- unbind_resource(resource);
- wl_resource_set_destructor(resource, NULL);
- wl_resource_set_user_data(resource, NULL);
- }
-
- wl_resource_for_each(resource, &head->xdg_output_resource_list) {
- /* It's sufficient to unset the destructor, then the list elements
- * won't be accessed.
- */
- wl_resource_set_destructor(resource, NULL);
- }
- wl_list_init(&head->xdg_output_resource_list);
-}
-
-/** Get the backing object of wl_output
- *
- * \param resource A wl_output protocol object.
- * \return The backing object (user data) of a wl_resource representing a
- * wl_output protocol object.
- *
- * \ingroup head
- */
-WL_EXPORT struct weston_head *
-weston_head_from_resource(struct wl_resource *resource)
-{
- assert(wl_resource_instance_of(resource, &wl_output_interface,
- &output_interface));
-
- return wl_resource_get_user_data(resource);
-}
-
-/** Initialize a pre-allocated weston_head
- *
- * \param head The head to initialize.
- * \param name The head name, e.g. the connector name or equivalent.
- *
- * The head will be safe to attach, detach and release.
- *
- * The name is used in logs, and can be used by compositors as a configuration
- * identifier.
- *
- * \ingroup head
- * \internal
- */
-WL_EXPORT void
-weston_head_init(struct weston_head *head, const char *name)
-{
- /* Add some (in)sane defaults which can be used
- * for checking if an output was properly configured
- */
- memset(head, 0, sizeof *head);
-
- wl_list_init(&head->compositor_link);
- wl_signal_init(&head->destroy_signal);
- wl_list_init(&head->output_link);
- wl_list_init(&head->resource_list);
- wl_list_init(&head->xdg_output_resource_list);
- head->name = strdup(name);
- head->current_protection = WESTON_HDCP_DISABLE;
-}
-
-/** Send output heads changed signal
- *
- * \param output The output that changed.
- *
- * Notify that the enabled output gained and/or lost heads, or that the
- * associated heads may have changed their connection status. This does not
- * include cases where the output becomes enabled or disabled. The registered
- * callbacks are called after the change has successfully happened.
- *
- * If connection status change causes the compositor to attach or detach a head
- * to an enabled output, the registered callbacks may be called multiple times.
- *
- * \ingroup output
- */
-static void
-weston_output_emit_heads_changed(struct weston_output *output)
-{
- wl_signal_emit(&output->compositor->output_heads_changed_signal,
- output);
-}
-
-/** Idle task for emitting heads_changed_signal */
-static void
-weston_compositor_call_heads_changed(void *data)
-{
- struct weston_compositor *compositor = data;
- struct weston_head *head;
-
- compositor->heads_changed_source = NULL;
-
- wl_signal_emit(&compositor->heads_changed_signal, compositor);
-
- wl_list_for_each(head, &compositor->head_list, compositor_link) {
- if (head->output && head->output->enabled)
- weston_output_emit_heads_changed(head->output);
- }
-}
-
-/** Schedule a call on idle to heads_changed callback
- *
- * \param compositor The Compositor.
- *
- * \ingroup compositor
- * \internal
- */
-static void
-weston_compositor_schedule_heads_changed(struct weston_compositor *compositor)
-{
- struct wl_event_loop *loop;
-
- if (compositor->heads_changed_source)
- return;
-
- loop = wl_display_get_event_loop(compositor->wl_display);
- compositor->heads_changed_source = wl_event_loop_add_idle(loop,
- weston_compositor_call_heads_changed, compositor);
-}
-
-/** Register a new head
- *
- * \param compositor The compositor.
- * \param head The head to register, must not be already registered.
- *
- * This signals the core that a new head has become available, leading to
- * heads_changed hook being called later.
- *
- * \ingroup compositor
- * \internal
- */
-WL_EXPORT void
-weston_compositor_add_head(struct weston_compositor *compositor,
- struct weston_head *head)
-{
- assert(wl_list_empty(&head->compositor_link));
- assert(head->name);
-
- wl_list_insert(compositor->head_list.prev, &head->compositor_link);
- head->compositor = compositor;
- weston_compositor_schedule_heads_changed(compositor);
-}
-
-/** Adds a listener to be called when heads change
- *
- * \param compositor The compositor.
- * \param listener The listener to add.
- *
- * The listener notify function argument is weston_compositor.
- *
- * The listener function will be called after heads are added or their
- * connection status has changed. Several changes may be accumulated into a
- * single call. The user is expected to iterate over the existing heads and
- * check their statuses to find out what changed.
- *
- * \sa weston_compositor_iterate_heads, weston_head_is_connected,
- * weston_head_is_enabled
- * \ingroup compositor
- */
-WL_EXPORT void
-weston_compositor_add_heads_changed_listener(struct weston_compositor *compositor,
- struct wl_listener *listener)
-{
- wl_signal_add(&compositor->heads_changed_signal, listener);
-}
-
-/** Iterate over available heads
- *
- * \param compositor The compositor.
- * \param iter The iterator, or NULL for start.
- * \return The next available head in the list.
- *
- * Returns all available heads, regardless of being connected or enabled.
- *
- * You can iterate over all heads as follows:
- * \code
- * struct weston_head *head = NULL;
- *
- * while ((head = weston_compositor_iterate_heads(compositor, head))) {
- * ...
- * }
- * \endcode
- *
- * If you cause \c iter to be removed from the list, you cannot use it to
- * continue iterating. Removing any other item is safe.
- *
- * \ingroup compositor
- */
-WL_EXPORT struct weston_head *
-weston_compositor_iterate_heads(struct weston_compositor *compositor,
- struct weston_head *iter)
-{
- struct wl_list *list = &compositor->head_list;
- struct wl_list *node;
-
- assert(compositor);
- assert(!iter || iter->compositor == compositor);
-
- if (iter)
- node = iter->compositor_link.next;
- else
- node = list->next;
-
- assert(node);
- assert(!iter || node != &iter->compositor_link);
-
- if (node == list)
- return NULL;
-
- return container_of(node, struct weston_head, compositor_link);
-}
-
-/** Iterate over attached heads
- *
- * \param output The output whose heads to iterate.
- * \param iter The iterator, or NULL for start.
- * \return The next attached head in the list.
- *
- * Returns all heads currently attached to the output.
- *
- * You can iterate over all heads as follows:
- * \code
- * struct weston_head *head = NULL;
- *
- * while ((head = weston_output_iterate_heads(output, head))) {
- * ...
- * }
- * \endcode
- *
- * If you cause \c iter to be removed from the list, you cannot use it to
- * continue iterating. Removing any other item is safe.
- *
- * \ingroup ouput
- */
-WL_EXPORT struct weston_head *
-weston_output_iterate_heads(struct weston_output *output,
- struct weston_head *iter)
-{
- struct wl_list *list = &output->head_list;
- struct wl_list *node;
-
- assert(output);
- assert(!iter || iter->output == output);
-
- if (iter)
- node = iter->output_link.next;
- else
- node = list->next;
-
- assert(node);
- assert(!iter || node != &iter->output_link);
-
- if (node == list)
- return NULL;
-
- return container_of(node, struct weston_head, output_link);
-}
-
-/** Attach a head to an output
- *
- * \param output The output to attach to.
- * \param head The head that is not yet attached.
- * \return 0 on success, -1 on failure.
- *
- * Attaches the given head to the output. All heads of an output are clones
- * and share the resolution and timings.
- *
- * Cloning heads this way uses less resources than creating an output for
- * each head, but is not always possible due to environment, driver and hardware
- * limitations.
- *
- * On failure, the head remains unattached. Success of this function does not
- * guarantee the output configuration is actually valid. The final checks are
- * made on weston_output_enable() unless the output was already enabled.
- *
- * \ingroup output
- */
-WL_EXPORT int
-weston_output_attach_head(struct weston_output *output,
- struct weston_head *head)
-{
- char *head_names;
-
- if (!wl_list_empty(&head->output_link))
- return -1;
-
- if (output->attach_head) {
- if (output->attach_head(output, head) < 0)
- return -1;
- } else if (!wl_list_empty(&output->head_list)) {
- /* No support for clones in the legacy path. */
- return -1;
- }
-
- head->output = output;
- wl_list_insert(output->head_list.prev, &head->output_link);
-
- if (output->enabled) {
- weston_head_add_global(head);
-
- head_names = weston_output_create_heads_string(output);
- weston_log("Output '%s' updated to have head(s) %s\n",
- output->name, head_names);
- free(head_names);
-
- weston_output_emit_heads_changed(output);
- }
-
- return 0;
-}
-
-/** Detach a head from its output
- *
- * \param head The head to detach.
- *
- * It is safe to detach a non-attached head.
- *
- * If the head is attached to an enabled output and the output will be left
- * with no heads, the output will be disabled.
- *
- * \ingroup head
- * \sa weston_output_disable
- */
-WL_EXPORT void
-weston_head_detach(struct weston_head *head)
-{
- struct weston_output *output = head->output;
- char *head_names;
-
- wl_list_remove(&head->output_link);
- wl_list_init(&head->output_link);
- head->output = NULL;
-
- if (!output)
- return;
-
- if (output->detach_head)
- output->detach_head(output, head);
-
- if (output->enabled) {
- weston_head_remove_global(head);
-
- if (wl_list_empty(&output->head_list)) {
- weston_log("Output '%s' no heads left, disabling.\n",
- output->name);
- weston_output_disable(output);
- } else {
- head_names = weston_output_create_heads_string(output);
- weston_log("Output '%s' updated to have head(s) %s\n",
- output->name, head_names);
- free(head_names);
-
- weston_output_emit_heads_changed(output);
- }
- }
-}
-
-/** Destroy a head
- *
- * \param head The head to be released.
- *
- * Destroys the head. The caller is responsible for freeing the memory pointed
- * to by \c head.
- *
- * \ingroup head
- * \internal
- */
-WL_EXPORT void
-weston_head_release(struct weston_head *head)
-{
- wl_signal_emit(&head->destroy_signal, head);
-
- weston_head_detach(head);
-
- free(head->make);
- free(head->model);
- free(head->serial_number);
- free(head->name);
-
- wl_list_remove(&head->compositor_link);
-}
-
-static void
-weston_head_set_device_changed(struct weston_head *head)
-{
- head->device_changed = true;
-
- if (head->compositor)
- weston_compositor_schedule_heads_changed(head->compositor);
-}
-
-/** String equal comparison with NULLs being equal */
-static bool
-str_null_eq(const char *a, const char *b)
-{
- if (!a && !b)
- return true;
-
- if (!!a != !!b)
- return false;
-
- return strcmp(a, b) == 0;
-}
-
-/** Store monitor make, model and serial number
- *
- * \param head The head to modify.
- * \param make The monitor make. If EDID is available, the PNP ID. Otherwise
- * any string, or NULL for none.
- * \param model The monitor model or name, or a made-up string, or NULL for
- * none.
- * \param serialno The monitor serial number, a made-up string, or NULL for
- * none.
- *
- * This may set the device_changed flag.
- *
- * \ingroup head
- * \internal
- */
-WL_EXPORT void
-weston_head_set_monitor_strings(struct weston_head *head,
- const char *make,
- const char *model,
- const char *serialno)
-{
- if (str_null_eq(head->make, make) &&
- str_null_eq(head->model, model) &&
- str_null_eq(head->serial_number, serialno))
- return;
-
- free(head->make);
- free(head->model);
- free(head->serial_number);
-
- head->make = make ? strdup(make) : NULL;
- head->model = model ? strdup(model) : NULL;
- head->serial_number = serialno ? strdup(serialno) : NULL;
-
- weston_head_set_device_changed(head);
-}
-
-/** Store display non-desktop status
- *
- * \param head The head to modify.
- * \param non_desktop Whether the head connects to a non-desktop display.
- *
- * \ingroup head
- * \internal
- */
-WL_EXPORT void
-weston_head_set_non_desktop(struct weston_head *head, bool non_desktop)
-{
- if (head->non_desktop == non_desktop)
- return;
-
- head->non_desktop = non_desktop;
-
- weston_head_set_device_changed(head);
-}
-
-/** Store physical image size
- *
- * \param head The head to modify.
- * \param mm_width Image area width in millimeters.
- * \param mm_height Image area height in millimeters.
- *
- * This may set the device_changed flag.
- *
- * \ingroup head
- * \internal
- */
-WL_EXPORT void
-weston_head_set_physical_size(struct weston_head *head,
- int32_t mm_width, int32_t mm_height)
-{
- if (head->mm_width == mm_width &&
- head->mm_height == mm_height)
- return;
-
- head->mm_width = mm_width;
- head->mm_height = mm_height;
-
- weston_head_set_device_changed(head);
-}
-
-/** Store monitor sub-pixel layout
- *
- * \param head The head to modify.
- * \param sp Sub-pixel layout. The possible values are:
- * - WL_OUTPUT_SUBPIXEL_UNKNOWN,
- * - WL_OUTPUT_SUBPIXEL_NONE,
- * - WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB,
- * - WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR,
- * - WL_OUTPUT_SUBPIXEL_VERTICAL_RGB,
- * - WL_OUTPUT_SUBPIXEL_VERTICAL_BGR
- *
- * This may set the device_changed flag.
- *
- * \ingroup head
- * \internal
- */
-WL_EXPORT void
-weston_head_set_subpixel(struct weston_head *head,
- enum wl_output_subpixel sp)
-{
- if (head->subpixel == sp)
- return;
-
- head->subpixel = sp;
-
- weston_head_set_device_changed(head);
-}
-
-/** Mark the monitor as internal
- *
- * This is used for embedded screens, like laptop panels.
- *
- * \param head The head to mark as internal.
- *
- * By default a head is external. The type is often inferred from the physical
- * connector type.
- *
- * \ingroup head
- * \internal
- */
-WL_EXPORT void
-weston_head_set_internal(struct weston_head *head)
-{
- head->connection_internal = true;
-}
-
-/** Store connector status
- *
- * \param head The head to modify.
- * \param connected Whether the head is connected.
- *
- * Connectors are created as disconnected. This function can be used to
- * set the connector status.
- *
- * The status should be set to true when a physical connector is connected to
- * a video sink device like a monitor and to false when the connector is
- * disconnected. For nested backends, the connection status should reflect the
- * connection to the parent display server.
- *
- * When the connection status changes, it schedules a call to the heads_changed
- * hook and sets the device_changed flag.
- *
- * \sa weston_compositor_set_heads_changed_cb
- * \ingroup head
- * \internal
- */
-WL_EXPORT void
-weston_head_set_connection_status(struct weston_head *head, bool connected)
-{
- if (head->connected == connected)
- return;
-
- head->connected = connected;
-
- weston_head_set_device_changed(head);
-}
-
-static void
-weston_output_compute_protection(struct weston_output *output)
-{
- struct weston_head *head;
- enum weston_hdcp_protection op_protection;
- bool op_protection_valid = false;
- struct weston_compositor *wc = output->compositor;
-
- wl_list_for_each(head, &output->head_list, output_link) {
- if (!op_protection_valid) {
- op_protection = head->current_protection;
- op_protection_valid = true;
- }
- if (head->current_protection < op_protection)
- op_protection = head->current_protection;
- }
-
- if (!op_protection_valid)
- op_protection = WESTON_HDCP_DISABLE;
-
- if (output->current_protection != op_protection) {
- output->current_protection = op_protection;
- weston_output_damage(output);
- weston_schedule_surface_protection_update(wc);
- }
-}
-
-WL_EXPORT void
-weston_head_set_content_protection_status(struct weston_head *head,
- enum weston_hdcp_protection status)
-{
- head->current_protection = status;
- if (head->output)
- weston_output_compute_protection(head->output);
-}
-
-/** Is the head currently connected?
- *
- * \param head The head to query.
- * \return Connection status.
- *
- * Returns true if the head is physically connected to a monitor, or in
- * case of a nested backend returns true when there is a connection to the
- * parent display server.
- *
- * This is independent from the head being enabled.
- *
- * \sa weston_head_is_enabled
- * \ingroup head
- */
-WL_EXPORT bool
-weston_head_is_connected(struct weston_head *head)
-{
- return head->connected;
-}
-
-/** Is the head currently enabled?
- *
- * \param head The head to query.
- * \return Video status.
- *
- * Returns true if the head is currently transmitting a video stream.
- *
- * This is independent of the head being connected.
- *
- * \sa weston_head_is_connected
- * \ingroup head
- */
-WL_EXPORT bool
-weston_head_is_enabled(struct weston_head *head)
-{
- if (!head->output)
- return false;
-
- return head->output->enabled;
-}
-
-/** Has the device information changed?
- *
- * \param head The head to query.
- * \return True if the device information has changed since last reset.
- *
- * The information about the connected display device, e.g. a monitor, may
- * change without being disconnected in between. Changing information
- * causes a call to the heads_changed hook.
- *
- * The information includes make, model, serial number, physical size,
- * and sub-pixel type. The connection status is also included.
- *
- * \sa weston_head_reset_device_changed, weston_compositor_set_heads_changed_cb
- * \ingroup head
- */
-WL_EXPORT bool
-weston_head_is_device_changed(struct weston_head *head)
-{
- return head->device_changed;
-}
-
-/** Does the head represent a non-desktop display?
- *
- * \param head The head to query.
- * \return True if the device is a non-desktop display.
- *
- * Non-desktop heads are not attached to outputs by default.
- * This stops weston from extending the desktop onto head mounted displays.
- *
- * \ingroup head
- */
-WL_EXPORT bool
-weston_head_is_non_desktop(struct weston_head *head)
-{
- return head->non_desktop;
-}
-
-/** Acknowledge device information change
- *
- * \param head The head to acknowledge.
- *
- * Clears the device changed flag on this head. When a compositor has processed
- * device information, it should call this to be able to notice further
- * changes.
- *
- * \sa weston_head_is_device_changed
- * \ingroup head
- */
-WL_EXPORT void
-weston_head_reset_device_changed(struct weston_head *head)
-{
- head->device_changed = false;
-}
-
-/** Get the name of a head
- *
- * \param head The head to query.
- * \return The head's name, not NULL.
- *
- * The name depends on the backend. The DRM backend uses connector names,
- * other backends may use hardcoded names or user-given names.
- *
- * \ingroup head
- */
-WL_EXPORT const char *
-weston_head_get_name(struct weston_head *head)
-{
- return head->name;
-}
-
-/** Get the output the head is attached to
- *
- * \param head The head to query.
- * \return The output the head is attached to, or NULL if detached.
- * \ingroup head
- */
-WL_EXPORT struct weston_output *
-weston_head_get_output(struct weston_head *head)
-{
- return head->output;
-}
-
-/** Add destroy callback for a head
- *
- * \param head The head to watch for.
- * \param listener The listener to add. The \c notify member must be set.
- *
- * Heads may get destroyed for various reasons by the backends. If a head is
- * attached to an output, the compositor should listen for head destruction
- * and reconfigure or destroy the output if necessary.
- *
- * The destroy callbacks will be called on weston_head destruction before any
- * automatic detaching from an associated weston_output and before any
- * weston_head information is lost.
- *
- * The \c data argument to the notify callback is the weston_head being
- * destroyed.
- *
- * \ingroup head
- */
-WL_EXPORT void
-weston_head_add_destroy_listener(struct weston_head *head,
- struct wl_listener *listener)
-{
- wl_signal_add(&head->destroy_signal, listener);
-}
-
-/** Look up destroy listener for a head
- *
- * \param head The head to query.
- * \param notify The notify function used used for the added destroy listener.
- * \return The listener, or NULL if not found.
- *
- * This looks up the previously added destroy listener struct based on the
- * notify function it has. The listener can be used to access user data
- * through \c container_of().
- *
- * \sa wl_signal_get()
- * \ingroup head
- */
-WL_EXPORT struct wl_listener *
-weston_head_get_destroy_listener(struct weston_head *head,
- wl_notify_func_t notify)
-{
- return wl_signal_get(&head->destroy_signal, notify);
-}
-
-/* Move other outputs when one is resized so the space remains contiguous. */
-static void
-weston_compositor_reflow_outputs(struct weston_compositor *compositor,
- struct weston_output *resized_output, int delta_width)
-{
- struct weston_output *output;
- bool start_resizing = false;
-
- if (!delta_width)
- return;
-
- wl_list_for_each(output, &compositor->output_list, link) {
- if (output == resized_output) {
- start_resizing = true;
- continue;
- }
-
- if (start_resizing) {
- weston_output_move(output, output->x + delta_width, output->y);
- output->dirty = 1;
- }
- }
-}
-
-static void
-weston_output_update_matrix(struct weston_output *output)
-{
- float magnification;
-
- weston_matrix_init(&output->matrix);
- weston_matrix_translate(&output->matrix, -output->x, -output->y, 0);
-
- if (output->zoom.active) {
- magnification = 1 / (1 - output->zoom.spring_z.current);
- weston_output_update_zoom(output);
- weston_matrix_translate(&output->matrix, -output->zoom.trans_x,
- -output->zoom.trans_y, 0);
- weston_matrix_scale(&output->matrix, magnification,
- magnification, 1.0);
- }
-
- switch (output->transform) {
- case WL_OUTPUT_TRANSFORM_FLIPPED:
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- case WL_OUTPUT_TRANSFORM_FLIPPED_180:
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- weston_matrix_translate(&output->matrix, -output->width, 0, 0);
- weston_matrix_scale(&output->matrix, -1, 1, 1);
- break;
- }
-
- switch (output->transform) {
- default:
- case WL_OUTPUT_TRANSFORM_NORMAL:
- case WL_OUTPUT_TRANSFORM_FLIPPED:
- break;
- case WL_OUTPUT_TRANSFORM_90:
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- weston_matrix_translate(&output->matrix, 0, -output->height, 0);
- weston_matrix_rotate_xy(&output->matrix, 0, 1);
- break;
- case WL_OUTPUT_TRANSFORM_180:
- case WL_OUTPUT_TRANSFORM_FLIPPED_180:
- weston_matrix_translate(&output->matrix,
- -output->width, -output->height, 0);
- weston_matrix_rotate_xy(&output->matrix, -1, 0);
- break;
- case WL_OUTPUT_TRANSFORM_270:
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- weston_matrix_translate(&output->matrix, -output->width, 0, 0);
- weston_matrix_rotate_xy(&output->matrix, 0, -1);
- break;
- }
-
- if (output->current_scale != 1)
- weston_matrix_scale(&output->matrix,
- output->current_scale,
- output->current_scale, 1);
-
- output->dirty = 0;
-
- weston_matrix_invert(&output->inverse_matrix, &output->matrix);
-}
-
-static void
-weston_output_transform_scale_init(struct weston_output *output, uint32_t transform, uint32_t scale)
-{
- output->transform = transform;
- output->native_scale = scale;
- output->current_scale = scale;
-
- convert_size_by_transform_scale(&output->width, &output->height,
- output->current_mode->width,
- output->current_mode->height,
- transform, scale);
-}
-
-static void
-weston_output_init_geometry(struct weston_output *output, int x, int y)
-{
- output->x = x;
- output->y = y;
-
- pixman_region32_fini(&output->region);
- pixman_region32_init_rect(&output->region, x, y,
- output->width,
- output->height);
-}
-
-/**
- * \ingroup output
- */
-WL_EXPORT void
-weston_output_move(struct weston_output *output, int x, int y)
-{
- struct weston_head *head;
- struct wl_resource *resource;
- int ver;
-
- output->move_x = x - output->x;
- output->move_y = y - output->y;
-
- if (output->move_x == 0 && output->move_y == 0)
- return;
-
- weston_output_init_geometry(output, x, y);
-
- output->dirty = 1;
-
- /* Move views on this output. */
- wl_signal_emit(&output->compositor->output_moved_signal, output);
-
- /* Notify clients of the change for output position. */
- wl_list_for_each(head, &output->head_list, output_link) {
- wl_resource_for_each(resource, &head->resource_list) {
- wl_output_send_geometry(resource,
- output->x,
- output->y,
- head->mm_width,
- head->mm_height,
- head->subpixel,
- head->make,
- head->model,
- output->transform);
-
- ver = wl_resource_get_version(resource);
- if (ver >= WL_OUTPUT_DONE_SINCE_VERSION)
- wl_output_send_done(resource);
- }
-
- wl_resource_for_each(resource, &head->xdg_output_resource_list) {
- zxdg_output_v1_send_logical_position(resource,
- output->x,
- output->y);
- zxdg_output_v1_send_done(resource);
- }
- }
-}
-
-/** Signal that a pending output is taken into use.
- *
- * Removes the output from the pending list and adds it to the compositor's
- * list of enabled outputs. The output created signal is emitted.
- *
- * The output gets an internal ID assigned, and the wl_output global is
- * created.
- *
- * \param compositor The compositor instance.
- * \param output The output to be added.
- *
- * \internal
- * \ingroup compositor
- */
-static void
-weston_compositor_add_output(struct weston_compositor *compositor,
- struct weston_output *output)
-{
- struct weston_view *view, *next;
- struct weston_head *head;
-
- assert(!output->enabled);
-
- /* Verify we haven't reached the limit of 32 available output IDs */
- assert(ffs(~compositor->output_id_pool) > 0);
-
- /* Invert the output id pool and look for the lowest numbered
- * switch (the least significant bit). Take that bit's position
- * as our ID, and mark it used in the compositor's output_id_pool.
- */
- output->id = ffs(~compositor->output_id_pool) - 1;
- compositor->output_id_pool |= 1u << output->id;
-
- wl_list_remove(&output->link);
- wl_list_insert(compositor->output_list.prev, &output->link);
- output->enabled = true;
-
- wl_list_for_each(head, &output->head_list, output_link)
- weston_head_add_global(head);
-
- wl_signal_emit(&compositor->output_created_signal, output);
-
- wl_list_for_each_safe(view, next, &compositor->view_list, link)
- weston_view_geometry_dirty(view);
-}
-
-/** Transform device coordinates into global coordinates
- *
- * \param output the weston_output object
- * \param[in] device_x X coordinate in device units.
- * \param[in] device_y Y coordinate in device units.
- * \param[out] x X coordinate in the global space.
- * \param[out] y Y coordinate in the global space.
- *
- * Transforms coordinates from the device coordinate space (physical pixel
- * units) to the global coordinate space (logical pixel units). This takes
- * into account output transform and scale.
- *
- * \ingroup output
- * \internal
- */
-WL_EXPORT void
-weston_output_transform_coordinate(struct weston_output *output,
- double device_x, double device_y,
- double *x, double *y)
-{
- struct weston_vector p = { {
- device_x,
- device_y,
- 0.0,
- 1.0 } };
-
- weston_matrix_transform(&output->inverse_matrix, &p);
-
- *x = p.f[0] / p.f[3];
- *y = p.f[1] / p.f[3];
-}
-
-/** Removes output from compositor's list of enabled outputs
- *
- * \param output The weston_output object that is being removed.
- *
- * The following happens:
- *
- * - The output assignments of all views in the current scenegraph are
- * recomputed.
- *
- * - Presentation feedback is discarded.
- *
- * - Compositor is notified that outputs were changed and
- * applies the necessary changes to re-layout outputs.
- *
- * - The output is put back in the pending outputs list.
- *
- * - Signal is emitted to notify all users of the weston_output
- * object that the output is being destroyed.
- *
- * - wl_output protocol objects referencing this weston_output
- * are made inert, and the wl_output global is removed.
- *
- * - The output's internal ID is released.
- *
- * \ingroup compositor
- * \internal
- */
-static void
-weston_compositor_remove_output(struct weston_output *output)
-{
- struct weston_compositor *compositor = output->compositor;
- struct weston_view *view;
- struct weston_head *head;
-
- assert(output->destroying);
- assert(output->enabled);
-
- wl_list_for_each(view, &compositor->view_list, link) {
- if (view->output_mask & (1u << output->id))
- weston_view_assign_output(view);
- }
-
- weston_presentation_feedback_discard_list(&output->feedback_list);
-
- weston_compositor_reflow_outputs(compositor, output, -output->width);
-
- wl_list_remove(&output->link);
- wl_list_insert(compositor->pending_output_list.prev, &output->link);
- output->enabled = false;
-
- wl_signal_emit(&compositor->output_destroyed_signal, output);
- wl_signal_emit(&output->destroy_signal, output);
-
- wl_list_for_each(head, &output->head_list, output_link)
- weston_head_remove_global(head);
-
- compositor->output_id_pool &= ~(1u << output->id);
- output->id = 0xffffffff; /* invalid */
-}
-
-/** Sets the output scale for a given output.
- *
- * \param output The weston_output object that the scale is set for.
- * \param scale Scale factor for the given output.
- *
- * It only supports setting scale for an output that
- * is not enabled and it can only be ran once.
- *
- * \ingroup ouput
- */
-WL_EXPORT void
-weston_output_set_scale(struct weston_output *output,
- int32_t scale)
-{
- /* We can only set scale on a disabled output */
- assert(!output->enabled);
-
- /* We only want to set scale once */
- assert(!output->scale);
-
- output->scale = scale;
-}
-
-/** Sets the output transform for a given output.
- *
- * \param output The weston_output object that the transform is set for.
- * \param transform Transform value for the given output.
- *
- * Refer to wl_output::transform section located at
- * https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_output
- * for list of values that can be passed to this function.
- *
- * \ingroup output
- */
-WL_EXPORT void
-weston_output_set_transform(struct weston_output *output,
- uint32_t transform)
-{
- struct weston_pointer_motion_event ev;
- struct wl_resource *resource;
- struct weston_seat *seat;
- pixman_region32_t old_region;
- int mid_x, mid_y;
- struct weston_head *head;
- int ver;
-
- if (!output->enabled && output->transform == UINT32_MAX) {
- output->transform = transform;
- return;
- }
-
- weston_output_transform_scale_init(output, transform, output->scale);
-
- pixman_region32_init(&old_region);
- pixman_region32_copy(&old_region, &output->region);
-
- weston_output_init_geometry(output, output->x, output->y);
-
- output->dirty = 1;
-
- /* Notify clients of the change for output transform. */
- wl_list_for_each(head, &output->head_list, output_link) {
- wl_resource_for_each(resource, &head->resource_list) {
- wl_output_send_geometry(resource,
- output->x,
- output->y,
- head->mm_width,
- head->mm_height,
- head->subpixel,
- head->make,
- head->model,
- output->transform);
-
- ver = wl_resource_get_version(resource);
- if (ver >= WL_OUTPUT_DONE_SINCE_VERSION)
- wl_output_send_done(resource);
- }
- wl_resource_for_each(resource, &head->xdg_output_resource_list) {
- zxdg_output_v1_send_logical_position(resource,
- output->x,
- output->y);
- zxdg_output_v1_send_logical_size(resource,
- output->width,
- output->height);
- zxdg_output_v1_send_done(resource);
- }
- }
-
- /* we must ensure that pointers are inside output, otherwise they disappear */
- mid_x = output->x + output->width / 2;
- mid_y = output->y + output->height / 2;
-
- ev.mask = WESTON_POINTER_MOTION_ABS;
- ev.x = wl_fixed_to_double(wl_fixed_from_int(mid_x));
- ev.y = wl_fixed_to_double(wl_fixed_from_int(mid_y));
-
- wl_list_for_each(seat, &output->compositor->seat_list, link) {
- struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
- if (pointer && pixman_region32_contains_point(&old_region,
- wl_fixed_to_int(pointer->x),
- wl_fixed_to_int(pointer->y),
- NULL))
- weston_pointer_move(pointer, &ev);
- }
-}
-
-/** Initializes a weston_output object with enough data so
- ** an output can be configured.
- *
- * \param output The weston_output object to initialize
- * \param compositor The compositor instance.
- * \param name Name for the output (the string is copied).
- *
- * Sets initial values for fields that are expected to be
- * configured either by compositors or backends.
- *
- * The name is used in logs, and can be used by compositors as a configuration
- * identifier.
- *
- * \ingroup output
- * \internal
- */
-WL_EXPORT void
-weston_output_init(struct weston_output *output,
- struct weston_compositor *compositor,
- const char *name)
-{
- output->compositor = compositor;
- output->destroying = 0;
- output->name = strdup(name);
- wl_list_init(&output->link);
- wl_signal_init(&output->user_destroy_signal);
- output->enabled = false;
- output->desired_protection = WESTON_HDCP_DISABLE;
- output->allow_protection = true;
-
- wl_list_init(&output->head_list);
-
- /* Add some (in)sane defaults which can be used
- * for checking if an output was properly configured
- */
- output->scale = 0;
- /* Can't use -1 on uint32_t and 0 is valid enum value */
- output->transform = UINT32_MAX;
-
- pixman_region32_init(&output->region);
- wl_list_init(&output->mode_list);
-}
-
-/** Adds weston_output object to pending output list.
- *
- * \param output The weston_output object to add
- * \param compositor The compositor instance.
- *
- * The opposite of this operation is built into weston_output_release().
- *
- * \ingroup compositor
- * \internal
- */
-WL_EXPORT void
-weston_compositor_add_pending_output(struct weston_output *output,
- struct weston_compositor *compositor)
-{
- assert(output->disable);
- assert(output->enable);
-
- wl_list_remove(&output->link);
- wl_list_insert(compositor->pending_output_list.prev, &output->link);
-}
-
-/** Create a string with the attached heads' names.
- *
- * The string must be free()'d.
- *
- * \ingroup output
- */
-static char *
-weston_output_create_heads_string(struct weston_output *output)
-{
- FILE *fp;
- char *str = NULL;
- size_t size = 0;
- struct weston_head *head;
- const char *sep = "";
-
- fp = open_memstream(&str, &size);
- if (!fp)
- return NULL;
-
- wl_list_for_each(head, &output->head_list, output_link) {
- fprintf(fp, "%s%s", sep, head->name);
- sep = ", ";
- }
- fclose(fp);
-
- return str;
-}
-
-/** Constructs a weston_output object that can be used by the compositor.
- *
- * \param output The weston_output object that needs to be enabled. Must not
- * be enabled already. Must have at least one head attached.
- *
- * Output coordinates are calculated and each new output is by default
- * assigned to the right of previous one.
- *
- * Sets up the transformation, zoom, and geometry of the output using
- * the properties that need to be configured by the compositor.
- *
- * Establishes a repaint timer for the output with the relevant display
- * object's event loop. See output_repaint_timer_handler().
- *
- * The output is assigned an ID. Weston can support up to 32 distinct
- * outputs, with IDs numbered from 0-31; the compositor's output_id_pool
- * is referred to and used to find the first available ID number, and
- * then this ID is marked as used in output_id_pool.
- *
- * The output is also assigned a Wayland global with the wl_output
- * external interface.
- *
- * Backend specific function is called to set up the output output.
- *
- * Output is added to the compositor's output list
- *
- * If the backend specific function fails, the weston_output object
- * is returned to a state it was before calling this function and
- * is added to the compositor's pending_output_list in case it needs
- * to be reconfigured or just so it can be destroyed at shutdown.
- *
- * 0 is returned on success, -1 on failure.
- *
- * \ingroup output
- */
-WL_EXPORT int
-weston_output_enable(struct weston_output *output)
-{
- struct weston_compositor *c = output->compositor;
- struct weston_output *iterator;
- struct weston_head *head;
- char *head_names;
- int x = 0, y = 0;
-
- if (output->enabled) {
- weston_log("Error: attempt to enable an enabled output '%s'\n",
- output->name);
- return -1;
- }
-
- if (wl_list_empty(&output->head_list)) {
- weston_log("Error: cannot enable output '%s' without heads.\n",
- output->name);
- return -1;
- }
-
- if (wl_list_empty(&output->mode_list) || !output->current_mode) {
- weston_log("Error: no video mode for output '%s'.\n",
- output->name);
- return -1;
- }
-
- wl_list_for_each(head, &output->head_list, output_link) {
- assert(head->make);
- assert(head->model);
- }
-
- iterator = container_of(c->output_list.prev,
- struct weston_output, link);
-
- if (!wl_list_empty(&c->output_list))
- x = iterator->x + iterator->width;
-
- /* Make sure the scale is set up */
- assert(output->scale);
-
- /* Make sure we have a transform set */
- assert(output->transform != UINT32_MAX);
-
- output->x = x;
- output->y = y;
- output->dirty = 1;
- output->original_scale = output->scale;
-
- wl_signal_init(&output->frame_signal);
- wl_signal_init(&output->destroy_signal);
-
- weston_output_transform_scale_init(output, output->transform, output->scale);
- weston_output_init_zoom(output);
-
- weston_output_init_geometry(output, x, y);
- weston_output_damage(output);
-
- wl_list_init(&output->animation_list);
- wl_list_init(&output->feedback_list);
-
- /* Enable the output (set up the crtc or create a
- * window representing the output, set up the
- * renderer, etc)
- */
- if (output->enable(output) < 0) {
- weston_log("Enabling output \"%s\" failed.\n", output->name);
- return -1;
- }
-
- weston_compositor_add_output(output->compositor, output);
-
- head_names = weston_output_create_heads_string(output);
- weston_log("Output '%s' enabled with head(s) %s\n",
- output->name, head_names);
- free(head_names);
-
- return 0;
-}
-
-/** Converts a weston_output object to a pending output state, so it
- ** can be configured again or destroyed.
- *
- * \param output The weston_output object that needs to be disabled.
- *
- * Calls a backend specific function to disable an output, in case
- * such function exists.
- *
- * The backend specific disable function may choose to postpone the disabling
- * by returning a negative value, in which case this function returns early.
- * In that case the backend will guarantee the output will be disabled soon
- * by the backend calling this function again. One must not attempt to re-enable
- * the output until that happens.
- *
- * Otherwise, if the output is being used by the compositor, it is removed
- * from weston's output_list (see weston_compositor_remove_output())
- * and is returned to a state it was before weston_output_enable()
- * was ran (see weston_output_enable_undo()).
- *
- * See weston_output_init() for more information on the
- * state output is returned to.
- *
- * If the output has never been enabled yet, this function can still be
- * called to ensure that the output is actually turned off rather than left
- * in the state it was discovered in.
- *
- * \ingroup output
- */
-WL_EXPORT void
-weston_output_disable(struct weston_output *output)
-{
- /* Should we rename this? */
- output->destroying = 1;
-
- /* Disable is called unconditionally also for not-enabled outputs,
- * because at compositor start-up, if there is an output that is
- * already on but the compositor wants to turn it off, we have to
- * forward the turn-off to the backend so it knows to do it.
- * The backend cannot initially turn off everything, because it
- * would cause unnecessary mode-sets for all outputs the compositor
- * wants to be on.
- */
- if (output->disable(output) < 0)
- return;
-
- if (output->enabled)
- weston_compositor_remove_output(output);
-
- output->destroying = 0;
-}
-
-/** Forces a synchronous call to heads_changed hook
- *
- * \param compositor The compositor instance
- *
- * If there are new or changed heads, calls the heads_changed hook and
- * returns after the hook returns.
- *
- * \ingroup compositor
- */
-WL_EXPORT void
-weston_compositor_flush_heads_changed(struct weston_compositor *compositor)
-{
- if (compositor->heads_changed_source) {
- wl_event_source_remove(compositor->heads_changed_source);
- weston_compositor_call_heads_changed(compositor);
- }
-}
-
-/** Add destroy callback for an output
- *
- * \param output The output to watch.
- * \param listener The listener to add. The \c notify member must be set.
- *
- * The listener callback will be called when user destroys an output. This
- * may be delayed by a backend in some cases. The main purpose of the
- * listener is to allow hooking up custom data to the output. The custom data
- * can be fetched via weston_output_get_destroy_listener() followed by
- * container_of().
- *
- * The \c data argument to the notify callback is the weston_output being
- * destroyed.
- *
- * @note This is for the final destruction of an output, not when it gets
- * disabled. If you want to keep track of enabled outputs, this is not it.
- *
- * \ingroup ouput
- */
-WL_EXPORT void
-weston_output_add_destroy_listener(struct weston_output *output,
- struct wl_listener *listener)
-{
- wl_signal_add(&output->user_destroy_signal, listener);
-}
-
-/** Look up destroy listener for an output
- *
- * \param output The output to query.
- * \param notify The notify function used used for the added destroy listener.
- * \return The listener, or NULL if not found.
- *
- * This looks up the previously added destroy listener struct based on the
- * notify function it has. The listener can be used to access user data
- * through \c container_of().
- *
- * \sa wl_signal_get() weston_output_add_destroy_listener()
- * \ingroup output
- */
-WL_EXPORT struct wl_listener *
-weston_output_get_destroy_listener(struct weston_output *output,
- wl_notify_func_t notify)
-{
- return wl_signal_get(&output->user_destroy_signal, notify);
-}
-
-/** Uninitialize an output
- *
- * Removes the output from the list of enabled outputs if necessary, but
- * does not call the backend's output disable function. The output will no
- * longer be in the list of pending outputs either.
- *
- * All fields of weston_output become uninitialized, i.e. should not be used
- * anymore. The caller can free the memory after this.
- *
- * \ingroup ouput
- * \internal
- */
-WL_EXPORT void
-weston_output_release(struct weston_output *output)
-{
- struct weston_head *head, *tmp;
-
- output->destroying = 1;
-
- wl_signal_emit(&output->user_destroy_signal, output);
-
- if (output->idle_repaint_source)
- wl_event_source_remove(output->idle_repaint_source);
-
- if (output->enabled)
- weston_compositor_remove_output(output);
-
- pixman_region32_fini(&output->region);
- wl_list_remove(&output->link);
-
- wl_list_for_each_safe(head, tmp, &output->head_list, output_link)
- weston_head_detach(head);
-
- free(output->name);
-}
-
-/** Find an output by its given name
- *
- * \param compositor The compositor to search in.
- * \param name The output name to search for.
- * \return An existing output with the given name, or NULL if not found.
- *
- * \ingroup compositor
- */
-WL_EXPORT struct weston_output *
-weston_compositor_find_output_by_name(struct weston_compositor *compositor,
- const char *name)
-{
- struct weston_output *output;
-
- wl_list_for_each(output, &compositor->output_list, link)
- if (strcmp(output->name, name) == 0)
- return output;
-
- wl_list_for_each(output, &compositor->pending_output_list, link)
- if (strcmp(output->name, name) == 0)
- return output;
-
- return NULL;
-}
-
-/** Create a named output
- *
- * \param compositor The compositor.
- * \param name The name for the output.
- * \return A new \c weston_output, or NULL on failure.
- *
- * This creates a new weston_output that starts with no heads attached.
- *
- * An output must be configured and it must have at least one head before
- * it can be enabled.
- *
- * \ingroup compositor
- */
-WL_EXPORT struct weston_output *
-weston_compositor_create_output(struct weston_compositor *compositor,
- const char *name)
-{
- assert(compositor->backend->create_output);
-
- if (weston_compositor_find_output_by_name(compositor, name)) {
- weston_log("Warning: attempted to create an output with a "
- "duplicate name '%s'.\n", name);
- return NULL;
- }
-
- return compositor->backend->create_output(compositor, name);
-}
-
-/** Create an output for an unused head
- *
- * \param compositor The compositor.
- * \param head The head to attach to the output.
- * \return A new \c weston_output, or NULL on failure.
- *
- * This creates a new weston_output that starts with the given head attached.
- * The output inherits the name of the head. The head must not be already
- * attached to another output.
- *
- * An output must be configured before it can be enabled.
- *
- * \ingroup compositor
- */
-WL_EXPORT struct weston_output *
-weston_compositor_create_output_with_head(struct weston_compositor *compositor,
- struct weston_head *head)
-{
- struct weston_output *output;
-
- output = weston_compositor_create_output(compositor, head->name);
- if (!output)
- return NULL;
-
- if (weston_output_attach_head(output, head) < 0) {
- weston_output_destroy(output);
- return NULL;
- }
-
- return output;
-}
-
-/** Destroy an output
- *
- * \param output The output to destroy.
- *
- * The heads attached to the given output are detached and become unused again.
- *
- * It is not necessary to explicitly destroy all outputs at compositor exit.
- * weston_compositor_tear_down() will automatically destroy any remaining
- * outputs.
- *
- * \ingroup ouput
- */
-WL_EXPORT void
-weston_output_destroy(struct weston_output *output)
-{
- output->destroy(output);
-}
-
-/** When you need a head...
- *
- * This function is a hack, used until all code has been converted to become
- * multi-head aware.
- *
- * \param output The weston_output whose head to get.
- * \return The first head in the output's list.
- *
- * \ingroup ouput
- */
-WL_EXPORT struct weston_head *
-weston_output_get_first_head(struct weston_output *output)
-{
- if (wl_list_empty(&output->head_list))
- return NULL;
-
- return container_of(output->head_list.next,
- struct weston_head, output_link);
-}
-
-/** Allow/Disallow content-protection support for an output
- *
- * This function sets the allow_protection member for an output. Setting of
- * this field will allow the compositor to attempt content-protection for this
- * output, for a backend that supports the content-protection protocol.
- *
- * \param output The weston_output for whom the content-protection is to be
- * allowed.
- * \param allow_protection The bool value which is to be set.
- */
-WL_EXPORT void
-weston_output_allow_protection(struct weston_output *output,
- bool allow_protection)
-{
- output->allow_protection = allow_protection;
-}
-
-static void
-xdg_output_unlist(struct wl_resource *resource)
-{
- wl_list_remove(wl_resource_get_link(resource));
-}
-
-static void
-xdg_output_destroy(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static const struct zxdg_output_v1_interface xdg_output_interface = {
- xdg_output_destroy
-};
-
-static void
-xdg_output_manager_destroy(struct wl_client *client,
- struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-xdg_output_manager_get_xdg_output(struct wl_client *client,
- struct wl_resource *manager,
- uint32_t id,
- struct wl_resource *output_resource)
-{
- int version = wl_resource_get_version(manager);
- struct weston_head *head = wl_resource_get_user_data(output_resource);
- struct weston_output *output = head->output;
- struct wl_resource *resource;
-
- resource = wl_resource_create(client, &zxdg_output_v1_interface,
- version, id);
- if (resource == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_list_insert(&head->xdg_output_resource_list,
- wl_resource_get_link(resource));
-
- wl_resource_set_implementation(resource, &xdg_output_interface,
- NULL, xdg_output_unlist);
-
- zxdg_output_v1_send_logical_position(resource, output->x, output->y);
- zxdg_output_v1_send_logical_size(resource,
- output->width,
- output->height);
- if (version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION)
- zxdg_output_v1_send_name(resource, head->name);
-
- zxdg_output_v1_send_done(resource);
-}
-
-static const struct zxdg_output_manager_v1_interface xdg_output_manager_interface = {
- xdg_output_manager_destroy,
- xdg_output_manager_get_xdg_output
-};
-
-static void
-bind_xdg_output_manager(struct wl_client *client,
- void *data, uint32_t version, uint32_t id)
-{
- struct wl_resource *resource;
-
- resource = wl_resource_create(client, &zxdg_output_manager_v1_interface,
- version, id);
- if (resource == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_resource_set_implementation(resource, &xdg_output_manager_interface,
- NULL, NULL);
-}
-
-static void
-destroy_viewport(struct wl_resource *resource)
-{
- struct weston_surface *surface =
- wl_resource_get_user_data(resource);
-
- if (!surface)
- return;
-
- surface->viewport_resource = NULL;
- surface->pending.buffer_viewport.buffer.src_width =
- wl_fixed_from_int(-1);
- surface->pending.buffer_viewport.surface.width = -1;
- surface->pending.buffer_viewport.changed = 1;
-}
-
-static void
-viewport_destroy(struct wl_client *client,
- struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-viewport_set_source(struct wl_client *client,
- struct wl_resource *resource,
- wl_fixed_t src_x,
- wl_fixed_t src_y,
- wl_fixed_t src_width,
- wl_fixed_t src_height)
-{
- struct weston_surface *surface =
- wl_resource_get_user_data(resource);
-
- if (!surface) {
- wl_resource_post_error(resource,
- WP_VIEWPORT_ERROR_NO_SURFACE,
- "wl_surface for this viewport is no longer exists");
- return;
- }
-
- assert(surface->viewport_resource == resource);
- assert(surface->resource);
-
- if (src_width == wl_fixed_from_int(-1) &&
- src_height == wl_fixed_from_int(-1) &&
- src_x == wl_fixed_from_int(-1) &&
- src_y == wl_fixed_from_int(-1)) {
- /* unset source rect */
- surface->pending.buffer_viewport.buffer.src_width =
- wl_fixed_from_int(-1);
- surface->pending.buffer_viewport.changed = 1;
- return;
- }
-
- if (src_width <= 0 || src_height <= 0 || src_x < 0 || src_y < 0) {
- wl_resource_post_error(resource,
- WP_VIEWPORT_ERROR_BAD_VALUE,
- "wl_surface@%d viewport source "
- "w=%f <= 0, h=%f <= 0, x=%f < 0, or y=%f < 0",
- wl_resource_get_id(surface->resource),
- wl_fixed_to_double(src_width),
- wl_fixed_to_double(src_height),
- wl_fixed_to_double(src_x),
- wl_fixed_to_double(src_y));
- return;
- }
-
- surface->pending.buffer_viewport.buffer.src_x = src_x;
- surface->pending.buffer_viewport.buffer.src_y = src_y;
- surface->pending.buffer_viewport.buffer.src_width = src_width;
- surface->pending.buffer_viewport.buffer.src_height = src_height;
- surface->pending.buffer_viewport.changed = 1;
-}
-
-static void
-viewport_set_destination(struct wl_client *client,
- struct wl_resource *resource,
- int32_t dst_width,
- int32_t dst_height)
-{
- struct weston_surface *surface =
- wl_resource_get_user_data(resource);
-
- if (!surface) {
- wl_resource_post_error(resource,
- WP_VIEWPORT_ERROR_NO_SURFACE,
- "wl_surface for this viewport no longer exists");
- return;
- }
-
- assert(surface->viewport_resource == resource);
-
- if (dst_width == -1 && dst_height == -1) {
- /* unset destination size */
- surface->pending.buffer_viewport.surface.width = -1;
- surface->pending.buffer_viewport.changed = 1;
- return;
- }
-
- if (dst_width <= 0 || dst_height <= 0) {
- wl_resource_post_error(resource,
- WP_VIEWPORT_ERROR_BAD_VALUE,
- "destination size must be positive (%dx%d)",
- dst_width, dst_height);
- return;
- }
-
- surface->pending.buffer_viewport.surface.width = dst_width;
- surface->pending.buffer_viewport.surface.height = dst_height;
- surface->pending.buffer_viewport.changed = 1;
-}
-
-static const struct wp_viewport_interface viewport_interface = {
- viewport_destroy,
- viewport_set_source,
- viewport_set_destination
-};
-
-static void
-viewporter_destroy(struct wl_client *client,
- struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-viewporter_get_viewport(struct wl_client *client,
- struct wl_resource *viewporter,
- uint32_t id,
- struct wl_resource *surface_resource)
-{
- int version = wl_resource_get_version(viewporter);
- struct weston_surface *surface =
- wl_resource_get_user_data(surface_resource);
- struct wl_resource *resource;
-
- if (surface->viewport_resource) {
- wl_resource_post_error(viewporter,
- WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS,
- "a viewport for that surface already exists");
- return;
- }
-
- resource = wl_resource_create(client, &wp_viewport_interface,
- version, id);
- if (resource == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_resource_set_implementation(resource, &viewport_interface,
- surface, destroy_viewport);
-
- surface->viewport_resource = resource;
-}
-
-static const struct wp_viewporter_interface viewporter_interface = {
- viewporter_destroy,
- viewporter_get_viewport
-};
-
-static void
-bind_viewporter(struct wl_client *client,
- void *data, uint32_t version, uint32_t id)
-{
- struct wl_resource *resource;
-
- resource = wl_resource_create(client, &wp_viewporter_interface,
- version, id);
- if (resource == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_resource_set_implementation(resource, &viewporter_interface,
- NULL, NULL);
-}
-
-static void
-destroy_presentation_feedback(struct wl_resource *feedback_resource)
-{
- struct weston_presentation_feedback *feedback;
-
- feedback = wl_resource_get_user_data(feedback_resource);
-
- wl_list_remove(&feedback->link);
- free(feedback);
-}
-
-static void
-presentation_destroy(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-presentation_feedback(struct wl_client *client,
- struct wl_resource *presentation_resource,
- struct wl_resource *surface_resource,
- uint32_t callback)
-{
- struct weston_surface *surface;
- struct weston_presentation_feedback *feedback;
-
- surface = wl_resource_get_user_data(surface_resource);
-
- feedback = zalloc(sizeof *feedback);
- if (feedback == NULL)
- goto err_calloc;
-
- feedback->resource = wl_resource_create(client,
- &wp_presentation_feedback_interface,
- 1, callback);
- if (!feedback->resource)
- goto err_create;
-
- wl_resource_set_implementation(feedback->resource, NULL, feedback,
- destroy_presentation_feedback);
-
- wl_list_insert(&surface->pending.feedback_list, &feedback->link);
-
- return;
-
-err_create:
- free(feedback);
-
-err_calloc:
- wl_client_post_no_memory(client);
-}
-
-static const struct wp_presentation_interface presentation_implementation = {
- presentation_destroy,
- presentation_feedback
-};
-
-static void
-bind_presentation(struct wl_client *client,
- void *data, uint32_t version, uint32_t id)
-{
- struct weston_compositor *compositor = data;
- struct wl_resource *resource;
-
- resource = wl_resource_create(client, &wp_presentation_interface,
- version, id);
- if (resource == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_resource_set_implementation(resource, &presentation_implementation,
- compositor, NULL);
- wp_presentation_send_clock_id(resource, compositor->presentation_clock);
-}
-
-static void
-compositor_bind(struct wl_client *client,
- void *data, uint32_t version, uint32_t id)
-{
- struct weston_compositor *compositor = data;
- struct wl_resource *resource;
-
- resource = wl_resource_create(client, &wl_compositor_interface,
- version, id);
- if (resource == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_resource_set_implementation(resource, &compositor_interface,
- compositor, NULL);
-}
-
-WL_EXPORT int
-weston_environment_get_fd(const char *env)
-{
- char *e;
- int fd, flags;
-
- e = getenv(env);
- if (!e || !safe_strtoint(e, &fd))
- return -1;
-
- flags = fcntl(fd, F_GETFD);
- if (flags == -1)
- return -1;
-
- fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
- unsetenv(env);
-
- return fd;
-}
-
-static const char *
-output_repaint_status_text(struct weston_output *output)
-{
- switch (output->repaint_status) {
- case REPAINT_NOT_SCHEDULED:
- return "no repaint";
- case REPAINT_BEGIN_FROM_IDLE:
- return "start_repaint_loop scheduled";
- case REPAINT_SCHEDULED:
- return "repaint scheduled";
- case REPAINT_AWAITING_COMPLETION:
- return "awaiting completion";
- }
-
- assert(!"output_repaint_status_text missing enum");
- return NULL;
-}
-
-static void
-debug_scene_view_print_buffer(FILE *fp, struct weston_view *view)
-{
- struct weston_buffer *buffer = view->surface->buffer_ref.buffer;
- struct wl_shm_buffer *shm;
- struct linux_dmabuf_buffer *dmabuf;
- const struct pixel_format_info *pixel_info = NULL;
-
- if (!buffer) {
- fprintf(fp, "\t\t[buffer not available]\n");
- return;
- }
-
- shm = wl_shm_buffer_get(buffer->resource);
- if (shm) {
- uint32_t _format = wl_shm_buffer_get_format(shm);
- pixel_info = pixel_format_get_info_shm(_format);
- fprintf(fp, "\t\tSHM buffer\n");
- fprintf(fp, "\t\t\tformat: 0x%lx %s\n",
- (unsigned long) _format,
- pixel_info ? pixel_info->drm_format_name : "UNKNOWN");
- return;
- }
-
- dmabuf = linux_dmabuf_buffer_get(buffer->resource);
- if (dmabuf) {
- pixel_info = pixel_format_get_info(dmabuf->attributes.format);
- fprintf(fp, "\t\tdmabuf buffer\n");
- fprintf(fp, "\t\t\tformat: 0x%lx %s\n",
- (unsigned long) dmabuf->attributes.format,
- pixel_info ? pixel_info->drm_format_name : "UNKNOWN");
- fprintf(fp, "\t\t\tmodifier: 0x%llx\n",
- (unsigned long long) dmabuf->attributes.modifier[0]);
- return;
- }
-
- fprintf(fp, "\t\tEGL buffer\n");
-}
-
-static void
-debug_scene_view_print(FILE *fp, struct weston_view *view, int view_idx)
-{
- struct weston_compositor *ec = view->surface->compositor;
- struct weston_output *output;
- char desc[512];
- pixman_box32_t *box;
- uint32_t surface_id = 0;
- pid_t pid = 0;
-
- if (view->surface->resource) {
- struct wl_resource *resource = view->surface->resource;
- wl_client_get_credentials(wl_resource_get_client(resource),
- &pid, NULL, NULL);
- surface_id = wl_resource_get_id(view->surface->resource);
- }
-
- if (!view->surface->get_label ||
- view->surface->get_label(view->surface, desc, sizeof(desc)) < 0) {
- strcpy(desc, "[no description available]");
- }
- fprintf(fp, "\tView %d (role %s, PID %d, surface ID %u, %s, %p):\n",
- view_idx, view->surface->role_name, pid, surface_id,
- desc, view);
-
- box = pixman_region32_extents(&view->transform.boundingbox);
- fprintf(fp, "\t\tposition: (%d, %d) -> (%d, %d)\n",
- box->x1, box->y1, box->x2, box->y2);
- box = pixman_region32_extents(&view->transform.opaque);
-
- if (pixman_region32_equal(&view->transform.opaque,
- &view->transform.boundingbox)) {
- fprintf(fp, "\t\t[fully opaque]\n");
- } else if (!pixman_region32_not_empty(&view->transform.opaque)) {
- fprintf(fp, "\t\t[not opaque]\n");
- } else {
- fprintf(fp, "\t\t[opaque: (%d, %d) -> (%d, %d)]\n",
- box->x1, box->y1, box->x2, box->y2);
- }
-
- if (view->alpha < 1.0)
- fprintf(fp, "\t\talpha: %f\n", view->alpha);
-
- if (view->output_mask != 0) {
- bool first_output = true;
- fprintf(fp, "\t\toutputs: ");
- wl_list_for_each(output, &ec->output_list, link) {
- if (!(view->output_mask & (1 << output->id)))
- continue;
- fprintf(fp, "%s%d (%s)%s",
- (first_output) ? "" : ", ",
- output->id, output->name,
- (view->output == output) ? " (primary)" : "");
- first_output = false;
- }
- } else {
- fprintf(fp, "\t\t[no outputs]");
- }
-
- fprintf(fp, "\n");
-
- debug_scene_view_print_buffer(fp, view);
-}
-
-static void
-debug_scene_view_print_tree(struct weston_view *view,
- FILE *fp, int *view_idx)
-{
- struct weston_subsurface *sub;
- struct weston_view *ev;
-
- /*
- * print the view first, then we recursively go on printing
- * sub-surfaces. We bail out once no more sub-surfaces are available.
- */
- debug_scene_view_print(fp, view, *view_idx);
-
- /* no more sub-surfaces */
- if (wl_list_empty(&view->surface->subsurface_list))
- return;
-
- wl_list_for_each(sub, &view->surface->subsurface_list, parent_link) {
- wl_list_for_each(ev, &sub->surface->views, surface_link) {
- /* do not print again the parent view */
- if (view == ev)
- continue;
-
- (*view_idx)++;
- debug_scene_view_print_tree(ev, fp, view_idx);
- }
- }
-}
-
-/**
- * Output information on how libweston is currently composing the scene
- * graph.
- *
- * \ingroup compositor
- */
-WL_EXPORT char *
-weston_compositor_print_scene_graph(struct weston_compositor *ec)
-{
- struct weston_output *output;
- struct weston_layer *layer;
- struct timespec now;
- int layer_idx = 0;
- FILE *fp;
- char *ret;
- size_t len;
- int err;
-
- fp = open_memstream(&ret, &len);
- assert(fp);
-
- weston_compositor_read_presentation_clock(ec, &now);
- fprintf(fp, "Weston scene graph at %ld.%09ld:\n\n",
- now.tv_sec, now.tv_nsec);
-
- wl_list_for_each(output, &ec->output_list, link) {
- struct weston_head *head;
- int head_idx = 0;
-
- fprintf(fp, "Output %d (%s):\n", output->id, output->name);
- assert(output->enabled);
-
- fprintf(fp, "\tposition: (%d, %d) -> (%d, %d)\n",
- output->x, output->y,
- output->x + output->width,
- output->y + output->height);
- fprintf(fp, "\tmode: %dx%d@%.3fHz\n",
- output->current_mode->width,
- output->current_mode->height,
- output->current_mode->refresh / 1000.0);
- fprintf(fp, "\tscale: %d\n", output->scale);
-
- fprintf(fp, "\trepaint status: %s\n",
- output_repaint_status_text(output));
- if (output->repaint_status == REPAINT_SCHEDULED)
- fprintf(fp, "\tnext repaint: %ld.%09ld\n",
- output->next_repaint.tv_sec,
- output->next_repaint.tv_nsec);
-
- wl_list_for_each(head, &output->head_list, output_link) {
- fprintf(fp, "\tHead %d (%s): %sconnected\n",
- head_idx++, head->name,
- (head->connected) ? "" : "not ");
- }
- }
-
- fprintf(fp, "\n");
-
- wl_list_for_each(layer, &ec->layer_list, link) {
- struct weston_view *view;
- int view_idx = 0;
-
- fprintf(fp, "Layer %d (pos 0x%lx):\n", layer_idx++,
- (unsigned long) layer->position);
-
- if (!weston_layer_mask_is_infinite(layer)) {
- fprintf(fp, "\t[mask: (%d, %d) -> (%d,%d)]\n\n",
- layer->mask.x1, layer->mask.y1,
- layer->mask.x2, layer->mask.y2);
- }
-
- wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
- debug_scene_view_print_tree(view, fp, &view_idx);
- view_idx++;
- }
-
- if (wl_list_empty(&layer->view_list.link))
- fprintf(fp, "\t[no views]\n");
-
- fprintf(fp, "\n");
- }
-
- err = fclose(fp);
- assert(err == 0);
-
- return ret;
-}
-
-/**
- * Called when the 'scene-graph' debug scope is bound by a client. This
- * one-shot weston-debug scope prints the current scene graph when bound,
- * and then terminates the stream.
- */
-static void
-debug_scene_graph_cb(struct weston_log_subscription *sub, void *data)
-{
- struct weston_compositor *ec = data;
- char *str = weston_compositor_print_scene_graph(ec);
-
- weston_log_subscription_printf(sub, "%s", str);
- free(str);
- weston_log_subscription_complete(sub);
-}
-
-/** Create the compositor.
- *
- * This functions creates and initializes a compositor instance.
- *
- * \param display The Wayland display to be used.
- * \param user_data A pointer to an object that can later be retrieved
- * \param log_ctx A pointer to weston_debug_compositor
- * using the \ref weston_compositor_get_user_data function.
- * \return The compositor instance on success or NULL on failure.
- *
- * \ingroup compositor
- */
-WL_EXPORT struct weston_compositor *
-weston_compositor_create(struct wl_display *display,
- struct weston_log_context *log_ctx,
- void *user_data)
-{
- struct weston_compositor *ec;
- struct wl_event_loop *loop;
-
- ec = zalloc(sizeof *ec);
- if (!ec)
- return NULL;
-
- ec->wl_display = display;
- ec->user_data = user_data;
- wl_signal_init(&ec->destroy_signal);
- wl_signal_init(&ec->create_surface_signal);
- wl_signal_init(&ec->activate_signal);
- wl_signal_init(&ec->transform_signal);
- wl_signal_init(&ec->kill_signal);
- wl_signal_init(&ec->idle_signal);
- wl_signal_init(&ec->wake_signal);
- wl_signal_init(&ec->show_input_panel_signal);
- wl_signal_init(&ec->hide_input_panel_signal);
- wl_signal_init(&ec->update_input_panel_signal);
- wl_signal_init(&ec->seat_created_signal);
- wl_signal_init(&ec->output_created_signal);
- wl_signal_init(&ec->output_destroyed_signal);
- wl_signal_init(&ec->output_moved_signal);
- wl_signal_init(&ec->output_resized_signal);
- wl_signal_init(&ec->heads_changed_signal);
- wl_signal_init(&ec->output_heads_changed_signal);
- wl_signal_init(&ec->session_signal);
- ec->session_active = true;
-
- ec->output_id_pool = 0;
- ec->repaint_msec = DEFAULT_REPAINT_WINDOW;
-
- ec->activate_serial = 1;
-
- ec->touch_mode = WESTON_TOUCH_MODE_NORMAL;
-
- ec->content_protection = NULL;
-
- if (!wl_global_create(ec->wl_display, &wl_compositor_interface, 4,
- ec, compositor_bind))
- goto fail;
-
- if (!wl_global_create(ec->wl_display, &wl_subcompositor_interface, 1,
- ec, bind_subcompositor))
- goto fail;
-
- if (!wl_global_create(ec->wl_display, &wp_viewporter_interface, 1,
- ec, bind_viewporter))
- goto fail;
-
- if (!wl_global_create(ec->wl_display, &zxdg_output_manager_v1_interface, 2,
- ec, bind_xdg_output_manager))
- goto fail;
-
- if (!wl_global_create(ec->wl_display, &wp_presentation_interface, 1,
- ec, bind_presentation))
- goto fail;
-
- if (weston_log_ctx_compositor_setup(ec, log_ctx) < 0)
- goto fail;
-
- if (weston_input_init(ec) != 0)
- goto fail;
-
- wl_list_init(&ec->view_list);
- wl_list_init(&ec->plane_list);
- wl_list_init(&ec->layer_list);
- wl_list_init(&ec->seat_list);
- wl_list_init(&ec->pending_output_list);
- wl_list_init(&ec->output_list);
- wl_list_init(&ec->head_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->touch_binding_list);
- wl_list_init(&ec->axis_binding_list);
- wl_list_init(&ec->debug_binding_list);
-
- wl_list_init(&ec->plugin_api_list);
-
- weston_plane_init(&ec->primary_plane, ec, 0, 0);
- weston_compositor_stack_plane(ec, &ec->primary_plane, NULL);
-
- wl_data_device_manager_init(ec->wl_display);
-
- wl_display_init_shm(ec->wl_display);
-
- loop = wl_display_get_event_loop(ec->wl_display);
- ec->idle_source = wl_event_loop_add_timer(loop, idle_handler, ec);
- ec->repaint_timer =
- wl_event_loop_add_timer(loop, output_repaint_timer_handler,
- ec);
-
- weston_layer_init(&ec->fade_layer, ec);
- weston_layer_init(&ec->cursor_layer, ec);
-
- weston_layer_set_position(&ec->fade_layer, WESTON_LAYER_POSITION_FADE);
- weston_layer_set_position(&ec->cursor_layer,
- WESTON_LAYER_POSITION_CURSOR);
-
- ec->debug_scene =
- weston_compositor_add_log_scope(ec->weston_log_ctx, "scene-graph",
- "Scene graph details\n",
- debug_scene_graph_cb, NULL,
- ec);
-
- ec->timeline =
- weston_compositor_add_log_scope(ec->weston_log_ctx, "timeline",
- "Timeline event points\n",
- weston_timeline_create_subscription,
- weston_timeline_destroy_subscription,
- ec);
- return ec;
-
-fail:
- free(ec);
- return NULL;
-}
-
-/** weston_compositor_shutdown
- * \ingroup compositor
- */
-WL_EXPORT void
-weston_compositor_shutdown(struct weston_compositor *ec)
-{
- struct weston_output *output, *next;
-
- wl_event_source_remove(ec->idle_source);
-
- /* Destroy all outputs associated with this compositor */
- wl_list_for_each_safe(output, next, &ec->output_list, link)
- output->destroy(output);
-
- /* Destroy all pending outputs associated with this compositor */
- wl_list_for_each_safe(output, next, &ec->pending_output_list, link)
- output->destroy(output);
-
- if (ec->renderer)
- ec->renderer->destroy(ec);
-
- weston_binding_list_destroy_all(&ec->key_binding_list);
- weston_binding_list_destroy_all(&ec->modifier_binding_list);
- weston_binding_list_destroy_all(&ec->button_binding_list);
- weston_binding_list_destroy_all(&ec->touch_binding_list);
- weston_binding_list_destroy_all(&ec->axis_binding_list);
- weston_binding_list_destroy_all(&ec->debug_binding_list);
-
- weston_plane_release(&ec->primary_plane);
-}
-
-/** weston_compositor_exit_with_code
- * \ingroup compositor
- */
-WL_EXPORT void
-weston_compositor_exit_with_code(struct weston_compositor *compositor,
- int exit_code)
-{
- if (compositor->exit_code == EXIT_SUCCESS)
- compositor->exit_code = exit_code;
-
- weston_compositor_exit(compositor);
-}
-
-/** weston_compositor_set_default_pointer_grab
- * \ingroup compositor
- */
-WL_EXPORT void
-weston_compositor_set_default_pointer_grab(struct weston_compositor *ec,
- const struct weston_pointer_grab_interface *interface)
-{
- struct weston_seat *seat;
-
- ec->default_pointer_grab = interface;
- wl_list_for_each(seat, &ec->seat_list, link) {
- struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
- if (pointer)
- weston_pointer_set_default_grab(pointer, interface);
- }
-}
-
-/** weston_compositor_set_presentation_clock
- * \ingroup compositor
- */
-WL_EXPORT int
-weston_compositor_set_presentation_clock(struct weston_compositor *compositor,
- clockid_t clk_id)
-{
- struct timespec ts;
-
- if (clock_gettime(clk_id, &ts) < 0)
- return -1;
-
- compositor->presentation_clock = clk_id;
-
- return 0;
-}
-
-/** For choosing the software clock, when the display hardware or API
- * does not expose a compatible presentation timestamp.
- *
- * \ingroup compositor
- */
-WL_EXPORT int
-weston_compositor_set_presentation_clock_software(
- struct weston_compositor *compositor)
-{
- /* In order of preference */
- static const clockid_t clocks[] = {
- CLOCK_MONOTONIC_RAW, /* no jumps, no crawling */
- CLOCK_MONOTONIC_COARSE, /* no jumps, may crawl, fast & coarse */
- CLOCK_MONOTONIC, /* no jumps, may crawl */
- CLOCK_REALTIME_COARSE, /* may jump and crawl, fast & coarse */
- CLOCK_REALTIME /* may jump and crawl */
- };
- unsigned i;
-
- for (i = 0; i < ARRAY_LENGTH(clocks); i++)
- if (weston_compositor_set_presentation_clock(compositor,
- clocks[i]) == 0)
- return 0;
-
- weston_log("Error: no suitable presentation clock available.\n");
-
- return -1;
-}
-
-/** Read the current time from the Presentation clock
- *
- * \param compositor
- * \param[out] ts The current time.
- *
- * \note Reading the current time in user space is always imprecise to some
- * degree.
- *
- * This function is never meant to fail. If reading the clock does fail,
- * an error message is logged and a zero time is returned. Callers are not
- * supposed to detect or react to failures.
- *
- * \ingroup compositor
- */
-WL_EXPORT void
-weston_compositor_read_presentation_clock(
- const struct weston_compositor *compositor,
- struct timespec *ts)
-{
- static bool warned;
- int ret;
-
- ret = clock_gettime(compositor->presentation_clock, ts);
- if (ret < 0) {
- ts->tv_sec = 0;
- ts->tv_nsec = 0;
-
- if (!warned)
- weston_log("Error: failure to read "
- "the presentation clock %#x: '%s' (%d)\n",
- compositor->presentation_clock,
- strerror(errno), errno);
- warned = true;
- }
-}
-
-/** Import dmabuf buffer into current renderer
- *
- * \param compositor
- * \param buffer the dmabuf buffer to import
- * \return true on usable buffers, false otherwise
- *
- * This function tests that the linux_dmabuf_buffer is usable
- * for the current renderer. Returns false on unusable buffers. Usually
- * usability is tested by importing the dmabufs for composition.
- *
- * This hook is also used for detecting if the renderer supports
- * dmabufs at all. If the renderer hook is NULL, dmabufs are not
- * supported.
- *
- * \ingroup compositor
- */
-WL_EXPORT bool
-weston_compositor_import_dmabuf(struct weston_compositor *compositor,
- struct linux_dmabuf_buffer *buffer)
-{
- struct weston_renderer *renderer;
-
- renderer = compositor->renderer;
-
- if (renderer->import_dmabuf == NULL)
- return false;
-
- return renderer->import_dmabuf(compositor, buffer);
-}
-
-WL_EXPORT bool
-weston_compositor_dmabuf_can_scanout(struct weston_compositor *compositor,
- struct linux_dmabuf_buffer *buffer)
-{
- struct weston_backend *backend = compositor->backend;
-
- if (backend->can_scanout_dmabuf == NULL)
- return false;
-
- return backend->can_scanout_dmabuf(compositor, buffer);
-}
-
-WL_EXPORT void
-weston_version(int *major, int *minor, int *micro)
-{
- *major = WESTON_VERSION_MAJOR;
- *minor = WESTON_VERSION_MINOR;
- *micro = WESTON_VERSION_MICRO;
-}
-
-/**
- * Attempts to find a module path from the module map specified in the
- * environment. If found, writes the full path into the path variable.
- *
- * The module map is a string in environment variable WESTON_MODULE_MAP, where
- * each entry is of the form "name=path" and entries are separated by
- * semicolons. Whitespace is significant.
- *
- * \param name The name to search for.
- * \param path Where the path is written to if found.
- * \param path_len Allocated bytes at \c path .
- * \returns The length of the string written to path on success, or 0 if the
- * module was not specified in the environment map or path_len was too small.
- */
-WL_EXPORT size_t
-weston_module_path_from_env(const char *name, char *path, size_t path_len)
-{
- const char *mapping = getenv("WESTON_MODULE_MAP");
- const char *end;
- const int name_len = strlen(name);
-
- if (!mapping)
- return 0;
-
- end = mapping + strlen(mapping);
- while (mapping < end && *mapping) {
- const char *filename, *next;
-
- /* early out: impossibly short string */
- if (end - mapping < name_len + 1)
- return 0;
-
- filename = &mapping[name_len + 1];
- next = strchrnul(mapping, ';');
-
- if (strncmp(mapping, name, name_len) == 0 &&
- mapping[name_len] == '=') {
- size_t file_len = next - filename; /* no trailing NUL */
- if (file_len >= path_len)
- return 0;
- strncpy(path, filename, file_len);
- path[file_len] = '\0';
- return file_len;
- }
-
- mapping = next + 1;
- }
-
- return 0;
-}
-
-WL_EXPORT void *
-weston_load_module(const char *name, const char *entrypoint)
-{
- char path[PATH_MAX];
- void *module, *init;
- size_t len;
-
- if (name == NULL)
- return NULL;
-
- if (name[0] != '/') {
- len = weston_module_path_from_env(name, path, sizeof path);
- if (len == 0)
- len = snprintf(path, sizeof path, "%s/%s",
- LIBWESTON_MODULEDIR, name);
- } else {
- len = snprintf(path, sizeof path, "%s", name);
- }
-
- /* snprintf returns the length of the string it would've written,
- * _excluding_ the NUL byte. So even being equal to the size of
- * our buffer is an error here. */
- if (len >= sizeof path)
- return NULL;
-
- module = dlopen(path, RTLD_NOW | RTLD_NOLOAD);
- if (module) {
- weston_log("Module '%s' already loaded\n", path);
- } else {
- weston_log("Loading module '%s'\n", path);
- module = dlopen(path, RTLD_NOW);
- if (!module) {
- weston_log("Failed to load module: %s\n", dlerror());
- return NULL;
- }
- }
-
- init = dlsym(module, entrypoint);
- if (!init) {
- weston_log("Failed to lookup init function: %s\n", dlerror());
- dlclose(module);
- return NULL;
- }
-
- return init;
-}
-
-/** Add a compositor destroy listener only once
- *
- * \param compositor The compositor whose destroy to watch for.
- * \param listener The listener struct to initialize.
- * \param destroy_handler The callback when compositor is destroyed.
- * \return True if listener is added, or false if there already is a listener
- * with the given \c destroy_handler.
- *
- * This function does nothing and returns false if the given callback function
- * is already present in the weston_compositor destroy callbacks list.
- * Otherwise, this function initializes the given listener with the given
- * callback pointer and adds it to the compositor's destroy callbacks list.
- *
- * This can be used to ensure that plugin initialization is done only once
- * in case the same plugin is loaded multiple times. If this function returns
- * false, the plugin should be already initialized successfully.
- *
- * All plugins should register a destroy listener for cleaning up. Note, that
- * the plugin destruction order is not guaranteed: plugins that depend on other
- * plugins must be able to be torn down in arbitrary order.
- *
- * \sa weston_compositor_tear_down, weston_compositor_destroy
- */
-WL_EXPORT bool
-weston_compositor_add_destroy_listener_once(struct weston_compositor *compositor,
- struct wl_listener *listener,
- wl_notify_func_t destroy_handler)
-{
- if (wl_signal_get(&compositor->destroy_signal, destroy_handler))
- return false;
-
- listener->notify = destroy_handler;
- wl_signal_add(&compositor->destroy_signal, listener);
- return true;
-}
-
-/** Tear down the compositor.
- *
- * This function cleans up the compositor state. While the compositor state has
- * been cleaned do note that **only** weston_compositor_destroy() can be called
- * afterwards, in order to destroy the compositor instance.
- *
- * @param compositor The compositor to be tear-down/cleaned.
- *
- * @ingroup compositor
- * @sa weston_compositor_destroy
- */
-WL_EXPORT void
-weston_compositor_tear_down(struct weston_compositor *compositor)
-{
- /* prevent further rendering while shutting down */
- compositor->state = WESTON_COMPOSITOR_OFFSCREEN;
-
- wl_signal_emit(&compositor->destroy_signal, compositor);
-
- weston_compositor_xkb_destroy(compositor);
-
- if (compositor->backend)
- compositor->backend->destroy(compositor);
-
- /* The backend is responsible for destroying the heads. */
- assert(wl_list_empty(&compositor->head_list));
-
- weston_plugin_api_destroy_list(compositor);
-
- if (compositor->heads_changed_source)
- wl_event_source_remove(compositor->heads_changed_source);
-
- weston_compositor_log_scope_destroy(compositor->debug_scene);
- compositor->debug_scene = NULL;
-
- weston_compositor_log_scope_destroy(compositor->timeline);
- compositor->timeline = NULL;
-}
-
-/** Destroys the compositor.
- *
- * This function destroys the compositor. **Do not** call this before
- * calling weston_compositor_tear_down()
- *
- * @param compositor The compositor to be destroyed.
- * @ingroup compositor
- * @sa weston_compositor_tear_down()
- */
-WL_EXPORT void
-weston_compositor_destroy(struct weston_compositor *compositor)
-{
- free(compositor);
-}
-
-/** Instruct the compositor to exit.
- *
- * This functions does not directly destroy the compositor object, it merely
- * command it to start the tear down process. It is not guaranteed that the
- * tear down will happen immediately.
- *
- * \param compositor The compositor to tear down.
- *
- * \ingroup compositor
- */
-WL_EXPORT void
-weston_compositor_exit(struct weston_compositor *compositor)
-{
- compositor->exit(compositor);
-}
-
-/** Return the user data stored in the compositor.
- *
- * This function returns the user data pointer set with user_data parameter
- * to the \ref weston_compositor_create function.
- *
- * \ingroup compositor
- */
-WL_EXPORT void *
-weston_compositor_get_user_data(struct weston_compositor *compositor)
-{
- return compositor->user_data;
-}
-
-static const char * const backend_map[] = {
- [WESTON_BACKEND_DRM] = "drm-backend.so",
- [WESTON_BACKEND_FBDEV] = "fbdev-backend.so",
- [WESTON_BACKEND_HEADLESS] = "headless-backend.so",
- [WESTON_BACKEND_RDP] = "rdp-backend.so",
- [WESTON_BACKEND_WAYLAND] = "wayland-backend.so",
- [WESTON_BACKEND_X11] = "x11-backend.so",
- [WESTON_BACKEND_TDM] = "tdm-backend.so",
-};
-
-/** Load a backend into a weston_compositor
- *
- * A backend must be loaded to make a weston_compositor work. A backend
- * provides input and output capabilities, and determines the renderer to use.
- *
- * \param compositor A compositor that has not had a backend loaded yet.
- * \param backend Name of the backend file.
- * \param config_base A pointer to a backend-specific configuration
- * structure's 'base' member.
- *
- * \return 0 on success, or -1 on error.
- *
- * \ingroup compositor
- */
-WL_EXPORT int
-weston_compositor_load_backend(struct weston_compositor *compositor,
- enum weston_compositor_backend backend,
- struct weston_backend_config *config_base)
-{
- int (*backend_init)(struct weston_compositor *c,
- struct weston_backend_config *config_base);
-
- if (compositor->backend) {
- weston_log("Error: attempt to load a backend when one is already loaded\n");
- return -1;
- }
-
- if (backend >= ARRAY_LENGTH(backend_map))
- return -1;
-
- backend_init = weston_load_module(backend_map[backend], "weston_backend_init");
- if (!backend_init)
- return -1;
-
- if (backend_init(compositor, config_base) < 0) {
- compositor->backend = NULL;
- return -1;
- }
-
- return 0;
-}
-
-/** weston_compositor_load_xwayland
- * \ingroup compositor
- */
-WL_EXPORT int
-weston_compositor_load_xwayland(struct weston_compositor *compositor)
-{
- int (*module_init)(struct weston_compositor *ec);
-
- module_init = weston_load_module("xwayland.so", "weston_module_init");
- if (!module_init)
- return -1;
- if (module_init(compositor) < 0)
- return -1;
- return 0;
-}
-
-/** Resolve an internal compositor error by disconnecting the client.
- *
- * This function is used in cases when the wl_buffer turns out
- * unusable and there is no fallback path.
- *
- * It is possible the fault is caused by a compositor bug, the underlying
- * graphics stack bug or normal behaviour, or perhaps a client mistake.
- * In any case, the options are to either composite garbage or nothing,
- * or disconnect the client. This is a helper function for the latter.
- *
- * The error is sent as an INVALID_OBJECT error on the client's wl_display.
- *
- * \param buffer The weston buffer that is unusable.
- * \param msg A custom error message attached to the protocol error.
- */
-WL_EXPORT void
-weston_buffer_send_server_error(struct weston_buffer *buffer,
- const char *msg)
-{
- struct wl_client *client;
- struct wl_resource *display_resource;
- uint32_t id;
-
- assert(buffer->resource);
- id = wl_resource_get_id(buffer->resource);
- client = wl_resource_get_client(buffer->resource);
- display_resource = wl_client_get_object(client, 1);
-
- assert(display_resource);
- wl_resource_post_error(display_resource,
- WL_DISPLAY_ERROR_INVALID_OBJECT,
- "server error with "
- "wl_buffer@%u: %s", id, msg);
-}
-
-WL_EXPORT void
-weston_output_disable_planes_incr(struct weston_output *output)
-{
- output->disable_planes++;
- /*
- * If disable_planes changes from 0 to non-zero, it means some type of
- * recording of content has started, and therefore protection level of
- * the protected surfaces must be updated to avoid the recording of
- * the protected content.
- */
- if (output->disable_planes == 1)
- weston_schedule_surface_protection_update(output->compositor);
-}
-
-WL_EXPORT void
-weston_output_disable_planes_decr(struct weston_output *output)
-{
- output->disable_planes--;
- /*
- * If disable_planes changes from non-zero to 0, it means no content
- * recording is going on any more, and the protected and surfaces can be
- * shown without any apprehensions about content being recorded.
- */
- if (output->disable_planes == 0)
- weston_schedule_surface_protection_update(output->compositor);
-
-}
diff --git a/libweston/content-protection.c b/libweston/content-protection.c
deleted file mode 100644
index 23661453..00000000
--- a/libweston/content-protection.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Copyright © 2019 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-#include <stdint.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <signal.h>
-#include <unistd.h>
-#include <string.h>
-#include <libweston/libweston.h>
-#include <libweston/weston-log.h>
-#include "weston-content-protection-server-protocol.h"
-#include "shared/helpers.h"
-#include "shared/timespec-util.h"
-
-#define content_protection_log(cp, ...) \
- weston_log_scope_printf((cp)->debug, __VA_ARGS__)
-
-static const char * const content_type_name [] = {
- [WESTON_PROTECTED_SURFACE_TYPE_UNPROTECTED] = "UNPROTECTED",
- [WESTON_PROTECTED_SURFACE_TYPE_HDCP_0] = "TYPE-0",
- [WESTON_PROTECTED_SURFACE_TYPE_HDCP_1] = "TYPE-1",
-};
-
-void
-weston_protected_surface_send_event(struct protected_surface *psurface,
- enum weston_hdcp_protection protection)
-{
- struct wl_resource *p_resource;
- enum weston_protected_surface_type protection_type;
- struct content_protection *cp;
- struct wl_resource *surface_resource;
-
- p_resource = psurface->protection_resource;
- if (!p_resource)
- return;
- /* No event to be sent to client, in case of enforced mode */
- if (psurface->surface->protection_mode == WESTON_SURFACE_PROTECTION_MODE_ENFORCED)
- return;
- protection_type = (enum weston_protected_surface_type) protection;
- weston_protected_surface_send_status(p_resource, protection_type);
-
- cp = psurface->cp_backptr;
- surface_resource = psurface->surface->resource;
- content_protection_log(cp, "wl_surface@%"PRIu32" Protection type set to %s\n",
- wl_resource_get_id(surface_resource),
- content_type_name[protection_type]);
-}
-
-static void
-set_type(struct wl_client *client, struct wl_resource *resource,
- enum weston_protected_surface_type content_type)
-{
- struct content_protection *cp;
- struct protected_surface *psurface;
- enum weston_hdcp_protection weston_cp;
- struct wl_resource *surface_resource;
-
- psurface = wl_resource_get_user_data(resource);
- if (!psurface)
- return;
- cp = psurface->cp_backptr;
- surface_resource = psurface->surface->resource;
-
- if (content_type < WESTON_PROTECTED_SURFACE_TYPE_UNPROTECTED ||
- content_type > WESTON_PROTECTED_SURFACE_TYPE_HDCP_1) {
- wl_resource_post_error(resource,
- WESTON_PROTECTED_SURFACE_ERROR_INVALID_TYPE,
- "wl_surface@%"PRIu32" Invalid content-type %d for request:set_type\n",
- wl_resource_get_id(surface_resource), content_type);
-
- content_protection_log(cp, "wl_surface@%"PRIu32" Invalid content-type %d for resquest:set_type\n",
- wl_resource_get_id(surface_resource), content_type);
- return;
- }
-
- content_protection_log(cp, "wl_surface@%"PRIu32" Request: Enable Content-Protection Type: %s\n",
- wl_resource_get_id(surface_resource),
- content_type_name[content_type]);
-
- weston_cp = (enum weston_hdcp_protection) content_type;
- psurface->surface->pending.desired_protection = weston_cp;
-}
-
-static void
-protected_surface_destroy(struct wl_client *client, struct wl_resource *resource)
-{
- struct protected_surface *psurface;
-
- psurface = wl_resource_get_user_data(resource);
- if (!psurface)
- return;
- psurface->surface->pending.desired_protection = WESTON_HDCP_DISABLE;
-}
-
-static void
-set_enforce_mode(struct wl_client *client, struct wl_resource *resource)
-{
- /*
- * Enforce Censored-Visibility. Compositor censors the protected
- * surface on an unsecured output.
- * In case of a surface, being shown on an unprotected output, the
- * compositor hides the surface, not allowing it to be displayed on
- * the unprotected output, without bothering the client. No difference
- * for the protected outputs.
- *
- * The member 'protection_mode' is "double-buffered", so setting it in
- * pending_state will cause the setting of the corresponding
- * 'protection_mode' in weston_surface, after the commit.
- *
- * This function sets the 'protection_mode' of the weston_surface_state
- * to 'enfoced'. The renderers inspect the flag and compare the
- * desired_protection of the surface, to the current_protection of the
- * output, based on that the real surface or a place-holder content,
- * (e.g. solid color) are shown.
- */
-
- struct protected_surface *psurface;
-
- psurface = wl_resource_get_user_data(resource);
- if (!psurface)
- return;
-
- psurface->surface->pending.protection_mode =
- WESTON_SURFACE_PROTECTION_MODE_ENFORCED;
-}
-
-static void
-set_relax_mode(struct wl_client *client, struct wl_resource *resource)
-{
- /*
- * Relaxed mode. By default this mode will be activated.
- * In case of a surface, being shown in unprotected output,
- * compositor just sends the event for protection status changed.
- *
- * On setting the relaxed mode, the 'protection_mode' member is queued
- * to be set to 'relax' from the existing 'enforce' mode.
- */
-
- struct protected_surface *psurface;
-
- psurface = wl_resource_get_user_data(resource);
- if (!psurface)
- return;
-
- psurface->surface->pending.protection_mode =
- WESTON_SURFACE_PROTECTION_MODE_RELAXED;
-}
-
-static const struct weston_protected_surface_interface protected_surface_implementation = {
- protected_surface_destroy,
- set_type,
- set_enforce_mode,
- set_relax_mode,
-};
-
-static void
-cp_destroy_listener(struct wl_listener *listener, void *data)
-{
- struct content_protection *cp;
-
- cp = container_of(listener, struct content_protection,
- destroy_listener);
- wl_list_remove(&cp->destroy_listener.link);
- wl_list_remove(&cp->protected_list);
- weston_compositor_log_scope_destroy(cp->debug);
- cp->debug = NULL;
- cp->surface_protection_update = NULL;
- free(cp);
-}
-
-static void
-free_protected_surface(struct protected_surface *psurface)
-{
- psurface->surface->pending.desired_protection = WESTON_HDCP_DISABLE;
- wl_resource_set_user_data(psurface->protection_resource, NULL);
- wl_list_remove(&psurface->surface_destroy_listener.link);
- wl_list_remove(&psurface->link);
- free(psurface);
-}
-
-static void
-surface_destroyed(struct wl_listener *listener, void *data)
-{
- struct protected_surface *psurface;
-
- psurface = container_of(listener, struct protected_surface,
- surface_destroy_listener);
- free_protected_surface(psurface);
-}
-
-static void
-destroy_protected_surface(struct wl_resource *resource)
-{
- struct protected_surface *psurface;
-
- psurface = wl_resource_get_user_data(resource);
- if (!psurface)
- return;
- free_protected_surface(psurface);
-}
-
-static void
-get_protection(struct wl_client *client, struct wl_resource *cp_resource,
- uint32_t id, struct wl_resource *surface_resource)
-{
- struct wl_resource *resource;
- struct weston_surface *surface;
- struct content_protection *cp;
- struct protected_surface *psurface;
- struct wl_listener *listener;
-
- surface = wl_resource_get_user_data(surface_resource);
- assert(surface);
- cp = wl_resource_get_user_data(cp_resource);
- assert(cp);
-
- /*
- * Check if this client has a corresponding protected-surface
- */
-
- listener = wl_resource_get_destroy_listener(surface->resource,
- surface_destroyed);
-
- if (listener) {
- wl_resource_post_error(cp_resource,
- WESTON_CONTENT_PROTECTION_ERROR_SURFACE_EXISTS,
- "wl_surface@%"PRIu32" Protection already exists",
- wl_resource_get_id(surface_resource));
- return;
- }
-
- psurface = zalloc(sizeof(struct protected_surface));
- if (!psurface) {
- wl_client_post_no_memory(client);
- return;
- }
- psurface->cp_backptr = cp;
- resource = wl_resource_create(client, &weston_protected_surface_interface,
- 1, id);
- if (!resource) {
- free(psurface);
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_list_insert(&cp->protected_list, &psurface->link);
- wl_resource_set_implementation(resource, &protected_surface_implementation,
- psurface,
- destroy_protected_surface);
-
- psurface->protection_resource = resource;
- psurface->surface = surface;
- psurface->surface_destroy_listener.notify = surface_destroyed;
- wl_resource_add_destroy_listener(surface->resource,
- &psurface->surface_destroy_listener);
- weston_protected_surface_send_event(psurface,
- psurface->surface->current_protection);
-}
-
-static void
-destroy_protection(struct wl_client *client, struct wl_resource *cp_resource)
-{
- wl_resource_destroy(cp_resource);
-}
-
-static const
-struct weston_content_protection_interface content_protection_implementation = {
- destroy_protection,
- get_protection,
-};
-
-static void
-bind_weston_content_protection(struct wl_client *client, void *data,
- uint32_t version, uint32_t id)
-{
- struct content_protection *cp = data;
- struct wl_resource *resource;
-
- resource = wl_resource_create(client,
- &weston_content_protection_interface,
- 1, id);
- if (!resource) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_resource_set_implementation(resource,
- &content_protection_implementation,
- cp, NULL);
-}
-/* Advertise the content-protection support.
- *
- * Calling this function sets up the content-protection support via HDCP.
- * This exposes the global interface, visible to the client, enabling them to
- * request for content-protection for their surfaces according to the type of
- * content.
- */
-
-WL_EXPORT int
-weston_compositor_enable_content_protection(struct weston_compositor *compositor)
-{
- struct content_protection *cp;
-
- cp = zalloc(sizeof(*cp));
- if (cp == NULL)
- return -1;
- cp->compositor = compositor;
-
- compositor->content_protection = cp;
- wl_list_init(&cp->protected_list);
- if (wl_global_create(compositor->wl_display,
- &weston_content_protection_interface, 1, cp,
- bind_weston_content_protection) == NULL)
- return -1;
-
- cp->destroy_listener.notify = cp_destroy_listener;
- wl_signal_add(&compositor->destroy_signal, &cp->destroy_listener);
- cp->debug = weston_compositor_add_log_scope(compositor->weston_log_ctx,
- "content-protection-debug",
- "debug-logs for content-protection",
- NULL, NULL, NULL);
- return 0;
-}
diff --git a/libweston/data-device.c b/libweston/data-device.c
deleted file mode 100644
index 865d7497..00000000
--- a/libweston/data-device.c
+++ /dev/null
@@ -1,1369 +0,0 @@
-/*
- * Copyright © 2011 Kristian Høgsberg
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <assert.h>
-
-#include <libweston/libweston.h>
-#include "shared/helpers.h"
-#include "shared/timespec-util.h"
-
-struct weston_drag {
- struct wl_client *client;
- struct weston_data_source *data_source;
- struct wl_listener data_source_listener;
- struct weston_view *focus;
- struct wl_resource *focus_resource;
- struct wl_listener focus_listener;
- struct weston_view *icon;
- struct wl_listener icon_destroy_listener;
- int32_t dx, dy;
- struct weston_keyboard_grab keyboard_grab;
-};
-
-struct weston_pointer_drag {
- struct weston_drag base;
- struct weston_pointer_grab grab;
-};
-
-struct weston_touch_drag {
- struct weston_drag base;
- struct weston_touch_grab grab;
-};
-
-#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
- WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
- WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
-
-static void
-data_offer_accept(struct wl_client *client, struct wl_resource *resource,
- uint32_t serial, const char *mime_type)
-{
- struct weston_data_offer *offer = wl_resource_get_user_data(resource);
-
- /* Protect against untimely calls from older data offers */
- if (!offer->source || offer != offer->source->offer)
- return;
-
- /* FIXME: Check that client is currently focused by the input
- * device that is currently dragging this data source. Should
- * this be a wl_data_device request? */
-
- offer->source->accept(offer->source, serial, mime_type);
- offer->source->accepted = mime_type != NULL;
-}
-
-static void
-data_offer_receive(struct wl_client *client, struct wl_resource *resource,
- const char *mime_type, int32_t fd)
-{
- struct weston_data_offer *offer = wl_resource_get_user_data(resource);
-
- if (offer->source && offer == offer->source->offer)
- offer->source->send(offer->source, mime_type, fd);
- else
- close(fd);
-}
-
-static void
-data_offer_destroy(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-data_source_notify_finish(struct weston_data_source *source)
-{
- if (!source->actions_set)
- return;
-
- if (source->offer->in_ask &&
- wl_resource_get_version(source->resource) >=
- WL_DATA_SOURCE_ACTION_SINCE_VERSION) {
- wl_data_source_send_action(source->resource,
- source->current_dnd_action);
- }
-
- if (wl_resource_get_version(source->resource) >=
- WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
- wl_data_source_send_dnd_finished(source->resource);
- }
-
- source->offer = NULL;
-}
-
-static uint32_t
-data_offer_choose_action(struct weston_data_offer *offer)
-{
- uint32_t available_actions, preferred_action = 0;
- uint32_t source_actions, offer_actions;
-
- if (wl_resource_get_version(offer->resource) >=
- WL_DATA_OFFER_ACTION_SINCE_VERSION) {
- offer_actions = offer->dnd_actions;
- preferred_action = offer->preferred_dnd_action;
- } else {
- offer_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
- }
-
- if (wl_resource_get_version(offer->source->resource) >=
- WL_DATA_SOURCE_ACTION_SINCE_VERSION)
- source_actions = offer->source->dnd_actions;
- else
- source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
-
- available_actions = offer_actions & source_actions;
-
- if (!available_actions)
- return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
-
- if (offer->source->seat &&
- offer->source->compositor_action & available_actions)
- return offer->source->compositor_action;
-
- /* If the dest side has a preferred DnD action, use it */
- if ((preferred_action & available_actions) != 0)
- return preferred_action;
-
- /* Use the first found action, in bit order */
- return 1 << (ffs(available_actions) - 1);
-}
-
-static void
-data_offer_update_action(struct weston_data_offer *offer)
-{
- uint32_t action;
-
- if (!offer->source)
- return;
-
- action = data_offer_choose_action(offer);
-
- if (offer->source->current_dnd_action == action)
- return;
-
- offer->source->current_dnd_action = action;
-
- if (offer->in_ask)
- return;
-
- if (wl_resource_get_version(offer->source->resource) >=
- WL_DATA_SOURCE_ACTION_SINCE_VERSION)
- wl_data_source_send_action(offer->source->resource, action);
-
- if (wl_resource_get_version(offer->resource) >=
- WL_DATA_OFFER_ACTION_SINCE_VERSION)
- wl_data_offer_send_action(offer->resource, action);
-}
-
-static void
-data_offer_set_actions(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t dnd_actions, uint32_t preferred_action)
-{
- struct weston_data_offer *offer = wl_resource_get_user_data(resource);
-
- if (dnd_actions & ~ALL_ACTIONS) {
- wl_resource_post_error(offer->resource,
- WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK,
- "invalid action mask %x", dnd_actions);
- return;
- }
-
- if (preferred_action &&
- (!(preferred_action & dnd_actions) ||
- __builtin_popcount(preferred_action) > 1)) {
- wl_resource_post_error(offer->resource,
- WL_DATA_OFFER_ERROR_INVALID_ACTION,
- "invalid action %x", preferred_action);
- return;
- }
-
- offer->dnd_actions = dnd_actions;
- offer->preferred_dnd_action = preferred_action;
- data_offer_update_action(offer);
-}
-
-static void
-data_offer_finish(struct wl_client *client, struct wl_resource *resource)
-{
- struct weston_data_offer *offer = wl_resource_get_user_data(resource);
-
- if (!offer->source || offer->source->offer != offer)
- return;
-
- if (offer->source->set_selection) {
- wl_resource_post_error(offer->resource,
- WL_DATA_OFFER_ERROR_INVALID_FINISH,
- "finish only valid for drag n drop");
- return;
- }
-
- /* Disallow finish while we have a grab driving drag-and-drop, or
- * if the negotiation is not at the right stage
- */
- if (offer->source->seat ||
- !offer->source->accepted) {
- wl_resource_post_error(offer->resource,
- WL_DATA_OFFER_ERROR_INVALID_FINISH,
- "premature finish request");
- return;
- }
-
- switch (offer->source->current_dnd_action) {
- case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE:
- case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK:
- wl_resource_post_error(offer->resource,
- WL_DATA_OFFER_ERROR_INVALID_OFFER,
- "offer finished with an invalid action");
- return;
- default:
- break;
- }
-
- data_source_notify_finish(offer->source);
-}
-
-static const struct wl_data_offer_interface data_offer_interface = {
- data_offer_accept,
- data_offer_receive,
- data_offer_destroy,
- data_offer_finish,
- data_offer_set_actions,
-};
-
-static void
-destroy_data_offer(struct wl_resource *resource)
-{
- struct weston_data_offer *offer = wl_resource_get_user_data(resource);
-
- if (!offer->source)
- goto out;
-
- wl_list_remove(&offer->source_destroy_listener.link);
-
- if (offer->source->offer != offer)
- goto out;
-
- /* If the drag destination has version < 3, wl_data_offer.finish
- * won't be called, so do this here as a safety net, because
- * we still want the version >=3 drag source to be happy.
- */
- if (wl_resource_get_version(offer->resource) <
- WL_DATA_OFFER_ACTION_SINCE_VERSION) {
- data_source_notify_finish(offer->source);
- } else if (offer->source->resource &&
- wl_resource_get_version(offer->source->resource) >=
- WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
- wl_data_source_send_cancelled(offer->source->resource);
- }
-
- offer->source->offer = NULL;
-out:
- free(offer);
-}
-
-static void
-destroy_offer_data_source(struct wl_listener *listener, void *data)
-{
- struct weston_data_offer *offer;
-
- offer = container_of(listener, struct weston_data_offer,
- source_destroy_listener);
-
- offer->source = NULL;
-}
-
-static struct weston_data_offer *
-weston_data_source_send_offer(struct weston_data_source *source,
- struct wl_resource *target)
-{
- struct weston_data_offer *offer;
- char **p;
-
- offer = malloc(sizeof *offer);
- if (offer == NULL)
- return NULL;
-
- offer->resource =
- wl_resource_create(wl_resource_get_client(target),
- &wl_data_offer_interface,
- wl_resource_get_version(target), 0);
- if (offer->resource == NULL) {
- free(offer);
- return NULL;
- }
-
- wl_resource_set_implementation(offer->resource, &data_offer_interface,
- offer, destroy_data_offer);
-
- offer->in_ask = false;
- offer->dnd_actions = 0;
- offer->preferred_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
- offer->source = source;
- offer->source_destroy_listener.notify = destroy_offer_data_source;
- wl_signal_add(&source->destroy_signal,
- &offer->source_destroy_listener);
-
- wl_data_device_send_data_offer(target, offer->resource);
-
- wl_array_for_each(p, &source->mime_types)
- wl_data_offer_send_offer(offer->resource, *p);
-
- source->offer = offer;
- source->accepted = false;
-
- return offer;
-}
-
-static void
-data_source_offer(struct wl_client *client,
- struct wl_resource *resource,
- const char *type)
-{
- struct weston_data_source *source =
- wl_resource_get_user_data(resource);
- char **p;
-
- p = wl_array_add(&source->mime_types, sizeof *p);
- if (p)
- *p = strdup(type);
- if (!p || !*p)
- wl_resource_post_no_memory(resource);
-}
-
-static void
-data_source_destroy(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-data_source_set_actions(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t dnd_actions)
-{
- struct weston_data_source *source =
- wl_resource_get_user_data(resource);
-
- if (source->actions_set) {
- wl_resource_post_error(source->resource,
- WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
- "cannot set actions more than once");
- return;
- }
-
- if (dnd_actions & ~ALL_ACTIONS) {
- wl_resource_post_error(source->resource,
- WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
- "invalid action mask %x", dnd_actions);
- return;
- }
-
- if (source->seat) {
- wl_resource_post_error(source->resource,
- WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
- "invalid action change after "
- "wl_data_device.start_drag");
- return;
- }
-
- source->dnd_actions = dnd_actions;
- source->actions_set = true;
-}
-
-static struct wl_data_source_interface data_source_interface = {
- data_source_offer,
- data_source_destroy,
- data_source_set_actions
-};
-
-static void
-drag_surface_configure(struct weston_drag *drag,
- struct weston_pointer *pointer,
- struct weston_touch *touch,
- struct weston_surface *es,
- int32_t sx, int32_t sy)
-{
- struct weston_layer_entry *list;
- float fx, fy;
-
- assert((pointer != NULL && touch == NULL) ||
- (pointer == NULL && touch != NULL));
-
- if (!weston_surface_is_mapped(es) && es->buffer_ref.buffer) {
- if (pointer && pointer->sprite &&
- weston_view_is_mapped(pointer->sprite))
- list = &pointer->sprite->layer_link;
- else
- list = &es->compositor->cursor_layer.view_list;
-
- weston_layer_entry_remove(&drag->icon->layer_link);
- weston_layer_entry_insert(list, &drag->icon->layer_link);
- weston_view_update_transform(drag->icon);
- pixman_region32_clear(&es->pending.input);
- es->is_mapped = true;
- drag->icon->is_mapped = true;
- }
-
- drag->dx += sx;
- drag->dy += sy;
-
- /* init to 0 for avoiding a compile warning */
- fx = fy = 0;
- if (pointer) {
- fx = wl_fixed_to_double(pointer->x) + drag->dx;
- fy = wl_fixed_to_double(pointer->y) + drag->dy;
- } else if (touch) {
- fx = wl_fixed_to_double(touch->grab_x) + drag->dx;
- fy = wl_fixed_to_double(touch->grab_y) + drag->dy;
- }
- weston_view_set_position(drag->icon, fx, fy);
-}
-
-static int
-pointer_drag_surface_get_label(struct weston_surface *surface,
- char *buf, size_t len)
-{
- return snprintf(buf, len, "pointer drag icon");
-}
-
-static void
-pointer_drag_surface_committed(struct weston_surface *es,
- int32_t sx, int32_t sy)
-{
- struct weston_pointer_drag *drag = es->committed_private;
- struct weston_pointer *pointer = drag->grab.pointer;
-
- assert(es->committed == pointer_drag_surface_committed);
-
- drag_surface_configure(&drag->base, pointer, NULL, es, sx, sy);
-}
-
-static int
-touch_drag_surface_get_label(struct weston_surface *surface,
- char *buf, size_t len)
-{
- return snprintf(buf, len, "touch drag icon");
-}
-
-static void
-touch_drag_surface_committed(struct weston_surface *es, int32_t sx, int32_t sy)
-{
- struct weston_touch_drag *drag = es->committed_private;
- struct weston_touch *touch = drag->grab.touch;
-
- assert(es->committed == touch_drag_surface_committed);
-
- drag_surface_configure(&drag->base, NULL, touch, es, sx, sy);
-}
-
-static void
-destroy_drag_focus(struct wl_listener *listener, void *data)
-{
- struct weston_drag *drag =
- container_of(listener, struct weston_drag, focus_listener);
-
- drag->focus_resource = NULL;
-}
-
-static void
-weston_drag_set_focus(struct weston_drag *drag,
- struct weston_seat *seat,
- struct weston_view *view,
- wl_fixed_t sx, wl_fixed_t sy)
-{
- struct wl_resource *resource, *offer_resource = NULL;
- struct wl_display *display = seat->compositor->wl_display;
- struct weston_data_offer *offer;
- uint32_t serial;
-
- if (drag->focus && view && drag->focus->surface == view->surface) {
- drag->focus = view;
- return;
- }
-
- if (drag->focus_resource) {
- wl_data_device_send_leave(drag->focus_resource);
- wl_list_remove(&drag->focus_listener.link);
- drag->focus_resource = NULL;
- drag->focus = NULL;
- }
-
- if (!view || !view->surface->resource)
- return;
-
- if (!drag->data_source &&
- wl_resource_get_client(view->surface->resource) != drag->client)
- return;
-
- if (drag->data_source &&
- drag->data_source->offer) {
- /* Unlink the offer from the source */
- offer = drag->data_source->offer;
- offer->source = NULL;
- drag->data_source->offer = NULL;
- wl_list_remove(&offer->source_destroy_listener.link);
- }
-
- resource = wl_resource_find_for_client(&seat->drag_resource_list,
- wl_resource_get_client(view->surface->resource));
- if (!resource)
- return;
-
- serial = wl_display_next_serial(display);
-
- if (drag->data_source) {
- drag->data_source->accepted = false;
- offer = weston_data_source_send_offer(drag->data_source, resource);
- if (offer == NULL)
- return;
-
- data_offer_update_action(offer);
-
- offer_resource = offer->resource;
- if (wl_resource_get_version (offer_resource) >=
- WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) {
- wl_data_offer_send_source_actions (offer_resource,
- drag->data_source->dnd_actions);
- }
- }
-
- wl_data_device_send_enter(resource, serial, view->surface->resource,
- sx, sy, offer_resource);
-
- drag->focus = view;
- drag->focus_listener.notify = destroy_drag_focus;
- wl_resource_add_destroy_listener(resource, &drag->focus_listener);
- drag->focus_resource = resource;
-}
-
-static void
-drag_grab_focus(struct weston_pointer_grab *grab)
-{
- struct weston_pointer_drag *drag =
- container_of(grab, struct weston_pointer_drag, grab);
- struct weston_pointer *pointer = grab->pointer;
- struct weston_view *view;
- wl_fixed_t sx, sy;
-
- view = weston_compositor_pick_view(pointer->seat->compositor,
- pointer->x, pointer->y,
- &sx, &sy);
- if (drag->base.focus != view)
- weston_drag_set_focus(&drag->base, pointer->seat, view, sx, sy);
-}
-
-static void
-drag_grab_motion(struct weston_pointer_grab *grab,
- const struct timespec *time,
- struct weston_pointer_motion_event *event)
-{
- struct weston_pointer_drag *drag =
- container_of(grab, struct weston_pointer_drag, grab);
- struct weston_pointer *pointer = drag->grab.pointer;
- float fx, fy;
- wl_fixed_t sx, sy;
- uint32_t msecs;
-
- weston_pointer_move(pointer, event);
-
- if (drag->base.icon) {
- fx = wl_fixed_to_double(pointer->x) + drag->base.dx;
- fy = wl_fixed_to_double(pointer->y) + drag->base.dy;
- weston_view_set_position(drag->base.icon, fx, fy);
- weston_view_schedule_repaint(drag->base.icon);
- }
-
- if (drag->base.focus_resource) {
- msecs = timespec_to_msec(time);
- weston_view_from_global_fixed(drag->base.focus,
- pointer->x, pointer->y,
- &sx, &sy);
-
- wl_data_device_send_motion(drag->base.focus_resource, msecs, sx, sy);
- }
-}
-
-static void
-data_device_end_drag_grab(struct weston_drag *drag,
- struct weston_seat *seat)
-{
- if (drag->icon) {
- if (weston_view_is_mapped(drag->icon))
- weston_view_unmap(drag->icon);
-
- drag->icon->surface->committed = NULL;
- weston_surface_set_label_func(drag->icon->surface, NULL);
- pixman_region32_clear(&drag->icon->surface->pending.input);
- wl_list_remove(&drag->icon_destroy_listener.link);
- weston_view_destroy(drag->icon);
- }
-
- weston_drag_set_focus(drag, seat, NULL, 0, 0);
-}
-
-static void
-data_device_end_pointer_drag_grab(struct weston_pointer_drag *drag)
-{
- struct weston_pointer *pointer = drag->grab.pointer;
- struct weston_keyboard *keyboard = drag->base.keyboard_grab.keyboard;
-
- data_device_end_drag_grab(&drag->base, pointer->seat);
- weston_pointer_end_grab(pointer);
- weston_keyboard_end_grab(keyboard);
- free(drag);
-}
-
-static void
-drag_grab_button(struct weston_pointer_grab *grab,
- const struct timespec *time,
- uint32_t button, uint32_t state_w)
-{
- struct weston_pointer_drag *drag =
- container_of(grab, struct weston_pointer_drag, grab);
- struct weston_pointer *pointer = drag->grab.pointer;
- enum wl_pointer_button_state state = state_w;
- struct weston_data_source *data_source = drag->base.data_source;
-
- if (data_source &&
- pointer->grab_button == button &&
- state == WL_POINTER_BUTTON_STATE_RELEASED) {
- if (drag->base.focus_resource &&
- data_source->accepted &&
- data_source->current_dnd_action) {
- wl_data_device_send_drop(drag->base.focus_resource);
-
- if (wl_resource_get_version(data_source->resource) >=
- WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION)
- wl_data_source_send_dnd_drop_performed(data_source->resource);
-
- data_source->offer->in_ask =
- data_source->current_dnd_action ==
- WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
-
- data_source->seat = NULL;
- } else if (wl_resource_get_version(data_source->resource) >=
- WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
- wl_data_source_send_cancelled(data_source->resource);
- }
- }
-
- if (pointer->button_count == 0 &&
- state == WL_POINTER_BUTTON_STATE_RELEASED) {
- if (drag->base.data_source)
- wl_list_remove(&drag->base.data_source_listener.link);
- data_device_end_pointer_drag_grab(drag);
- }
-}
-
-static void
-drag_grab_axis(struct weston_pointer_grab *grab,
- const struct timespec *time,
- struct weston_pointer_axis_event *event)
-{
-}
-
-static void
-drag_grab_axis_source(struct weston_pointer_grab *grab, uint32_t source)
-{
-}
-
-static void
-drag_grab_frame(struct weston_pointer_grab *grab)
-{
-}
-
-static void
-drag_grab_cancel(struct weston_pointer_grab *grab)
-{
- struct weston_pointer_drag *drag =
- container_of(grab, struct weston_pointer_drag, grab);
-
- if (drag->base.data_source)
- wl_list_remove(&drag->base.data_source_listener.link);
-
- data_device_end_pointer_drag_grab(drag);
-}
-
-static const struct weston_pointer_grab_interface pointer_drag_grab_interface = {
- drag_grab_focus,
- drag_grab_motion,
- drag_grab_button,
- drag_grab_axis,
- drag_grab_axis_source,
- drag_grab_frame,
- drag_grab_cancel,
-};
-
-static void
-drag_grab_touch_down(struct weston_touch_grab *grab,
- const struct timespec *time, int touch_id,
- wl_fixed_t sx, wl_fixed_t sy)
-{
-}
-
-static void
-data_device_end_touch_drag_grab(struct weston_touch_drag *drag)
-{
- struct weston_touch *touch = drag->grab.touch;
- struct weston_keyboard *keyboard = drag->base.keyboard_grab.keyboard;
-
- data_device_end_drag_grab(&drag->base, touch->seat);
- weston_touch_end_grab(touch);
- weston_keyboard_end_grab(keyboard);
- free(drag);
-}
-
-static void
-drag_grab_touch_up(struct weston_touch_grab *grab,
- const struct timespec *time, int touch_id)
-{
- struct weston_touch_drag *touch_drag =
- container_of(grab, struct weston_touch_drag, grab);
- struct weston_touch *touch = grab->touch;
-
- if (touch_id != touch->grab_touch_id)
- return;
-
- if (touch_drag->base.focus_resource)
- wl_data_device_send_drop(touch_drag->base.focus_resource);
- if (touch_drag->base.data_source)
- wl_list_remove(&touch_drag->base.data_source_listener.link);
- data_device_end_touch_drag_grab(touch_drag);
-}
-
-static void
-drag_grab_touch_focus(struct weston_touch_drag *drag)
-{
- struct weston_touch *touch = drag->grab.touch;
- struct weston_view *view;
- wl_fixed_t view_x, view_y;
-
- view = weston_compositor_pick_view(touch->seat->compositor,
- touch->grab_x, touch->grab_y,
- &view_x, &view_y);
- if (drag->base.focus != view)
- weston_drag_set_focus(&drag->base, touch->seat,
- view, view_x, view_y);
-}
-
-static void
-drag_grab_touch_motion(struct weston_touch_grab *grab,
- const struct timespec *time,
- int touch_id, wl_fixed_t x, wl_fixed_t y)
-{
- struct weston_touch_drag *touch_drag =
- container_of(grab, struct weston_touch_drag, grab);
- struct weston_touch *touch = grab->touch;
- wl_fixed_t view_x, view_y;
- float fx, fy;
- uint32_t msecs;
-
- if (touch_id != touch->grab_touch_id)
- return;
-
- drag_grab_touch_focus(touch_drag);
- if (touch_drag->base.icon) {
- fx = wl_fixed_to_double(touch->grab_x) + touch_drag->base.dx;
- fy = wl_fixed_to_double(touch->grab_y) + touch_drag->base.dy;
- weston_view_set_position(touch_drag->base.icon, fx, fy);
- weston_view_schedule_repaint(touch_drag->base.icon);
- }
-
- if (touch_drag->base.focus_resource) {
- msecs = timespec_to_msec(time);
- weston_view_from_global_fixed(touch_drag->base.focus,
- touch->grab_x, touch->grab_y,
- &view_x, &view_y);
- wl_data_device_send_motion(touch_drag->base.focus_resource,
- msecs, view_x, view_y);
- }
-}
-
-static void
-drag_grab_touch_frame(struct weston_touch_grab *grab)
-{
-}
-
-static void
-drag_grab_touch_cancel(struct weston_touch_grab *grab)
-{
- struct weston_touch_drag *touch_drag =
- container_of(grab, struct weston_touch_drag, grab);
-
- if (touch_drag->base.data_source)
- wl_list_remove(&touch_drag->base.data_source_listener.link);
- data_device_end_touch_drag_grab(touch_drag);
-}
-
-static const struct weston_touch_grab_interface touch_drag_grab_interface = {
- drag_grab_touch_down,
- drag_grab_touch_up,
- drag_grab_touch_motion,
- drag_grab_touch_frame,
- drag_grab_touch_cancel
-};
-
-static void
-drag_grab_keyboard_key(struct weston_keyboard_grab *grab,
- const struct timespec *time, uint32_t key, uint32_t state)
-{
-}
-
-static void
-drag_grab_keyboard_modifiers(struct weston_keyboard_grab *grab,
- uint32_t serial, uint32_t mods_depressed,
- uint32_t mods_latched,
- uint32_t mods_locked, uint32_t group)
-{
- struct weston_keyboard *keyboard = grab->keyboard;
- struct weston_drag *drag =
- container_of(grab, struct weston_drag, keyboard_grab);
- uint32_t compositor_action;
-
- if (mods_depressed & (1 << keyboard->xkb_info->shift_mod))
- compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
- else if (mods_depressed & (1 << keyboard->xkb_info->ctrl_mod))
- compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
- else
- compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
-
- drag->data_source->compositor_action = compositor_action;
-
- if (drag->data_source->offer)
- data_offer_update_action(drag->data_source->offer);
-}
-
-static void
-drag_grab_keyboard_cancel(struct weston_keyboard_grab *grab)
-{
- struct weston_drag *drag =
- container_of(grab, struct weston_drag, keyboard_grab);
- struct weston_pointer *pointer = grab->keyboard->seat->pointer_state;
- struct weston_touch *touch = grab->keyboard->seat->touch_state;
-
- if (pointer && pointer->grab->interface == &pointer_drag_grab_interface) {
- struct weston_touch_drag *touch_drag =
- (struct weston_touch_drag *) drag;
- drag_grab_touch_cancel(&touch_drag->grab);
- } else if (touch && touch->grab->interface == &touch_drag_grab_interface) {
- struct weston_pointer_drag *pointer_drag =
- (struct weston_pointer_drag *) drag;
- drag_grab_cancel(&pointer_drag->grab);
- }
-}
-
-static const struct weston_keyboard_grab_interface keyboard_drag_grab_interface = {
- drag_grab_keyboard_key,
- drag_grab_keyboard_modifiers,
- drag_grab_keyboard_cancel
-};
-
-static void
-destroy_pointer_data_device_source(struct wl_listener *listener, void *data)
-{
- struct weston_pointer_drag *drag = container_of(listener,
- struct weston_pointer_drag, base.data_source_listener);
-
- data_device_end_pointer_drag_grab(drag);
-}
-
-static void
-handle_drag_icon_destroy(struct wl_listener *listener, void *data)
-{
- struct weston_drag *drag = container_of(listener, struct weston_drag,
- icon_destroy_listener);
-
- drag->icon = NULL;
-}
-
-WL_EXPORT int
-weston_pointer_start_drag(struct weston_pointer *pointer,
- struct weston_data_source *source,
- struct weston_surface *icon,
- struct wl_client *client)
-{
- struct weston_pointer_drag *drag;
- struct weston_keyboard *keyboard =
- weston_seat_get_keyboard(pointer->seat);
-
- drag = zalloc(sizeof *drag);
- if (drag == NULL)
- return -1;
-
- drag->grab.interface = &pointer_drag_grab_interface;
- drag->base.keyboard_grab.interface = &keyboard_drag_grab_interface;
- drag->base.client = client;
- drag->base.data_source = source;
-
- if (icon) {
- drag->base.icon = weston_view_create(icon);
- if (drag->base.icon == NULL) {
- free(drag);
- return -1;
- }
-
- drag->base.icon_destroy_listener.notify = handle_drag_icon_destroy;
- wl_signal_add(&icon->destroy_signal,
- &drag->base.icon_destroy_listener);
-
- icon->committed = pointer_drag_surface_committed;
- icon->committed_private = drag;
- weston_surface_set_label_func(icon,
- pointer_drag_surface_get_label);
- } else {
- drag->base.icon = NULL;
- }
-
- if (source) {
- drag->base.data_source_listener.notify = destroy_pointer_data_device_source;
- wl_signal_add(&source->destroy_signal,
- &drag->base.data_source_listener);
- }
-
- weston_pointer_clear_focus(pointer);
- weston_keyboard_set_focus(keyboard, NULL);
-
- weston_pointer_start_grab(pointer, &drag->grab);
- weston_keyboard_start_grab(keyboard, &drag->base.keyboard_grab);
-
- return 0;
-}
-
-static void
-destroy_touch_data_device_source(struct wl_listener *listener, void *data)
-{
- struct weston_touch_drag *drag = container_of(listener,
- struct weston_touch_drag, base.data_source_listener);
-
- data_device_end_touch_drag_grab(drag);
-}
-
-WL_EXPORT int
-weston_touch_start_drag(struct weston_touch *touch,
- struct weston_data_source *source,
- struct weston_surface *icon,
- struct wl_client *client)
-{
- struct weston_touch_drag *drag;
- struct weston_keyboard *keyboard =
- weston_seat_get_keyboard(touch->seat);
-
- drag = zalloc(sizeof *drag);
- if (drag == NULL)
- return -1;
-
- drag->grab.interface = &touch_drag_grab_interface;
- drag->base.client = client;
- drag->base.data_source = source;
-
- if (icon) {
- drag->base.icon = weston_view_create(icon);
- if (drag->base.icon == NULL) {
- free(drag);
- return -1;
- }
-
- drag->base.icon_destroy_listener.notify = handle_drag_icon_destroy;
- wl_signal_add(&icon->destroy_signal,
- &drag->base.icon_destroy_listener);
-
- icon->committed = touch_drag_surface_committed;
- icon->committed_private = drag;
- weston_surface_set_label_func(icon,
- touch_drag_surface_get_label);
- } else {
- drag->base.icon = NULL;
- }
-
- if (source) {
- drag->base.data_source_listener.notify = destroy_touch_data_device_source;
- wl_signal_add(&source->destroy_signal,
- &drag->base.data_source_listener);
- }
-
- weston_keyboard_set_focus(keyboard, NULL);
-
- weston_touch_start_grab(touch, &drag->grab);
- weston_keyboard_start_grab(keyboard, &drag->base.keyboard_grab);
-
- drag_grab_touch_focus(drag);
-
- return 0;
-}
-
-static void
-data_device_start_drag(struct wl_client *client, struct wl_resource *resource,
- struct wl_resource *source_resource,
- struct wl_resource *origin_resource,
- struct wl_resource *icon_resource, uint32_t serial)
-{
- struct weston_seat *seat = wl_resource_get_user_data(resource);
- struct weston_pointer *pointer = weston_seat_get_pointer(seat);
- struct weston_touch *touch = weston_seat_get_touch(seat);
- struct weston_surface *origin = wl_resource_get_user_data(origin_resource);
- struct weston_data_source *source = NULL;
- struct weston_surface *icon = NULL;
- int is_pointer_grab, is_touch_grab;
- int32_t ret = 0;
-
- is_pointer_grab = pointer &&
- pointer->button_count == 1 &&
- pointer->grab_serial == serial &&
- pointer->focus &&
- pointer->focus->surface == origin;
-
- is_touch_grab = touch &&
- touch->num_tp == 1 &&
- touch->grab_serial == serial &&
- touch->focus &&
- touch->focus->surface == origin;
-
- if (!is_pointer_grab && !is_touch_grab)
- return;
-
- /* FIXME: Check that the data source type array isn't empty. */
-
- if (source_resource)
- source = wl_resource_get_user_data(source_resource);
- if (icon_resource)
- icon = wl_resource_get_user_data(icon_resource);
-
- if (icon) {
- if (weston_surface_set_role(icon, "wl_data_device-icon",
- resource,
- WL_DATA_DEVICE_ERROR_ROLE) < 0)
- return;
- }
-
- if (is_pointer_grab)
- ret = weston_pointer_start_drag(pointer, source, icon, client);
- else if (is_touch_grab)
- ret = weston_touch_start_drag(touch, source, icon, client);
-
- if (ret < 0)
- wl_resource_post_no_memory(resource);
- else
- source->seat = seat;
-}
-
-static void
-destroy_selection_data_source(struct wl_listener *listener, void *data)
-{
- struct weston_seat *seat = container_of(listener, struct weston_seat,
- selection_data_source_listener);
- struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
- struct wl_resource *data_device;
- struct weston_surface *focus = NULL;
-
- seat->selection_data_source = NULL;
-
- if (keyboard)
- focus = keyboard->focus;
- if (focus && focus->resource) {
- data_device = wl_resource_find_for_client(&seat->drag_resource_list,
- wl_resource_get_client(focus->resource));
- if (data_device)
- wl_data_device_send_selection(data_device, NULL);
- }
-
- wl_signal_emit(&seat->selection_signal, seat);
-}
-
-/** \brief Send the selection to the specified client
- *
- * This function creates a new wl_data_offer if there is a wl_data_source
- * currently set as the selection and sends it to the specified client,
- * followed by the wl_data_device.selection() event.
- * If there is no current selection the wl_data_device.selection() event
- * will carry a NULL wl_data_offer.
- *
- * If the client does not have a wl_data_device for the specified seat
- * nothing will be done.
- *
- * \param seat The seat owning the wl_data_device used to send the events.
- * \param client The client to which to send the selection.
- */
-WL_EXPORT void
-weston_seat_send_selection(struct weston_seat *seat, struct wl_client *client)
-{
- struct weston_data_offer *offer;
- struct wl_resource *data_device;
-
- wl_resource_for_each(data_device, &seat->drag_resource_list) {
- if (wl_resource_get_client(data_device) != client)
- continue;
-
- if (seat->selection_data_source) {
- offer = weston_data_source_send_offer(seat->selection_data_source,
- data_device);
- wl_data_device_send_selection(data_device, offer->resource);
- } else {
- wl_data_device_send_selection(data_device, NULL);
- }
- }
-}
-
-WL_EXPORT void
-weston_seat_set_selection(struct weston_seat *seat,
- struct weston_data_source *source, uint32_t serial)
-{
- struct weston_surface *focus = NULL;
- struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-
- if (seat->selection_data_source &&
- seat->selection_serial - serial < UINT32_MAX / 2)
- return;
-
- if (seat->selection_data_source) {
- seat->selection_data_source->cancel(seat->selection_data_source);
- wl_list_remove(&seat->selection_data_source_listener.link);
- seat->selection_data_source = NULL;
- }
-
- seat->selection_data_source = source;
- seat->selection_serial = serial;
-
- if (source)
- source->set_selection = true;
-
- if (keyboard)
- focus = keyboard->focus;
- if (focus && focus->resource) {
- weston_seat_send_selection(seat, wl_resource_get_client(focus->resource));
- }
-
- wl_signal_emit(&seat->selection_signal, seat);
-
- if (source) {
- seat->selection_data_source_listener.notify =
- destroy_selection_data_source;
- wl_signal_add(&source->destroy_signal,
- &seat->selection_data_source_listener);
- }
-}
-
-static void
-data_device_set_selection(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *source_resource, uint32_t serial)
-{
- struct weston_seat *seat = wl_resource_get_user_data(resource);
- struct weston_data_source *source;
-
- if (!seat || !source_resource)
- return;
-
- source = wl_resource_get_user_data(source_resource);
-
- if (source->actions_set) {
- wl_resource_post_error(source_resource,
- WL_DATA_SOURCE_ERROR_INVALID_SOURCE,
- "cannot set drag-and-drop source as selection");
- return;
- }
-
- /* FIXME: Store serial and check against incoming serial here. */
- weston_seat_set_selection(seat, source, serial);
-}
-static void
-data_device_release(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static const struct wl_data_device_interface data_device_interface = {
- data_device_start_drag,
- data_device_set_selection,
- data_device_release
-};
-
-static void
-destroy_data_source(struct wl_resource *resource)
-{
- struct weston_data_source *source =
- wl_resource_get_user_data(resource);
- char **p;
-
- wl_signal_emit(&source->destroy_signal, source);
-
- wl_array_for_each(p, &source->mime_types)
- free(*p);
-
- wl_array_release(&source->mime_types);
-
- free(source);
-}
-
-static void
-client_source_accept(struct weston_data_source *source,
- uint32_t time, const char *mime_type)
-{
- wl_data_source_send_target(source->resource, mime_type);
-}
-
-static void
-client_source_send(struct weston_data_source *source,
- const char *mime_type, int32_t fd)
-{
- wl_data_source_send_send(source->resource, mime_type, fd);
- close(fd);
-}
-
-static void
-client_source_cancel(struct weston_data_source *source)
-{
- wl_data_source_send_cancelled(source->resource);
-}
-
-static void
-create_data_source(struct wl_client *client,
- struct wl_resource *resource, uint32_t id)
-{
- struct weston_data_source *source;
-
- source = malloc(sizeof *source);
- if (source == NULL) {
- wl_resource_post_no_memory(resource);
- return;
- }
-
- source->resource =
- wl_resource_create(client, &wl_data_source_interface,
- wl_resource_get_version(resource), id);
- if (source->resource == NULL) {
- free(source);
- wl_resource_post_no_memory(resource);
- return;
- }
-
- wl_signal_init(&source->destroy_signal);
- source->accept = client_source_accept;
- source->send = client_source_send;
- source->cancel = client_source_cancel;
- source->offer = NULL;
- source->accepted = false;
- source->seat = NULL;
- source->actions_set = false;
- source->dnd_actions = 0;
- source->current_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
- source->compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
- source->set_selection = false;
-
- wl_array_init(&source->mime_types);
-
- wl_resource_set_implementation(source->resource, &data_source_interface,
- source, destroy_data_source);
-}
-
-static void unbind_data_device(struct wl_resource *resource)
-{
- wl_list_remove(wl_resource_get_link(resource));
-}
-
-static void
-get_data_device(struct wl_client *client,
- struct wl_resource *manager_resource,
- uint32_t id, struct wl_resource *seat_resource)
-{
- struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
- struct wl_resource *resource;
-
- resource = wl_resource_create(client,
- &wl_data_device_interface,
- wl_resource_get_version(manager_resource),
- id);
- if (resource == NULL) {
- wl_resource_post_no_memory(manager_resource);
- return;
- }
-
- if (seat) {
- wl_list_insert(&seat->drag_resource_list,
- wl_resource_get_link(resource));
- } else {
- wl_list_init(wl_resource_get_link(resource));
- }
-
- wl_resource_set_implementation(resource, &data_device_interface,
- seat, unbind_data_device);
-}
-
-static const struct wl_data_device_manager_interface manager_interface = {
- create_data_source,
- get_data_device
-};
-
-static void
-bind_manager(struct wl_client *client,
- void *data, uint32_t version, uint32_t id)
-{
- struct wl_resource *resource;
-
- resource = wl_resource_create(client,
- &wl_data_device_manager_interface,
- version, id);
- if (resource == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_resource_set_implementation(resource, &manager_interface,
- NULL, NULL);
-}
-
-WL_EXPORT void
-wl_data_device_set_keyboard_focus(struct weston_seat *seat)
-{
- struct weston_surface *focus;
- struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-
- if (!keyboard)
- return;
-
- focus = keyboard->focus;
- if (!focus || !focus->resource)
- return;
-
- weston_seat_send_selection(seat, wl_resource_get_client(focus->resource));
-}
-
-WL_EXPORT int
-wl_data_device_manager_init(struct wl_display *display)
-{
- if (wl_global_create(display,
- &wl_data_device_manager_interface, 3,
- NULL, bind_manager) == NULL)
- return -1;
-
- return 0;
-}
diff --git a/libweston/dbus.c b/libweston/dbus.c
deleted file mode 100644
index 91f2be7e..00000000
--- a/libweston/dbus.c
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- * Copyright © 2013 David Herrmann <dh.herrmann@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * DBus Helpers
- * This file contains the dbus mainloop integration and several helpers to
- * make lowlevel libdbus access easier.
- */
-
-#include "config.h"
-
-#include <dbus/dbus.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/eventfd.h>
-#include <sys/timerfd.h>
-#include <unistd.h>
-#include <wayland-server.h>
-
-#include <libweston/libweston.h>
-#include "dbus.h"
-
-/*
- * DBus Mainloop Integration
- * weston_dbus_bind() and weston_dbus_unbind() allow to bind an existing
- * DBusConnection to an existing wl_event_loop object. All dbus dispatching
- * is then nicely integrated into the wayland event loop.
- * Note that this only provides basic watch and timeout dispatching. No
- * remote thread wakeup, signal handling or other dbus insanity is supported.
- * This is fine as long as you don't use any of the deprecated libdbus
- * interfaces (like waking up remote threads..). There is really no rational
- * reason to support these.
- */
-
-static int weston_dbus_dispatch_watch(int fd, uint32_t mask, void *data)
-{
- DBusWatch *watch = data;
- uint32_t flags = 0;
-
- if (dbus_watch_get_enabled(watch)) {
- if (mask & WL_EVENT_READABLE)
- flags |= DBUS_WATCH_READABLE;
- if (mask & WL_EVENT_WRITABLE)
- flags |= DBUS_WATCH_WRITABLE;
- if (mask & WL_EVENT_HANGUP)
- flags |= DBUS_WATCH_HANGUP;
- if (mask & WL_EVENT_ERROR)
- flags |= DBUS_WATCH_ERROR;
-
- dbus_watch_handle(watch, flags);
- }
-
- return 0;
-}
-
-static dbus_bool_t weston_dbus_add_watch(DBusWatch *watch, void *data)
-{
- struct wl_event_loop *loop = data;
- struct wl_event_source *s;
- int fd;
- uint32_t mask = 0, flags;
-
- if (dbus_watch_get_enabled(watch)) {
- flags = dbus_watch_get_flags(watch);
- if (flags & DBUS_WATCH_READABLE)
- mask |= WL_EVENT_READABLE;
- if (flags & DBUS_WATCH_WRITABLE)
- mask |= WL_EVENT_WRITABLE;
- }
-
- fd = dbus_watch_get_unix_fd(watch);
- s = wl_event_loop_add_fd(loop, fd, mask, weston_dbus_dispatch_watch,
- watch);
- if (!s)
- return FALSE;
-
- dbus_watch_set_data(watch, s, NULL);
- return TRUE;
-}
-
-static void weston_dbus_remove_watch(DBusWatch *watch, void *data)
-{
- struct wl_event_source *s;
-
- s = dbus_watch_get_data(watch);
- if (!s)
- return;
-
- wl_event_source_remove(s);
-}
-
-static void weston_dbus_toggle_watch(DBusWatch *watch, void *data)
-{
- struct wl_event_source *s;
- uint32_t mask = 0, flags;
-
- s = dbus_watch_get_data(watch);
- if (!s)
- return;
-
- if (dbus_watch_get_enabled(watch)) {
- flags = dbus_watch_get_flags(watch);
- if (flags & DBUS_WATCH_READABLE)
- mask |= WL_EVENT_READABLE;
- if (flags & DBUS_WATCH_WRITABLE)
- mask |= WL_EVENT_WRITABLE;
- }
-
- wl_event_source_fd_update(s, mask);
-}
-
-static int weston_dbus_dispatch_timeout(void *data)
-{
- DBusTimeout *timeout = data;
-
- if (dbus_timeout_get_enabled(timeout))
- dbus_timeout_handle(timeout);
-
- return 0;
-}
-
-static int weston_dbus_adjust_timeout(DBusTimeout *timeout,
- struct wl_event_source *s)
-{
- int64_t t = 0;
-
- if (dbus_timeout_get_enabled(timeout))
- t = dbus_timeout_get_interval(timeout);
-
- return wl_event_source_timer_update(s, t);
-}
-
-static dbus_bool_t weston_dbus_add_timeout(DBusTimeout *timeout, void *data)
-{
- struct wl_event_loop *loop = data;
- struct wl_event_source *s;
- int r;
-
- s = wl_event_loop_add_timer(loop, weston_dbus_dispatch_timeout,
- timeout);
- if (!s)
- return FALSE;
-
- r = weston_dbus_adjust_timeout(timeout, s);
- if (r < 0) {
- wl_event_source_remove(s);
- return FALSE;
- }
-
- dbus_timeout_set_data(timeout, s, NULL);
- return TRUE;
-}
-
-static void weston_dbus_remove_timeout(DBusTimeout *timeout, void *data)
-{
- struct wl_event_source *s;
-
- s = dbus_timeout_get_data(timeout);
- if (!s)
- return;
-
- wl_event_source_remove(s);
-}
-
-static void weston_dbus_toggle_timeout(DBusTimeout *timeout, void *data)
-{
- struct wl_event_source *s;
-
- s = dbus_timeout_get_data(timeout);
- if (!s)
- return;
-
- weston_dbus_adjust_timeout(timeout, s);
-}
-
-static int weston_dbus_dispatch(int fd, uint32_t mask, void *data)
-{
- DBusConnection *c = data;
- int r;
-
- do {
- r = dbus_connection_dispatch(c);
- if (r == DBUS_DISPATCH_COMPLETE)
- r = 0;
- else if (r == DBUS_DISPATCH_DATA_REMAINS)
- r = -EAGAIN;
- else if (r == DBUS_DISPATCH_NEED_MEMORY)
- r = -ENOMEM;
- else
- r = -EIO;
- } while (r == -EAGAIN);
-
- if (r)
- weston_log("cannot dispatch dbus events: %d\n", r);
-
- return 0;
-}
-
-static int weston_dbus_bind(struct wl_event_loop *loop, DBusConnection *c,
- struct wl_event_source **ctx_out)
-{
- bool b;
- int r, fd;
-
- /* Idle events cannot reschedule themselves, therefore we use a dummy
- * event-fd and mark it for post-dispatch. Hence, the dbus
- * dispatcher is called after every dispatch-round.
- * This is required as dbus doesn't allow dispatching events from
- * within its own event sources. */
- fd = eventfd(0, EFD_CLOEXEC);
- if (fd < 0)
- return -errno;
-
- *ctx_out = wl_event_loop_add_fd(loop, fd, 0, weston_dbus_dispatch, c);
- close(fd);
-
- if (!*ctx_out)
- return -ENOMEM;
-
- wl_event_source_check(*ctx_out);
-
- b = dbus_connection_set_watch_functions(c,
- weston_dbus_add_watch,
- weston_dbus_remove_watch,
- weston_dbus_toggle_watch,
- loop,
- NULL);
- if (!b) {
- r = -ENOMEM;
- goto error;
- }
-
- b = dbus_connection_set_timeout_functions(c,
- weston_dbus_add_timeout,
- weston_dbus_remove_timeout,
- weston_dbus_toggle_timeout,
- loop,
- NULL);
- if (!b) {
- r = -ENOMEM;
- goto error;
- }
-
- dbus_connection_ref(c);
- return 0;
-
-error:
- dbus_connection_set_timeout_functions(c, NULL, NULL, NULL,
- NULL, NULL);
- dbus_connection_set_watch_functions(c, NULL, NULL, NULL,
- NULL, NULL);
- wl_event_source_remove(*ctx_out);
- *ctx_out = NULL;
- return r;
-}
-
-static void weston_dbus_unbind(DBusConnection *c, struct wl_event_source *ctx)
-{
- dbus_connection_set_timeout_functions(c, NULL, NULL, NULL,
- NULL, NULL);
- dbus_connection_set_watch_functions(c, NULL, NULL, NULL,
- NULL, NULL);
- dbus_connection_unref(c);
- wl_event_source_remove(ctx);
-}
-
-/*
- * Convenience Helpers
- * Several convenience helpers are provided to make using dbus in weston
- * easier. We don't use any of the gdbus or qdbus helpers as they pull in
- * huge dependencies and actually are quite awful to use. Instead, we only
- * use the basic low-level libdbus library.
- */
-
-int weston_dbus_open(struct wl_event_loop *loop, DBusBusType bus,
- DBusConnection **out, struct wl_event_source **ctx_out)
-{
- DBusConnection *c;
- int r;
-
- /* Ihhh, global state.. stupid dbus. */
- dbus_connection_set_change_sigpipe(FALSE);
-
- /* This is actually synchronous. It blocks for some authentication and
- * setup. We just trust the dbus-server here and accept this blocking
- * call. There is no real reason to complicate things further and make
- * this asynchronous/non-blocking. A context should be created during
- * thead/process/app setup, so blocking calls should be fine. */
- c = dbus_bus_get_private(bus, NULL);
- if (!c)
- return -EIO;
-
- dbus_connection_set_exit_on_disconnect(c, FALSE);
-
- r = weston_dbus_bind(loop, c, ctx_out);
- if (r < 0)
- goto error;
-
- *out = c;
- return r;
-
-error:
- dbus_connection_close(c);
- dbus_connection_unref(c);
- return r;
-}
-
-void weston_dbus_close(DBusConnection *c, struct wl_event_source *ctx)
-{
- weston_dbus_unbind(c, ctx);
- dbus_connection_close(c);
- dbus_connection_unref(c);
-}
-
-int weston_dbus_add_match(DBusConnection *c, const char *format, ...)
-{
- DBusError err;
- int r;
- va_list list;
- char *str;
-
- va_start(list, format);
- r = vasprintf(&str, format, list);
- va_end(list);
-
- if (r < 0)
- return -ENOMEM;
-
- dbus_error_init(&err);
- dbus_bus_add_match(c, str, &err);
- free(str);
- if (dbus_error_is_set(&err)) {
- dbus_error_free(&err);
- return -EIO;
- }
-
- return 0;
-}
-
-int weston_dbus_add_match_signal(DBusConnection *c, const char *sender,
- const char *iface, const char *member,
- const char *path)
-{
- return weston_dbus_add_match(c,
- "type='signal',"
- "sender='%s',"
- "interface='%s',"
- "member='%s',"
- "path='%s'",
- sender, iface, member, path);
-}
-
-void weston_dbus_remove_match(DBusConnection *c, const char *format, ...)
-{
- int r;
- va_list list;
- char *str;
-
- va_start(list, format);
- r = vasprintf(&str, format, list);
- va_end(list);
-
- if (r < 0)
- return;
-
- dbus_bus_remove_match(c, str, NULL);
- free(str);
-}
-
-void weston_dbus_remove_match_signal(DBusConnection *c, const char *sender,
- const char *iface, const char *member,
- const char *path)
-{
- weston_dbus_remove_match(c,
- "type='signal',"
- "sender='%s',"
- "interface='%s',"
- "member='%s',"
- "path='%s'",
- sender, iface, member, path);
-}
diff --git a/libweston/dbus.h b/libweston/dbus.h
deleted file mode 100644
index 639946ce..00000000
--- a/libweston/dbus.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright © 2013 David Herrmann <dh.herrmann@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _WESTON_DBUS_H_
-#define _WESTON_DBUS_H_
-
-#include "config.h"
-
-#include <errno.h>
-#include <wayland-server.h>
-
-#include <libweston/libweston.h>
-
-#ifdef HAVE_DBUS
-
-#include <dbus/dbus.h>
-
-/*
- * weston_dbus_open() - Open new dbus connection
- *
- * Opens a new dbus connection to the bus given as @bus. It automatically
- * integrates the new connection into the main-loop @loop. The connection
- * itself is returned in @out.
- * This also returns a context source used for dbus dispatching. It is
- * returned on success in @ctx_out and must be passed to weston_dbus_close()
- * unchanged. You must not access it from outside of a dbus helper!
- *
- * Returns 0 on success, negative error code on failure.
- */
-int weston_dbus_open(struct wl_event_loop *loop, DBusBusType bus,
- DBusConnection **out, struct wl_event_source **ctx_out);
-
-/*
- * weston_dbus_close() - Close dbus connection
- *
- * Closes a dbus connection that was previously opened via weston_dbus_open().
- * It unbinds the connection from the main-loop it was previously bound to,
- * closes the dbus connection and frees all resources. If you want to access
- * @c after this call returns, you must hold a dbus-reference to it. But
- * notice that the connection is closed after this returns so it cannot be
- * used to spawn new dbus requests.
- * You must pass the context source returns by weston_dbus_open() as @ctx.
- */
-void weston_dbus_close(DBusConnection *c, struct wl_event_source *ctx);
-
-/*
- * weston_dbus_add_match() - Add dbus match
- *
- * Configure a dbus-match on the given dbus-connection. This match is saved
- * on the dbus-server as long as the connection is open. See dbus-manual
- * for information. Compared to the dbus_bus_add_match() this allows a
- * var-arg formatted match-string.
- */
-int weston_dbus_add_match(DBusConnection *c, const char *format, ...);
-
-/*
- * weston_dbus_add_match_signal() - Add dbus signal match
- *
- * Same as weston_dbus_add_match() but does the dbus-match formatting for
- * signals internally.
- */
-int weston_dbus_add_match_signal(DBusConnection *c, const char *sender,
- const char *iface, const char *member,
- const char *path);
-
-/*
- * weston_dbus_remove_match() - Remove dbus match
- *
- * Remove a previously configured dbus-match from the dbus server. There is
- * no need to remove dbus-matches if you close the connection, anyway.
- * Compared to dbus_bus_remove_match() this allows a var-arg formatted
- * match string.
- */
-void weston_dbus_remove_match(DBusConnection *c, const char *format, ...);
-
-/*
- * weston_dbus_remove_match_signal() - Remove dbus signal match
- *
- * Same as weston_dbus_remove_match() but does the dbus-match formatting for
- * signals internally.
- */
-void weston_dbus_remove_match_signal(DBusConnection *c, const char *sender,
- const char *iface, const char *member,
- const char *path);
-
-#endif /* HAVE_DBUS */
-
-#endif // _WESTON_DBUS_H_
diff --git a/libweston/git-version.h.meson b/libweston/git-version.h.meson
deleted file mode 100644
index d91f19c4..00000000
--- a/libweston/git-version.h.meson
+++ /dev/null
@@ -1 +0,0 @@
-#define BUILD_ID "@VCS_TAG@"
diff --git a/libweston/input.c b/libweston/input.c
deleted file mode 100644
index 28dcb0b9..00000000
--- a/libweston/input.c
+++ /dev/null
@@ -1,5086 +0,0 @@
-/*
- * Copyright © 2013 Intel Corporation
- * Copyright 2017-2018 Collabora, Ltd.
- * Copyright 2017-2018 General Electric Company
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <assert.h>
-#include <unistd.h>
-#include <values.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <errno.h>
-
-#include "shared/helpers.h"
-#include "shared/os-compatibility.h"
-#include "shared/timespec-util.h"
-#include <libweston/libweston.h>
-#include "backend.h"
-#include "libweston-internal.h"
-#include "relative-pointer-unstable-v1-server-protocol.h"
-#include "pointer-constraints-unstable-v1-server-protocol.h"
-#include "input-timestamps-unstable-v1-server-protocol.h"
-
-enum pointer_constraint_type {
- POINTER_CONSTRAINT_TYPE_LOCK,
- POINTER_CONSTRAINT_TYPE_CONFINE,
-};
-
-enum motion_direction {
- MOTION_DIRECTION_POSITIVE_X = 1 << 0,
- MOTION_DIRECTION_NEGATIVE_X = 1 << 1,
- MOTION_DIRECTION_POSITIVE_Y = 1 << 2,
- MOTION_DIRECTION_NEGATIVE_Y = 1 << 3,
-};
-
-struct vec2d {
- double x, y;
-};
-
-struct line {
- struct vec2d a;
- struct vec2d b;
-};
-
-struct border {
- struct line line;
- enum motion_direction blocking_dir;
-};
-
-static void
-maybe_warp_confined_pointer(struct weston_pointer_constraint *constraint);
-
-static void
-empty_region(pixman_region32_t *region)
-{
- pixman_region32_fini(region);
- pixman_region32_init(region);
-}
-
-static void
-region_init_infinite(pixman_region32_t *region)
-{
- pixman_region32_init_rect(region, INT32_MIN, INT32_MIN,
- UINT32_MAX, UINT32_MAX);
-}
-
-static void
-send_timestamp(struct wl_resource *resource,
- const struct timespec *time)
-{
- uint32_t tv_sec_hi, tv_sec_lo, tv_nsec;
-
- timespec_to_proto(time, &tv_sec_hi, &tv_sec_lo, &tv_nsec);
- zwp_input_timestamps_v1_send_timestamp(resource, tv_sec_hi, tv_sec_lo,
- tv_nsec);
-}
-
-static void
-send_timestamps_for_input_resource(struct wl_resource *input_resource,
- struct wl_list *list,
- const struct timespec *time)
-{
- struct wl_resource *resource;
-
- wl_resource_for_each(resource, list) {
- if (wl_resource_get_user_data(resource) == input_resource)
- send_timestamp(resource, time);
- }
-}
-
-static void
-remove_input_resource_from_timestamps(struct wl_resource *input_resource,
- struct wl_list *list)
-{
- struct wl_resource *resource;
-
- wl_resource_for_each(resource, list) {
- if (wl_resource_get_user_data(resource) == input_resource)
- wl_resource_set_user_data(resource, NULL);
- }
-}
-
-/** Register a touchscreen input device
- *
- * \param touch The parent weston_touch that identifies the seat.
- * \param syspath Unique device name.
- * \param backend_data Backend private data if necessary.
- * \param ops Calibration operations, or NULL for not able to run calibration.
- * \return New touch device, or NULL on failure.
- */
-WL_EXPORT struct weston_touch_device *
-weston_touch_create_touch_device(struct weston_touch *touch,
- const char *syspath,
- void *backend_data,
- const struct weston_touch_device_ops *ops)
-{
- struct weston_touch_device *device;
-
- assert(syspath);
- if (ops) {
- assert(ops->get_output);
- assert(ops->get_calibration_head_name);
- assert(ops->get_calibration);
- assert(ops->set_calibration);
- }
-
- device = zalloc(sizeof *device);
- if (!device)
- return NULL;
-
- wl_signal_init(&device->destroy_signal);
-
- device->syspath = strdup(syspath);
- if (!device->syspath) {
- free(device);
- return NULL;
- }
-
- device->backend_data = backend_data;
- device->ops = ops;
-
- device->aggregate = touch;
- wl_list_insert(touch->device_list.prev, &device->link);
-
- return device;
-}
-
-/** Destroy the touch device. */
-WL_EXPORT void
-weston_touch_device_destroy(struct weston_touch_device *device)
-{
- wl_list_remove(&device->link);
- wl_signal_emit(&device->destroy_signal, device);
- free(device->syspath);
- free(device);
-}
-
-/** Is it possible to run calibration on this touch device? */
-WL_EXPORT bool
-weston_touch_device_can_calibrate(struct weston_touch_device *device)
-{
- return !!device->ops;
-}
-
-static enum weston_touch_mode
-weston_touch_device_get_mode(struct weston_touch_device *device)
-{
- return device->aggregate->seat->compositor->touch_mode;
-}
-
-static struct weston_pointer_client *
-weston_pointer_client_create(struct wl_client *client)
-{
- struct weston_pointer_client *pointer_client;
-
- pointer_client = zalloc(sizeof *pointer_client);
- if (!pointer_client)
- return NULL;
-
- pointer_client->client = client;
- wl_list_init(&pointer_client->pointer_resources);
- wl_list_init(&pointer_client->relative_pointer_resources);
-
- return pointer_client;
-}
-
-static void
-weston_pointer_client_destroy(struct weston_pointer_client *pointer_client)
-{
- struct wl_resource *resource;
-
- wl_resource_for_each(resource, &pointer_client->pointer_resources) {
- wl_resource_set_user_data(resource, NULL);
- }
-
- wl_resource_for_each(resource,
- &pointer_client->relative_pointer_resources) {
- wl_resource_set_user_data(resource, NULL);
- }
-
- wl_list_remove(&pointer_client->pointer_resources);
- wl_list_remove(&pointer_client->relative_pointer_resources);
- free(pointer_client);
-}
-
-static bool
-weston_pointer_client_is_empty(struct weston_pointer_client *pointer_client)
-{
- return (wl_list_empty(&pointer_client->pointer_resources) &&
- wl_list_empty(&pointer_client->relative_pointer_resources));
-}
-
-static struct weston_pointer_client *
-weston_pointer_get_pointer_client(struct weston_pointer *pointer,
- struct wl_client *client)
-{
- struct weston_pointer_client *pointer_client;
-
- wl_list_for_each(pointer_client, &pointer->pointer_clients, link) {
- if (pointer_client->client == client)
- return pointer_client;
- }
-
- return NULL;
-}
-
-static struct weston_pointer_client *
-weston_pointer_ensure_pointer_client(struct weston_pointer *pointer,
- struct wl_client *client)
-{
- struct weston_pointer_client *pointer_client;
-
- pointer_client = weston_pointer_get_pointer_client(pointer, client);
- if (pointer_client)
- return pointer_client;
-
- pointer_client = weston_pointer_client_create(client);
- wl_list_insert(&pointer->pointer_clients, &pointer_client->link);
-
- if (pointer->focus &&
- pointer->focus->surface->resource &&
- wl_resource_get_client(pointer->focus->surface->resource) == client) {
- pointer->focus_client = pointer_client;
- }
-
- return pointer_client;
-}
-
-static void
-weston_pointer_cleanup_pointer_client(struct weston_pointer *pointer,
- struct weston_pointer_client *pointer_client)
-{
- if (weston_pointer_client_is_empty(pointer_client)) {
- if (pointer->focus_client == pointer_client)
- pointer->focus_client = NULL;
- wl_list_remove(&pointer_client->link);
- weston_pointer_client_destroy(pointer_client);
- }
-}
-
-static void
-unbind_pointer_client_resource(struct wl_resource *resource)
-{
- struct weston_pointer *pointer = wl_resource_get_user_data(resource);
- struct wl_client *client = wl_resource_get_client(resource);
- struct weston_pointer_client *pointer_client;
-
- wl_list_remove(wl_resource_get_link(resource));
-
- if (pointer) {
- pointer_client = weston_pointer_get_pointer_client(pointer,
- client);
- assert(pointer_client);
- remove_input_resource_from_timestamps(resource,
- &pointer->timestamps_list);
- weston_pointer_cleanup_pointer_client(pointer, pointer_client);
- }
-}
-
-static void unbind_resource(struct wl_resource *resource)
-{
- wl_list_remove(wl_resource_get_link(resource));
-}
-
-WL_EXPORT void
-weston_pointer_motion_to_abs(struct weston_pointer *pointer,
- struct weston_pointer_motion_event *event,
- wl_fixed_t *x, wl_fixed_t *y)
-{
- if (event->mask & WESTON_POINTER_MOTION_ABS) {
- *x = wl_fixed_from_double(event->x);
- *y = wl_fixed_from_double(event->y);
- } else if (event->mask & WESTON_POINTER_MOTION_REL) {
- *x = pointer->x + wl_fixed_from_double(event->dx);
- *y = pointer->y + wl_fixed_from_double(event->dy);
- } else {
- assert(!"invalid motion event");
- *x = *y = 0;
- }
-}
-
-static bool
-weston_pointer_motion_to_rel(struct weston_pointer *pointer,
- struct weston_pointer_motion_event *event,
- double *dx, double *dy,
- double *dx_unaccel, double *dy_unaccel)
-{
- if (event->mask & WESTON_POINTER_MOTION_REL &&
- event->mask & WESTON_POINTER_MOTION_REL_UNACCEL) {
- *dx = event->dx;
- *dy = event->dy;
- *dx_unaccel = event->dx_unaccel;
- *dy_unaccel = event->dy_unaccel;
- return true;
- } else if (event->mask & WESTON_POINTER_MOTION_REL) {
- *dx_unaccel = *dx = event->dx;
- *dy_unaccel = *dy = event->dy;
- return true;
- } else if (event->mask & WESTON_POINTER_MOTION_REL_UNACCEL) {
- *dx_unaccel = *dx = event->dx_unaccel;
- *dy_unaccel = *dy = event->dy_unaccel;
- return true;
- } else {
- return false;
- }
-}
-
-WL_EXPORT void
-weston_seat_repick(struct weston_seat *seat)
-{
- const struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
- if (!pointer)
- return;
-
- pointer->grab->interface->focus(pointer->grab);
-}
-
-static void
-weston_compositor_idle_inhibit(struct weston_compositor *compositor)
-{
- weston_compositor_wake(compositor);
- compositor->idle_inhibit++;
-}
-
-static void
-weston_compositor_idle_release(struct weston_compositor *compositor)
-{
- compositor->idle_inhibit--;
- weston_compositor_wake(compositor);
-}
-
-static void
-pointer_focus_view_destroyed(struct wl_listener *listener, void *data)
-{
- struct weston_pointer *pointer =
- container_of(listener, struct weston_pointer,
- focus_view_listener);
-
- weston_pointer_clear_focus(pointer);
-}
-
-static void
-pointer_focus_resource_destroyed(struct wl_listener *listener, void *data)
-{
- struct weston_pointer *pointer =
- container_of(listener, struct weston_pointer,
- focus_resource_listener);
-
- weston_pointer_clear_focus(pointer);
-}
-
-static void
-keyboard_focus_resource_destroyed(struct wl_listener *listener, void *data)
-{
- struct weston_keyboard *keyboard =
- container_of(listener, struct weston_keyboard,
- focus_resource_listener);
-
- weston_keyboard_set_focus(keyboard, NULL);
-}
-
-static void
-touch_focus_view_destroyed(struct wl_listener *listener, void *data)
-{
- struct weston_touch *touch =
- container_of(listener, struct weston_touch,
- focus_view_listener);
-
- weston_touch_set_focus(touch, NULL);
-}
-
-static void
-touch_focus_resource_destroyed(struct wl_listener *listener, void *data)
-{
- struct weston_touch *touch =
- container_of(listener, struct weston_touch,
- focus_resource_listener);
-
- weston_touch_set_focus(touch, NULL);
-}
-
-static void
-move_resources(struct wl_list *destination, struct wl_list *source)
-{
- wl_list_insert_list(destination, source);
- wl_list_init(source);
-}
-
-static void
-move_resources_for_client(struct wl_list *destination,
- struct wl_list *source,
- struct wl_client *client)
-{
- struct wl_resource *resource, *tmp;
- wl_resource_for_each_safe(resource, tmp, source) {
- if (wl_resource_get_client(resource) == client) {
- wl_list_remove(wl_resource_get_link(resource));
- wl_list_insert(destination,
- wl_resource_get_link(resource));
- }
- }
-}
-
-static void
-default_grab_pointer_focus(struct weston_pointer_grab *grab)
-{
- struct weston_pointer *pointer = grab->pointer;
- struct weston_view *view;
- wl_fixed_t sx, sy;
-
- if (pointer->button_count > 0)
- return;
-
- view = weston_compositor_pick_view(pointer->seat->compositor,
- pointer->x, pointer->y,
- &sx, &sy);
-
- if (pointer->focus != view || pointer->sx != sx || pointer->sy != sy)
- weston_pointer_set_focus(pointer, view, sx, sy);
-}
-
-static void
-pointer_send_relative_motion(struct weston_pointer *pointer,
- const struct timespec *time,
- struct weston_pointer_motion_event *event)
-{
- uint64_t time_usec;
- double dx, dy, dx_unaccel, dy_unaccel;
- wl_fixed_t dxf, dyf, dxf_unaccel, dyf_unaccel;
- struct wl_list *resource_list;
- struct wl_resource *resource;
-
- if (!pointer->focus_client)
- return;
-
- if (!weston_pointer_motion_to_rel(pointer, event,
- &dx, &dy,
- &dx_unaccel, &dy_unaccel))
- return;
-
- resource_list = &pointer->focus_client->relative_pointer_resources;
- time_usec = timespec_to_usec(&event->time);
- if (time_usec == 0)
- time_usec = timespec_to_usec(time);
-
- dxf = wl_fixed_from_double(dx);
- dyf = wl_fixed_from_double(dy);
- dxf_unaccel = wl_fixed_from_double(dx_unaccel);
- dyf_unaccel = wl_fixed_from_double(dy_unaccel);
-
- wl_resource_for_each(resource, resource_list) {
- zwp_relative_pointer_v1_send_relative_motion(
- resource,
- (uint32_t) (time_usec >> 32),
- (uint32_t) time_usec,
- dxf, dyf,
- dxf_unaccel, dyf_unaccel);
- }
-}
-
-static void
-pointer_send_motion(struct weston_pointer *pointer,
- const struct timespec *time,
- wl_fixed_t sx, wl_fixed_t sy)
-{
- struct wl_list *resource_list;
- struct wl_resource *resource;
- uint32_t msecs;
-
- if (!pointer->focus_client)
- return;
-
- resource_list = &pointer->focus_client->pointer_resources;
- msecs = timespec_to_msec(time);
- wl_resource_for_each(resource, resource_list) {
- send_timestamps_for_input_resource(resource,
- &pointer->timestamps_list,
- time);
- wl_pointer_send_motion(resource, msecs, sx, sy);
- }
-}
-
-WL_EXPORT void
-weston_pointer_send_motion(struct weston_pointer *pointer,
- const struct timespec *time,
- struct weston_pointer_motion_event *event)
-{
- wl_fixed_t x, y;
- wl_fixed_t old_sx = pointer->sx;
- wl_fixed_t old_sy = pointer->sy;
-
- if (pointer->focus) {
- weston_pointer_motion_to_abs(pointer, event, &x, &y);
- weston_view_from_global_fixed(pointer->focus, x, y,
- &pointer->sx, &pointer->sy);
- }
-
- weston_pointer_move(pointer, event);
-
- if (old_sx != pointer->sx || old_sy != pointer->sy) {
- pointer_send_motion(pointer, time,
- pointer->sx, pointer->sy);
- }
-
- pointer_send_relative_motion(pointer, time, event);
-}
-
-static void
-default_grab_pointer_motion(struct weston_pointer_grab *grab,
- const struct timespec *time,
- struct weston_pointer_motion_event *event)
-{
- weston_pointer_send_motion(grab->pointer, time, event);
-}
-
-/** Check if the pointer has focused resources.
- *
- * \param pointer The pointer to check for focused resources.
- * \return Whether or not this pointer has focused resources
- */
-WL_EXPORT bool
-weston_pointer_has_focus_resource(struct weston_pointer *pointer)
-{
- if (!pointer->focus_client)
- return false;
-
- if (wl_list_empty(&pointer->focus_client->pointer_resources))
- return false;
-
- return true;
-}
-
-/** Send wl_pointer.button events to focused resources.
- *
- * \param pointer The pointer where the button events originates from.
- * \param time The timestamp of the event
- * \param button The button value of the event
- * \param state The state enum value of the event
- *
- * For every resource that is currently in focus, send a wl_pointer.button event
- * with the passed parameters. The focused resources are the wl_pointer
- * resources of the client which currently has the surface with pointer focus.
- */
-WL_EXPORT void
-weston_pointer_send_button(struct weston_pointer *pointer,
- const struct timespec *time, uint32_t button,
- enum wl_pointer_button_state state)
-{
- struct wl_display *display = pointer->seat->compositor->wl_display;
- struct wl_list *resource_list;
- struct wl_resource *resource;
- uint32_t serial;
- uint32_t msecs;
-
- if (!weston_pointer_has_focus_resource(pointer))
- return;
-
- resource_list = &pointer->focus_client->pointer_resources;
- serial = wl_display_next_serial(display);
- msecs = timespec_to_msec(time);
- wl_resource_for_each(resource, resource_list) {
- send_timestamps_for_input_resource(resource,
- &pointer->timestamps_list,
- time);
- wl_pointer_send_button(resource, serial, msecs, button, state);
- }
-}
-
-static void
-default_grab_pointer_button(struct weston_pointer_grab *grab,
- const struct timespec *time, uint32_t button,
- enum wl_pointer_button_state state)
-{
- struct weston_pointer *pointer = grab->pointer;
- struct weston_compositor *compositor = pointer->seat->compositor;
- struct weston_view *view;
- wl_fixed_t sx, sy;
-
- weston_pointer_send_button(pointer, time, button, state);
-
- if (pointer->button_count == 0 &&
- state == WL_POINTER_BUTTON_STATE_RELEASED) {
- view = weston_compositor_pick_view(compositor,
- pointer->x, pointer->y,
- &sx, &sy);
-
- weston_pointer_set_focus(pointer, view, sx, sy);
- }
-}
-
-/** Send wl_pointer.axis events to focused resources.
- *
- * \param pointer The pointer where the axis events originates from.
- * \param time The timestamp of the event
- * \param event The axis value of the event
- *
- * For every resource that is currently in focus, send a wl_pointer.axis event
- * with the passed parameters. The focused resources are the wl_pointer
- * resources of the client which currently has the surface with pointer focus.
- */
-WL_EXPORT void
-weston_pointer_send_axis(struct weston_pointer *pointer,
- const struct timespec *time,
- struct weston_pointer_axis_event *event)
-{
- struct wl_resource *resource;
- struct wl_list *resource_list;
- uint32_t msecs;
-
- if (!weston_pointer_has_focus_resource(pointer))
- return;
-
- resource_list = &pointer->focus_client->pointer_resources;
- msecs = timespec_to_msec(time);
- wl_resource_for_each(resource, resource_list) {
- if (event->has_discrete &&
- wl_resource_get_version(resource) >=
- WL_POINTER_AXIS_DISCRETE_SINCE_VERSION)
- wl_pointer_send_axis_discrete(resource, event->axis,
- event->discrete);
-
- if (event->value) {
- send_timestamps_for_input_resource(resource,
- &pointer->timestamps_list,
- time);
- wl_pointer_send_axis(resource, msecs,
- event->axis,
- wl_fixed_from_double(event->value));
- } else if (wl_resource_get_version(resource) >=
- WL_POINTER_AXIS_STOP_SINCE_VERSION) {
- send_timestamps_for_input_resource(resource,
- &pointer->timestamps_list,
- time);
- wl_pointer_send_axis_stop(resource, msecs,
- event->axis);
- }
- }
-}
-
-/** Send wl_pointer.axis_source events to focused resources.
- *
- * \param pointer The pointer where the axis_source events originates from.
- * \param source The axis_source enum value of the event
- *
- * For every resource that is currently in focus, send a wl_pointer.axis_source
- * event with the passed parameter. The focused resources are the wl_pointer
- * resources of the client which currently has the surface with pointer focus.
- */
-WL_EXPORT void
-weston_pointer_send_axis_source(struct weston_pointer *pointer,
- enum wl_pointer_axis_source source)
-{
- struct wl_resource *resource;
- struct wl_list *resource_list;
-
- if (!weston_pointer_has_focus_resource(pointer))
- return;
-
- resource_list = &pointer->focus_client->pointer_resources;
- wl_resource_for_each(resource, resource_list) {
- if (wl_resource_get_version(resource) >=
- WL_POINTER_AXIS_SOURCE_SINCE_VERSION) {
- wl_pointer_send_axis_source(resource, source);
- }
- }
-}
-
-static void
-pointer_send_frame(struct wl_resource *resource)
-{
- if (wl_resource_get_version(resource) >=
- WL_POINTER_FRAME_SINCE_VERSION) {
- wl_pointer_send_frame(resource);
- }
-}
-
-/** Send wl_pointer.frame events to focused resources.
- *
- * \param pointer The pointer where the frame events originates from.
- *
- * For every resource that is currently in focus, send a wl_pointer.frame event.
- * The focused resources are the wl_pointer resources of the client which
- * currently has the surface with pointer focus.
- */
-WL_EXPORT void
-weston_pointer_send_frame(struct weston_pointer *pointer)
-{
- struct wl_resource *resource;
- struct wl_list *resource_list;
-
- if (!weston_pointer_has_focus_resource(pointer))
- return;
-
- resource_list = &pointer->focus_client->pointer_resources;
- wl_resource_for_each(resource, resource_list)
- pointer_send_frame(resource);
-}
-
-static void
-default_grab_pointer_axis(struct weston_pointer_grab *grab,
- const struct timespec *time,
- struct weston_pointer_axis_event *event)
-{
- weston_pointer_send_axis(grab->pointer, time, event);
-}
-
-static void
-default_grab_pointer_axis_source(struct weston_pointer_grab *grab,
- enum wl_pointer_axis_source source)
-{
- weston_pointer_send_axis_source(grab->pointer, source);
-}
-
-static void
-default_grab_pointer_frame(struct weston_pointer_grab *grab)
-{
- weston_pointer_send_frame(grab->pointer);
-}
-
-static void
-default_grab_pointer_cancel(struct weston_pointer_grab *grab)
-{
-}
-
-static const struct weston_pointer_grab_interface
- default_pointer_grab_interface = {
- default_grab_pointer_focus,
- default_grab_pointer_motion,
- default_grab_pointer_button,
- default_grab_pointer_axis,
- default_grab_pointer_axis_source,
- default_grab_pointer_frame,
- default_grab_pointer_cancel,
-};
-
-/** Check if the touch has focused resources.
- *
- * \param touch The touch to check for focused resources.
- * \return Whether or not this touch has focused resources
- */
-WL_EXPORT bool
-weston_touch_has_focus_resource(struct weston_touch *touch)
-{
- if (!touch->focus)
- return false;
-
- if (wl_list_empty(&touch->focus_resource_list))
- return false;
-
- return true;
-}
-
-/** Send wl_touch.down events to focused resources.
- *
- * \param touch The touch where the down events originates from.
- * \param time The timestamp of the event
- * \param touch_id The touch_id value of the event
- * \param x The x value of the event
- * \param y The y value of the event
- *
- * For every resource that is currently in focus, send a wl_touch.down event
- * with the passed parameters. The focused resources are the wl_touch
- * resources of the client which currently has the surface with touch focus.
- */
-WL_EXPORT void
-weston_touch_send_down(struct weston_touch *touch, const struct timespec *time,
- int touch_id, wl_fixed_t x, wl_fixed_t y)
-{
- struct wl_display *display = touch->seat->compositor->wl_display;
- uint32_t serial;
- struct wl_resource *resource;
- struct wl_list *resource_list;
- wl_fixed_t sx, sy;
- uint32_t msecs;
-
- if (!weston_touch_has_focus_resource(touch))
- return;
-
- weston_view_from_global_fixed(touch->focus, x, y, &sx, &sy);
-
- resource_list = &touch->focus_resource_list;
- serial = wl_display_next_serial(display);
- msecs = timespec_to_msec(time);
- wl_resource_for_each(resource, resource_list) {
- send_timestamps_for_input_resource(resource,
- &touch->timestamps_list,
- time);
- wl_touch_send_down(resource, serial, msecs,
- touch->focus->surface->resource,
- touch_id, sx, sy);
- }
-}
-
-static void
-default_grab_touch_down(struct weston_touch_grab *grab,
- const struct timespec *time, int touch_id,
- wl_fixed_t x, wl_fixed_t y)
-{
- weston_touch_send_down(grab->touch, time, touch_id, x, y);
-}
-
-/** Send wl_touch.up events to focused resources.
- *
- * \param touch The touch where the up events originates from.
- * \param time The timestamp of the event
- * \param touch_id The touch_id value of the event
- *
- * For every resource that is currently in focus, send a wl_touch.up event
- * with the passed parameters. The focused resources are the wl_touch
- * resources of the client which currently has the surface with touch focus.
- */
-WL_EXPORT void
-weston_touch_send_up(struct weston_touch *touch, const struct timespec *time,
- int touch_id)
-{
- struct wl_display *display = touch->seat->compositor->wl_display;
- uint32_t serial;
- struct wl_resource *resource;
- struct wl_list *resource_list;
- uint32_t msecs;
-
- if (!weston_touch_has_focus_resource(touch))
- return;
-
- resource_list = &touch->focus_resource_list;
- serial = wl_display_next_serial(display);
- msecs = timespec_to_msec(time);
- wl_resource_for_each(resource, resource_list) {
- send_timestamps_for_input_resource(resource,
- &touch->timestamps_list,
- time);
- wl_touch_send_up(resource, serial, msecs, touch_id);
- }
-}
-
-static void
-default_grab_touch_up(struct weston_touch_grab *grab,
- const struct timespec *time, int touch_id)
-{
- weston_touch_send_up(grab->touch, time, touch_id);
-}
-
-/** Send wl_touch.motion events to focused resources.
- *
- * \param touch The touch where the motion events originates from.
- * \param time The timestamp of the event
- * \param touch_id The touch_id value of the event
- * \param x The x value of the event
- * \param y The y value of the event
- *
- * For every resource that is currently in focus, send a wl_touch.motion event
- * with the passed parameters. The focused resources are the wl_touch
- * resources of the client which currently has the surface with touch focus.
- */
-WL_EXPORT void
-weston_touch_send_motion(struct weston_touch *touch,
- const struct timespec *time, int touch_id,
- wl_fixed_t x, wl_fixed_t y)
-{
- struct wl_resource *resource;
- struct wl_list *resource_list;
- wl_fixed_t sx, sy;
- uint32_t msecs;
-
- if (!weston_touch_has_focus_resource(touch))
- return;
-
- weston_view_from_global_fixed(touch->focus, x, y, &sx, &sy);
-
- resource_list = &touch->focus_resource_list;
- msecs = timespec_to_msec(time);
- wl_resource_for_each(resource, resource_list) {
- send_timestamps_for_input_resource(resource,
- &touch->timestamps_list,
- time);
- wl_touch_send_motion(resource, msecs,
- touch_id, sx, sy);
- }
-}
-
-static void
-default_grab_touch_motion(struct weston_touch_grab *grab,
- const struct timespec *time, int touch_id,
- wl_fixed_t x, wl_fixed_t y)
-{
- weston_touch_send_motion(grab->touch, time, touch_id, x, y);
-}
-
-
-/** Send wl_touch.frame events to focused resources.
- *
- * \param touch The touch where the frame events originates from.
- *
- * For every resource that is currently in focus, send a wl_touch.frame event.
- * The focused resources are the wl_touch resources of the client which
- * currently has the surface with touch focus.
- */
-WL_EXPORT void
-weston_touch_send_frame(struct weston_touch *touch)
-{
- struct wl_resource *resource;
-
- if (!weston_touch_has_focus_resource(touch))
- return;
-
- wl_resource_for_each(resource, &touch->focus_resource_list)
- wl_touch_send_frame(resource);
-}
-
-static void
-default_grab_touch_frame(struct weston_touch_grab *grab)
-{
- weston_touch_send_frame(grab->touch);
-}
-
-static void
-default_grab_touch_cancel(struct weston_touch_grab *grab)
-{
-}
-
-static const struct weston_touch_grab_interface default_touch_grab_interface = {
- default_grab_touch_down,
- default_grab_touch_up,
- default_grab_touch_motion,
- default_grab_touch_frame,
- default_grab_touch_cancel,
-};
-
-/** Check if the keyboard has focused resources.
- *
- * \param keyboard The keyboard to check for focused resources.
- * \return Whether or not this keyboard has focused resources
- */
-WL_EXPORT bool
-weston_keyboard_has_focus_resource(struct weston_keyboard *keyboard)
-{
- if (!keyboard->focus)
- return false;
-
- if (wl_list_empty(&keyboard->focus_resource_list))
- return false;
-
- return true;
-}
-
-/** Send wl_keyboard.key events to focused resources.
- *
- * \param keyboard The keyboard where the key events originates from.
- * \param time The timestamp of the event
- * \param key The key value of the event
- * \param state The state enum value of the event
- *
- * For every resource that is currently in focus, send a wl_keyboard.key event
- * with the passed parameters. The focused resources are the wl_keyboard
- * resources of the client which currently has the surface with keyboard focus.
- */
-WL_EXPORT void
-weston_keyboard_send_key(struct weston_keyboard *keyboard,
- const struct timespec *time, uint32_t key,
- enum wl_keyboard_key_state state)
-{
- struct wl_resource *resource;
- struct wl_display *display = keyboard->seat->compositor->wl_display;
- uint32_t serial;
- struct wl_list *resource_list;
- uint32_t msecs;
-
- if (!weston_keyboard_has_focus_resource(keyboard))
- return;
-
- resource_list = &keyboard->focus_resource_list;
- serial = wl_display_next_serial(display);
- msecs = timespec_to_msec(time);
- wl_resource_for_each(resource, resource_list) {
- send_timestamps_for_input_resource(resource,
- &keyboard->timestamps_list,
- time);
- wl_keyboard_send_key(resource, serial, msecs, key, state);
- }
-};
-
-static void
-default_grab_keyboard_key(struct weston_keyboard_grab *grab,
- const struct timespec *time, uint32_t key,
- uint32_t state)
-{
- weston_keyboard_send_key(grab->keyboard, time, key, state);
-}
-
-static void
-send_modifiers_to_resource(struct weston_keyboard *keyboard,
- struct wl_resource *resource,
- uint32_t serial)
-{
- wl_keyboard_send_modifiers(resource,
- serial,
- keyboard->modifiers.mods_depressed,
- keyboard->modifiers.mods_latched,
- keyboard->modifiers.mods_locked,
- keyboard->modifiers.group);
-}
-
-static void
-send_modifiers_to_client_in_list(struct wl_client *client,
- struct wl_list *list,
- uint32_t serial,
- struct weston_keyboard *keyboard)
-{
- struct wl_resource *resource;
-
- wl_resource_for_each(resource, list) {
- if (wl_resource_get_client(resource) == client)
- send_modifiers_to_resource(keyboard,
- resource,
- serial);
- }
-}
-
-static struct weston_pointer_client *
-find_pointer_client_for_surface(struct weston_pointer *pointer,
- struct weston_surface *surface)
-{
- struct wl_client *client;
-
- if (!surface)
- return NULL;
-
- if (!surface->resource)
- return NULL;
-
- client = wl_resource_get_client(surface->resource);
- return weston_pointer_get_pointer_client(pointer, client);
-}
-
-static struct weston_pointer_client *
-find_pointer_client_for_view(struct weston_pointer *pointer, struct weston_view *view)
-{
- if (!view)
- return NULL;
-
- return find_pointer_client_for_surface(pointer, view->surface);
-}
-
-static struct wl_resource *
-find_resource_for_surface(struct wl_list *list, struct weston_surface *surface)
-{
- if (!surface)
- return NULL;
-
- if (!surface->resource)
- return NULL;
-
- return wl_resource_find_for_client(list, wl_resource_get_client(surface->resource));
-}
-
-/** Send wl_keyboard.modifiers events to focused resources and pointer
- * focused resources.
- *
- * \param keyboard The keyboard where the modifiers events originates from.
- * \param serial The serial of the event
- * \param mods_depressed The mods_depressed value of the event
- * \param mods_latched The mods_latched value of the event
- * \param mods_locked The mods_locked value of the event
- * \param group The group value of the event
- *
- * For every resource that is currently in focus, send a wl_keyboard.modifiers
- * event with the passed parameters. The focused resources are the wl_keyboard
- * resources of the client which currently has the surface with keyboard focus.
- * This also sends wl_keyboard.modifiers events to the wl_keyboard resources of
- * the client having pointer focus (if different from the keyboard focus client).
- */
-WL_EXPORT void
-weston_keyboard_send_modifiers(struct weston_keyboard *keyboard,
- uint32_t serial, uint32_t mods_depressed,
- uint32_t mods_latched,
- uint32_t mods_locked, uint32_t group)
-{
- struct weston_pointer *pointer =
- weston_seat_get_pointer(keyboard->seat);
-
- if (weston_keyboard_has_focus_resource(keyboard)) {
- struct wl_list *resource_list;
- struct wl_resource *resource;
-
- resource_list = &keyboard->focus_resource_list;
- wl_resource_for_each(resource, resource_list) {
- wl_keyboard_send_modifiers(resource, serial,
- mods_depressed, mods_latched,
- mods_locked, group);
- }
- }
-
- if (pointer && pointer->focus && pointer->focus->surface->resource &&
- pointer->focus->surface != keyboard->focus) {
- struct wl_client *pointer_client =
- wl_resource_get_client(pointer->focus->surface->resource);
-
- send_modifiers_to_client_in_list(pointer_client,
- &keyboard->resource_list,
- serial,
- keyboard);
- }
-}
-
-static void
-default_grab_keyboard_modifiers(struct weston_keyboard_grab *grab,
- uint32_t serial, uint32_t mods_depressed,
- uint32_t mods_latched,
- uint32_t mods_locked, uint32_t group)
-{
- weston_keyboard_send_modifiers(grab->keyboard, serial, mods_depressed,
- mods_latched, mods_locked, group);
-}
-
-static void
-default_grab_keyboard_cancel(struct weston_keyboard_grab *grab)
-{
-}
-
-static const struct weston_keyboard_grab_interface
- default_keyboard_grab_interface = {
- default_grab_keyboard_key,
- default_grab_keyboard_modifiers,
- default_grab_keyboard_cancel,
-};
-
-static void
-pointer_unmap_sprite(struct weston_pointer *pointer)
-{
- struct weston_surface *surface = pointer->sprite->surface;
-
- if (weston_surface_is_mapped(surface))
- weston_surface_unmap(surface);
-
- wl_list_remove(&pointer->sprite_destroy_listener.link);
- surface->committed = NULL;
- surface->committed_private = NULL;
- weston_surface_set_label_func(surface, NULL);
- weston_view_destroy(pointer->sprite);
- pointer->sprite = NULL;
-}
-
-static void
-pointer_handle_sprite_destroy(struct wl_listener *listener, void *data)
-{
- struct weston_pointer *pointer =
- container_of(listener, struct weston_pointer,
- sprite_destroy_listener);
-
- pointer->sprite = NULL;
-}
-
-static void
-weston_pointer_reset_state(struct weston_pointer *pointer)
-{
- pointer->button_count = 0;
-}
-
-static void
-weston_pointer_handle_output_destroy(struct wl_listener *listener, void *data);
-
-static struct weston_pointer *
-weston_pointer_create(struct weston_seat *seat)
-{
- struct weston_pointer *pointer;
-
- pointer = zalloc(sizeof *pointer);
- if (pointer == NULL)
- return NULL;
-
- wl_list_init(&pointer->pointer_clients);
- weston_pointer_set_default_grab(pointer,
- seat->compositor->default_pointer_grab);
- wl_list_init(&pointer->focus_resource_listener.link);
- pointer->focus_resource_listener.notify = pointer_focus_resource_destroyed;
- pointer->default_grab.pointer = pointer;
- pointer->grab = &pointer->default_grab;
- wl_signal_init(&pointer->motion_signal);
- wl_signal_init(&pointer->focus_signal);
- wl_list_init(&pointer->focus_view_listener.link);
- wl_signal_init(&pointer->destroy_signal);
- wl_list_init(&pointer->timestamps_list);
-
- pointer->sprite_destroy_listener.notify = pointer_handle_sprite_destroy;
-
- /* FIXME: Pick better co-ords. */
- pointer->x = wl_fixed_from_int(100);
- pointer->y = wl_fixed_from_int(100);
-
- pointer->output_destroy_listener.notify =
- weston_pointer_handle_output_destroy;
- wl_signal_add(&seat->compositor->output_destroyed_signal,
- &pointer->output_destroy_listener);
-
- pointer->sx = wl_fixed_from_int(-1000000);
- pointer->sy = wl_fixed_from_int(-1000000);
-
- return pointer;
-}
-
-static void
-weston_pointer_destroy(struct weston_pointer *pointer)
-{
- struct weston_pointer_client *pointer_client, *tmp;
-
- wl_signal_emit(&pointer->destroy_signal, pointer);
-
- if (pointer->sprite)
- pointer_unmap_sprite(pointer);
-
- wl_list_for_each_safe(pointer_client, tmp, &pointer->pointer_clients,
- link) {
- wl_list_remove(&pointer_client->link);
- weston_pointer_client_destroy(pointer_client);
- }
-
- wl_list_remove(&pointer->focus_resource_listener.link);
- wl_list_remove(&pointer->focus_view_listener.link);
- wl_list_remove(&pointer->output_destroy_listener.link);
- wl_list_remove(&pointer->timestamps_list);
- free(pointer);
-}
-
-void
-weston_pointer_set_default_grab(struct weston_pointer *pointer,
- const struct weston_pointer_grab_interface *interface)
-{
- if (interface)
- pointer->default_grab.interface = interface;
- else
- pointer->default_grab.interface =
- &default_pointer_grab_interface;
-}
-
-static struct weston_keyboard *
-weston_keyboard_create(void)
-{
- struct weston_keyboard *keyboard;
-
- keyboard = zalloc(sizeof *keyboard);
- if (keyboard == NULL)
- return NULL;
-
- wl_list_init(&keyboard->resource_list);
- wl_list_init(&keyboard->focus_resource_list);
- wl_list_init(&keyboard->focus_resource_listener.link);
- keyboard->focus_resource_listener.notify = keyboard_focus_resource_destroyed;
- wl_array_init(&keyboard->keys);
- keyboard->default_grab.interface = &default_keyboard_grab_interface;
- keyboard->default_grab.keyboard = keyboard;
- keyboard->grab = &keyboard->default_grab;
- wl_signal_init(&keyboard->focus_signal);
- wl_list_init(&keyboard->timestamps_list);
-
- return keyboard;
-}
-
-static void
-weston_xkb_info_destroy(struct weston_xkb_info *xkb_info);
-
-static void
-weston_keyboard_destroy(struct weston_keyboard *keyboard)
-{
- struct wl_resource *resource;
-
- wl_resource_for_each(resource, &keyboard->resource_list) {
- wl_resource_set_user_data(resource, NULL);
- }
-
- wl_resource_for_each(resource, &keyboard->focus_resource_list) {
- wl_resource_set_user_data(resource, NULL);
- }
-
- wl_list_remove(&keyboard->resource_list);
- wl_list_remove(&keyboard->focus_resource_list);
-
- xkb_state_unref(keyboard->xkb_state.state);
- if (keyboard->xkb_info)
- weston_xkb_info_destroy(keyboard->xkb_info);
- xkb_keymap_unref(keyboard->pending_keymap);
-
- wl_array_release(&keyboard->keys);
- wl_list_remove(&keyboard->focus_resource_listener.link);
- wl_list_remove(&keyboard->timestamps_list);
- free(keyboard);
-}
-
-static void
-weston_touch_reset_state(struct weston_touch *touch)
-{
- touch->num_tp = 0;
-}
-
-static struct weston_touch *
-weston_touch_create(void)
-{
- struct weston_touch *touch;
-
- touch = zalloc(sizeof *touch);
- if (touch == NULL)
- return NULL;
-
- wl_list_init(&touch->device_list);
- wl_list_init(&touch->resource_list);
- wl_list_init(&touch->focus_resource_list);
- wl_list_init(&touch->focus_view_listener.link);
- touch->focus_view_listener.notify = touch_focus_view_destroyed;
- wl_list_init(&touch->focus_resource_listener.link);
- touch->focus_resource_listener.notify = touch_focus_resource_destroyed;
- touch->default_grab.interface = &default_touch_grab_interface;
- touch->default_grab.touch = touch;
- touch->grab = &touch->default_grab;
- wl_signal_init(&touch->focus_signal);
- wl_list_init(&touch->timestamps_list);
-
- return touch;
-}
-
-static void
-weston_touch_destroy(struct weston_touch *touch)
-{
- struct wl_resource *resource;
-
- assert(wl_list_empty(&touch->device_list));
-
- wl_resource_for_each(resource, &touch->resource_list) {
- wl_resource_set_user_data(resource, NULL);
- }
-
- wl_resource_for_each(resource, &touch->focus_resource_list) {
- wl_resource_set_user_data(resource, NULL);
- }
-
- wl_list_remove(&touch->resource_list);
- wl_list_remove(&touch->focus_resource_list);
- wl_list_remove(&touch->focus_view_listener.link);
- wl_list_remove(&touch->focus_resource_listener.link);
- wl_list_remove(&touch->timestamps_list);
- free(touch);
-}
-
-static void
-seat_send_updated_caps(struct weston_seat *seat)
-{
- enum wl_seat_capability caps = 0;
- struct wl_resource *resource;
-
- if (seat->pointer_device_count > 0)
- caps |= WL_SEAT_CAPABILITY_POINTER;
- if (seat->keyboard_device_count > 0)
- caps |= WL_SEAT_CAPABILITY_KEYBOARD;
- if (seat->touch_device_count > 0)
- caps |= WL_SEAT_CAPABILITY_TOUCH;
-
- wl_resource_for_each(resource, &seat->base_resource_list) {
- wl_seat_send_capabilities(resource, caps);
- }
- wl_signal_emit(&seat->updated_caps_signal, seat);
-}
-
-
-/** Clear the pointer focus
- *
- * \param pointer the pointer to clear focus for.
- *
- * This can be used to unset pointer focus and set the co-ordinates to the
- * arbitrary values we use for the no focus case.
- *
- * There's no requirement to use this function. For example, passing the
- * results of a weston_compositor_pick_view() directly to
- * weston_pointer_set_focus() will do the right thing when no view is found.
- */
-WL_EXPORT void
-weston_pointer_clear_focus(struct weston_pointer *pointer)
-{
- weston_pointer_set_focus(pointer, NULL,
- wl_fixed_from_int(-1000000),
- wl_fixed_from_int(-1000000));
-}
-
-WL_EXPORT void
-weston_pointer_set_focus(struct weston_pointer *pointer,
- struct weston_view *view,
- wl_fixed_t sx, wl_fixed_t sy)
-{
- struct weston_pointer_client *pointer_client;
- struct weston_keyboard *kbd = weston_seat_get_keyboard(pointer->seat);
- struct wl_resource *resource;
- struct wl_resource *surface_resource;
- struct wl_display *display = pointer->seat->compositor->wl_display;
- uint32_t serial;
- struct wl_list *focus_resource_list;
- int refocus = 0;
-
- if ((!pointer->focus && view) ||
- (pointer->focus && !view) ||
- (pointer->focus && pointer->focus->surface != view->surface) ||
- pointer->sx != sx || pointer->sy != sy)
- refocus = 1;
-
- if (pointer->focus_client && refocus) {
- focus_resource_list = &pointer->focus_client->pointer_resources;
- if (!wl_list_empty(focus_resource_list)) {
- serial = wl_display_next_serial(display);
- surface_resource = pointer->focus->surface->resource;
- wl_resource_for_each(resource, focus_resource_list) {
- wl_pointer_send_leave(resource, serial,
- surface_resource);
- pointer_send_frame(resource);
- }
- }
-
- pointer->focus_client = NULL;
- }
-
- pointer_client = find_pointer_client_for_view(pointer, view);
- if (pointer_client && refocus) {
- struct wl_client *surface_client = pointer_client->client;
-
- serial = wl_display_next_serial(display);
-
- if (kbd && kbd->focus != view->surface)
- send_modifiers_to_client_in_list(surface_client,
- &kbd->resource_list,
- serial,
- kbd);
-
- pointer->focus_client = pointer_client;
-
- focus_resource_list = &pointer->focus_client->pointer_resources;
- wl_resource_for_each(resource, focus_resource_list) {
- wl_pointer_send_enter(resource,
- serial,
- view->surface->resource,
- sx, sy);
- pointer_send_frame(resource);
- }
-
- pointer->focus_serial = serial;
- }
-
- wl_list_remove(&pointer->focus_view_listener.link);
- wl_list_init(&pointer->focus_view_listener.link);
- wl_list_remove(&pointer->focus_resource_listener.link);
- wl_list_init(&pointer->focus_resource_listener.link);
- if (view)
- wl_signal_add(&view->destroy_signal, &pointer->focus_view_listener);
- if (view && view->surface->resource)
- wl_resource_add_destroy_listener(view->surface->resource,
- &pointer->focus_resource_listener);
-
- pointer->focus = view;
- pointer->focus_view_listener.notify = pointer_focus_view_destroyed;
- pointer->sx = sx;
- pointer->sy = sy;
-
- assert(view || sx == wl_fixed_from_int(-1000000));
- assert(view || sy == wl_fixed_from_int(-1000000));
-
- wl_signal_emit(&pointer->focus_signal, pointer);
-}
-
-static void
-send_enter_to_resource_list(struct wl_list *list,
- struct weston_keyboard *keyboard,
- struct weston_surface *surface,
- uint32_t serial)
-{
- struct wl_resource *resource;
-
- wl_resource_for_each(resource, list) {
- send_modifiers_to_resource(keyboard, resource, serial);
- wl_keyboard_send_enter(resource, serial,
- surface->resource,
- &keyboard->keys);
- }
-}
-
-WL_EXPORT void
-weston_keyboard_set_focus(struct weston_keyboard *keyboard,
- struct weston_surface *surface)
-{
- struct weston_seat *seat = keyboard->seat;
- struct wl_resource *resource;
- struct wl_display *display = keyboard->seat->compositor->wl_display;
- uint32_t serial;
- struct wl_list *focus_resource_list;
-
- /* Keyboard focus on a surface without a client is equivalent to NULL
- * focus as nothing would react to the keyboard events anyway.
- * Just set focus to NULL instead - the destroy listener hangs on the
- * wl_resource anyway.
- */
- if (surface && !surface->resource)
- surface = NULL;
-
- focus_resource_list = &keyboard->focus_resource_list;
-
- if (!wl_list_empty(focus_resource_list) && keyboard->focus != surface) {
- serial = wl_display_next_serial(display);
- wl_resource_for_each(resource, focus_resource_list) {
- wl_keyboard_send_leave(resource, serial,
- keyboard->focus->resource);
- }
- move_resources(&keyboard->resource_list, focus_resource_list);
- }
-
- if (find_resource_for_surface(&keyboard->resource_list, surface) &&
- keyboard->focus != surface) {
- struct wl_client *surface_client =
- wl_resource_get_client(surface->resource);
-
- serial = wl_display_next_serial(display);
-
- move_resources_for_client(focus_resource_list,
- &keyboard->resource_list,
- surface_client);
- send_enter_to_resource_list(focus_resource_list,
- keyboard,
- surface,
- serial);
- keyboard->focus_serial = serial;
- }
-
- if (seat->saved_kbd_focus) {
- wl_list_remove(&seat->saved_kbd_focus_listener.link);
- seat->saved_kbd_focus = NULL;
- }
-
- wl_list_remove(&keyboard->focus_resource_listener.link);
- wl_list_init(&keyboard->focus_resource_listener.link);
- if (surface)
- wl_resource_add_destroy_listener(surface->resource,
- &keyboard->focus_resource_listener);
-
- keyboard->focus = surface;
- wl_signal_emit(&keyboard->focus_signal, keyboard);
-}
-
-/* Users of this function must manually manage the keyboard focus */
-WL_EXPORT void
-weston_keyboard_start_grab(struct weston_keyboard *keyboard,
- struct weston_keyboard_grab *grab)
-{
- keyboard->grab = grab;
- grab->keyboard = keyboard;
-}
-
-WL_EXPORT void
-weston_keyboard_end_grab(struct weston_keyboard *keyboard)
-{
- keyboard->grab = &keyboard->default_grab;
-}
-
-static void
-weston_keyboard_cancel_grab(struct weston_keyboard *keyboard)
-{
- keyboard->grab->interface->cancel(keyboard->grab);
-}
-
-WL_EXPORT void
-weston_pointer_start_grab(struct weston_pointer *pointer,
- struct weston_pointer_grab *grab)
-{
- pointer->grab = grab;
- grab->pointer = pointer;
- pointer->grab->interface->focus(pointer->grab);
-}
-
-WL_EXPORT void
-weston_pointer_end_grab(struct weston_pointer *pointer)
-{
- pointer->grab = &pointer->default_grab;
- pointer->grab->interface->focus(pointer->grab);
-}
-
-static void
-weston_pointer_cancel_grab(struct weston_pointer *pointer)
-{
- pointer->grab->interface->cancel(pointer->grab);
-}
-
-WL_EXPORT void
-weston_touch_start_grab(struct weston_touch *touch, struct weston_touch_grab *grab)
-{
- touch->grab = grab;
- grab->touch = touch;
-}
-
-WL_EXPORT void
-weston_touch_end_grab(struct weston_touch *touch)
-{
- touch->grab = &touch->default_grab;
-}
-
-static void
-weston_touch_cancel_grab(struct weston_touch *touch)
-{
- touch->grab->interface->cancel(touch->grab);
-}
-
-static void
-weston_pointer_clamp_for_output(struct weston_pointer *pointer,
- struct weston_output *output,
- wl_fixed_t *fx, wl_fixed_t *fy)
-{
- int x, y;
-
- x = wl_fixed_to_int(*fx);
- y = wl_fixed_to_int(*fy);
-
- if (x < output->x)
- *fx = wl_fixed_from_int(output->x);
- else if (x >= output->x + output->width)
- *fx = wl_fixed_from_int(output->x +
- output->width - 1);
- if (y < output->y)
- *fy = wl_fixed_from_int(output->y);
- else if (y >= output->y + output->height)
- *fy = wl_fixed_from_int(output->y +
- output->height - 1);
-}
-
-WL_EXPORT void
-weston_pointer_clamp(struct weston_pointer *pointer, wl_fixed_t *fx, wl_fixed_t *fy)
-{
- struct weston_compositor *ec = pointer->seat->compositor;
- struct weston_output *output, *prev = NULL;
- int x, y, old_x, old_y, valid = 0;
-
- x = wl_fixed_to_int(*fx);
- y = wl_fixed_to_int(*fy);
- old_x = wl_fixed_to_int(pointer->x);
- old_y = wl_fixed_to_int(pointer->y);
-
- wl_list_for_each(output, &ec->output_list, link) {
- if (pointer->seat->output && pointer->seat->output != output)
- continue;
- if (pixman_region32_contains_point(&output->region,
- x, y, NULL))
- valid = 1;
- if (pixman_region32_contains_point(&output->region,
- old_x, old_y, NULL))
- prev = output;
- }
-
- if (!prev)
- prev = pointer->seat->output;
-
- if (prev && !valid)
- weston_pointer_clamp_for_output(pointer, prev, fx, fy);
-}
-
-static void
-weston_pointer_move_to(struct weston_pointer *pointer,
- wl_fixed_t x, wl_fixed_t y)
-{
- int32_t ix, iy;
-
- weston_pointer_clamp (pointer, &x, &y);
-
- pointer->x = x;
- pointer->y = y;
-
- ix = wl_fixed_to_int(x);
- iy = wl_fixed_to_int(y);
-
- if (pointer->sprite) {
- weston_view_set_position(pointer->sprite,
- ix - pointer->hotspot_x,
- iy - pointer->hotspot_y);
- weston_view_schedule_repaint(pointer->sprite);
- }
-
- pointer->grab->interface->focus(pointer->grab);
- wl_signal_emit(&pointer->motion_signal, pointer);
-}
-
-WL_EXPORT void
-weston_pointer_move(struct weston_pointer *pointer,
- struct weston_pointer_motion_event *event)
-{
- wl_fixed_t x, y;
-
- weston_pointer_motion_to_abs(pointer, event, &x, &y);
- weston_pointer_move_to(pointer, x, y);
-}
-
-/** Verify if the pointer is in a valid position and move it if it isn't.
- */
-static void
-weston_pointer_handle_output_destroy(struct wl_listener *listener, void *data)
-{
- struct weston_pointer *pointer;
- struct weston_compositor *ec;
- struct weston_output *output, *closest = NULL;
- int x, y, distance, min = INT_MAX;
- wl_fixed_t fx, fy;
-
- pointer = container_of(listener, struct weston_pointer,
- output_destroy_listener);
- ec = pointer->seat->compositor;
-
- x = wl_fixed_to_int(pointer->x);
- y = wl_fixed_to_int(pointer->y);
-
- wl_list_for_each(output, &ec->output_list, link) {
- if (pixman_region32_contains_point(&output->region,
- x, y, NULL))
- return;
-
- /* Aproximante the distance from the pointer to the center of
- * the output. */
- distance = abs(output->x + output->width / 2 - x) +
- abs(output->y + output->height / 2 - y);
- if (distance < min) {
- min = distance;
- closest = output;
- }
- }
-
- /* Nothing to do if there's no output left. */
- if (!closest)
- return;
-
- fx = pointer->x;
- fy = pointer->y;
-
- weston_pointer_clamp_for_output(pointer, closest, &fx, &fy);
- weston_pointer_move_to(pointer, fx, fy);
-}
-
-WL_EXPORT void
-notify_motion(struct weston_seat *seat,
- const struct timespec *time,
- struct weston_pointer_motion_event *event)
-{
- struct weston_compositor *ec = seat->compositor;
- struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
- weston_compositor_wake(ec);
- pointer->grab->interface->motion(pointer->grab, time, event);
-}
-
-static void
-run_modifier_bindings(struct weston_seat *seat, uint32_t old, uint32_t new)
-{
- struct weston_compositor *compositor = seat->compositor;
- struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
- uint32_t diff;
- unsigned int i;
- struct {
- uint32_t xkb;
- enum weston_keyboard_modifier weston;
- } mods[] = {
- { keyboard->xkb_info->ctrl_mod, MODIFIER_CTRL },
- { keyboard->xkb_info->alt_mod, MODIFIER_ALT },
- { keyboard->xkb_info->super_mod, MODIFIER_SUPER },
- { keyboard->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,
- keyboard,
- 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,
- keyboard,
- mods[i].weston,
- WL_KEYBOARD_KEY_STATE_RELEASED);
- }
-}
-
-WL_EXPORT void
-notify_motion_absolute(struct weston_seat *seat, const struct timespec *time,
- double x, double y)
-{
- struct weston_compositor *ec = seat->compositor;
- struct weston_pointer *pointer = weston_seat_get_pointer(seat);
- struct weston_pointer_motion_event event = { 0 };
-
- weston_compositor_wake(ec);
-
- event = (struct weston_pointer_motion_event) {
- .mask = WESTON_POINTER_MOTION_ABS,
- .x = x,
- .y = y,
- };
-
- pointer->grab->interface->motion(pointer->grab, time, &event);
-}
-
-static unsigned int
-peek_next_activate_serial(struct weston_compositor *c)
-{
- unsigned serial = c->activate_serial + 1;
-
- return serial == 0 ? 1 : serial;
-}
-
-static void
-inc_activate_serial(struct weston_compositor *c)
-{
- c->activate_serial = peek_next_activate_serial (c);
-}
-
-WL_EXPORT void
-weston_view_activate(struct weston_view *view,
- struct weston_seat *seat,
- uint32_t flags)
-{
- struct weston_compositor *compositor = seat->compositor;
-
- if (flags & WESTON_ACTIVATE_FLAG_CLICKED) {
- view->click_to_activate_serial =
- peek_next_activate_serial(compositor);
- }
-
- weston_seat_set_keyboard_focus(seat, view->surface);
-}
-
-WL_EXPORT void
-notify_button(struct weston_seat *seat, const struct timespec *time,
- int32_t button, enum wl_pointer_button_state state)
-{
- struct weston_compositor *compositor = seat->compositor;
- struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
- if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
- weston_compositor_idle_inhibit(compositor);
- if (pointer->button_count == 0) {
- pointer->grab_button = button;
- pointer->grab_time = *time;
- pointer->grab_x = pointer->x;
- pointer->grab_y = pointer->y;
- }
- pointer->button_count++;
- } else {
- weston_compositor_idle_release(compositor);
- pointer->button_count--;
- }
-
- weston_compositor_run_button_binding(compositor, pointer, time, button,
- state);
-
- pointer->grab->interface->button(pointer->grab, time, button, state);
-
- if (pointer->button_count == 1)
- pointer->grab_serial =
- wl_display_get_serial(compositor->wl_display);
-}
-
-WL_EXPORT void
-notify_axis(struct weston_seat *seat, const struct timespec *time,
- struct weston_pointer_axis_event *event)
-{
- struct weston_compositor *compositor = seat->compositor;
- struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
- weston_compositor_wake(compositor);
-
- if (weston_compositor_run_axis_binding(compositor, pointer,
- time, event))
- return;
-
- pointer->grab->interface->axis(pointer->grab, time, event);
-}
-
-WL_EXPORT void
-notify_axis_source(struct weston_seat *seat, uint32_t source)
-{
- struct weston_compositor *compositor = seat->compositor;
- struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
- weston_compositor_wake(compositor);
-
- pointer->grab->interface->axis_source(pointer->grab, source);
-}
-
-WL_EXPORT void
-notify_pointer_frame(struct weston_seat *seat)
-{
- struct weston_compositor *compositor = seat->compositor;
- struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
- weston_compositor_wake(compositor);
-
- pointer->grab->interface->frame(pointer->grab);
-}
-
-WL_EXPORT int
-weston_keyboard_set_locks(struct weston_keyboard *keyboard,
- uint32_t mask, uint32_t value)
-{
- uint32_t serial;
- xkb_mod_mask_t mods_depressed, mods_latched, mods_locked, group;
- xkb_mod_mask_t num, caps;
-
- /* We don't want the leds to go out of sync with the actual state
- * so if the backend has no way to change the leds don't try to
- * change the state */
- if (!keyboard->seat->led_update)
- return -1;
-
- mods_depressed = xkb_state_serialize_mods(keyboard->xkb_state.state,
- XKB_STATE_DEPRESSED);
- mods_latched = xkb_state_serialize_mods(keyboard->xkb_state.state,
- XKB_STATE_LATCHED);
- mods_locked = xkb_state_serialize_mods(keyboard->xkb_state.state,
- XKB_STATE_LOCKED);
- group = xkb_state_serialize_group(keyboard->xkb_state.state,
- XKB_STATE_EFFECTIVE);
-
- num = (1 << keyboard->xkb_info->mod2_mod);
- caps = (1 << keyboard->xkb_info->caps_mod);
- if (mask & WESTON_NUM_LOCK) {
- if (value & WESTON_NUM_LOCK)
- mods_locked |= num;
- else
- mods_locked &= ~num;
- }
- if (mask & WESTON_CAPS_LOCK) {
- if (value & WESTON_CAPS_LOCK)
- mods_locked |= caps;
- else
- mods_locked &= ~caps;
- }
-
- xkb_state_update_mask(keyboard->xkb_state.state, mods_depressed,
- mods_latched, mods_locked, 0, 0, group);
-
- serial = wl_display_next_serial(
- keyboard->seat->compositor->wl_display);
- notify_modifiers(keyboard->seat, serial);
-
- return 0;
-}
-
-WL_EXPORT void
-notify_modifiers(struct weston_seat *seat, uint32_t serial)
-{
- struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
- struct weston_keyboard_grab *grab = keyboard->grab;
- uint32_t mods_depressed, mods_latched, mods_locked, group;
- uint32_t mods_lookup;
- enum weston_led leds = 0;
- int changed = 0;
-
- /* Serialize and update our internal state, checking to see if it's
- * different to the previous state. */
- mods_depressed = xkb_state_serialize_mods(keyboard->xkb_state.state,
- XKB_STATE_MODS_DEPRESSED);
- mods_latched = xkb_state_serialize_mods(keyboard->xkb_state.state,
- XKB_STATE_MODS_LATCHED);
- mods_locked = xkb_state_serialize_mods(keyboard->xkb_state.state,
- XKB_STATE_MODS_LOCKED);
- group = xkb_state_serialize_layout(keyboard->xkb_state.state,
- XKB_STATE_LAYOUT_EFFECTIVE);
-
- if (mods_depressed != keyboard->modifiers.mods_depressed ||
- mods_latched != keyboard->modifiers.mods_latched ||
- mods_locked != keyboard->modifiers.mods_locked ||
- group != keyboard->modifiers.group)
- changed = 1;
-
- run_modifier_bindings(seat, keyboard->modifiers.mods_depressed,
- mods_depressed);
-
- keyboard->modifiers.mods_depressed = mods_depressed;
- keyboard->modifiers.mods_latched = mods_latched;
- keyboard->modifiers.mods_locked = mods_locked;
- keyboard->modifiers.group = group;
-
- /* And update the modifier_state for bindings. */
- mods_lookup = mods_depressed | mods_latched;
- seat->modifier_state = 0;
- if (mods_lookup & (1 << keyboard->xkb_info->ctrl_mod))
- seat->modifier_state |= MODIFIER_CTRL;
- if (mods_lookup & (1 << keyboard->xkb_info->alt_mod))
- seat->modifier_state |= MODIFIER_ALT;
- if (mods_lookup & (1 << keyboard->xkb_info->super_mod))
- seat->modifier_state |= MODIFIER_SUPER;
- if (mods_lookup & (1 << keyboard->xkb_info->shift_mod))
- seat->modifier_state |= MODIFIER_SHIFT;
-
- /* Finally, notify the compositor that LEDs have changed. */
- if (xkb_state_led_index_is_active(keyboard->xkb_state.state,
- keyboard->xkb_info->num_led))
- leds |= LED_NUM_LOCK;
- if (xkb_state_led_index_is_active(keyboard->xkb_state.state,
- keyboard->xkb_info->caps_led))
- leds |= LED_CAPS_LOCK;
- if (xkb_state_led_index_is_active(keyboard->xkb_state.state,
- keyboard->xkb_info->scroll_led))
- leds |= LED_SCROLL_LOCK;
- if (leds != keyboard->xkb_state.leds && seat->led_update)
- seat->led_update(seat, leds);
- keyboard->xkb_state.leds = leds;
-
- if (changed) {
- grab->interface->modifiers(grab,
- serial,
- keyboard->modifiers.mods_depressed,
- keyboard->modifiers.mods_latched,
- keyboard->modifiers.mods_locked,
- keyboard->modifiers.group);
- }
-}
-
-static void
-update_modifier_state(struct weston_seat *seat, uint32_t serial, uint32_t key,
- enum wl_keyboard_key_state state)
-{
- struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
- enum xkb_key_direction direction;
-
- if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
- direction = XKB_KEY_DOWN;
- else
- direction = XKB_KEY_UP;
-
- /* Offset the keycode by 8, as the evdev XKB rules reflect X's
- * broken keycode system, which starts at 8. */
- xkb_state_update_key(keyboard->xkb_state.state, key + 8, direction);
-
- notify_modifiers(seat, serial);
-}
-
-WL_EXPORT void
-weston_keyboard_send_keymap(struct weston_keyboard *kbd, struct wl_resource *resource)
-{
- struct weston_xkb_info *xkb_info = kbd->xkb_info;
- int fd;
- size_t size;
- enum ro_anonymous_file_mapmode mapmode;
-
- if (wl_resource_get_version(resource) < 7)
- mapmode = RO_ANONYMOUS_FILE_MAPMODE_SHARED;
- else
- mapmode = RO_ANONYMOUS_FILE_MAPMODE_PRIVATE;
-
- fd = os_ro_anonymous_file_get_fd(xkb_info->keymap_rofile, mapmode);
- size = os_ro_anonymous_file_size(xkb_info->keymap_rofile);
-
- if (fd == -1) {
- weston_log("creating a keymap file failed: %s\n",
- strerror(errno));
- return;
- }
-
- wl_keyboard_send_keymap(resource,
- WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
- fd,
- size);
-
- os_ro_anonymous_file_put_fd(fd);
-}
-
-static void
-send_modifiers(struct wl_resource *resource, uint32_t serial, struct weston_keyboard *keyboard)
-{
- wl_keyboard_send_modifiers(resource, serial,
- keyboard->modifiers.mods_depressed,
- keyboard->modifiers.mods_latched,
- keyboard->modifiers.mods_locked,
- keyboard->modifiers.group);
-}
-
-static struct weston_xkb_info *
-weston_xkb_info_create(struct xkb_keymap *keymap);
-
-static void
-update_keymap(struct weston_seat *seat)
-{
- struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
- struct wl_resource *resource;
- struct weston_xkb_info *xkb_info;
- struct xkb_state *state;
- xkb_mod_mask_t latched_mods;
- xkb_mod_mask_t locked_mods;
-
- xkb_info = weston_xkb_info_create(keyboard->pending_keymap);
-
- xkb_keymap_unref(keyboard->pending_keymap);
- keyboard->pending_keymap = NULL;
-
- if (!xkb_info) {
- weston_log("failed to create XKB info\n");
- return;
- }
-
- state = xkb_state_new(xkb_info->keymap);
- if (!state) {
- weston_log("failed to initialise XKB state\n");
- weston_xkb_info_destroy(xkb_info);
- return;
- }
-
- latched_mods = xkb_state_serialize_mods(keyboard->xkb_state.state,
- XKB_STATE_MODS_LATCHED);
- locked_mods = xkb_state_serialize_mods(keyboard->xkb_state.state,
- XKB_STATE_MODS_LOCKED);
- xkb_state_update_mask(state,
- 0, /* depressed */
- latched_mods,
- locked_mods,
- 0, 0, 0);
-
- weston_xkb_info_destroy(keyboard->xkb_info);
- keyboard->xkb_info = xkb_info;
-
- xkb_state_unref(keyboard->xkb_state.state);
- keyboard->xkb_state.state = state;
-
- wl_resource_for_each(resource, &keyboard->resource_list)
- weston_keyboard_send_keymap(keyboard, resource);
- wl_resource_for_each(resource, &keyboard->focus_resource_list)
- weston_keyboard_send_keymap(keyboard, resource);
-
- notify_modifiers(seat, wl_display_next_serial(seat->compositor->wl_display));
-
- if (!latched_mods && !locked_mods)
- return;
-
- wl_resource_for_each(resource, &keyboard->resource_list)
- send_modifiers(resource, wl_display_get_serial(seat->compositor->wl_display), keyboard);
- wl_resource_for_each(resource, &keyboard->focus_resource_list)
- send_modifiers(resource, wl_display_get_serial(seat->compositor->wl_display), keyboard);
-}
-
-WL_EXPORT void
-notify_key(struct weston_seat *seat, const struct timespec *time, uint32_t key,
- enum wl_keyboard_key_state state,
- enum weston_key_state_update update_state)
-{
- struct weston_compositor *compositor = seat->compositor;
- struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
- struct weston_keyboard_grab *grab = keyboard->grab;
- uint32_t *k, *end;
-
- if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
- weston_compositor_idle_inhibit(compositor);
- } else {
- weston_compositor_idle_release(compositor);
- }
-
- end = keyboard->keys.data + keyboard->keys.size;
- for (k = keyboard->keys.data; k < end; k++) {
- if (*k == key) {
- /* Ignore server-generated repeats. */
- if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
- return;
- *k = *--end;
- }
- }
- keyboard->keys.size = (void *) end - keyboard->keys.data;
- if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
- k = wl_array_add(&keyboard->keys, sizeof *k);
- *k = key;
- }
-
- if (grab == &keyboard->default_grab ||
- grab == &keyboard->input_method_grab) {
- weston_compositor_run_key_binding(compositor, keyboard, time,
- key, state);
- grab = keyboard->grab;
- }
-
- grab->interface->key(grab, time, key, state);
-
- if (keyboard->pending_keymap &&
- keyboard->keys.size == 0)
- update_keymap(seat);
-
- if (update_state == STATE_UPDATE_AUTOMATIC) {
- update_modifier_state(seat,
- wl_display_get_serial(compositor->wl_display),
- key,
- state);
- }
-
- keyboard->grab_serial = wl_display_get_serial(compositor->wl_display);
- if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
- keyboard->grab_time = *time;
- keyboard->grab_key = key;
- }
-}
-
-WL_EXPORT void
-notify_pointer_focus(struct weston_seat *seat, struct weston_output *output,
- double x, double y)
-{
- struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
- if (output) {
- weston_pointer_move_to(pointer,
- wl_fixed_from_double(x),
- wl_fixed_from_double(y));
- } else {
- /* FIXME: We should call weston_pointer_set_focus(seat,
- * NULL) here, but somehow that breaks re-entry... */
- }
-}
-
-static void
-destroy_device_saved_kbd_focus(struct wl_listener *listener, void *data)
-{
- struct weston_seat *ws;
-
- ws = container_of(listener, struct weston_seat,
- saved_kbd_focus_listener);
-
- ws->saved_kbd_focus = NULL;
-}
-
-WL_EXPORT void
-notify_keyboard_focus_in(struct weston_seat *seat, struct wl_array *keys,
- enum weston_key_state_update update_state)
-{
- struct weston_compositor *compositor = seat->compositor;
- struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
- struct weston_surface *surface;
- uint32_t *k, serial;
-
- serial = wl_display_next_serial(compositor->wl_display);
- wl_array_copy(&keyboard->keys, keys);
- wl_array_for_each(k, &keyboard->keys) {
- weston_compositor_idle_inhibit(compositor);
- if (update_state == STATE_UPDATE_AUTOMATIC)
- update_modifier_state(seat, serial, *k,
- WL_KEYBOARD_KEY_STATE_PRESSED);
- }
-
- surface = seat->saved_kbd_focus;
- if (surface) {
- weston_keyboard_set_focus(keyboard, surface);
- }
-}
-
-WL_EXPORT void
-notify_keyboard_focus_out(struct weston_seat *seat)
-{
- struct weston_compositor *compositor = seat->compositor;
- struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
- struct weston_pointer *pointer = weston_seat_get_pointer(seat);
- struct weston_surface *focus = keyboard->focus;
- uint32_t *k, serial;
-
- serial = wl_display_next_serial(compositor->wl_display);
- wl_array_for_each(k, &keyboard->keys) {
- weston_compositor_idle_release(compositor);
- update_modifier_state(seat, serial, *k,
- WL_KEYBOARD_KEY_STATE_RELEASED);
- }
-
- seat->modifier_state = 0;
-
- weston_keyboard_set_focus(keyboard, NULL);
- weston_keyboard_cancel_grab(keyboard);
- if (pointer)
- weston_pointer_cancel_grab(pointer);
-
- if (focus) {
- seat->saved_kbd_focus = focus;
- seat->saved_kbd_focus_listener.notify =
- destroy_device_saved_kbd_focus;
- wl_signal_add(&focus->destroy_signal,
- &seat->saved_kbd_focus_listener);
- }
-}
-
-WL_EXPORT void
-weston_touch_set_focus(struct weston_touch *touch, struct weston_view *view)
-{
- struct wl_list *focus_resource_list;
-
- focus_resource_list = &touch->focus_resource_list;
-
- if (view && touch->focus &&
- touch->focus->surface == view->surface) {
- touch->focus = view;
- return;
- }
-
- wl_list_remove(&touch->focus_resource_listener.link);
- wl_list_init(&touch->focus_resource_listener.link);
- wl_list_remove(&touch->focus_view_listener.link);
- wl_list_init(&touch->focus_view_listener.link);
-
- if (!wl_list_empty(focus_resource_list)) {
- move_resources(&touch->resource_list,
- focus_resource_list);
- }
-
- if (view) {
- struct wl_client *surface_client;
-
- if (!view->surface->resource) {
- touch->focus = NULL;
- return;
- }
-
- surface_client = wl_resource_get_client(view->surface->resource);
- move_resources_for_client(focus_resource_list,
- &touch->resource_list,
- surface_client);
- wl_resource_add_destroy_listener(view->surface->resource,
- &touch->focus_resource_listener);
- wl_signal_add(&view->destroy_signal, &touch->focus_view_listener);
- }
- touch->focus = view;
-}
-
-static void
-process_touch_normal(struct weston_touch_device *device,
- const struct timespec *time, int touch_id,
- double double_x, double double_y, int touch_type)
-{
- struct weston_touch *touch = device->aggregate;
- struct weston_touch_grab *grab = device->aggregate->grab;
- struct weston_compositor *ec = device->aggregate->seat->compositor;
- struct weston_view *ev;
- wl_fixed_t sx, sy;
- wl_fixed_t x = wl_fixed_from_double(double_x);
- wl_fixed_t y = wl_fixed_from_double(double_y);
-
- /* Update grab's global coordinates. */
- if (touch_id == touch->grab_touch_id && touch_type != WL_TOUCH_UP) {
- touch->grab_x = x;
- touch->grab_y = y;
- }
-
- switch (touch_type) {
- case WL_TOUCH_DOWN:
- /* the first finger down picks the view, and all further go
- * to that view for the remainder of the touch session i.e.
- * until all touch points are up again. */
- if (touch->num_tp == 1) {
- ev = weston_compositor_pick_view(ec, x, y, &sx, &sy);
- weston_touch_set_focus(touch, ev);
- } else if (!touch->focus) {
- /* Unexpected condition: We have non-initial touch but
- * there is no focused surface.
- */
- weston_log("touch event received with %d points down "
- "but no surface focused\n", touch->num_tp);
- return;
- }
-
- weston_compositor_run_touch_binding(ec, touch,
- time, touch_type);
-
- grab->interface->down(grab, time, touch_id, x, y);
- if (touch->num_tp == 1) {
- touch->grab_serial =
- wl_display_get_serial(ec->wl_display);
- touch->grab_touch_id = touch_id;
- touch->grab_time = *time;
- touch->grab_x = x;
- touch->grab_y = y;
- }
-
- break;
- case WL_TOUCH_MOTION:
- ev = touch->focus;
- if (!ev)
- break;
-
- grab->interface->motion(grab, time, touch_id, x, y);
- break;
- case WL_TOUCH_UP:
- grab->interface->up(grab, time, touch_id);
- if (touch->num_tp == 0)
- weston_touch_set_focus(touch, NULL);
- break;
- }
-}
-
-static enum weston_touch_mode
-get_next_touch_mode(enum weston_touch_mode from)
-{
- switch (from) {
- case WESTON_TOUCH_MODE_PREP_NORMAL:
- return WESTON_TOUCH_MODE_NORMAL;
-
- case WESTON_TOUCH_MODE_PREP_CALIB:
- return WESTON_TOUCH_MODE_CALIB;
-
- case WESTON_TOUCH_MODE_NORMAL:
- case WESTON_TOUCH_MODE_CALIB:
- return from;
- }
-
- return WESTON_TOUCH_MODE_NORMAL;
-}
-
-/** Global touch mode update
- *
- * If no seat has a touch down and the compositor is in a PREP touch mode,
- * set the compositor to the goal touch mode.
- *
- * Calls calibrator if touch mode changed.
- */
-static void
-weston_compositor_update_touch_mode(struct weston_compositor *compositor)
-{
- struct weston_seat *seat;
- struct weston_touch *touch;
- enum weston_touch_mode goal;
-
- wl_list_for_each(seat, &compositor->seat_list, link) {
- touch = weston_seat_get_touch(seat);
- if (!touch)
- continue;
-
- if (touch->num_tp > 0)
- return;
- }
-
- goal = get_next_touch_mode(compositor->touch_mode);
- if (compositor->touch_mode != goal) {
- compositor->touch_mode = goal;
- touch_calibrator_mode_changed(compositor);
- }
-}
-
-/** Start transition to normal touch event handling
- *
- * The touch event mode changes when all touches on all touch devices have
- * been lifted. If no touches are currently down, the transition is immediate.
- *
- * \sa weston_touch_mode
- */
-void
-weston_compositor_set_touch_mode_normal(struct weston_compositor *compositor)
-{
- switch (compositor->touch_mode) {
- case WESTON_TOUCH_MODE_PREP_NORMAL:
- case WESTON_TOUCH_MODE_NORMAL:
- return;
- case WESTON_TOUCH_MODE_PREP_CALIB:
- compositor->touch_mode = WESTON_TOUCH_MODE_NORMAL;
- touch_calibrator_mode_changed(compositor);
- return;
- case WESTON_TOUCH_MODE_CALIB:
- compositor->touch_mode = WESTON_TOUCH_MODE_PREP_NORMAL;
- }
-
- weston_compositor_update_touch_mode(compositor);
-}
-
-/** Start transition to calibrator touch event handling
- *
- * The touch event mode changes when all touches on all touch devices have
- * been lifted. If no touches are currently down, the transition is immediate.
- *
- * \sa weston_touch_mode
- */
-void
-weston_compositor_set_touch_mode_calib(struct weston_compositor *compositor)
-{
- switch (compositor->touch_mode) {
- case WESTON_TOUCH_MODE_PREP_CALIB:
- case WESTON_TOUCH_MODE_CALIB:
- assert(0);
- return;
- case WESTON_TOUCH_MODE_PREP_NORMAL:
- compositor->touch_mode = WESTON_TOUCH_MODE_CALIB;
- touch_calibrator_mode_changed(compositor);
- return;
- case WESTON_TOUCH_MODE_NORMAL:
- compositor->touch_mode = WESTON_TOUCH_MODE_PREP_CALIB;
- }
-
- weston_compositor_update_touch_mode(compositor);
-}
-
-/** Feed in touch down, motion, and up events, calibratable device.
- *
- * It assumes always the correct cycle sequence until it gets here: touch_down
- * → touch_update → ... → touch_update → touch_end. The driver is responsible
- * for sending along such order.
- *
- * \param device The physical device that generated the event.
- * \param time The event timestamp.
- * \param touch_id ID for the touch point of this event (multi-touch).
- * \param x X coordinate in compositor global space.
- * \param y Y coordinate in compositor global space.
- * \param norm Normalized device X, Y coordinates in calibration space, or NULL.
- * \param touch_type Either WL_TOUCH_DOWN, WL_TOUCH_UP, or WL_TOUCH_MOTION.
- *
- * Coordinates double_x and double_y are used for normal operation.
- *
- * Coordinates norm are only used for touch device calibration. If and only if
- * the weston_touch_device does not support calibrating, norm must be NULL.
- *
- * The calibration space is the normalized coordinate space
- * [0.0, 1.0]×[0.0, 1.0] of the weston_touch_device. This is assumed to
- * map to the similar normalized coordinate space of the associated
- * weston_output.
- */
-WL_EXPORT void
-notify_touch_normalized(struct weston_touch_device *device,
- const struct timespec *time,
- int touch_id,
- double x, double y,
- const struct weston_point2d_device_normalized *norm,
- int touch_type)
-{
- struct weston_seat *seat = device->aggregate->seat;
- struct weston_touch *touch = device->aggregate;
-
- if (touch_type != WL_TOUCH_UP) {
- if (weston_touch_device_can_calibrate(device))
- assert(norm != NULL);
- else
- assert(norm == NULL);
- }
-
- /* Update touchpoints count regardless of the current mode. */
- switch (touch_type) {
- case WL_TOUCH_DOWN:
- weston_compositor_idle_inhibit(seat->compositor);
-
- touch->num_tp++;
- break;
- case WL_TOUCH_UP:
- if (touch->num_tp == 0) {
- /* This can happen if we start out with one or
- * more fingers on the touch screen, in which
- * case we didn't get the corresponding down
- * event. */
- weston_log("Unmatched touch up event on seat %s, device %s\n",
- seat->seat_name, device->syspath);
- return;
- }
- weston_compositor_idle_release(seat->compositor);
-
- touch->num_tp--;
- break;
- default:
- break;
- }
-
- /* Properly forward the touch event */
- switch (weston_touch_device_get_mode(device)) {
- case WESTON_TOUCH_MODE_NORMAL:
- case WESTON_TOUCH_MODE_PREP_CALIB:
- process_touch_normal(device, time, touch_id, x, y, touch_type);
- break;
- case WESTON_TOUCH_MODE_CALIB:
- case WESTON_TOUCH_MODE_PREP_NORMAL:
- notify_touch_calibrator(device, time, touch_id,
- norm, touch_type);
- break;
- }
-}
-
-WL_EXPORT void
-notify_touch_frame(struct weston_touch_device *device)
-{
- struct weston_touch_grab *grab;
-
- switch (weston_touch_device_get_mode(device)) {
- case WESTON_TOUCH_MODE_NORMAL:
- case WESTON_TOUCH_MODE_PREP_CALIB:
- grab = device->aggregate->grab;
- grab->interface->frame(grab);
- break;
- case WESTON_TOUCH_MODE_CALIB:
- case WESTON_TOUCH_MODE_PREP_NORMAL:
- notify_touch_calibrator_frame(device);
- break;
- }
-
- weston_compositor_update_touch_mode(device->aggregate->seat->compositor);
-}
-
-WL_EXPORT void
-notify_touch_cancel(struct weston_touch_device *device)
-{
- struct weston_touch_grab *grab;
-
- switch (weston_touch_device_get_mode(device)) {
- case WESTON_TOUCH_MODE_NORMAL:
- case WESTON_TOUCH_MODE_PREP_CALIB:
- grab = device->aggregate->grab;
- grab->interface->cancel(grab);
- break;
- case WESTON_TOUCH_MODE_CALIB:
- case WESTON_TOUCH_MODE_PREP_NORMAL:
- notify_touch_calibrator_cancel(device);
- break;
- }
-
- weston_compositor_update_touch_mode(device->aggregate->seat->compositor);
-}
-
-static int
-pointer_cursor_surface_get_label(struct weston_surface *surface,
- char *buf, size_t len)
-{
- return snprintf(buf, len, "cursor");
-}
-
-static void
-pointer_cursor_surface_committed(struct weston_surface *es,
- int32_t dx, int32_t dy)
-{
- struct weston_pointer *pointer = es->committed_private;
- int x, y;
-
- if (es->width == 0)
- return;
-
- assert(es == pointer->sprite->surface);
-
- pointer->hotspot_x -= dx;
- pointer->hotspot_y -= dy;
-
- x = wl_fixed_to_int(pointer->x) - pointer->hotspot_x;
- y = wl_fixed_to_int(pointer->y) - pointer->hotspot_y;
-
- weston_view_set_position(pointer->sprite, x, y);
-
- empty_region(&es->pending.input);
- empty_region(&es->input);
-
- if (!weston_surface_is_mapped(es)) {
- weston_layer_entry_insert(&es->compositor->cursor_layer.view_list,
- &pointer->sprite->layer_link);
- weston_view_update_transform(pointer->sprite);
- es->is_mapped = true;
- pointer->sprite->is_mapped = true;
- }
-}
-
-static void
-pointer_set_cursor(struct wl_client *client, struct wl_resource *resource,
- uint32_t serial, struct wl_resource *surface_resource,
- int32_t x, int32_t y)
-{
- struct weston_pointer *pointer = wl_resource_get_user_data(resource);
- struct weston_surface *surface = NULL;
-
- if (!pointer)
- return;
-
- if (surface_resource)
- surface = wl_resource_get_user_data(surface_resource);
-
- if (pointer->focus == NULL)
- return;
- /* pointer->focus->surface->resource can be NULL. Surfaces like the
- black_surface used in shell.c for fullscreen don't have
- a resource, but can still have focus */
- if (pointer->focus->surface->resource == NULL)
- return;
- if (wl_resource_get_client(pointer->focus->surface->resource) != client)
- return;
- if (pointer->focus_serial - serial > UINT32_MAX / 2)
- return;
-
- if (!surface) {
- if (pointer->sprite)
- pointer_unmap_sprite(pointer);
- return;
- }
-
- if (pointer->sprite && pointer->sprite->surface == surface &&
- pointer->hotspot_x == x && pointer->hotspot_y == y)
- return;
-
- if (!pointer->sprite || pointer->sprite->surface != surface) {
- if (weston_surface_set_role(surface, "wl_pointer-cursor",
- resource,
- WL_POINTER_ERROR_ROLE) < 0)
- return;
-
- if (pointer->sprite)
- pointer_unmap_sprite(pointer);
-
- wl_signal_add(&surface->destroy_signal,
- &pointer->sprite_destroy_listener);
-
- surface->committed = pointer_cursor_surface_committed;
- surface->committed_private = pointer;
- weston_surface_set_label_func(surface,
- pointer_cursor_surface_get_label);
- pointer->sprite = weston_view_create(surface);
- }
-
- pointer->hotspot_x = x;
- pointer->hotspot_y = y;
-
- if (surface->buffer_ref.buffer) {
- pointer_cursor_surface_committed(surface, 0, 0);
- weston_view_schedule_repaint(pointer->sprite);
- }
-}
-
-static void
-pointer_release(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static const struct wl_pointer_interface pointer_interface = {
- pointer_set_cursor,
- pointer_release
-};
-
-static void
-seat_get_pointer(struct wl_client *client, struct wl_resource *resource,
- uint32_t id)
-{
- struct weston_seat *seat = wl_resource_get_user_data(resource);
- /* We use the pointer_state directly, which means we'll
- * give a wl_pointer if the seat has ever had one - even though
- * the spec explicitly states that this request only takes effect
- * if the seat has the pointer capability.
- *
- * This prevents a race between the compositor sending new
- * capabilities and the client trying to use the old ones.
- */
- struct weston_pointer *pointer = seat ? seat->pointer_state : NULL;
- struct wl_resource *cr;
- struct weston_pointer_client *pointer_client;
-
- cr = wl_resource_create(client, &wl_pointer_interface,
- wl_resource_get_version(resource), id);
- if (cr == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_list_init(wl_resource_get_link(cr));
- wl_resource_set_implementation(cr, &pointer_interface, pointer,
- unbind_pointer_client_resource);
-
- /* If we don't have a pointer_state, the resource is inert, so there
- * is nothing more to set up */
- if (!pointer)
- return;
-
- pointer_client = weston_pointer_ensure_pointer_client(pointer, client);
- if (!pointer_client) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_list_insert(&pointer_client->pointer_resources,
- wl_resource_get_link(cr));
-
- if (pointer->focus && pointer->focus->surface->resource &&
- wl_resource_get_client(pointer->focus->surface->resource) == client) {
- wl_fixed_t sx, sy;
-
- weston_view_from_global_fixed(pointer->focus,
- pointer->x,
- pointer->y,
- &sx, &sy);
-
- wl_pointer_send_enter(cr,
- pointer->focus_serial,
- pointer->focus->surface->resource,
- sx, sy);
- pointer_send_frame(cr);
- }
-}
-
-static void
-destroy_keyboard_resource(struct wl_resource *resource)
-{
- struct weston_keyboard *keyboard = wl_resource_get_user_data(resource);
-
- wl_list_remove(wl_resource_get_link(resource));
-
- if (keyboard) {
- remove_input_resource_from_timestamps(resource,
- &keyboard->timestamps_list);
- }
-}
-
-static void
-keyboard_release(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static const struct wl_keyboard_interface keyboard_interface = {
- keyboard_release
-};
-
-static bool
-should_send_modifiers_to_client(struct weston_seat *seat,
- struct wl_client *client)
-{
- struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
- struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
- if (keyboard &&
- keyboard->focus &&
- keyboard->focus->resource &&
- wl_resource_get_client(keyboard->focus->resource) == client)
- return true;
-
- if (pointer &&
- pointer->focus &&
- pointer->focus->surface->resource &&
- wl_resource_get_client(pointer->focus->surface->resource) == client)
- return true;
-
- return false;
-}
-
-static void
-seat_get_keyboard(struct wl_client *client, struct wl_resource *resource,
- uint32_t id)
-{
- struct weston_seat *seat = wl_resource_get_user_data(resource);
- /* We use the keyboard_state directly, which means we'll
- * give a wl_keyboard if the seat has ever had one - even though
- * the spec explicitly states that this request only takes effect
- * if the seat has the keyboard capability.
- *
- * This prevents a race between the compositor sending new
- * capabilities and the client trying to use the old ones.
- */
- struct weston_keyboard *keyboard = seat ? seat->keyboard_state : NULL;
- struct wl_resource *cr;
-
- cr = wl_resource_create(client, &wl_keyboard_interface,
- wl_resource_get_version(resource), id);
- if (cr == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_list_init(wl_resource_get_link(cr));
- wl_resource_set_implementation(cr, &keyboard_interface,
- keyboard, destroy_keyboard_resource);
-
- /* If we don't have a keyboard_state, the resource is inert, so there
- * is nothing more to set up */
- if (!keyboard)
- return;
-
- /* May be moved to focused list later by either
- * weston_keyboard_set_focus or directly if this client is already
- * focused */
- wl_list_insert(&keyboard->resource_list, wl_resource_get_link(cr));
-
- if (wl_resource_get_version(cr) >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) {
- wl_keyboard_send_repeat_info(cr,
- seat->compositor->kb_repeat_rate,
- seat->compositor->kb_repeat_delay);
- }
-
- weston_keyboard_send_keymap(keyboard, cr);
-
- if (should_send_modifiers_to_client(seat, client)) {
- send_modifiers_to_resource(keyboard,
- cr,
- keyboard->focus_serial);
- }
-
- if (keyboard->focus && keyboard->focus->resource &&
- wl_resource_get_client(keyboard->focus->resource) == client) {
- struct weston_surface *surface =
- (struct weston_surface *)keyboard->focus;
-
- wl_list_remove(wl_resource_get_link(cr));
- wl_list_insert(&keyboard->focus_resource_list,
- wl_resource_get_link(cr));
- wl_keyboard_send_enter(cr,
- keyboard->focus_serial,
- surface->resource,
- &keyboard->keys);
-
- /* If this is the first keyboard resource for this
- * client... */
- if (keyboard->focus_resource_list.prev ==
- wl_resource_get_link(cr))
- wl_data_device_set_keyboard_focus(seat);
- }
-}
-
-static void
-destroy_touch_resource(struct wl_resource *resource)
-{
- struct weston_touch *touch = wl_resource_get_user_data(resource);
-
- wl_list_remove(wl_resource_get_link(resource));
-
- if (touch) {
- remove_input_resource_from_timestamps(resource,
- &touch->timestamps_list);
- }
-}
-
-static void
-touch_release(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static const struct wl_touch_interface touch_interface = {
- touch_release
-};
-
-static void
-seat_get_touch(struct wl_client *client, struct wl_resource *resource,
- uint32_t id)
-{
- struct weston_seat *seat = wl_resource_get_user_data(resource);
- /* We use the touch_state directly, which means we'll
- * give a wl_touch if the seat has ever had one - even though
- * the spec explicitly states that this request only takes effect
- * if the seat has the touch capability.
- *
- * This prevents a race between the compositor sending new
- * capabilities and the client trying to use the old ones.
- */
- struct weston_touch *touch = seat ? seat->touch_state : NULL;
- struct wl_resource *cr;
-
- cr = wl_resource_create(client, &wl_touch_interface,
- wl_resource_get_version(resource), id);
- if (cr == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_list_init(wl_resource_get_link(cr));
- wl_resource_set_implementation(cr, &touch_interface,
- touch, destroy_touch_resource);
-
- /* If we don't have a touch_state, the resource is inert, so there
- * is nothing more to set up */
- if (!touch)
- return;
-
- if (touch->focus &&
- wl_resource_get_client(touch->focus->surface->resource) == client) {
- wl_list_insert(&touch->focus_resource_list,
- wl_resource_get_link(cr));
- } else {
- wl_list_insert(&touch->resource_list,
- wl_resource_get_link(cr));
- }
-}
-
-static void
-seat_release(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static const struct wl_seat_interface seat_interface = {
- seat_get_pointer,
- seat_get_keyboard,
- seat_get_touch,
- seat_release,
-};
-
-static void
-bind_seat(struct wl_client *client, void *data, uint32_t version, uint32_t id)
-{
- struct weston_seat *seat = data;
- struct wl_resource *resource;
- enum wl_seat_capability caps = 0;
-
- resource = wl_resource_create(client,
- &wl_seat_interface, version, id);
- wl_list_insert(&seat->base_resource_list, wl_resource_get_link(resource));
- wl_resource_set_implementation(resource, &seat_interface, data,
- unbind_resource);
-
- if (weston_seat_get_pointer(seat))
- caps |= WL_SEAT_CAPABILITY_POINTER;
- if (weston_seat_get_keyboard(seat))
- caps |= WL_SEAT_CAPABILITY_KEYBOARD;
- if (weston_seat_get_touch(seat))
- caps |= WL_SEAT_CAPABILITY_TOUCH;
-
- wl_seat_send_capabilities(resource, caps);
- if (version >= WL_SEAT_NAME_SINCE_VERSION)
- wl_seat_send_name(resource, seat->seat_name);
-}
-
-static void
-relative_pointer_destroy(struct wl_client *client,
- struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static const struct zwp_relative_pointer_v1_interface relative_pointer_interface = {
- relative_pointer_destroy
-};
-
-static void
-relative_pointer_manager_destroy(struct wl_client *client,
- struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-relative_pointer_manager_get_relative_pointer(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t id,
- struct wl_resource *pointer_resource)
-{
- struct weston_pointer *pointer =
- wl_resource_get_user_data(pointer_resource);
- struct weston_pointer_client *pointer_client;
- struct wl_resource *cr;
-
- cr = wl_resource_create(client, &zwp_relative_pointer_v1_interface,
- wl_resource_get_version(resource), id);
- if (cr == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- pointer_client = weston_pointer_ensure_pointer_client(pointer, client);
- if (!pointer_client) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_list_insert(&pointer_client->relative_pointer_resources,
- wl_resource_get_link(cr));
- wl_resource_set_implementation(cr, &relative_pointer_interface,
- pointer,
- unbind_pointer_client_resource);
-}
-
-static const struct zwp_relative_pointer_manager_v1_interface relative_pointer_manager = {
- relative_pointer_manager_destroy,
- relative_pointer_manager_get_relative_pointer,
-};
-
-static void
-bind_relative_pointer_manager(struct wl_client *client, void *data,
- uint32_t version, uint32_t id)
-{
- struct weston_compositor *compositor = data;
- struct wl_resource *resource;
-
- resource = wl_resource_create(client,
- &zwp_relative_pointer_manager_v1_interface,
- 1, id);
-
- wl_resource_set_implementation(resource, &relative_pointer_manager,
- compositor,
- NULL);
-}
-
-WL_EXPORT int
-weston_compositor_set_xkb_rule_names(struct weston_compositor *ec,
- struct xkb_rule_names *names)
-{
- if (ec->xkb_context == NULL) {
- ec->xkb_context = xkb_context_new(0);
- if (ec->xkb_context == NULL) {
- weston_log("failed to create XKB context\n");
- return -1;
- }
- }
-
- if (names)
- ec->xkb_names = *names;
- if (!ec->xkb_names.rules)
- ec->xkb_names.rules = strdup("evdev");
- if (!ec->xkb_names.model)
- ec->xkb_names.model = strdup("pc105");
- if (!ec->xkb_names.layout)
- ec->xkb_names.layout = strdup("us");
-
- return 0;
-}
-
-static void
-weston_xkb_info_destroy(struct weston_xkb_info *xkb_info)
-{
- if (--xkb_info->ref_count > 0)
- return;
-
- xkb_keymap_unref(xkb_info->keymap);
-
- os_ro_anonymous_file_destroy(xkb_info->keymap_rofile);
- free(xkb_info);
-}
-
-void
-weston_compositor_xkb_destroy(struct weston_compositor *ec)
-{
- free((char *) ec->xkb_names.rules);
- free((char *) ec->xkb_names.model);
- free((char *) ec->xkb_names.layout);
- free((char *) ec->xkb_names.variant);
- free((char *) ec->xkb_names.options);
-
- if (ec->xkb_info)
- weston_xkb_info_destroy(ec->xkb_info);
- xkb_context_unref(ec->xkb_context);
-}
-
-static struct weston_xkb_info *
-weston_xkb_info_create(struct xkb_keymap *keymap)
-{
- char *keymap_string;
- size_t keymap_size;
- struct weston_xkb_info *xkb_info = zalloc(sizeof *xkb_info);
- if (xkb_info == NULL)
- return NULL;
-
- xkb_info->keymap = xkb_keymap_ref(keymap);
- xkb_info->ref_count = 1;
-
- xkb_info->shift_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
- XKB_MOD_NAME_SHIFT);
- xkb_info->caps_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
- XKB_MOD_NAME_CAPS);
- xkb_info->ctrl_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
- XKB_MOD_NAME_CTRL);
- xkb_info->alt_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
- XKB_MOD_NAME_ALT);
- xkb_info->mod2_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
- "Mod2");
- xkb_info->mod3_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
- "Mod3");
- xkb_info->super_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
- XKB_MOD_NAME_LOGO);
- xkb_info->mod5_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
- "Mod5");
-
- xkb_info->num_led = xkb_keymap_led_get_index(xkb_info->keymap,
- XKB_LED_NAME_NUM);
- xkb_info->caps_led = xkb_keymap_led_get_index(xkb_info->keymap,
- XKB_LED_NAME_CAPS);
- xkb_info->scroll_led = xkb_keymap_led_get_index(xkb_info->keymap,
- XKB_LED_NAME_SCROLL);
-
- keymap_string = xkb_keymap_get_as_string(xkb_info->keymap,
- XKB_KEYMAP_FORMAT_TEXT_V1);
- if (keymap_string == NULL) {
- weston_log("failed to get string version of keymap\n");
- goto err_keymap;
- }
- keymap_size = strlen(keymap_string) + 1;
-
- xkb_info->keymap_rofile = os_ro_anonymous_file_create(keymap_size,
- keymap_string);
- free(keymap_string);
-
- if (!xkb_info->keymap_rofile) {
- weston_log("failed to create anonymous file for keymap\n");
- goto err_keymap;
- }
-
- return xkb_info;
-
-err_keymap:
- xkb_keymap_unref(xkb_info->keymap);
- free(xkb_info);
- return NULL;
-}
-
-static int
-weston_compositor_build_global_keymap(struct weston_compositor *ec)
-{
- struct xkb_keymap *keymap;
-
- if (ec->xkb_info != NULL)
- return 0;
-
- keymap = xkb_keymap_new_from_names(ec->xkb_context,
- &ec->xkb_names,
- 0);
- if (keymap == NULL) {
- weston_log("failed to compile global XKB keymap\n");
- weston_log(" tried rules %s, model %s, layout %s, variant %s, "
- "options %s\n",
- ec->xkb_names.rules, ec->xkb_names.model,
- ec->xkb_names.layout, ec->xkb_names.variant,
- ec->xkb_names.options);
- return -1;
- }
-
- ec->xkb_info = weston_xkb_info_create(keymap);
- xkb_keymap_unref(keymap);
- if (ec->xkb_info == NULL)
- return -1;
-
- return 0;
-}
-
-WL_EXPORT void
-weston_seat_update_keymap(struct weston_seat *seat, struct xkb_keymap *keymap)
-{
- struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-
- if (!keyboard || !keymap)
- return;
-
- xkb_keymap_unref(keyboard->pending_keymap);
- keyboard->pending_keymap = xkb_keymap_ref(keymap);
-
- if (keyboard->keys.size == 0)
- update_keymap(seat);
-}
-
-WL_EXPORT int
-weston_seat_init_keyboard(struct weston_seat *seat, struct xkb_keymap *keymap)
-{
- struct weston_keyboard *keyboard;
-
- if (seat->keyboard_state) {
- seat->keyboard_device_count += 1;
- if (seat->keyboard_device_count == 1)
- seat_send_updated_caps(seat);
- return 0;
- }
-
- keyboard = weston_keyboard_create();
- if (keyboard == NULL) {
- weston_log("failed to allocate weston keyboard struct\n");
- return -1;
- }
-
- if (keymap != NULL) {
- keyboard->xkb_info = weston_xkb_info_create(keymap);
- if (keyboard->xkb_info == NULL)
- goto err;
- } else {
- if (weston_compositor_build_global_keymap(seat->compositor) < 0)
- goto err;
- keyboard->xkb_info = seat->compositor->xkb_info;
- keyboard->xkb_info->ref_count++;
- }
-
- keyboard->xkb_state.state = xkb_state_new(keyboard->xkb_info->keymap);
- if (keyboard->xkb_state.state == NULL) {
- weston_log("failed to initialise XKB state\n");
- goto err;
- }
-
- keyboard->xkb_state.leds = 0;
-
- seat->keyboard_state = keyboard;
- seat->keyboard_device_count = 1;
- keyboard->seat = seat;
-
- seat_send_updated_caps(seat);
-
- return 0;
-
-err:
- if (keyboard->xkb_info)
- weston_xkb_info_destroy(keyboard->xkb_info);
- free(keyboard);
-
- return -1;
-}
-
-static void
-weston_keyboard_reset_state(struct weston_keyboard *keyboard)
-{
- struct weston_seat *seat = keyboard->seat;
- struct xkb_state *state;
-
- state = xkb_state_new(keyboard->xkb_info->keymap);
- if (!state) {
- weston_log("failed to reset XKB state\n");
- return;
- }
- xkb_state_unref(keyboard->xkb_state.state);
- keyboard->xkb_state.state = state;
-
- keyboard->xkb_state.leds = 0;
-
- seat->modifier_state = 0;
-}
-
-WL_EXPORT void
-weston_seat_release_keyboard(struct weston_seat *seat)
-{
- seat->keyboard_device_count--;
- assert(seat->keyboard_device_count >= 0);
- if (seat->keyboard_device_count == 0) {
- weston_keyboard_set_focus(seat->keyboard_state, NULL);
- weston_keyboard_cancel_grab(seat->keyboard_state);
- weston_keyboard_reset_state(seat->keyboard_state);
- seat_send_updated_caps(seat);
- }
-}
-
-WL_EXPORT void
-weston_seat_init_pointer(struct weston_seat *seat)
-{
- struct weston_pointer *pointer;
-
- if (seat->pointer_state) {
- seat->pointer_device_count += 1;
- if (seat->pointer_device_count == 1)
- seat_send_updated_caps(seat);
- return;
- }
-
- pointer = weston_pointer_create(seat);
- if (pointer == NULL)
- return;
-
- seat->pointer_state = pointer;
- seat->pointer_device_count = 1;
- pointer->seat = seat;
-
- seat_send_updated_caps(seat);
-}
-
-WL_EXPORT void
-weston_seat_release_pointer(struct weston_seat *seat)
-{
- struct weston_pointer *pointer = seat->pointer_state;
-
- seat->pointer_device_count--;
- if (seat->pointer_device_count == 0) {
- weston_pointer_clear_focus(pointer);
- weston_pointer_cancel_grab(pointer);
-
- if (pointer->sprite)
- pointer_unmap_sprite(pointer);
-
- weston_pointer_reset_state(pointer);
- seat_send_updated_caps(seat);
-
- /* seat->pointer is intentionally not destroyed so that
- * a newly attached pointer on this seat will retain
- * the previous cursor co-ordinates.
- */
- }
-}
-
-WL_EXPORT void
-weston_seat_init_touch(struct weston_seat *seat)
-{
- struct weston_touch *touch;
-
- if (seat->touch_state) {
- seat->touch_device_count += 1;
- if (seat->touch_device_count == 1)
- seat_send_updated_caps(seat);
- return;
- }
-
- touch = weston_touch_create();
- if (touch == NULL)
- return;
-
- seat->touch_state = touch;
- seat->touch_device_count = 1;
- touch->seat = seat;
-
- seat_send_updated_caps(seat);
-}
-
-WL_EXPORT void
-weston_seat_release_touch(struct weston_seat *seat)
-{
- seat->touch_device_count--;
- if (seat->touch_device_count == 0) {
- weston_touch_set_focus(seat->touch_state, NULL);
- weston_touch_cancel_grab(seat->touch_state);
- weston_touch_reset_state(seat->touch_state);
- seat_send_updated_caps(seat);
- }
-}
-
-WL_EXPORT void
-weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec,
- const char *seat_name)
-{
- memset(seat, 0, sizeof *seat);
-
- seat->selection_data_source = NULL;
- wl_list_init(&seat->base_resource_list);
- wl_signal_init(&seat->selection_signal);
- wl_list_init(&seat->drag_resource_list);
- wl_signal_init(&seat->destroy_signal);
- wl_signal_init(&seat->updated_caps_signal);
-
- seat->global = wl_global_create(ec->wl_display, &wl_seat_interface,
- MIN(wl_seat_interface.version, 7),
- seat, bind_seat);
-
- seat->compositor = ec;
- seat->modifier_state = 0;
- seat->seat_name = strdup(seat_name);
-
- wl_list_insert(ec->seat_list.prev, &seat->link);
-
- clipboard_create(seat);
-
- wl_signal_emit(&ec->seat_created_signal, seat);
-}
-
-WL_EXPORT void
-weston_seat_release(struct weston_seat *seat)
-{
- struct wl_resource *resource;
-
- wl_resource_for_each(resource, &seat->base_resource_list) {
- wl_resource_set_user_data(resource, NULL);
- }
-
- wl_resource_for_each(resource, &seat->drag_resource_list) {
- wl_resource_set_user_data(resource, NULL);
- }
-
- wl_list_remove(&seat->base_resource_list);
- wl_list_remove(&seat->drag_resource_list);
-
- wl_list_remove(&seat->link);
-
- if (seat->saved_kbd_focus)
- wl_list_remove(&seat->saved_kbd_focus_listener.link);
-
- if (seat->pointer_state)
- weston_pointer_destroy(seat->pointer_state);
- if (seat->keyboard_state)
- weston_keyboard_destroy(seat->keyboard_state);
- if (seat->touch_state)
- weston_touch_destroy(seat->touch_state);
-
- free (seat->seat_name);
-
- wl_global_destroy(seat->global);
-
- wl_signal_emit(&seat->destroy_signal, seat);
-}
-
-/** Get a seat's keyboard pointer
- *
- * \param seat The seat to query
- * \return The seat's keyboard pointer, or NULL if no keyboard is present
- *
- * The keyboard pointer for a seat isn't freed when all keyboards are removed,
- * so it should only be used when the seat's keyboard_device_count is greater
- * than zero. This function does that test and only returns a pointer
- * when a keyboard is present.
- */
-WL_EXPORT struct weston_keyboard *
-weston_seat_get_keyboard(struct weston_seat *seat)
-{
- if (!seat)
- return NULL;
-
- if (seat->keyboard_device_count)
- return seat->keyboard_state;
-
- return NULL;
-}
-
-/** Get a seat's pointer pointer
- *
- * \param seat The seat to query
- * \return The seat's pointer pointer, or NULL if no pointer device is present
- *
- * The pointer pointer for a seat isn't freed when all mice are removed,
- * so it should only be used when the seat's pointer_device_count is greater
- * than zero. This function does that test and only returns a pointer
- * when a pointing device is present.
- */
-WL_EXPORT struct weston_pointer *
-weston_seat_get_pointer(struct weston_seat *seat)
-{
- if (!seat)
- return NULL;
-
- if (seat->pointer_device_count)
- return seat->pointer_state;
-
- return NULL;
-}
-
-static const struct zwp_locked_pointer_v1_interface locked_pointer_interface;
-static const struct zwp_confined_pointer_v1_interface confined_pointer_interface;
-
-static enum pointer_constraint_type
-pointer_constraint_get_type(struct weston_pointer_constraint *constraint)
-{
- if (wl_resource_instance_of(constraint->resource,
- &zwp_locked_pointer_v1_interface,
- &locked_pointer_interface)) {
- return POINTER_CONSTRAINT_TYPE_LOCK;
- } else if (wl_resource_instance_of(constraint->resource,
- &zwp_confined_pointer_v1_interface,
- &confined_pointer_interface)) {
- return POINTER_CONSTRAINT_TYPE_CONFINE;
- }
-
- abort();
- return 0;
-}
-
-static void
-pointer_constraint_notify_activated(struct weston_pointer_constraint *constraint)
-{
- struct wl_resource *resource = constraint->resource;
-
- switch (pointer_constraint_get_type(constraint)) {
- case POINTER_CONSTRAINT_TYPE_LOCK:
- zwp_locked_pointer_v1_send_locked(resource);
- break;
- case POINTER_CONSTRAINT_TYPE_CONFINE:
- zwp_confined_pointer_v1_send_confined(resource);
- break;
- }
-}
-
-static void
-pointer_constraint_notify_deactivated(struct weston_pointer_constraint *constraint)
-{
- struct wl_resource *resource = constraint->resource;
-
- switch (pointer_constraint_get_type(constraint)) {
- case POINTER_CONSTRAINT_TYPE_LOCK:
- zwp_locked_pointer_v1_send_unlocked(resource);
- break;
- case POINTER_CONSTRAINT_TYPE_CONFINE:
- zwp_confined_pointer_v1_send_unconfined(resource);
- break;
- }
-}
-
-static struct weston_pointer_constraint *
-get_pointer_constraint_for_pointer(struct weston_surface *surface,
- struct weston_pointer *pointer)
-{
- struct weston_pointer_constraint *constraint;
-
- wl_list_for_each(constraint, &surface->pointer_constraints, link) {
- if (constraint->pointer == pointer)
- return constraint;
- }
-
- return NULL;
-}
-
-/** Get a seat's touch pointer
- *
- * \param seat The seat to query
- * \return The seat's touch pointer, or NULL if no touch device is present
- *
- * The touch pointer for a seat isn't freed when all touch devices are removed,
- * so it should only be used when the seat's touch_device_count is greater
- * than zero. This function does that test and only returns a pointer
- * when a touch device is present.
- */
-WL_EXPORT struct weston_touch *
-weston_seat_get_touch(struct weston_seat *seat)
-{
- if (!seat)
- return NULL;
-
- if (seat->touch_device_count)
- return seat->touch_state;
-
- return NULL;
-}
-
-/** Sets the keyboard focus to the given surface
- *
- * \param surface the surface to focus on
- * \param seat The seat to query
- */
-WL_EXPORT void
-weston_seat_set_keyboard_focus(struct weston_seat *seat,
- struct weston_surface *surface)
-{
- struct weston_compositor *compositor = seat->compositor;
- struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
- struct weston_surface_activation_data activation_data;
-
- if (keyboard && keyboard->focus != surface) {
- weston_keyboard_set_focus(keyboard, surface);
- wl_data_device_set_keyboard_focus(seat);
- }
-
- inc_activate_serial(compositor);
-
- activation_data = (struct weston_surface_activation_data) {
- .surface = surface,
- .seat = seat,
- };
- wl_signal_emit(&compositor->activate_signal, &activation_data);
-}
-
-static void
-enable_pointer_constraint(struct weston_pointer_constraint *constraint,
- struct weston_view *view)
-{
- assert(constraint->view == NULL);
- 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);
-}
-
-static bool
-is_pointer_constraint_enabled(struct weston_pointer_constraint *constraint)
-{
- return constraint->view != NULL;
-}
-
-static void
-weston_pointer_constraint_disable(struct weston_pointer_constraint *constraint)
-{
- constraint->view = NULL;
- pointer_constraint_notify_deactivated(constraint);
- weston_pointer_end_grab(constraint->grab.pointer);
-}
-
-void
-weston_pointer_constraint_destroy(struct weston_pointer_constraint *constraint)
-{
- if (is_pointer_constraint_enabled(constraint))
- weston_pointer_constraint_disable(constraint);
-
- wl_list_remove(&constraint->pointer_destroy_listener.link);
- wl_list_remove(&constraint->surface_destroy_listener.link);
- wl_list_remove(&constraint->surface_commit_listener.link);
- wl_list_remove(&constraint->surface_activate_listener.link);
-
- wl_resource_set_user_data(constraint->resource, NULL);
- pixman_region32_fini(&constraint->region);
- wl_list_remove(&constraint->link);
- free(constraint);
-}
-
-static void
-disable_pointer_constraint(struct weston_pointer_constraint *constraint)
-{
- switch (constraint->lifetime) {
- case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT:
- weston_pointer_constraint_destroy(constraint);
- break;
- case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT:
- weston_pointer_constraint_disable(constraint);
- break;
- }
-}
-
-static bool
-is_within_constraint_region(struct weston_pointer_constraint *constraint,
- wl_fixed_t sx, wl_fixed_t sy)
-{
- struct weston_surface *surface = constraint->surface;
- pixman_region32_t constraint_region;
- bool result;
-
- pixman_region32_init(&constraint_region);
- pixman_region32_intersect(&constraint_region,
- &surface->input,
- &constraint->region);
- result = pixman_region32_contains_point(&constraint_region,
- wl_fixed_to_int(sx),
- wl_fixed_to_int(sy),
- NULL);
- pixman_region32_fini(&constraint_region);
-
- return result;
-}
-
-static void
-maybe_enable_pointer_constraint(struct weston_pointer_constraint *constraint)
-{
- struct weston_surface *surface = constraint->surface;
- struct weston_view *vit;
- struct weston_view *view = NULL;
- struct weston_pointer *pointer = constraint->pointer;
- struct weston_keyboard *keyboard;
- struct weston_seat *seat = pointer->seat;
- int32_t x, y;
-
- /* Postpone if no view of the surface was most recently clicked. */
- wl_list_for_each(vit, &surface->views, surface_link) {
- if (vit->click_to_activate_serial ==
- surface->compositor->activate_serial) {
- view = vit;
- }
- }
- if (view == NULL)
- return;
-
- /* Postpone if surface doesn't have keyboard focus. */
- keyboard = weston_seat_get_keyboard(seat);
- if (!keyboard || keyboard->focus != surface)
- return;
-
- /* Postpone constraint if the pointer is not within the
- * constraint region.
- */
- weston_view_from_global(view,
- wl_fixed_to_int(pointer->x),
- wl_fixed_to_int(pointer->y),
- &x, &y);
- if (!is_within_constraint_region(constraint,
- wl_fixed_from_int(x),
- wl_fixed_from_int(y)))
- return;
-
- enable_pointer_constraint(constraint, view);
-}
-
-static void
-locked_pointer_grab_pointer_focus(struct weston_pointer_grab *grab)
-{
-}
-
-static void
-locked_pointer_grab_pointer_motion(struct weston_pointer_grab *grab,
- const struct timespec *time,
- struct weston_pointer_motion_event *event)
-{
- pointer_send_relative_motion(grab->pointer, time, event);
-}
-
-static void
-locked_pointer_grab_pointer_button(struct weston_pointer_grab *grab,
- const struct timespec *time,
- uint32_t button,
- uint32_t state_w)
-{
- weston_pointer_send_button(grab->pointer, time, button, state_w);
-}
-
-static void
-locked_pointer_grab_pointer_axis(struct weston_pointer_grab *grab,
- const struct timespec *time,
- struct weston_pointer_axis_event *event)
-{
- weston_pointer_send_axis(grab->pointer, time, event);
-}
-
-static void
-locked_pointer_grab_pointer_axis_source(struct weston_pointer_grab *grab,
- uint32_t source)
-{
- weston_pointer_send_axis_source(grab->pointer, source);
-}
-
-static void
-locked_pointer_grab_pointer_frame(struct weston_pointer_grab *grab)
-{
- weston_pointer_send_frame(grab->pointer);
-}
-
-static void
-locked_pointer_grab_pointer_cancel(struct weston_pointer_grab *grab)
-{
- struct weston_pointer_constraint *constraint =
- container_of(grab, struct weston_pointer_constraint, grab);
-
- disable_pointer_constraint(constraint);
-}
-
-static const struct weston_pointer_grab_interface
- locked_pointer_grab_interface = {
- locked_pointer_grab_pointer_focus,
- locked_pointer_grab_pointer_motion,
- locked_pointer_grab_pointer_button,
- locked_pointer_grab_pointer_axis,
- locked_pointer_grab_pointer_axis_source,
- locked_pointer_grab_pointer_frame,
- locked_pointer_grab_pointer_cancel,
-};
-
-static void
-pointer_constraint_constrain_resource_destroyed(struct wl_resource *resource)
-{
- struct weston_pointer_constraint *constraint =
- wl_resource_get_user_data(resource);
-
- if (!constraint)
- return;
-
- weston_pointer_constraint_destroy(constraint);
-}
-
-static void
-pointer_constraint_surface_activate(struct wl_listener *listener, void *data)
-{
- struct weston_surface_activation_data *activation = data;
- struct weston_pointer *pointer;
- struct weston_surface *focus = activation->surface;
- struct weston_pointer_constraint *constraint =
- container_of(listener, struct weston_pointer_constraint,
- surface_activate_listener);
- bool is_constraint_surface;
-
- pointer = weston_seat_get_pointer(activation->seat);
- if (!pointer)
- return;
-
- is_constraint_surface =
- get_pointer_constraint_for_pointer(focus, pointer) == constraint;
-
- if (is_constraint_surface &&
- !is_pointer_constraint_enabled(constraint))
- maybe_enable_pointer_constraint(constraint);
- else if (!is_constraint_surface &&
- is_pointer_constraint_enabled(constraint))
- disable_pointer_constraint(constraint);
-}
-
-static void
-pointer_constraint_pointer_destroyed(struct wl_listener *listener, void *data)
-{
- struct weston_pointer_constraint *constraint =
- container_of(listener, struct weston_pointer_constraint,
- pointer_destroy_listener);
-
- weston_pointer_constraint_destroy(constraint);
-}
-
-static void
-pointer_constraint_surface_destroyed(struct wl_listener *listener, void *data)
-{
- struct weston_pointer_constraint *constraint =
- container_of(listener, struct weston_pointer_constraint,
- surface_destroy_listener);
-
- weston_pointer_constraint_destroy(constraint);
-}
-
-static void
-pointer_constraint_surface_committed(struct wl_listener *listener, void *data)
-{
- struct weston_pointer_constraint *constraint =
- container_of(listener, struct weston_pointer_constraint,
- surface_commit_listener);
-
- if (constraint->region_is_pending) {
- constraint->region_is_pending = false;
- pixman_region32_copy(&constraint->region,
- &constraint->region_pending);
- pixman_region32_fini(&constraint->region_pending);
- pixman_region32_init(&constraint->region_pending);
- }
-
- if (constraint->hint_is_pending) {
- constraint->hint_is_pending = false;
-
- constraint->hint_is_pending = true;
- constraint->hint_x = constraint->hint_x_pending;
- constraint->hint_y = constraint->hint_y_pending;
- }
-
- if (pointer_constraint_get_type(constraint) ==
- POINTER_CONSTRAINT_TYPE_CONFINE &&
- is_pointer_constraint_enabled(constraint))
- maybe_warp_confined_pointer(constraint);
-}
-
-static struct weston_pointer_constraint *
-weston_pointer_constraint_create(struct weston_surface *surface,
- struct weston_pointer *pointer,
- struct weston_region *region,
- enum zwp_pointer_constraints_v1_lifetime lifetime,
- struct wl_resource *cr,
- const struct weston_pointer_grab_interface *grab_interface)
-{
- struct weston_pointer_constraint *constraint;
-
- constraint = zalloc(sizeof *constraint);
- if (!constraint)
- return NULL;
-
- constraint->lifetime = lifetime;
- pixman_region32_init(&constraint->region);
- pixman_region32_init(&constraint->region_pending);
- wl_list_insert(&surface->pointer_constraints, &constraint->link);
- constraint->surface = surface;
- constraint->pointer = pointer;
- constraint->resource = cr;
- constraint->grab.interface = grab_interface;
- if (region) {
- pixman_region32_copy(&constraint->region,
- &region->region);
- } else {
- pixman_region32_fini(&constraint->region);
- region_init_infinite(&constraint->region);
- }
-
- constraint->surface_activate_listener.notify =
- pointer_constraint_surface_activate;
- constraint->surface_destroy_listener.notify =
- pointer_constraint_surface_destroyed;
- constraint->surface_commit_listener.notify =
- pointer_constraint_surface_committed;
- constraint->pointer_destroy_listener.notify =
- pointer_constraint_pointer_destroyed;
-
- wl_signal_add(&surface->compositor->activate_signal,
- &constraint->surface_activate_listener);
- wl_signal_add(&pointer->destroy_signal,
- &constraint->pointer_destroy_listener);
- wl_signal_add(&surface->destroy_signal,
- &constraint->surface_destroy_listener);
- wl_signal_add(&surface->commit_signal,
- &constraint->surface_commit_listener);
-
- return constraint;
-}
-
-static void
-init_pointer_constraint(struct wl_resource *pointer_constraints_resource,
- uint32_t id,
- struct weston_surface *surface,
- struct weston_pointer *pointer,
- struct weston_region *region,
- enum zwp_pointer_constraints_v1_lifetime lifetime,
- const struct wl_interface *interface,
- const void *implementation,
- const struct weston_pointer_grab_interface *grab_interface)
-{
- struct wl_client *client =
- wl_resource_get_client(pointer_constraints_resource);
- struct wl_resource *cr;
- struct weston_pointer_constraint *constraint;
-
- if (pointer && get_pointer_constraint_for_pointer(surface, pointer)) {
- wl_resource_post_error(pointer_constraints_resource,
- ZWP_POINTER_CONSTRAINTS_V1_ERROR_ALREADY_CONSTRAINED,
- "the pointer has a lock/confine request on this surface");
- return;
- }
-
- cr = wl_resource_create(client, interface,
- wl_resource_get_version(pointer_constraints_resource),
- id);
- if (cr == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- if (pointer) {
- constraint = weston_pointer_constraint_create(surface, pointer,
- region, lifetime,
- cr, grab_interface);
- if (constraint == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
- } else {
- constraint = NULL;
- }
-
- wl_resource_set_implementation(cr, implementation, constraint,
- pointer_constraint_constrain_resource_destroyed);
-
- if (constraint)
- maybe_enable_pointer_constraint(constraint);
-}
-
-static void
-pointer_constraints_destroy(struct wl_client *client,
- struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-locked_pointer_destroy(struct wl_client *client,
- struct wl_resource *resource)
-{
- struct weston_pointer_constraint *constraint =
- wl_resource_get_user_data(resource);
- wl_fixed_t x, y;
-
- if (constraint && constraint->view && constraint->hint_is_pending &&
- is_within_constraint_region(constraint,
- constraint->hint_x,
- constraint->hint_y)) {
- weston_view_to_global_fixed(constraint->view,
- constraint->hint_x,
- constraint->hint_y,
- &x, &y);
- weston_pointer_move_to(constraint->pointer, x, y);
- }
- wl_resource_destroy(resource);
-}
-
-static void
-locked_pointer_set_cursor_position_hint(struct wl_client *client,
- struct wl_resource *resource,
- wl_fixed_t surface_x,
- wl_fixed_t surface_y)
-{
- struct weston_pointer_constraint *constraint =
- wl_resource_get_user_data(resource);
-
- /* Ignore a set cursor hint that was sent after the lock was cancelled.
- */
- if (!constraint ||
- !constraint->resource ||
- constraint->resource != resource)
- return;
-
- constraint->hint_is_pending = true;
- constraint->hint_x_pending = surface_x;
- constraint->hint_y_pending = surface_y;
-}
-
-static void
-locked_pointer_set_region(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *region_resource)
-{
- struct weston_pointer_constraint *constraint =
- wl_resource_get_user_data(resource);
- struct weston_region *region = region_resource ?
- wl_resource_get_user_data(region_resource) : NULL;
-
- if (!constraint)
- return;
-
- if (region) {
- pixman_region32_copy(&constraint->region_pending,
- &region->region);
- } else {
- pixman_region32_fini(&constraint->region_pending);
- region_init_infinite(&constraint->region_pending);
- }
- constraint->region_is_pending = true;
-}
-
-
-static const struct zwp_locked_pointer_v1_interface locked_pointer_interface = {
- locked_pointer_destroy,
- locked_pointer_set_cursor_position_hint,
- locked_pointer_set_region,
-};
-
-static void
-pointer_constraints_lock_pointer(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t id,
- struct wl_resource *surface_resource,
- struct wl_resource *pointer_resource,
- struct wl_resource *region_resource,
- uint32_t lifetime)
-{
- struct weston_surface *surface =
- wl_resource_get_user_data(surface_resource);
- struct weston_pointer *pointer = wl_resource_get_user_data(pointer_resource);
- struct weston_region *region = region_resource ?
- wl_resource_get_user_data(region_resource) : NULL;
-
- init_pointer_constraint(resource, id, surface, pointer, region, lifetime,
- &zwp_locked_pointer_v1_interface,
- &locked_pointer_interface,
- &locked_pointer_grab_interface);
-}
-
-static void
-confined_pointer_grab_pointer_focus(struct weston_pointer_grab *grab)
-{
-}
-
-static double
-vec2d_cross_product(struct vec2d a, struct vec2d b)
-{
- return a.x * b.y - a.y * b.x;
-}
-
-static struct vec2d
-vec2d_add(struct vec2d a, struct vec2d b)
-{
- return (struct vec2d) {
- .x = a.x + b.x,
- .y = a.y + b.y,
- };
-}
-
-static struct vec2d
-vec2d_subtract(struct vec2d a, struct vec2d b)
-{
- return (struct vec2d) {
- .x = a.x - b.x,
- .y = a.y - b.y,
- };
-}
-
-static struct vec2d
-vec2d_multiply_constant(double c, struct vec2d a)
-{
- return (struct vec2d) {
- .x = c * a.x,
- .y = c * a.y,
- };
-}
-
-static bool
-lines_intersect(struct line *line1, struct line *line2,
- struct vec2d *intersection)
-{
- struct vec2d p = line1->a;
- struct vec2d r = vec2d_subtract(line1->b, line1->a);
- struct vec2d q = line2->a;
- struct vec2d s = vec2d_subtract(line2->b, line2->a);
- double rxs;
- double sxr;
- double t;
- double u;
-
- /*
- * The line (p, r) and (q, s) intersects where
- *
- * p + t r = q + u s
- *
- * Calculate t:
- *
- * (p + t r) × s = (q + u s) × s
- * p × s + t (r × s) = q × s + u (s × s)
- * p × s + t (r × s) = q × s
- * t (r × s) = q × s - p × s
- * t (r × s) = (q - p) × s
- * t = ((q - p) × s) / (r × s)
- *
- * Using the same method, for u we get:
- *
- * u = ((p - q) × r) / (s × r)
- */
-
- rxs = vec2d_cross_product(r, s);
- sxr = vec2d_cross_product(s, r);
-
- /* If r × s = 0 then the lines are either parallel or collinear. */
- if (fabs(rxs) < DBL_MIN)
- return false;
-
- t = vec2d_cross_product(vec2d_subtract(q, p), s) / rxs;
- u = vec2d_cross_product(vec2d_subtract(p, q), r) / sxr;
-
- /* The lines only intersect if 0 ≤ t ≤ 1 and 0 ≤ u ≤ 1. */
- if (t < 0.0 || t > 1.0 || u < 0.0 || u > 1.0)
- return false;
-
- *intersection = vec2d_add(p, vec2d_multiply_constant(t, r));
- return true;
-}
-
-static struct border *
-add_border(struct wl_array *array,
- double x1, double y1,
- double x2, double y2,
- enum motion_direction blocking_dir)
-{
- struct border *border = wl_array_add(array, sizeof *border);
-
- *border = (struct border) {
- .line = (struct line) {
- .a = (struct vec2d) {
- .x = x1,
- .y = y1,
- },
- .b = (struct vec2d) {
- .x = x2,
- .y = y2,
- },
- },
- .blocking_dir = blocking_dir,
- };
-
- return border;
-}
-
-static int
-compare_lines_x(const void *a, const void *b)
-{
- const struct border *border_a = a;
- const struct border *border_b = b;
-
-
- if (border_a->line.a.x == border_b->line.a.x)
- return border_a->line.b.x < border_b->line.b.x;
- else
- return border_a->line.a.x > border_b->line.a.x;
-}
-
-static void
-add_non_overlapping_edges(pixman_box32_t *boxes,
- int band_above_start,
- int band_below_start,
- int band_below_end,
- struct wl_array *borders)
-{
- int i;
- struct wl_array band_merge;
- struct border *border;
- struct border *prev_border;
- struct border *new_border;
-
- wl_array_init(&band_merge);
-
- /* Add bottom band of previous row, and top band of current row, and
- * sort them so lower left x coordinate comes first. If there are two
- * borders with the same left x coordinate, the wider one comes first.
- */
- for (i = band_above_start; i < band_below_start; i++) {
- pixman_box32_t *box = &boxes[i];
- add_border(&band_merge, box->x1, box->y2, box->x2, box->y2,
- MOTION_DIRECTION_POSITIVE_Y);
- }
- for (i = band_below_start; i < band_below_end; i++) {
- pixman_box32_t *box= &boxes[i];
- add_border(&band_merge, box->x1, box->y1, box->x2, box->y1,
- MOTION_DIRECTION_NEGATIVE_Y);
- }
- qsort(band_merge.data,
- band_merge.size / sizeof *border,
- sizeof *border,
- compare_lines_x);
-
- /* Combine the two combined bands so that any overlapping border is
- * eliminated. */
- prev_border = NULL;
- wl_array_for_each(border, &band_merge) {
- assert(border->line.a.y == border->line.b.y);
- assert(!prev_border ||
- prev_border->line.a.y == border->line.a.y);
- assert(!prev_border ||
- (prev_border->line.a.x != border->line.a.x ||
- prev_border->line.b.x != border->line.b.x));
- assert(!prev_border ||
- prev_border->line.a.x <= border->line.a.x);
-
- if (prev_border &&
- prev_border->line.a.x == border->line.a.x) {
- /*
- * ------------ +
- * ------- =
- * [ ]-----
- */
- prev_border->line.a.x = border->line.b.x;
- } else if (prev_border &&
- prev_border->line.b.x == border->line.b.x) {
- /*
- * ------------ +
- * ------ =
- * ------[ ]
- */
- prev_border->line.b.x = border->line.a.x;
- } else if (prev_border &&
- prev_border->line.b.x == border->line.a.x) {
- /*
- * -------- +
- * ------ =
- * --------------
- */
- prev_border->line.b.x = border->line.b.x;
- } else if (prev_border &&
- prev_border->line.b.x >= border->line.a.x) {
- /*
- * --------------- +
- * ------ =
- * -----[ ]----
- */
- new_border = add_border(borders,
- border->line.b.x,
- border->line.b.y,
- prev_border->line.b.x,
- prev_border->line.b.y,
- prev_border->blocking_dir);
- prev_border->line.b.x = border->line.a.x;
- prev_border = new_border;
- } else {
- assert(!prev_border ||
- prev_border->line.b.x < border->line.a.x);
- /*
- * First border or non-overlapping.
- *
- * ----- +
- * ----- =
- * ----- -----
- */
- new_border = wl_array_add(borders, sizeof *border);
- *new_border = *border;
- prev_border = new_border;
- }
- }
-
- wl_array_release(&band_merge);
-}
-
-static void
-add_band_bottom_edges(pixman_box32_t *boxes,
- int band_start,
- int band_end,
- struct wl_array *borders)
-{
- int i;
-
- for (i = band_start; i < band_end; i++) {
- add_border(borders,
- boxes[i].x1, boxes[i].y2,
- boxes[i].x2, boxes[i].y2,
- MOTION_DIRECTION_POSITIVE_Y);
- }
-}
-
-static void
-region_to_outline(pixman_region32_t *region, struct wl_array *borders)
-{
- pixman_box32_t *boxes;
- int num_boxes;
- int i;
- int top_most, bottom_most;
- int current_roof;
- int prev_top;
- int band_start, prev_band_start;
-
- /*
- * Remove any overlapping lines from the set of rectangles. Note that
- * pixman regions are grouped as rows of rectangles, where rectangles
- * in one row never touch or overlap and are all of the same height.
- *
- * -------- --- -------- ---
- * | | | | | | | |
- * ----------====---- --- ----------- ----- ---
- * | | => | |
- * ----==========--------- ----- ----------
- * | | | |
- * ------------------- -------------------
- *
- */
-
- boxes = pixman_region32_rectangles(region, &num_boxes);
- prev_top = 0;
- top_most = boxes[0].y1;
- current_roof = top_most;
- bottom_most = boxes[num_boxes - 1].y2;
- band_start = 0;
- prev_band_start = 0;
- for (i = 0; i < num_boxes; i++) {
- /* Detect if there is a vertical empty space, and add the lower
- * level of the previous band if so was the case. */
- if (i > 0 &&
- boxes[i].y1 != prev_top &&
- boxes[i].y1 != boxes[i - 1].y2) {
- current_roof = boxes[i].y1;
- add_band_bottom_edges(boxes,
- band_start,
- i,
- borders);
- }
-
- /* Special case adding the last band, since it won't be handled
- * by the band change detection below. */
- if (boxes[i].y1 != current_roof && i == num_boxes - 1) {
- if (boxes[i].y1 != prev_top) {
- /* The last band is a single box, so we don't
- * have a prev_band_start to tell us when the
- * previous band started. */
- add_non_overlapping_edges(boxes,
- band_start,
- i,
- i + 1,
- borders);
- } else {
- add_non_overlapping_edges(boxes,
- prev_band_start,
- band_start,
- i + 1,
- borders);
- }
- }
-
- /* Detect when passing a band and combine the top border of the
- * just passed band with the bottom band of the previous band.
- */
- if (boxes[i].y1 != top_most && boxes[i].y1 != prev_top) {
- /* Combine the two passed bands. */
- if (prev_top != current_roof) {
- add_non_overlapping_edges(boxes,
- prev_band_start,
- band_start,
- i,
- borders);
- }
-
- prev_band_start = band_start;
- band_start = i;
- }
-
- /* Add the top border if the box is part of the current roof. */
- if (boxes[i].y1 == current_roof) {
- add_border(borders,
- boxes[i].x1, boxes[i].y1,
- boxes[i].x2, boxes[i].y1,
- MOTION_DIRECTION_NEGATIVE_Y);
- }
-
- /* Add the bottom border of the last band. */
- if (boxes[i].y2 == bottom_most) {
- add_border(borders,
- boxes[i].x1, boxes[i].y2,
- boxes[i].x2, boxes[i].y2,
- MOTION_DIRECTION_POSITIVE_Y);
- }
-
- /* Always add the left border. */
- add_border(borders,
- boxes[i].x1, boxes[i].y1,
- boxes[i].x1, boxes[i].y2,
- MOTION_DIRECTION_NEGATIVE_X);
-
- /* Always add the right border. */
- add_border(borders,
- boxes[i].x2, boxes[i].y1,
- boxes[i].x2, boxes[i].y2,
- MOTION_DIRECTION_POSITIVE_X);
-
- prev_top = boxes[i].y1;
- }
-}
-
-static bool
-is_border_horizontal (struct border *border)
-{
- return border->line.a.y == border->line.b.y;
-}
-
-static bool
-is_border_blocking_directions(struct border *border,
- uint32_t directions)
-{
- /* Don't block parallel motions. */
- if (is_border_horizontal(border)) {
- if ((directions & (MOTION_DIRECTION_POSITIVE_Y |
- MOTION_DIRECTION_NEGATIVE_Y)) == 0)
- return false;
- } else {
- if ((directions & (MOTION_DIRECTION_POSITIVE_X |
- MOTION_DIRECTION_NEGATIVE_X)) == 0)
- return false;
- }
-
- return (~border->blocking_dir & directions) != directions;
-}
-
-static struct border *
-get_closest_border(struct wl_array *borders,
- struct line *motion,
- uint32_t directions)
-{
- struct border *border;
- struct vec2d intersection;
- struct vec2d delta;
- double distance_2;
- struct border *closest_border = NULL;
- double closest_distance_2 = DBL_MAX;
-
- wl_array_for_each(border, borders) {
- if (!is_border_blocking_directions(border, directions))
- continue;
-
- if (!lines_intersect(&border->line, motion, &intersection))
- continue;
-
- delta = vec2d_subtract(intersection, motion->a);
- distance_2 = delta.x*delta.x + delta.y*delta.y;
- if (distance_2 < closest_distance_2) {
- closest_border = border;
- closest_distance_2 = distance_2;
- }
- }
-
- return closest_border;
-}
-
-static void
-clamp_to_border(struct border *border,
- struct line *motion,
- uint32_t *motion_dir)
-{
- /*
- * When clamping either rightward or downward motions, the motion needs
- * to be clamped so that the destination coordinate does not end up on
- * the border (see weston_pointer_clamp_event_to_region). Do this by
- * clamping such motions to the border minus the smallest possible
- * wl_fixed_t value.
- */
- if (is_border_horizontal(border)) {
- if (*motion_dir & MOTION_DIRECTION_POSITIVE_Y)
- motion->b.y = border->line.a.y - wl_fixed_to_double(1);
- else
- motion->b.y = border->line.a.y;
- *motion_dir &= ~(MOTION_DIRECTION_POSITIVE_Y |
- MOTION_DIRECTION_NEGATIVE_Y);
- } else {
- if (*motion_dir & MOTION_DIRECTION_POSITIVE_X)
- motion->b.x = border->line.a.x - wl_fixed_to_double(1);
- else
- motion->b.x = border->line.a.x;
- *motion_dir &= ~(MOTION_DIRECTION_POSITIVE_X |
- MOTION_DIRECTION_NEGATIVE_X);
- }
-}
-
-static uint32_t
-get_motion_directions(struct line *motion)
-{
- uint32_t directions = 0;
-
- if (motion->a.x < motion->b.x)
- directions |= MOTION_DIRECTION_POSITIVE_X;
- else if (motion->a.x > motion->b.x)
- directions |= MOTION_DIRECTION_NEGATIVE_X;
- if (motion->a.y < motion->b.y)
- directions |= MOTION_DIRECTION_POSITIVE_Y;
- else if (motion->a.y > motion->b.y)
- directions |= MOTION_DIRECTION_NEGATIVE_Y;
-
- return directions;
-}
-
-static void
-weston_pointer_clamp_event_to_region(struct weston_pointer *pointer,
- struct weston_pointer_motion_event *event,
- pixman_region32_t *region,
- wl_fixed_t *clamped_x,
- wl_fixed_t *clamped_y)
-{
- wl_fixed_t x, y;
- wl_fixed_t sx, sy;
- wl_fixed_t old_sx = pointer->sx;
- wl_fixed_t old_sy = pointer->sy;
- struct wl_array borders;
- struct line motion;
- struct border *closest_border;
- float new_x_f, new_y_f;
- uint32_t directions;
-
- weston_pointer_motion_to_abs(pointer, event, &x, &y);
- weston_view_from_global_fixed(pointer->focus, x, y, &sx, &sy);
-
- wl_array_init(&borders);
-
- /*
- * Generate borders given the confine region we are to use. The borders
- * are defined to be the outer region of the allowed area. This means
- * top/left borders are "within" the allowed area, while bottom/right
- * borders are outside. This needs to be considered when clamping
- * confined motion vectors.
- */
- region_to_outline(region, &borders);
-
- motion = (struct line) {
- .a = (struct vec2d) {
- .x = wl_fixed_to_double(old_sx),
- .y = wl_fixed_to_double(old_sy),
- },
- .b = (struct vec2d) {
- .x = wl_fixed_to_double(sx),
- .y = wl_fixed_to_double(sy),
- },
- };
- directions = get_motion_directions(&motion);
-
- while (directions) {
- closest_border = get_closest_border(&borders,
- &motion,
- directions);
- if (closest_border)
- clamp_to_border(closest_border, &motion, &directions);
- else
- break;
- }
-
- weston_view_to_global_float(pointer->focus,
- (float) motion.b.x, (float) motion.b.y,
- &new_x_f, &new_y_f);
- *clamped_x = wl_fixed_from_double(new_x_f);
- *clamped_y = wl_fixed_from_double(new_y_f);
-
- wl_array_release(&borders);
-}
-
-static double
-point_to_border_distance_2(struct border *border, double x, double y)
-{
- double orig_x, orig_y;
- double dx, dy;
-
- if (is_border_horizontal(border)) {
- if (x < border->line.a.x)
- orig_x = border->line.a.x;
- else if (x > border->line.b.x)
- orig_x = border->line.b.x;
- else
- orig_x = x;
- orig_y = border->line.a.y;
- } else {
- if (y < border->line.a.y)
- orig_y = border->line.a.y;
- else if (y > border->line.b.y)
- orig_y = border->line.b.y;
- else
- orig_y = y;
- orig_x = border->line.a.x;
- }
-
-
- dx = fabs(orig_x - x);
- dy = fabs(orig_y - y);
- return dx*dx + dy*dy;
-}
-
-static void
-warp_to_behind_border(struct border *border, wl_fixed_t *sx, wl_fixed_t *sy)
-{
- switch (border->blocking_dir) {
- case MOTION_DIRECTION_POSITIVE_X:
- case MOTION_DIRECTION_NEGATIVE_X:
- if (border->blocking_dir == MOTION_DIRECTION_POSITIVE_X)
- *sx = wl_fixed_from_double(border->line.a.x) - 1;
- else
- *sx = wl_fixed_from_double(border->line.a.x) + 1;
- if (*sy < wl_fixed_from_double(border->line.a.y))
- *sy = wl_fixed_from_double(border->line.a.y) + 1;
- else if (*sy > wl_fixed_from_double(border->line.b.y))
- *sy = wl_fixed_from_double(border->line.b.y) - 1;
- break;
- case MOTION_DIRECTION_POSITIVE_Y:
- case MOTION_DIRECTION_NEGATIVE_Y:
- if (border->blocking_dir == MOTION_DIRECTION_POSITIVE_Y)
- *sy = wl_fixed_from_double(border->line.a.y) - 1;
- else
- *sy = wl_fixed_from_double(border->line.a.y) + 1;
- if (*sx < wl_fixed_from_double(border->line.a.x))
- *sx = wl_fixed_from_double(border->line.a.x) + 1;
- else if (*sx > wl_fixed_from_double(border->line.b.x))
- *sx = wl_fixed_from_double(border->line.b.x) - 1;
- break;
- }
-}
-
-static void
-maybe_warp_confined_pointer(struct weston_pointer_constraint *constraint)
-{
- wl_fixed_t x;
- wl_fixed_t y;
- wl_fixed_t sx;
- wl_fixed_t sy;
-
- weston_view_from_global_fixed(constraint->view,
- constraint->pointer->x,
- constraint->pointer->y,
- &sx,
- &sy);
-
- if (!is_within_constraint_region(constraint, sx, sy)) {
- double xf = wl_fixed_to_double(sx);
- double yf = wl_fixed_to_double(sy);
- pixman_region32_t confine_region;
- struct wl_array borders;
- struct border *border;
- double closest_distance_2 = DBL_MAX;
- struct border *closest_border = NULL;
-
- wl_array_init(&borders);
-
- pixman_region32_init(&confine_region);
- pixman_region32_intersect(&confine_region,
- &constraint->view->surface->input,
- &constraint->region);
- region_to_outline(&confine_region, &borders);
- pixman_region32_fini(&confine_region);
-
- wl_array_for_each(border, &borders) {
- double distance_2;
-
- distance_2 = point_to_border_distance_2(border, xf, yf);
- if (distance_2 < closest_distance_2) {
- closest_border = border;
- closest_distance_2 = distance_2;
- }
- }
- assert(closest_border);
-
- warp_to_behind_border(closest_border, &sx, &sy);
-
- wl_array_release(&borders);
-
- weston_view_to_global_fixed(constraint->view, sx, sy, &x, &y);
- weston_pointer_move_to(constraint->pointer, x, y);
- }
-}
-
-static void
-confined_pointer_grab_pointer_motion(struct weston_pointer_grab *grab,
- const struct timespec *time,
- struct weston_pointer_motion_event *event)
-{
- struct weston_pointer_constraint *constraint =
- container_of(grab, struct weston_pointer_constraint, grab);
- struct weston_pointer *pointer = grab->pointer;
- struct weston_surface *surface;
- wl_fixed_t x, y;
- wl_fixed_t old_sx = pointer->sx;
- wl_fixed_t old_sy = pointer->sy;
- pixman_region32_t confine_region;
-
- assert(pointer->focus);
- assert(pointer->focus->surface == constraint->surface);
-
- surface = pointer->focus->surface;
-
- pixman_region32_init(&confine_region);
- pixman_region32_intersect(&confine_region,
- &surface->input,
- &constraint->region);
- weston_pointer_clamp_event_to_region(pointer, event,
- &confine_region, &x, &y);
- weston_pointer_move_to(pointer, x, y);
- pixman_region32_fini(&confine_region);
-
- weston_view_from_global_fixed(pointer->focus, x, y,
- &pointer->sx, &pointer->sy);
-
- if (old_sx != pointer->sx || old_sy != pointer->sy) {
- pointer_send_motion(pointer, time,
- pointer->sx, pointer->sy);
- }
-
- pointer_send_relative_motion(pointer, time, event);
-}
-
-static void
-confined_pointer_grab_pointer_button(struct weston_pointer_grab *grab,
- const struct timespec *time,
- uint32_t button,
- uint32_t state_w)
-{
- weston_pointer_send_button(grab->pointer, time, button, state_w);
-}
-
-static void
-confined_pointer_grab_pointer_axis(struct weston_pointer_grab *grab,
- const struct timespec *time,
- struct weston_pointer_axis_event *event)
-{
- weston_pointer_send_axis(grab->pointer, time, event);
-}
-
-static void
-confined_pointer_grab_pointer_axis_source(struct weston_pointer_grab *grab,
- uint32_t source)
-{
- weston_pointer_send_axis_source(grab->pointer, source);
-}
-
-static void
-confined_pointer_grab_pointer_frame(struct weston_pointer_grab *grab)
-{
- weston_pointer_send_frame(grab->pointer);
-}
-
-static void
-confined_pointer_grab_pointer_cancel(struct weston_pointer_grab *grab)
-{
- struct weston_pointer_constraint *constraint =
- container_of(grab, struct weston_pointer_constraint, grab);
-
- disable_pointer_constraint(constraint);
-}
-
-static const struct weston_pointer_grab_interface
- confined_pointer_grab_interface = {
- confined_pointer_grab_pointer_focus,
- confined_pointer_grab_pointer_motion,
- confined_pointer_grab_pointer_button,
- confined_pointer_grab_pointer_axis,
- confined_pointer_grab_pointer_axis_source,
- confined_pointer_grab_pointer_frame,
- confined_pointer_grab_pointer_cancel,
-};
-
-static void
-confined_pointer_destroy(struct wl_client *client,
- struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-confined_pointer_set_region(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *region_resource)
-{
- struct weston_pointer_constraint *constraint =
- wl_resource_get_user_data(resource);
- struct weston_region *region = region_resource ?
- wl_resource_get_user_data(region_resource) : NULL;
-
- if (!constraint)
- return;
-
- if (region) {
- pixman_region32_copy(&constraint->region_pending,
- &region->region);
- } else {
- pixman_region32_fini(&constraint->region_pending);
- region_init_infinite(&constraint->region_pending);
- }
- constraint->region_is_pending = true;
-}
-
-static const struct zwp_confined_pointer_v1_interface confined_pointer_interface = {
- confined_pointer_destroy,
- confined_pointer_set_region,
-};
-
-static void
-pointer_constraints_confine_pointer(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t id,
- struct wl_resource *surface_resource,
- struct wl_resource *pointer_resource,
- struct wl_resource *region_resource,
- uint32_t lifetime)
-{
- struct weston_surface *surface =
- wl_resource_get_user_data(surface_resource);
- struct weston_pointer *pointer = wl_resource_get_user_data(pointer_resource);
- struct weston_region *region = region_resource ?
- wl_resource_get_user_data(region_resource) : NULL;
-
- init_pointer_constraint(resource, id, surface, pointer, region, lifetime,
- &zwp_confined_pointer_v1_interface,
- &confined_pointer_interface,
- &confined_pointer_grab_interface);
-}
-
-static const struct zwp_pointer_constraints_v1_interface pointer_constraints_interface = {
- pointer_constraints_destroy,
- pointer_constraints_lock_pointer,
- pointer_constraints_confine_pointer,
-};
-
-static void
-bind_pointer_constraints(struct wl_client *client, void *data,
- uint32_t version, uint32_t id)
-{
- struct wl_resource *resource;
-
- resource = wl_resource_create(client,
- &zwp_pointer_constraints_v1_interface,
- 1, id);
-
- wl_resource_set_implementation(resource, &pointer_constraints_interface,
- NULL, NULL);
-}
-
-static void
-input_timestamps_destroy(struct wl_client *client,
- struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static const struct zwp_input_timestamps_v1_interface
- input_timestamps_interface = {
- input_timestamps_destroy,
-};
-
-static void
-input_timestamps_manager_destroy(struct wl_client *client,
- struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-input_timestamps_manager_get_keyboard_timestamps(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t id,
- struct wl_resource *keyboard_resource)
-{
- struct weston_keyboard *keyboard =
- wl_resource_get_user_data(keyboard_resource);
- struct wl_resource *input_ts;
-
- input_ts = wl_resource_create(client,
- &zwp_input_timestamps_v1_interface,
- 1, id);
- if (!input_ts) {
- wl_client_post_no_memory(client);
- return;
- }
-
- if (keyboard) {
- wl_list_insert(&keyboard->timestamps_list,
- wl_resource_get_link(input_ts));
- } else {
- wl_list_init(wl_resource_get_link(input_ts));
- }
-
- wl_resource_set_implementation(input_ts,
- &input_timestamps_interface,
- keyboard_resource,
- unbind_resource);
-}
-
-static void
-input_timestamps_manager_get_pointer_timestamps(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t id,
- struct wl_resource *pointer_resource)
-{
- struct weston_pointer *pointer =
- wl_resource_get_user_data(pointer_resource);
- struct wl_resource *input_ts;
-
- input_ts = wl_resource_create(client,
- &zwp_input_timestamps_v1_interface,
- 1, id);
- if (!input_ts) {
- wl_client_post_no_memory(client);
- return;
- }
-
- if (pointer) {
- wl_list_insert(&pointer->timestamps_list,
- wl_resource_get_link(input_ts));
- } else {
- wl_list_init(wl_resource_get_link(input_ts));
- }
-
- wl_resource_set_implementation(input_ts,
- &input_timestamps_interface,
- pointer_resource,
- unbind_resource);
-}
-
-static void
-input_timestamps_manager_get_touch_timestamps(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t id,
- struct wl_resource *touch_resource)
-{
- struct weston_touch *touch = wl_resource_get_user_data(touch_resource);
- struct wl_resource *input_ts;
-
- input_ts = wl_resource_create(client,
- &zwp_input_timestamps_v1_interface,
- 1, id);
- if (!input_ts) {
- wl_client_post_no_memory(client);
- return;
- }
-
- if (touch) {
- wl_list_insert(&touch->timestamps_list,
- wl_resource_get_link(input_ts));
- } else {
- wl_list_init(wl_resource_get_link(input_ts));
- }
-
- wl_resource_set_implementation(input_ts,
- &input_timestamps_interface,
- touch_resource,
- unbind_resource);
-}
-
-static const struct zwp_input_timestamps_manager_v1_interface
- input_timestamps_manager_interface = {
- input_timestamps_manager_destroy,
- input_timestamps_manager_get_keyboard_timestamps,
- input_timestamps_manager_get_pointer_timestamps,
- input_timestamps_manager_get_touch_timestamps,
-};
-
-static void
-bind_input_timestamps_manager(struct wl_client *client, void *data,
- uint32_t version, uint32_t id)
-{
- struct wl_resource *resource =
- wl_resource_create(client,
- &zwp_input_timestamps_manager_v1_interface,
- 1, id);
-
- if (resource == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_resource_set_implementation(resource,
- &input_timestamps_manager_interface,
- NULL, NULL);
-}
-
-int
-weston_input_init(struct weston_compositor *compositor)
-{
- if (!wl_global_create(compositor->wl_display,
- &zwp_relative_pointer_manager_v1_interface, 1,
- compositor, bind_relative_pointer_manager))
- return -1;
-
- if (!wl_global_create(compositor->wl_display,
- &zwp_pointer_constraints_v1_interface, 1,
- NULL, bind_pointer_constraints))
- return -1;
-
- if (!wl_global_create(compositor->wl_display,
- &zwp_input_timestamps_manager_v1_interface, 1,
- NULL, bind_input_timestamps_manager))
- return -1;
-
- return 0;
-}
diff --git a/libweston/launcher-direct.c b/libweston/launcher-direct.c
deleted file mode 100644
index 9fa329b6..00000000
--- a/libweston/launcher-direct.c
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright © 2012 Benjamin Franzke
- * Copyright © 2013 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <libweston/libweston.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <linux/vt.h>
-#include <linux/kd.h>
-#include <linux/major.h>
-
-#include "launcher-impl.h"
-
-#define DRM_MAJOR 226
-
-#ifndef KDSKBMUTE
-#define KDSKBMUTE 0x4B51
-#endif
-
-/* major()/minor() */
-#ifdef MAJOR_IN_MKDEV
-#include <sys/mkdev.h>
-#endif
-#ifdef MAJOR_IN_SYSMACROS
-#include <sys/sysmacros.h>
-#endif
-
-#ifdef BUILD_DRM_COMPOSITOR
-
-#include <xf86drm.h>
-
-static inline int
-is_drm_master(int drm_fd)
-{
- drm_magic_t magic;
-
- return drmGetMagic(drm_fd, &magic) == 0 &&
- drmAuthMagic(drm_fd, magic) == 0;
-}
-
-#else
-
-static inline int
-drmDropMaster(int drm_fd)
-{
- return 0;
-}
-
-static inline int
-drmSetMaster(int drm_fd)
-{
- return 0;
-}
-
-static inline int
-is_drm_master(int drm_fd)
-{
- return 0;
-}
-
-#endif
-
-struct launcher_direct {
- struct weston_launcher base;
- struct weston_compositor *compositor;
- int kb_mode, tty, drm_fd;
- struct wl_event_source *vt_source;
-};
-
-static int
-vt_handler(int signal_number, void *data)
-{
- struct launcher_direct *launcher = data;
- struct weston_compositor *compositor = launcher->compositor;
-
- if (compositor->session_active) {
- compositor->session_active = false;
- wl_signal_emit(&compositor->session_signal, compositor);
- drmDropMaster(launcher->drm_fd);
- ioctl(launcher->tty, VT_RELDISP, 1);
- } else {
- ioctl(launcher->tty, VT_RELDISP, VT_ACKACQ);
- drmSetMaster(launcher->drm_fd);
- compositor->session_active = true;
- wl_signal_emit(&compositor->session_signal, compositor);
- }
-
- return 1;
-}
-
-static int
-setup_tty(struct launcher_direct *launcher, int tty)
-{
- struct wl_event_loop *loop;
- struct vt_mode mode = { 0 };
- struct stat buf;
- char tty_device[32] ="<stdin>";
- int ret, kd_mode;
-
- if (tty == 0) {
- launcher->tty = dup(tty);
- if (launcher->tty == -1) {
- weston_log("couldn't dup stdin: %s\n",
- strerror(errno));
- return -1;
- }
- } else {
- snprintf(tty_device, sizeof tty_device, "/dev/tty%d", tty);
- launcher->tty = open(tty_device, O_RDWR | O_CLOEXEC);
- if (launcher->tty == -1) {
- weston_log("couldn't open tty %s: %s\n", tty_device,
- strerror(errno));
- return -1;
- }
- }
-
- if (fstat(launcher->tty, &buf) == -1 ||
- major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0) {
- weston_log("%s not a vt\n", tty_device);
- weston_log("if running weston from ssh, "
- "use --tty to specify a tty\n");
- goto err_close;
- }
-
- ret = ioctl(launcher->tty, KDGETMODE, &kd_mode);
- if (ret) {
- weston_log("failed to get VT mode: %s\n", strerror(errno));
- return -1;
- }
- if (kd_mode != KD_TEXT) {
- weston_log("%s is already in graphics mode, "
- "is another display server running?\n", tty_device);
- goto err_close;
- }
-
- ioctl(launcher->tty, VT_ACTIVATE, minor(buf.st_rdev));
- ioctl(launcher->tty, VT_WAITACTIVE, minor(buf.st_rdev));
-
- if (ioctl(launcher->tty, KDGKBMODE, &launcher->kb_mode)) {
- weston_log("failed to read keyboard mode: %s\n",
- strerror(errno));
- goto err_close;
- }
-
- if (ioctl(launcher->tty, KDSKBMUTE, 1) &&
- ioctl(launcher->tty, KDSKBMODE, K_OFF)) {
- weston_log("failed to set K_OFF keyboard mode: %s\n",
- strerror(errno));
- goto err_close;
- }
-
- ret = ioctl(launcher->tty, KDSETMODE, KD_GRAPHICS);
- if (ret) {
- weston_log("failed to set KD_GRAPHICS mode on tty: %s\n",
- strerror(errno));
- goto err_close;
- }
-
- /*
- * SIGRTMIN is used as global VT-acquire+release signal. Note that
- * SIGRT* must be tested on runtime, as their exact values are not
- * known at compile-time. POSIX requires 32 of them to be available.
- */
- if (SIGRTMIN > SIGRTMAX) {
- weston_log("not enough RT signals available: %u-%u\n",
- SIGRTMIN, SIGRTMAX);
- ret = -EINVAL;
- goto err_close;
- }
-
- mode.mode = VT_PROCESS;
- mode.relsig = SIGRTMIN;
- mode.acqsig = SIGRTMIN;
- if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0) {
- weston_log("failed to take control of vt handling\n");
- goto err_close;
- }
-
- loop = wl_display_get_event_loop(launcher->compositor->wl_display);
- launcher->vt_source =
- wl_event_loop_add_signal(loop, SIGRTMIN, vt_handler, launcher);
- if (!launcher->vt_source)
- goto err_close;
-
- return 0;
-
- err_close:
- close(launcher->tty);
- return -1;
-}
-
-static int
-launcher_direct_open(struct weston_launcher *launcher_base, const char *path, int flags)
-{
- struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
- struct stat s;
- int fd;
-
- fd = open(path, flags | O_CLOEXEC);
- if (fd == -1)
- return -1;
-
- if (fstat(fd, &s) == -1) {
- close(fd);
- return -1;
- }
-
- if (major(s.st_rdev) == DRM_MAJOR) {
- launcher->drm_fd = fd;
- if (!is_drm_master(fd)) {
- weston_log("drm fd not master\n");
- close(fd);
- return -1;
- }
- }
-
- return fd;
-}
-
-static void
-launcher_direct_close(struct weston_launcher *launcher_base, int fd)
-{
- close(fd);
-}
-
-static void
-launcher_direct_restore(struct weston_launcher *launcher_base)
-{
- struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
- struct vt_mode mode = { 0 };
-
- if (ioctl(launcher->tty, KDSKBMUTE, 0) &&
- ioctl(launcher->tty, KDSKBMODE, launcher->kb_mode))
- weston_log("failed to restore kb mode: %s\n",
- strerror(errno));
-
- if (ioctl(launcher->tty, KDSETMODE, KD_TEXT))
- weston_log("failed to set KD_TEXT mode on tty: %s\n",
- strerror(errno));
-
- /* We have to drop master before we switch the VT back in
- * VT_AUTO, so we don't risk switching to a VT with another
- * display server, that will then fail to set drm master. */
- drmDropMaster(launcher->drm_fd);
-
- mode.mode = VT_AUTO;
- if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0)
- weston_log("could not reset vt handling\n");
-}
-
-static int
-launcher_direct_activate_vt(struct weston_launcher *launcher_base, int vt)
-{
- struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
- return ioctl(launcher->tty, VT_ACTIVATE, vt);
-}
-
-static int
-launcher_direct_connect(struct weston_launcher **out, struct weston_compositor *compositor,
- int tty, const char *seat_id, bool sync_drm)
-{
- struct launcher_direct *launcher;
-
- if (geteuid() != 0)
- return -EINVAL;
-
- launcher = zalloc(sizeof(*launcher));
- if (launcher == NULL)
- return -ENOMEM;
-
- launcher->base.iface = &launcher_direct_iface;
- launcher->compositor = compositor;
-
- if (setup_tty(launcher, tty) == -1) {
- free(launcher);
- return -1;
- }
-
- * (struct launcher_direct **) out = launcher;
- return 0;
-}
-
-static void
-launcher_direct_destroy(struct weston_launcher *launcher_base)
-{
- struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
-
- launcher_direct_restore(&launcher->base);
- wl_event_source_remove(launcher->vt_source);
-
- if (launcher->tty >= 0)
- close(launcher->tty);
-
- free(launcher);
-}
-
-static int
-launcher_direct_get_vt(struct weston_launcher *base)
-{
- struct launcher_direct *launcher = wl_container_of(base, launcher, base);
- struct stat s;
- if (fstat(launcher->tty, &s) < 0)
- return -1;
-
- return minor(s.st_rdev);
-}
-
-const struct launcher_interface launcher_direct_iface = {
- .connect = launcher_direct_connect,
- .destroy = launcher_direct_destroy,
- .open = launcher_direct_open,
- .close = launcher_direct_close,
- .activate_vt = launcher_direct_activate_vt,
- .get_vt = launcher_direct_get_vt,
-};
diff --git a/libweston/launcher-impl.h b/libweston/launcher-impl.h
deleted file mode 100644
index 4161caff..00000000
--- a/libweston/launcher-impl.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright © 2015 Jasper St. Pierre
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <libweston/libweston.h>
-
-struct weston_launcher;
-
-struct launcher_interface {
- int (* connect) (struct weston_launcher **launcher_out, struct weston_compositor *compositor,
- int tty, const char *seat_id, bool sync_drm);
- void (* destroy) (struct weston_launcher *launcher);
- int (* open) (struct weston_launcher *launcher, const char *path, int flags);
- void (* close) (struct weston_launcher *launcher, int fd);
- int (* activate_vt) (struct weston_launcher *launcher, int vt);
- /* Get the number of the VT weston is running in */
- int (* get_vt) (struct weston_launcher *launcher);
-};
-
-struct weston_launcher {
- const struct launcher_interface *iface;
-};
-
-extern const struct launcher_interface launcher_logind_iface;
-extern const struct launcher_interface launcher_weston_launch_iface;
-extern const struct launcher_interface launcher_direct_iface;
diff --git a/libweston/launcher-logind.c b/libweston/launcher-logind.c
deleted file mode 100644
index 9b3c52fa..00000000
--- a/libweston/launcher-logind.c
+++ /dev/null
@@ -1,856 +0,0 @@
-/*
- * Copyright © 2013 David Herrmann
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <systemd/sd-login.h>
-#include <unistd.h>
-
-#include <libweston/libweston.h>
-#include "backend.h"
-#include "dbus.h"
-#include "launcher-impl.h"
-
-#define DRM_MAJOR 226
-
-/* major()/minor() */
-#ifdef MAJOR_IN_MKDEV
-#include <sys/mkdev.h>
-#endif
-#ifdef MAJOR_IN_SYSMACROS
-#include <sys/sysmacros.h>
-#endif
-
-struct launcher_logind {
- struct weston_launcher base;
- struct weston_compositor *compositor;
- bool sync_drm;
- char *seat;
- char *sid;
- unsigned int vtnr;
- int vt;
- int kb_mode;
-
- DBusConnection *dbus;
- struct wl_event_source *dbus_ctx;
- char *spath;
- DBusPendingCall *pending_active;
-};
-
-static int
-launcher_logind_take_device(struct launcher_logind *wl, uint32_t major,
- uint32_t minor, bool *paused_out)
-{
- DBusMessage *m, *reply;
- bool b;
- int r, fd;
- dbus_bool_t paused;
-
- m = dbus_message_new_method_call("org.freedesktop.login1",
- wl->spath,
- "org.freedesktop.login1.Session",
- "TakeDevice");
- if (!m)
- return -ENOMEM;
-
- b = dbus_message_append_args(m,
- DBUS_TYPE_UINT32, &major,
- DBUS_TYPE_UINT32, &minor,
- DBUS_TYPE_INVALID);
- if (!b) {
- r = -ENOMEM;
- goto err_unref;
- }
-
- reply = dbus_connection_send_with_reply_and_block(wl->dbus, m,
- -1, NULL);
- if (!reply) {
- r = -ENODEV;
- goto err_unref;
- }
-
- b = dbus_message_get_args(reply, NULL,
- DBUS_TYPE_UNIX_FD, &fd,
- DBUS_TYPE_BOOLEAN, &paused,
- DBUS_TYPE_INVALID);
- if (!b) {
- r = -ENODEV;
- goto err_reply;
- }
-
- r = fd;
- if (paused_out)
- *paused_out = paused;
-
-err_reply:
- dbus_message_unref(reply);
-err_unref:
- dbus_message_unref(m);
- return r;
-}
-
-static void
-launcher_logind_release_device(struct launcher_logind *wl, uint32_t major,
- uint32_t minor)
-{
- DBusMessage *m;
- bool b;
-
- m = dbus_message_new_method_call("org.freedesktop.login1",
- wl->spath,
- "org.freedesktop.login1.Session",
- "ReleaseDevice");
- if (m) {
- b = dbus_message_append_args(m,
- DBUS_TYPE_UINT32, &major,
- DBUS_TYPE_UINT32, &minor,
- DBUS_TYPE_INVALID);
- if (b)
- dbus_connection_send(wl->dbus, m, NULL);
- dbus_message_unref(m);
- }
-}
-
-static void
-launcher_logind_pause_device_complete(struct launcher_logind *wl, uint32_t major,
- uint32_t minor)
-{
- DBusMessage *m;
- bool b;
-
- m = dbus_message_new_method_call("org.freedesktop.login1",
- wl->spath,
- "org.freedesktop.login1.Session",
- "PauseDeviceComplete");
- if (m) {
- b = dbus_message_append_args(m,
- DBUS_TYPE_UINT32, &major,
- DBUS_TYPE_UINT32, &minor,
- DBUS_TYPE_INVALID);
- if (b)
- dbus_connection_send(wl->dbus, m, NULL);
- dbus_message_unref(m);
- }
-}
-
-static int
-launcher_logind_open(struct weston_launcher *launcher, const char *path, int flags)
-{
- struct launcher_logind *wl = wl_container_of(launcher, wl, base);
- struct stat st;
- int fl, r, fd;
-
- r = stat(path, &st);
- if (r < 0)
- return -1;
- if (!S_ISCHR(st.st_mode)) {
- errno = ENODEV;
- return -1;
- }
-
- fd = launcher_logind_take_device(wl, major(st.st_rdev),
- minor(st.st_rdev), NULL);
- if (fd < 0)
- return fd;
-
- /* Compared to weston_launcher_open() we cannot specify the open-mode
- * directly. Instead, logind passes us an fd with sane default modes.
- * For DRM and evdev this means O_RDWR | O_CLOEXEC. If we want
- * something else, we need to change it afterwards. We currently
- * only support setting O_NONBLOCK. Changing access-modes is not
- * possible so accept whatever logind passes us. */
-
- fl = fcntl(fd, F_GETFL);
- if (fl < 0) {
- r = -errno;
- goto err_close;
- }
-
- if (flags & O_NONBLOCK)
- fl |= O_NONBLOCK;
-
- r = fcntl(fd, F_SETFL, fl);
- if (r < 0) {
- r = -errno;
- goto err_close;
- }
- return fd;
-
-err_close:
- close(fd);
- launcher_logind_release_device(wl, major(st.st_rdev),
- minor(st.st_rdev));
- errno = -r;
- return -1;
-}
-
-static void
-launcher_logind_close(struct weston_launcher *launcher, int fd)
-{
- struct launcher_logind *wl = wl_container_of(launcher, wl, base);
- struct stat st;
- int r;
-
- r = fstat(fd, &st);
- close(fd);
- if (r < 0) {
- weston_log("logind: cannot fstat fd: %s\n", strerror(errno));
- return;
- }
-
- if (!S_ISCHR(st.st_mode)) {
- weston_log("logind: invalid device passed\n");
- return;
- }
-
- launcher_logind_release_device(wl, major(st.st_rdev),
- minor(st.st_rdev));
-}
-
-static int
-launcher_logind_activate_vt(struct weston_launcher *launcher, int vt)
-{
- struct launcher_logind *wl = wl_container_of(launcher, wl, base);
- DBusMessage *m;
- bool b;
- int r;
-
- m = dbus_message_new_method_call("org.freedesktop.login1",
- "/org/freedesktop/login1/seat/self",
- "org.freedesktop.login1.Seat",
- "SwitchTo");
- if (!m)
- return -ENOMEM;
-
- b = dbus_message_append_args(m,
- DBUS_TYPE_UINT32, &vt,
- DBUS_TYPE_INVALID);
- if (!b) {
- r = -ENOMEM;
- goto err_unref;
- }
-
- dbus_connection_send(wl->dbus, m, NULL);
- r = 0;
-
- err_unref:
- dbus_message_unref(m);
- return r;
-}
-
-static void
-launcher_logind_set_active(struct launcher_logind *wl, bool active)
-{
- if (wl->compositor->session_active == active)
- return;
-
- wl->compositor->session_active = active;
-
- wl_signal_emit(&wl->compositor->session_signal,
- wl->compositor);
-}
-
-static void
-parse_active(struct launcher_logind *wl, DBusMessage *m, DBusMessageIter *iter)
-{
- DBusMessageIter sub;
- dbus_bool_t b;
-
- if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
- return;
-
- dbus_message_iter_recurse(iter, &sub);
-
- if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
- return;
-
- dbus_message_iter_get_basic(&sub, &b);
-
- /* If the backend requested DRM master-device synchronization, we only
- * wake-up the compositor once the master-device is up and running. For
- * other backends, we immediately forward the Active-change event. */
- if (!wl->sync_drm || !b)
- launcher_logind_set_active(wl, b);
-}
-
-static void
-get_active_cb(DBusPendingCall *pending, void *data)
-{
- struct launcher_logind *wl = data;
- DBusMessageIter iter;
- DBusMessage *m;
- int type;
-
- dbus_pending_call_unref(wl->pending_active);
- wl->pending_active = NULL;
-
- m = dbus_pending_call_steal_reply(pending);
- if (!m)
- return;
-
- type = dbus_message_get_type(m);
- if (type == DBUS_MESSAGE_TYPE_METHOD_RETURN &&
- dbus_message_iter_init(m, &iter))
- parse_active(wl, m, &iter);
-
- dbus_message_unref(m);
-}
-
-static void
-launcher_logind_get_active(struct launcher_logind *wl)
-{
- DBusPendingCall *pending;
- DBusMessage *m;
- bool b;
- const char *iface, *name;
-
- m = dbus_message_new_method_call("org.freedesktop.login1",
- wl->spath,
- "org.freedesktop.DBus.Properties",
- "Get");
- if (!m)
- return;
-
- iface = "org.freedesktop.login1.Session";
- name = "Active";
- b = dbus_message_append_args(m,
- DBUS_TYPE_STRING, &iface,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_INVALID);
- if (!b)
- goto err_unref;
-
- b = dbus_connection_send_with_reply(wl->dbus, m, &pending, -1);
- if (!b)
- goto err_unref;
-
- b = dbus_pending_call_set_notify(pending, get_active_cb, wl, NULL);
- if (!b) {
- dbus_pending_call_cancel(pending);
- dbus_pending_call_unref(pending);
- goto err_unref;
- }
-
- if (wl->pending_active) {
- dbus_pending_call_cancel(wl->pending_active);
- dbus_pending_call_unref(wl->pending_active);
- }
- wl->pending_active = pending;
- return;
-
-err_unref:
- dbus_message_unref(m);
-}
-
-static void
-disconnected_dbus(struct launcher_logind *wl)
-{
- weston_log("logind: dbus connection lost, exiting..\n");
- exit(-1);
-}
-
-static void
-session_removed(struct launcher_logind *wl, DBusMessage *m)
-{
- const char *name, *obj;
- bool r;
-
- r = dbus_message_get_args(m, NULL,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_OBJECT_PATH, &obj,
- DBUS_TYPE_INVALID);
- if (!r) {
- weston_log("logind: cannot parse SessionRemoved dbus signal\n");
- return;
- }
-
- if (!strcmp(name, wl->sid)) {
- weston_log("logind: our session got closed, exiting..\n");
- exit(-1);
- }
-}
-
-static void
-property_changed(struct launcher_logind *wl, DBusMessage *m)
-{
- DBusMessageIter iter, sub, entry;
- const char *interface, *name;
-
- if (!dbus_message_iter_init(m, &iter) ||
- dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
- goto error;
-
- dbus_message_iter_get_basic(&iter, &interface);
-
- if (!dbus_message_iter_next(&iter) ||
- dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
- goto error;
-
- dbus_message_iter_recurse(&iter, &sub);
-
- while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY) {
- dbus_message_iter_recurse(&sub, &entry);
-
- if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
- goto error;
-
- dbus_message_iter_get_basic(&entry, &name);
- if (!dbus_message_iter_next(&entry))
- goto error;
-
- if (!strcmp(name, "Active")) {
- parse_active(wl, m, &entry);
- return;
- }
-
- dbus_message_iter_next(&sub);
- }
-
- if (!dbus_message_iter_next(&iter) ||
- dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
- goto error;
-
- dbus_message_iter_recurse(&iter, &sub);
-
- while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
- dbus_message_iter_get_basic(&sub, &name);
-
- if (!strcmp(name, "Active")) {
- launcher_logind_get_active(wl);
- return;
- }
-
- dbus_message_iter_next(&sub);
- }
-
- return;
-
-error:
- weston_log("logind: cannot parse PropertiesChanged dbus signal\n");
-}
-
-static void
-device_paused(struct launcher_logind *wl, DBusMessage *m)
-{
- bool r;
- const char *type;
- uint32_t major, minor;
-
- r = dbus_message_get_args(m, NULL,
- DBUS_TYPE_UINT32, &major,
- DBUS_TYPE_UINT32, &minor,
- DBUS_TYPE_STRING, &type,
- DBUS_TYPE_INVALID);
- if (!r) {
- weston_log("logind: cannot parse PauseDevice dbus signal\n");
- return;
- }
-
- /* "pause" means synchronous pausing. Acknowledge it unconditionally
- * as we support asynchronous device shutdowns, anyway.
- * "force" means asynchronous pausing.
- * "gone" means the device is gone. We handle it the same as "force" as
- * a following udev event will be caught, too.
- *
- * If it's our main DRM device, tell the compositor to go asleep. */
-
- if (!strcmp(type, "pause"))
- launcher_logind_pause_device_complete(wl, major, minor);
-
- if (wl->sync_drm && wl->compositor->backend->device_changed)
- wl->compositor->backend->device_changed(wl->compositor,
- makedev(major,minor),
- false);
-}
-
-static void
-device_resumed(struct launcher_logind *wl, DBusMessage *m)
-{
- bool r;
- uint32_t major, minor;
-
- r = dbus_message_get_args(m, NULL,
- DBUS_TYPE_UINT32, &major,
- DBUS_TYPE_UINT32, &minor,
- DBUS_TYPE_INVALID);
- if (!r) {
- weston_log("logind: cannot parse ResumeDevice dbus signal\n");
- return;
- }
-
- /* DeviceResumed messages provide us a new file-descriptor for
- * resumed devices. For DRM devices it's the same as before, for evdev
- * devices it's a new open-file. As we reopen evdev devices, anyway,
- * there is no need for us to handle this event for evdev. For DRM, we
- * notify the compositor to wake up. */
-
- if (wl->sync_drm && wl->compositor->backend->device_changed)
- wl->compositor->backend->device_changed(wl->compositor,
- makedev(major,minor),
- true);
-}
-
-static DBusHandlerResult
-filter_dbus(DBusConnection *c, DBusMessage *m, void *data)
-{
- struct launcher_logind *wl = data;
-
- if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) {
- disconnected_dbus(wl);
- } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Manager",
- "SessionRemoved")) {
- session_removed(wl, m);
- } else if (dbus_message_is_signal(m, "org.freedesktop.DBus.Properties",
- "PropertiesChanged")) {
- property_changed(wl, m);
- } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Session",
- "PauseDevice")) {
- device_paused(wl, m);
- } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Session",
- "ResumeDevice")) {
- device_resumed(wl, m);
- }
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static int
-launcher_logind_setup_dbus(struct launcher_logind *wl)
-{
- bool b;
- int r;
-
- r = asprintf(&wl->spath, "/org/freedesktop/login1/session/%s",
- wl->sid);
- if (r < 0)
- return -ENOMEM;
-
- b = dbus_connection_add_filter(wl->dbus, filter_dbus, wl, NULL);
- if (!b) {
- weston_log("logind: cannot add dbus filter\n");
- r = -ENOMEM;
- goto err_spath;
- }
-
- r = weston_dbus_add_match_signal(wl->dbus,
- "org.freedesktop.login1",
- "org.freedesktop.login1.Manager",
- "SessionRemoved",
- "/org/freedesktop/login1");
- if (r < 0) {
- weston_log("logind: cannot add dbus match\n");
- goto err_spath;
- }
-
- r = weston_dbus_add_match_signal(wl->dbus,
- "org.freedesktop.login1",
- "org.freedesktop.login1.Session",
- "PauseDevice",
- wl->spath);
- if (r < 0) {
- weston_log("logind: cannot add dbus match\n");
- goto err_spath;
- }
-
- r = weston_dbus_add_match_signal(wl->dbus,
- "org.freedesktop.login1",
- "org.freedesktop.login1.Session",
- "ResumeDevice",
- wl->spath);
- if (r < 0) {
- weston_log("logind: cannot add dbus match\n");
- goto err_spath;
- }
-
- r = weston_dbus_add_match_signal(wl->dbus,
- "org.freedesktop.login1",
- "org.freedesktop.DBus.Properties",
- "PropertiesChanged",
- wl->spath);
- if (r < 0) {
- weston_log("logind: cannot add dbus match\n");
- goto err_spath;
- }
-
- return 0;
-
-err_spath:
- /* don't remove any dbus-match as the connection is closed, anyway */
- free(wl->spath);
- return r;
-}
-
-static void
-launcher_logind_destroy_dbus(struct launcher_logind *wl)
-{
- /* don't remove any dbus-match as the connection is closed, anyway */
- free(wl->spath);
-}
-
-static int
-launcher_logind_take_control(struct launcher_logind *wl)
-{
- DBusError err;
- DBusMessage *m, *reply;
- dbus_bool_t force;
- bool b;
- int r;
-
- dbus_error_init(&err);
-
- m = dbus_message_new_method_call("org.freedesktop.login1",
- wl->spath,
- "org.freedesktop.login1.Session",
- "TakeControl");
- if (!m)
- return -ENOMEM;
-
- force = false;
- b = dbus_message_append_args(m,
- DBUS_TYPE_BOOLEAN, &force,
- DBUS_TYPE_INVALID);
- if (!b) {
- r = -ENOMEM;
- goto err_unref;
- }
-
- reply = dbus_connection_send_with_reply_and_block(wl->dbus,
- m, -1, &err);
- if (!reply) {
- if (dbus_error_has_name(&err, DBUS_ERROR_UNKNOWN_METHOD))
- weston_log("logind: old systemd version detected\n");
- else
- weston_log("logind: cannot take control over session %s\n", wl->sid);
-
- dbus_error_free(&err);
- r = -EIO;
- goto err_unref;
- }
-
- dbus_message_unref(reply);
- dbus_message_unref(m);
- return 0;
-
-err_unref:
- dbus_message_unref(m);
- return r;
-}
-
-static void
-launcher_logind_release_control(struct launcher_logind *wl)
-{
- DBusMessage *m;
-
- m = dbus_message_new_method_call("org.freedesktop.login1",
- wl->spath,
- "org.freedesktop.login1.Session",
- "ReleaseControl");
- if (m) {
- dbus_connection_send(wl->dbus, m, NULL);
- dbus_message_unref(m);
- }
-}
-
-static int
-weston_sd_session_get_vt(const char *sid, unsigned int *out)
-{
-#ifdef HAVE_SYSTEMD_LOGIN_209
- return sd_session_get_vt(sid, out);
-#else
- int r;
- char *tty;
-
- r = sd_session_get_tty(sid, &tty);
- if (r < 0)
- return r;
-
- r = sscanf(tty, "tty%u", out);
- free(tty);
-
- if (r != 1)
- return -EINVAL;
-
- return 0;
-#endif
-}
-
-static int
-launcher_logind_activate(struct launcher_logind *wl)
-{
- DBusMessage *m;
-
- m = dbus_message_new_method_call("org.freedesktop.login1",
- wl->spath,
- "org.freedesktop.login1.Session",
- "Activate");
- if (!m)
- return -ENOMEM;
-
- dbus_connection_send(wl->dbus, m, NULL);
- return 0;
-}
-
-static int
-launcher_logind_connect(struct weston_launcher **out, struct weston_compositor *compositor,
- int tty, const char *seat_id, bool sync_drm)
-{
- struct launcher_logind *wl;
- struct wl_event_loop *loop;
- char *t;
- int r;
-
- wl = zalloc(sizeof(*wl));
- if (wl == NULL) {
- r = -ENOMEM;
- goto err_out;
- }
-
- wl->base.iface = &launcher_logind_iface;
- wl->compositor = compositor;
- wl->sync_drm = sync_drm;
-
- wl->seat = strdup(seat_id);
- if (!wl->seat) {
- r = -ENOMEM;
- goto err_wl;
- }
-
- r = sd_pid_get_session(getpid(), &wl->sid);
- if (r < 0) {
- weston_log("logind: not running in a systemd session\n");
- goto err_seat;
- }
-
- t = NULL;
- r = sd_session_get_seat(wl->sid, &t);
- if (r < 0) {
- weston_log("logind: failed to get session seat\n");
- free(t);
- goto err_session;
- } else if (strcmp(seat_id, t)) {
- weston_log("logind: weston's seat '%s' differs from session-seat '%s'\n",
- seat_id, t);
- r = -EINVAL;
- free(t);
- goto err_session;
- }
-
- r = strcmp(t, "seat0");
- free(t);
- if (r == 0) {
- r = weston_sd_session_get_vt(wl->sid, &wl->vtnr);
- if (r < 0) {
- weston_log("logind: session not running on a VT\n");
- goto err_session;
- } else if (tty > 0 && wl->vtnr != (unsigned int )tty) {
- weston_log("logind: requested VT --tty=%d differs from real session VT %u\n",
- tty, wl->vtnr);
- r = -EINVAL;
- goto err_session;
- }
- }
-
- loop = wl_display_get_event_loop(compositor->wl_display);
- r = weston_dbus_open(loop, DBUS_BUS_SYSTEM, &wl->dbus, &wl->dbus_ctx);
- if (r < 0) {
- weston_log("logind: cannot connect to system dbus\n");
- goto err_session;
- }
-
- r = launcher_logind_setup_dbus(wl);
- if (r < 0)
- goto err_dbus;
-
- r = launcher_logind_take_control(wl);
- if (r < 0)
- goto err_dbus_cleanup;
-
- r = launcher_logind_activate(wl);
- if (r < 0)
- goto err_dbus_cleanup;
-
- weston_log("logind: session control granted\n");
- * (struct launcher_logind **) out = wl;
- return 0;
-
-err_dbus_cleanup:
- launcher_logind_destroy_dbus(wl);
-err_dbus:
- weston_dbus_close(wl->dbus, wl->dbus_ctx);
-err_session:
- free(wl->sid);
-err_seat:
- free(wl->seat);
-err_wl:
- free(wl);
-err_out:
- weston_log("logind: cannot setup systemd-logind helper (%d), using legacy fallback\n", r);
- errno = -r;
- return -1;
-}
-
-static void
-launcher_logind_destroy(struct weston_launcher *launcher)
-{
- struct launcher_logind *wl = wl_container_of(launcher, wl, base);
-
- if (wl->pending_active) {
- dbus_pending_call_cancel(wl->pending_active);
- dbus_pending_call_unref(wl->pending_active);
- }
-
- launcher_logind_release_control(wl);
- launcher_logind_destroy_dbus(wl);
- weston_dbus_close(wl->dbus, wl->dbus_ctx);
- free(wl->sid);
- free(wl->seat);
- free(wl);
-}
-
-static int
-launcher_logind_get_vt(struct weston_launcher *launcher)
-{
- struct launcher_logind *wl = wl_container_of(launcher, wl, base);
- return wl->vtnr;
-}
-
-const struct launcher_interface launcher_logind_iface = {
- .connect = launcher_logind_connect,
- .destroy = launcher_logind_destroy,
- .open = launcher_logind_open,
- .close = launcher_logind_close,
- .activate_vt = launcher_logind_activate_vt,
- .get_vt = launcher_logind_get_vt,
-};
diff --git a/libweston/launcher-util.c b/libweston/launcher-util.c
deleted file mode 100644
index 5cbb0abb..00000000
--- a/libweston/launcher-util.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright © 2012 Benjamin Franzke
- * Copyright © 2013 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <libweston/libweston.h>
-
-#include "launcher-util.h"
-#include "launcher-impl.h"
-
-#include <stdint.h>
-#include <unistd.h>
-#include <linux/input.h>
-
-static const struct launcher_interface *ifaces[] = {
-#ifdef HAVE_SYSTEMD_LOGIN
- &launcher_logind_iface,
-#endif
- &launcher_weston_launch_iface,
- &launcher_direct_iface,
- NULL,
-};
-
-WL_EXPORT struct weston_launcher *
-weston_launcher_connect(struct weston_compositor *compositor, int tty,
- const char *seat_id, bool sync_drm)
-{
- const struct launcher_interface **it;
-
- for (it = ifaces; *it != NULL; it++) {
- const struct launcher_interface *iface = *it;
- struct weston_launcher *launcher;
-
- if (iface->connect(&launcher, compositor, tty, seat_id, sync_drm) == 0)
- return launcher;
- }
-
- return NULL;
-}
-
-WL_EXPORT void
-weston_launcher_destroy(struct weston_launcher *launcher)
-{
- launcher->iface->destroy(launcher);
-}
-
-WL_EXPORT int
-weston_launcher_open(struct weston_launcher *launcher,
- const char *path, int flags)
-{
- return launcher->iface->open(launcher, path, flags);
-}
-
-WL_EXPORT void
-weston_launcher_close(struct weston_launcher *launcher, int fd)
-{
- launcher->iface->close(launcher, fd);
-}
-
-WL_EXPORT int
-weston_launcher_activate_vt(struct weston_launcher *launcher, int vt)
-{
- return launcher->iface->activate_vt(launcher, vt);
-}
-
-static void
-switch_vt_binding(struct weston_keyboard *keyboard,
- const struct timespec *time, uint32_t key, void *data)
-{
- struct weston_compositor *compositor = data;
- struct weston_launcher *launcher = compositor->launcher;
- int vt = key - KEY_F1 + 1;
-
- if (vt == launcher->iface->get_vt(launcher))
- return;
-
- weston_launcher_activate_vt(launcher, vt);
-}
-
-WL_EXPORT void
-weston_setup_vt_switch_bindings(struct weston_compositor *compositor)
-{
- uint32_t key;
- struct weston_launcher *launcher = compositor->launcher;
-
- if (launcher->iface->get_vt(launcher) <= 0)
- return;
-
- if (compositor->vt_switching == false)
- return;
-
- for (key = KEY_F1; key < KEY_F9; key++)
- weston_compositor_add_key_binding(compositor, key,
- MODIFIER_CTRL | MODIFIER_ALT,
- switch_vt_binding,
- compositor);
-}
diff --git a/libweston/launcher-util.h b/libweston/launcher-util.h
deleted file mode 100644
index dd7b7702..00000000
--- a/libweston/launcher-util.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright © 2012 Benjamin Franzke
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _WESTON_LAUNCHER_UTIL_H_
-#define _WESTON_LAUNCHER_UTIL_H_
-
-#include "config.h"
-
-#include <libweston/libweston.h>
-
-struct weston_launcher;
-
-struct weston_launcher *
-weston_launcher_connect(struct weston_compositor *compositor, int tty,
- const char *seat_id, bool sync_drm);
-
-void
-weston_launcher_destroy(struct weston_launcher *launcher);
-
-int
-weston_launcher_open(struct weston_launcher *launcher,
- const char *path, int flags);
-
-void
-weston_launcher_close(struct weston_launcher *launcher, int fd);
-
-int
-weston_launcher_activate_vt(struct weston_launcher *launcher, int vt);
-
-void
-weston_setup_vt_switch_bindings(struct weston_compositor *compositor);
-
-#endif
diff --git a/libweston/launcher-weston-launch.c b/libweston/launcher-weston-launch.c
deleted file mode 100644
index 7bac0a30..00000000
--- a/libweston/launcher-weston-launch.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright © 2012 Benjamin Franzke
- * Copyright © 2013 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <errno.h>
-#include <signal.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <linux/vt.h>
-#include <linux/kd.h>
-#include <linux/major.h>
-
-#include <libweston/libweston.h>
-#include "weston-launch.h"
-#include "launcher-impl.h"
-
-#define DRM_MAJOR 226
-
-#ifndef KDSKBMUTE
-#define KDSKBMUTE 0x4B51
-#endif
-
-#ifdef BUILD_DRM_COMPOSITOR
-
-#include <xf86drm.h>
-
-#else
-
-static inline int
-drmDropMaster(int drm_fd)
-{
- return 0;
-}
-
-static inline int
-drmSetMaster(int drm_fd)
-{
- return 0;
-}
-
-#endif
-
-/* major()/minor() */
-#ifdef MAJOR_IN_MKDEV
-#include <sys/mkdev.h>
-#endif
-#ifdef MAJOR_IN_SYSMACROS
-#include <sys/sysmacros.h>
-#endif
-
-union cmsg_data { unsigned char b[4]; int fd; };
-
-struct launcher_weston_launch {
- struct weston_launcher base;
- struct weston_compositor *compositor;
- struct wl_event_loop *loop;
- int fd;
- struct wl_event_source *source;
-
- int kb_mode, tty, drm_fd;
-};
-
-static int
-launcher_weston_launch_open(struct weston_launcher *launcher_base,
- const char *path, int flags)
-{
- struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
- int n, ret;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- struct iovec iov;
- union cmsg_data *data;
- char control[CMSG_SPACE(sizeof data->fd)];
- ssize_t len;
- struct weston_launcher_open *message;
-
- n = sizeof(*message) + strlen(path) + 1;
- message = malloc(n);
- if (!message)
- return -1;
-
- message->header.opcode = WESTON_LAUNCHER_OPEN;
- message->flags = flags;
- strcpy(message->path, path);
-
- do {
- len = send(launcher->fd, message, n, 0);
- } while (len < 0 && errno == EINTR);
- free(message);
-
- memset(&msg, 0, sizeof msg);
- iov.iov_base = &ret;
- iov.iov_len = sizeof ret;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = control;
- msg.msg_controllen = sizeof control;
-
- do {
- len = recvmsg(launcher->fd, &msg, MSG_CMSG_CLOEXEC);
- } while (len < 0 && errno == EINTR);
-
- if (len != sizeof ret ||
- ret < 0)
- return -1;
-
- cmsg = CMSG_FIRSTHDR(&msg);
- if (!cmsg ||
- cmsg->cmsg_level != SOL_SOCKET ||
- cmsg->cmsg_type != SCM_RIGHTS) {
- fprintf(stderr, "invalid control message\n");
- return -1;
- }
-
- data = (union cmsg_data *) CMSG_DATA(cmsg);
- if (data->fd == -1) {
- fprintf(stderr, "missing drm fd in socket request\n");
- return -1;
- }
-
- return data->fd;
-}
-
-static void
-launcher_weston_launch_close(struct weston_launcher *launcher_base, int fd)
-{
- close(fd);
-}
-
-static void
-launcher_weston_launch_restore(struct weston_launcher *launcher_base)
-{
- struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
- struct vt_mode mode = { 0 };
-
- if (ioctl(launcher->tty, KDSKBMUTE, 0) &&
- ioctl(launcher->tty, KDSKBMODE, launcher->kb_mode))
- weston_log("failed to restore kb mode: %s\n",
- strerror(errno));
-
- if (ioctl(launcher->tty, KDSETMODE, KD_TEXT))
- weston_log("failed to set KD_TEXT mode on tty: %s\n",
- strerror(errno));
-
- /* We have to drop master before we switch the VT back in
- * VT_AUTO, so we don't risk switching to a VT with another
- * display server, that will then fail to set drm master. */
- drmDropMaster(launcher->drm_fd);
-
- mode.mode = VT_AUTO;
- if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0)
- weston_log("could not reset vt handling\n");
-}
-
-static int
-launcher_weston_launch_data(int fd, uint32_t mask, void *data)
-{
- struct launcher_weston_launch *launcher = data;
- int len, ret;
-
- if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) {
- weston_log("launcher socket closed, exiting\n");
- /* Normally the weston-launch will reset the tty, but
- * in this case it died or something, so do it here so
- * we don't end up with a stuck vt. */
- launcher_weston_launch_restore(&launcher->base);
- exit(-1);
- }
-
- do {
- len = recv(launcher->fd, &ret, sizeof ret, 0);
- } while (len < 0 && errno == EINTR);
-
- switch (ret) {
- case WESTON_LAUNCHER_ACTIVATE:
- launcher->compositor->session_active = true;
- wl_signal_emit(&launcher->compositor->session_signal,
- launcher->compositor);
- break;
- case WESTON_LAUNCHER_DEACTIVATE:
- launcher->compositor->session_active = false;
- wl_signal_emit(&launcher->compositor->session_signal,
- launcher->compositor);
- break;
- default:
- weston_log("unexpected event from weston-launch\n");
- break;
- }
-
- return 1;
-}
-
-static int
-launcher_weston_launch_activate_vt(struct weston_launcher *launcher_base, int vt)
-{
- struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
- return ioctl(launcher->tty, VT_ACTIVATE, vt);
-}
-
-static int
-launcher_weston_launch_connect(struct weston_launcher **out, struct weston_compositor *compositor,
- int tty, const char *seat_id, bool sync_drm)
-{
- struct launcher_weston_launch *launcher;
- struct wl_event_loop *loop;
-
- launcher = malloc(sizeof *launcher);
- if (launcher == NULL)
- return -ENOMEM;
-
- launcher->base.iface = &launcher_weston_launch_iface;
- * (struct launcher_weston_launch **) out = launcher;
- launcher->compositor = compositor;
- launcher->drm_fd = -1;
- launcher->fd = weston_environment_get_fd("WESTON_LAUNCHER_SOCK");
- if (launcher->fd != -1) {
- launcher->tty = weston_environment_get_fd("WESTON_TTY_FD");
- /* We don't get a chance to read out the original kb
- * mode for the tty, so just hard code K_UNICODE here
- * in case we have to clean if weston-launch dies. */
- launcher->kb_mode = K_UNICODE;
-
- loop = wl_display_get_event_loop(compositor->wl_display);
- launcher->source = wl_event_loop_add_fd(loop, launcher->fd,
- WL_EVENT_READABLE,
- launcher_weston_launch_data,
- launcher);
- if (launcher->source == NULL) {
- free(launcher);
- return -ENOMEM;
- }
-
- return 0;
- } else {
- return -1;
- }
-}
-
-static void
-launcher_weston_launch_destroy(struct weston_launcher *launcher_base)
-{
- struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
-
- if (launcher->fd != -1) {
- close(launcher->fd);
- wl_event_source_remove(launcher->source);
- } else {
- launcher_weston_launch_restore(&launcher->base);
- }
-
- if (launcher->tty >= 0)
- close(launcher->tty);
-
- free(launcher);
-}
-
-static int
-launcher_weston_launch_get_vt(struct weston_launcher *base)
-{
- struct launcher_weston_launch *launcher = wl_container_of(base, launcher, base);
- struct stat s;
- if (fstat(launcher->tty, &s) < 0)
- return -1;
-
- return minor(s.st_rdev);
-}
-
-const struct launcher_interface launcher_weston_launch_iface = {
- .connect = launcher_weston_launch_connect,
- .destroy = launcher_weston_launch_destroy,
- .open = launcher_weston_launch_open,
- .close = launcher_weston_launch_close,
- .activate_vt = launcher_weston_launch_activate_vt,
- .get_vt = launcher_weston_launch_get_vt,
-};
diff --git a/libweston/libinput-device.c b/libweston/libinput-device.c
deleted file mode 100644
index 9a084cbf..00000000
--- a/libweston/libinput-device.c
+++ /dev/null
@@ -1,761 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- * Copyright © 2013 Jonas Ådahl
- * Copyright 2017-2018 Collabora, Ltd.
- * Copyright 2017-2018 General Electric Company
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <linux/input.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <assert.h>
-#include <libinput.h>
-
-#include <libweston/libweston.h>
-#include "backend.h"
-#include "libweston-internal.h"
-#include "libinput-device.h"
-#include "shared/helpers.h"
-#include "shared/timespec-util.h"
-
-void
-evdev_led_update(struct evdev_device *device, enum weston_led weston_leds)
-{
- enum libinput_led leds = 0;
-
- if (weston_leds & LED_NUM_LOCK)
- leds |= LIBINPUT_LED_NUM_LOCK;
- if (weston_leds & LED_CAPS_LOCK)
- leds |= LIBINPUT_LED_CAPS_LOCK;
- if (weston_leds & LED_SCROLL_LOCK)
- leds |= LIBINPUT_LED_SCROLL_LOCK;
-
- libinput_device_led_update(device->device, leds);
-}
-
-static void
-handle_keyboard_key(struct libinput_device *libinput_device,
- struct libinput_event_keyboard *keyboard_event)
-{
- struct evdev_device *device =
- libinput_device_get_user_data(libinput_device);
- int key_state =
- libinput_event_keyboard_get_key_state(keyboard_event);
- int seat_key_count =
- libinput_event_keyboard_get_seat_key_count(keyboard_event);
- struct timespec time;
-
- /* Ignore key events that are not seat wide state changes. */
- if ((key_state == LIBINPUT_KEY_STATE_PRESSED &&
- seat_key_count != 1) ||
- (key_state == LIBINPUT_KEY_STATE_RELEASED &&
- seat_key_count != 0))
- return;
-
- timespec_from_usec(&time,
- libinput_event_keyboard_get_time_usec(keyboard_event));
-
- notify_key(device->seat, &time,
- libinput_event_keyboard_get_key(keyboard_event),
- key_state, STATE_UPDATE_AUTOMATIC);
-}
-
-static bool
-handle_pointer_motion(struct libinput_device *libinput_device,
- struct libinput_event_pointer *pointer_event)
-{
- struct evdev_device *device =
- libinput_device_get_user_data(libinput_device);
- struct weston_pointer_motion_event event = { 0 };
- struct timespec time;
- double dx_unaccel, dy_unaccel;
-
- timespec_from_usec(&time,
- libinput_event_pointer_get_time_usec(pointer_event));
- dx_unaccel = libinput_event_pointer_get_dx_unaccelerated(pointer_event);
- dy_unaccel = libinput_event_pointer_get_dy_unaccelerated(pointer_event);
-
- event = (struct weston_pointer_motion_event) {
- .mask = WESTON_POINTER_MOTION_REL |
- WESTON_POINTER_MOTION_REL_UNACCEL,
- .time = time,
- .dx = libinput_event_pointer_get_dx(pointer_event),
- .dy = libinput_event_pointer_get_dy(pointer_event),
- .dx_unaccel = dx_unaccel,
- .dy_unaccel = dy_unaccel,
- };
-
- notify_motion(device->seat, &time, &event);
-
- return true;
-}
-
-static bool
-handle_pointer_motion_absolute(
- struct libinput_device *libinput_device,
- struct libinput_event_pointer *pointer_event)
-{
- struct evdev_device *device =
- libinput_device_get_user_data(libinput_device);
- struct weston_output *output = device->output;
- struct timespec time;
- double x, y;
- uint32_t width, height;
-
- if (!output)
- return false;
-
- timespec_from_usec(&time,
- libinput_event_pointer_get_time_usec(pointer_event));
- width = device->output->current_mode->width;
- height = device->output->current_mode->height;
-
- x = libinput_event_pointer_get_absolute_x_transformed(pointer_event,
- width);
- y = libinput_event_pointer_get_absolute_y_transformed(pointer_event,
- height);
-
- weston_output_transform_coordinate(device->output, x, y, &x, &y);
- notify_motion_absolute(device->seat, &time, x, y);
-
- return true;
-}
-
-static bool
-handle_pointer_button(struct libinput_device *libinput_device,
- struct libinput_event_pointer *pointer_event)
-{
- struct evdev_device *device =
- libinput_device_get_user_data(libinput_device);
- int button_state =
- libinput_event_pointer_get_button_state(pointer_event);
- int seat_button_count =
- libinput_event_pointer_get_seat_button_count(pointer_event);
- struct timespec time;
-
- /* Ignore button events that are not seat wide state changes. */
- if ((button_state == LIBINPUT_BUTTON_STATE_PRESSED &&
- seat_button_count != 1) ||
- (button_state == LIBINPUT_BUTTON_STATE_RELEASED &&
- seat_button_count != 0))
- return false;
-
- timespec_from_usec(&time,
- libinput_event_pointer_get_time_usec(pointer_event));
-
- notify_button(device->seat, &time,
- libinput_event_pointer_get_button(pointer_event),
- button_state);
-
- return true;
-}
-
-static double
-normalize_scroll(struct libinput_event_pointer *pointer_event,
- enum libinput_pointer_axis axis)
-{
- enum libinput_pointer_axis_source source;
- double value = 0.0;
-
- source = libinput_event_pointer_get_axis_source(pointer_event);
- /* libinput < 0.8 sent wheel click events with value 10. Since 0.8
- the value is the angle of the click in degrees. To keep
- backwards-compat with existing clients, we just send multiples of
- the click count.
- */
- switch (source) {
- case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL:
- value = 10 * libinput_event_pointer_get_axis_value_discrete(
- pointer_event,
- axis);
- break;
- case LIBINPUT_POINTER_AXIS_SOURCE_FINGER:
- case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS:
- value = libinput_event_pointer_get_axis_value(pointer_event,
- axis);
- break;
- default:
- assert(!"unhandled event source in normalize_scroll");
- }
-
- return value;
-}
-
-static int32_t
-get_axis_discrete(struct libinput_event_pointer *pointer_event,
- enum libinput_pointer_axis axis)
-{
- enum libinput_pointer_axis_source source;
-
- source = libinput_event_pointer_get_axis_source(pointer_event);
-
- if (source != LIBINPUT_POINTER_AXIS_SOURCE_WHEEL)
- return 0;
-
- return libinput_event_pointer_get_axis_value_discrete(pointer_event,
- axis);
-}
-
-static bool
-handle_pointer_axis(struct libinput_device *libinput_device,
- struct libinput_event_pointer *pointer_event)
-{
- static int warned;
- struct evdev_device *device =
- libinput_device_get_user_data(libinput_device);
- double vert, horiz;
- int32_t vert_discrete, horiz_discrete;
- enum libinput_pointer_axis axis;
- struct weston_pointer_axis_event weston_event;
- enum libinput_pointer_axis_source source;
- uint32_t wl_axis_source;
- bool has_vert, has_horiz;
- struct timespec time;
-
- has_vert = libinput_event_pointer_has_axis(pointer_event,
- LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
- has_horiz = libinput_event_pointer_has_axis(pointer_event,
- LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
-
- if (!has_vert && !has_horiz)
- return false;
-
- source = libinput_event_pointer_get_axis_source(pointer_event);
- switch (source) {
- case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL:
- wl_axis_source = WL_POINTER_AXIS_SOURCE_WHEEL;
- break;
- case LIBINPUT_POINTER_AXIS_SOURCE_FINGER:
- wl_axis_source = WL_POINTER_AXIS_SOURCE_FINGER;
- break;
- case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS:
- wl_axis_source = WL_POINTER_AXIS_SOURCE_CONTINUOUS;
- break;
- default:
- if (warned < 5) {
- weston_log("Unknown scroll source %d.\n", source);
- warned++;
- }
- return false;
- }
-
- notify_axis_source(device->seat, wl_axis_source);
-
- timespec_from_usec(&time,
- libinput_event_pointer_get_time_usec(pointer_event));
-
- if (has_vert) {
- axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
- vert_discrete = get_axis_discrete(pointer_event, axis);
- vert = normalize_scroll(pointer_event, axis);
-
- weston_event.axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
- weston_event.value = vert;
- weston_event.discrete = vert_discrete;
- weston_event.has_discrete = (vert_discrete != 0);
-
- notify_axis(device->seat, &time, &weston_event);
- }
-
- if (has_horiz) {
- axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
- horiz_discrete = get_axis_discrete(pointer_event, axis);
- horiz = normalize_scroll(pointer_event, axis);
-
- weston_event.axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
- weston_event.value = horiz;
- weston_event.discrete = horiz_discrete;
- weston_event.has_discrete = (horiz_discrete != 0);
-
- notify_axis(device->seat, &time, &weston_event);
- }
-
- return true;
-}
-
-static struct weston_output *
-touch_get_output(struct weston_touch_device *device)
-{
- struct evdev_device *evdev_device = device->backend_data;
-
- return evdev_device->output;
-}
-
-static const char *
-touch_get_calibration_head_name(struct weston_touch_device *device)
-{
- struct evdev_device *evdev_device = device->backend_data;
- struct weston_output *output = evdev_device->output;
- struct weston_head *head;
-
- if (!output)
- return NULL;
-
- assert(output->enabled);
- if (evdev_device->output_name)
- return evdev_device->output_name;
-
- /* No specific head was configured, so the association was made by
- * the default rule. Just grab whatever head's name.
- */
- wl_list_for_each(head, &output->head_list, output_link)
- return head->name;
-
- assert(0);
- return NULL;
-}
-
-static void
-touch_get_calibration(struct weston_touch_device *device,
- struct weston_touch_device_matrix *cal)
-{
- struct evdev_device *evdev_device = device->backend_data;
-
- libinput_device_config_calibration_get_matrix(evdev_device->device,
- cal->m);
-}
-
-static void
-do_set_calibration(struct evdev_device *evdev_device,
- const struct weston_touch_device_matrix *cal)
-{
- enum libinput_config_status status;
-
- weston_log("input device %s: applying calibration:\n",
- libinput_device_get_sysname(evdev_device->device));
- weston_log_continue(STAMP_SPACE " %f %f %f\n",
- cal->m[0], cal->m[1], cal->m[2]);
- weston_log_continue(STAMP_SPACE " %f %f %f\n",
- cal->m[3], cal->m[4], cal->m[5]);
-
- status = libinput_device_config_calibration_set_matrix(evdev_device->device,
- cal->m);
- if (status != LIBINPUT_CONFIG_STATUS_SUCCESS)
- weston_log("Error: Failed to apply calibration.\n");
-}
-
-static void
-touch_set_calibration(struct weston_touch_device *device,
- const struct weston_touch_device_matrix *cal)
-{
- struct evdev_device *evdev_device = device->backend_data;
-
- /* Stop output hotplug from reloading the WL_CALIBRATION values.
- * libinput will maintain the latest calibration for us.
- */
- evdev_device->override_wl_calibration = true;
-
- do_set_calibration(evdev_device, cal);
-}
-
-static const struct weston_touch_device_ops touch_calibration_ops = {
- .get_output = touch_get_output,
- .get_calibration_head_name = touch_get_calibration_head_name,
- .get_calibration = touch_get_calibration,
- .set_calibration = touch_set_calibration
-};
-
-static struct weston_touch_device *
-create_touch_device(struct evdev_device *device)
-{
- const struct weston_touch_device_ops *ops = NULL;
- struct weston_touch_device *touch_device;
- struct udev_device *udev_device;
-
- if (libinput_device_config_calibration_has_matrix(device->device))
- ops = &touch_calibration_ops;
-
- udev_device = libinput_device_get_udev_device(device->device);
- if (!udev_device)
- return NULL;
-
- touch_device = weston_touch_create_touch_device(device->seat->touch_state,
- udev_device_get_syspath(udev_device),
- device, ops);
-
- udev_device_unref(udev_device);
-
- if (!touch_device)
- return NULL;
-
- weston_log("Touchscreen - %s - %s\n",
- libinput_device_get_name(device->device),
- touch_device->syspath);
-
- return touch_device;
-}
-
-static void
-handle_touch_with_coords(struct libinput_device *libinput_device,
- struct libinput_event_touch *touch_event,
- int touch_type)
-{
- struct evdev_device *device =
- libinput_device_get_user_data(libinput_device);
- double x;
- double y;
- struct weston_point2d_device_normalized norm;
- uint32_t width, height;
- struct timespec time;
- int32_t slot;
-
- if (!device->output)
- return;
-
- timespec_from_usec(&time,
- libinput_event_touch_get_time_usec(touch_event));
- slot = libinput_event_touch_get_seat_slot(touch_event);
-
- width = device->output->current_mode->width;
- height = device->output->current_mode->height;
- x = libinput_event_touch_get_x_transformed(touch_event, width);
- y = libinput_event_touch_get_y_transformed(touch_event, height);
-
- weston_output_transform_coordinate(device->output,
- x, y, &x, &y);
-
- if (weston_touch_device_can_calibrate(device->touch_device)) {
- norm.x = libinput_event_touch_get_x_transformed(touch_event, 1);
- norm.y = libinput_event_touch_get_y_transformed(touch_event, 1);
- notify_touch_normalized(device->touch_device, &time, slot,
- x, y, &norm, touch_type);
- } else {
- notify_touch(device->touch_device, &time, slot, x, y, touch_type);
- }
-}
-
-static void
-handle_touch_down(struct libinput_device *device,
- struct libinput_event_touch *touch_event)
-{
- handle_touch_with_coords(device, touch_event, WL_TOUCH_DOWN);
-}
-
-static void
-handle_touch_motion(struct libinput_device *device,
- struct libinput_event_touch *touch_event)
-{
- handle_touch_with_coords(device, touch_event, WL_TOUCH_MOTION);
-}
-
-static void
-handle_touch_up(struct libinput_device *libinput_device,
- struct libinput_event_touch *touch_event)
-{
- struct evdev_device *device =
- libinput_device_get_user_data(libinput_device);
- struct timespec time;
- int32_t slot = libinput_event_touch_get_seat_slot(touch_event);
-
- timespec_from_usec(&time,
- libinput_event_touch_get_time_usec(touch_event));
-
- notify_touch(device->touch_device, &time, slot, 0, 0, WL_TOUCH_UP);
-}
-
-static void
-handle_touch_frame(struct libinput_device *libinput_device,
- struct libinput_event_touch *touch_event)
-{
- struct evdev_device *device =
- libinput_device_get_user_data(libinput_device);
-
- notify_touch_frame(device->touch_device);
-}
-
-int
-evdev_device_process_event(struct libinput_event *event)
-{
- struct libinput_device *libinput_device =
- libinput_event_get_device(event);
- struct evdev_device *device =
- libinput_device_get_user_data(libinput_device);
- int handled = 1;
- bool need_frame = false;
-
- switch (libinput_event_get_type(event)) {
- case LIBINPUT_EVENT_KEYBOARD_KEY:
- handle_keyboard_key(libinput_device,
- libinput_event_get_keyboard_event(event));
- break;
- case LIBINPUT_EVENT_POINTER_MOTION:
- need_frame = handle_pointer_motion(libinput_device,
- libinput_event_get_pointer_event(event));
- break;
- case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
- need_frame = handle_pointer_motion_absolute(
- libinput_device,
- libinput_event_get_pointer_event(event));
- break;
- case LIBINPUT_EVENT_POINTER_BUTTON:
- need_frame = handle_pointer_button(libinput_device,
- libinput_event_get_pointer_event(event));
- break;
- case LIBINPUT_EVENT_POINTER_AXIS:
- need_frame = handle_pointer_axis(
- libinput_device,
- libinput_event_get_pointer_event(event));
- break;
- case LIBINPUT_EVENT_TOUCH_DOWN:
- handle_touch_down(libinput_device,
- libinput_event_get_touch_event(event));
- break;
- case LIBINPUT_EVENT_TOUCH_MOTION:
- handle_touch_motion(libinput_device,
- libinput_event_get_touch_event(event));
- break;
- case LIBINPUT_EVENT_TOUCH_UP:
- handle_touch_up(libinput_device,
- libinput_event_get_touch_event(event));
- break;
- case LIBINPUT_EVENT_TOUCH_FRAME:
- handle_touch_frame(libinput_device,
- libinput_event_get_touch_event(event));
- break;
- default:
- handled = 0;
- weston_log("unknown libinput event %d\n",
- libinput_event_get_type(event));
- }
-
- if (need_frame)
- notify_pointer_frame(device->seat);
-
- return handled;
-}
-
-static void
-notify_output_destroy(struct wl_listener *listener, void *data)
-{
- struct evdev_device *device =
- container_of(listener,
- struct evdev_device, output_destroy_listener);
-
- evdev_device_set_output(device, NULL);
-}
-
-/**
- * The WL_CALIBRATION property requires a pixel-specific matrix to be
- * applied after scaling device coordinates to screen coordinates. libinput
- * can't do that, so we need to convert the calibration to the normalized
- * format libinput expects.
- */
-void
-evdev_device_set_calibration(struct evdev_device *device)
-{
- struct udev *udev;
- struct udev_device *udev_device = NULL;
- const char *sysname = libinput_device_get_sysname(device->device);
- const char *calibration_values;
- uint32_t width, height;
- struct weston_touch_device_matrix calibration;
-
- if (!libinput_device_config_calibration_has_matrix(device->device))
- return;
-
- /* If LIBINPUT_CALIBRATION_MATRIX was set to non-identity, we will not
- * override it with WL_CALIBRATION. It also means we don't need an
- * output to load a calibration. */
- if (libinput_device_config_calibration_get_default_matrix(
- device->device,
- calibration.m) != 0)
- return;
-
- /* touch_set_calibration() has updated the values, do not load old
- * values from WL_CALIBRATION.
- */
- if (device->override_wl_calibration)
- return;
-
- if (!device->output) {
- weston_log("input device %s has no enabled output associated "
- "(%s named), skipping calibration for now.\n",
- sysname, device->output_name ?: "none");
- return;
- }
-
- width = device->output->width;
- height = device->output->height;
- if (width == 0 || height == 0)
- return;
-
- udev = udev_new();
- if (!udev)
- return;
-
- udev_device = udev_device_new_from_subsystem_sysname(udev,
- "input",
- sysname);
- if (!udev_device)
- goto out;
-
- calibration_values =
- udev_device_get_property_value(udev_device,
- "WL_CALIBRATION");
-
- if (calibration_values) {
- weston_log("Warning: input device %s has WL_CALIBRATION property set. "
- "Support for it will be removed in the future. "
- "Please use LIBINPUT_CALIBRATION_MATRIX instead.\n",
- sysname);
- }
-
- if (!calibration_values || sscanf(calibration_values,
- "%f %f %f %f %f %f",
- &calibration.m[0],
- &calibration.m[1],
- &calibration.m[2],
- &calibration.m[3],
- &calibration.m[4],
- &calibration.m[5]) != 6)
- goto out;
-
- /* normalize to a format libinput can use. There is a chance of
- this being wrong if the width/height don't match the device
- width/height but I'm not sure how to fix that */
- calibration.m[2] /= width;
- calibration.m[5] /= height;
-
- do_set_calibration(device, &calibration);
-
- weston_log_continue(STAMP_SPACE " raw translation %f %f for output %s\n",
- calibration.m[2] * width,
- calibration.m[5] * height,
- device->output->name);
-
-out:
- if (udev_device)
- udev_device_unref(udev_device);
- udev_unref(udev);
-}
-
-void
-evdev_device_set_output(struct evdev_device *device,
- struct weston_output *output)
-{
- if (device->output == output)
- return;
-
- if (device->output_destroy_listener.notify) {
- wl_list_remove(&device->output_destroy_listener.link);
- device->output_destroy_listener.notify = NULL;
- }
-
- if (!output) {
- weston_log("output for input device %s removed\n",
- libinput_device_get_sysname(device->device));
-
- device->output = NULL;
- return;
- }
-
- weston_log("associating input device %s with output %s "
- "(%s by udev)\n",
- libinput_device_get_sysname(device->device),
- output->name,
- device->output_name ?: "none");
-
- device->output = output;
- device->output_destroy_listener.notify = notify_output_destroy;
- wl_signal_add(&output->destroy_signal,
- &device->output_destroy_listener);
- evdev_device_set_calibration(device);
-}
-
-struct evdev_device *
-evdev_device_create(struct libinput_device *libinput_device,
- struct weston_seat *seat)
-{
- struct evdev_device *device;
-
- device = zalloc(sizeof *device);
- if (device == NULL)
- return NULL;
-
- device->seat = seat;
- wl_list_init(&device->link);
- device->device = libinput_device;
-
- if (libinput_device_has_capability(libinput_device,
- LIBINPUT_DEVICE_CAP_KEYBOARD)) {
- weston_seat_init_keyboard(seat, NULL);
- device->seat_caps |= EVDEV_SEAT_KEYBOARD;
- }
- if (libinput_device_has_capability(libinput_device,
- LIBINPUT_DEVICE_CAP_POINTER)) {
- weston_seat_init_pointer(seat);
- device->seat_caps |= EVDEV_SEAT_POINTER;
- }
- if (libinput_device_has_capability(libinput_device,
- LIBINPUT_DEVICE_CAP_TOUCH)) {
- weston_seat_init_touch(seat);
- device->seat_caps |= EVDEV_SEAT_TOUCH;
- device->touch_device = create_touch_device(device);
- }
-
- libinput_device_set_user_data(libinput_device, device);
- libinput_device_ref(libinput_device);
-
- return device;
-}
-
-void
-evdev_device_destroy(struct evdev_device *device)
-{
- if (device->seat_caps & EVDEV_SEAT_POINTER)
- weston_seat_release_pointer(device->seat);
- if (device->seat_caps & EVDEV_SEAT_KEYBOARD)
- weston_seat_release_keyboard(device->seat);
- if (device->seat_caps & EVDEV_SEAT_TOUCH) {
- weston_touch_device_destroy(device->touch_device);
- weston_seat_release_touch(device->seat);
- }
-
- if (device->output)
- wl_list_remove(&device->output_destroy_listener.link);
- wl_list_remove(&device->link);
- libinput_device_unref(device->device);
- free(device->output_name);
- free(device);
-}
-
-void
-evdev_notify_keyboard_focus(struct weston_seat *seat,
- struct wl_list *evdev_devices)
-{
- struct wl_array keys;
-
- if (seat->keyboard_device_count == 0)
- return;
-
- wl_array_init(&keys);
- notify_keyboard_focus_in(seat, &keys, STATE_UPDATE_AUTOMATIC);
- wl_array_release(&keys);
-}
diff --git a/libweston/libinput-device.h b/libweston/libinput-device.h
deleted file mode 100644
index d3fc645d..00000000
--- a/libweston/libinput-device.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright © 2011, 2012 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _LIBINPUT_DEVICE_H_
-#define _LIBINPUT_DEVICE_H_
-
-#include "config.h"
-
-#include <linux/input.h>
-#include <wayland-util.h>
-#include <libinput.h>
-#include <stdbool.h>
-
-#include <libweston/libweston.h>
-
-enum evdev_device_seat_capability {
- EVDEV_SEAT_POINTER = (1 << 0),
- EVDEV_SEAT_KEYBOARD = (1 << 1),
- EVDEV_SEAT_TOUCH = (1 << 2)
-};
-
-struct evdev_device {
- struct weston_seat *seat;
- enum evdev_device_seat_capability seat_caps;
- struct libinput_device *device;
- struct weston_touch_device *touch_device;
- struct wl_list link;
- struct weston_output *output;
- struct wl_listener output_destroy_listener;
- char *output_name;
- int fd;
- bool override_wl_calibration;
-};
-
-void
-evdev_led_update(struct evdev_device *device, enum weston_led leds);
-
-struct evdev_device *
-evdev_device_create(struct libinput_device *libinput_device,
- struct weston_seat *seat);
-
-int
-evdev_device_process_event(struct libinput_event *event);
-
-void
-evdev_device_set_output(struct evdev_device *device,
- struct weston_output *output);
-void
-evdev_device_destroy(struct evdev_device *device);
-
-void
-evdev_notify_keyboard_focus(struct weston_seat *seat,
- struct wl_list *evdev_devices);
-void
-evdev_device_set_calibration(struct evdev_device *device);
-
-int
-dispatch_libinput(struct libinput *libinput);
-
-#endif /* _LIBINPUT_DEVICE_H_ */
diff --git a/libweston/libinput-seat.c b/libweston/libinput-seat.c
deleted file mode 100644
index 98015518..00000000
--- a/libweston/libinput-seat.c
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * Copyright © 2013 Intel Corporation
- * Copyright © 2013 Jonas Ådahl
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <libinput.h>
-#include <libudev.h>
-
-#include <libweston/libweston.h>
-#include "backend.h"
-#include "libweston-internal.h"
-#include "weston-log-internal.h"
-#include "launcher-util.h"
-#include "libinput-seat.h"
-#include "libinput-device.h"
-#include "shared/helpers.h"
-
-static void
-process_events(struct udev_input *input);
-static struct udev_seat *
-udev_seat_create(struct udev_input *input, const char *seat_name);
-static void
-udev_seat_destroy(struct udev_seat *seat);
-
-static struct udev_seat *
-get_udev_seat(struct udev_input *input, struct libinput_device *device)
-{
- struct libinput_seat *libinput_seat;
- const char *seat_name;
-
- libinput_seat = libinput_device_get_seat(device);
- seat_name = libinput_seat_get_logical_name(libinput_seat);
- return udev_seat_get_named(input, seat_name);
-}
-
-static struct weston_output *
-output_find_by_head_name(struct weston_compositor *compositor,
- const char *head_name)
-{
- struct weston_output *output;
- struct weston_head *head;
-
- if (!head_name)
- return NULL;
-
- /* Only enabled outputs with connected heads.
- * This means force-enabled outputs but with disconnected heads
- * will be ignored; if the touchscreen doesn't have a video signal,
- * touching it is meaningless.
- */
- wl_list_for_each(output, &compositor->output_list, link) {
- wl_list_for_each(head, &output->head_list, output_link) {
- if (!weston_head_is_connected(head))
- continue;
-
- if (strcmp(head_name, head->name) == 0)
- return output;
- }
- }
-
- return NULL;
-}
-
-static void
-device_added(struct udev_input *input, struct libinput_device *libinput_device)
-{
- struct weston_compositor *c;
- struct evdev_device *device;
- struct weston_output *output;
- const char *output_name;
- struct weston_seat *seat;
- struct udev_seat *udev_seat;
- struct weston_pointer *pointer;
-
- c = input->compositor;
-
- udev_seat = get_udev_seat(input, libinput_device);
- if (!udev_seat)
- return;
-
- seat = &udev_seat->base;
- device = evdev_device_create(libinput_device, seat);
- if (device == NULL)
- return;
-
- if (input->configure_device != NULL)
- input->configure_device(c, device->device);
- evdev_device_set_calibration(device);
- udev_seat = (struct udev_seat *) seat;
- wl_list_insert(udev_seat->devices_list.prev, &device->link);
-
- pointer = weston_seat_get_pointer(seat);
- if (seat->output && pointer)
- weston_pointer_clamp(pointer,
- &pointer->x,
- &pointer->y);
-
- output_name = libinput_device_get_output_name(libinput_device);
- if (output_name) {
- device->output_name = strdup(output_name);
- output = output_find_by_head_name(c, output_name);
- evdev_device_set_output(device, output);
- } else if (!wl_list_empty(&c->output_list)) {
- /* default assignment to an arbitrary output */
- output = container_of(c->output_list.next,
- struct weston_output, link);
- evdev_device_set_output(device, output);
- }
-
- if (!input->suspended)
- weston_seat_repick(seat);
-}
-
-static void
-device_removed(struct udev_input *input, struct libinput_device *libinput_device)
-{
- struct evdev_device *device;
-
- device = libinput_device_get_user_data(libinput_device);
- evdev_device_destroy(device);
-}
-
-static void
-udev_seat_remove_devices(struct udev_seat *seat)
-{
- struct evdev_device *device, *next;
-
- wl_list_for_each_safe(device, next, &seat->devices_list, link) {
- evdev_device_destroy(device);
- }
-}
-
-void
-udev_input_disable(struct udev_input *input)
-{
- if (input->suspended)
- return;
-
- wl_event_source_remove(input->libinput_source);
- input->libinput_source = NULL;
- libinput_suspend(input->libinput);
- process_events(input);
- input->suspended = 1;
-}
-
-static int
-udev_input_process_event(struct libinput_event *event)
-{
- struct libinput *libinput = libinput_event_get_context(event);
- struct libinput_device *libinput_device =
- libinput_event_get_device(event);
- struct udev_input *input = libinput_get_user_data(libinput);
- int handled = 1;
-
- switch (libinput_event_get_type(event)) {
- case LIBINPUT_EVENT_DEVICE_ADDED:
- device_added(input, libinput_device);
- break;
- case LIBINPUT_EVENT_DEVICE_REMOVED:
- device_removed(input, libinput_device);
- break;
- default:
- handled = 0;
- }
-
- return handled;
-}
-
-static void
-process_event(struct libinput_event *event)
-{
- if (udev_input_process_event(event))
- return;
- if (evdev_device_process_event(event))
- return;
-}
-
-static void
-process_events(struct udev_input *input)
-{
- struct libinput_event *event;
-
- while ((event = libinput_get_event(input->libinput))) {
- process_event(event);
- libinput_event_destroy(event);
- }
-}
-
-static int
-udev_input_dispatch(struct udev_input *input)
-{
- if (libinput_dispatch(input->libinput) != 0)
- weston_log("libinput: Failed to dispatch libinput\n");
-
- process_events(input);
-
- return 0;
-}
-
-static int
-libinput_source_dispatch(int fd, uint32_t mask, void *data)
-{
- struct udev_input *input = data;
-
- return udev_input_dispatch(input) != 0;
-}
-
-static int
-open_restricted(const char *path, int flags, void *user_data)
-{
- struct udev_input *input = user_data;
- struct weston_launcher *launcher = input->compositor->launcher;
-
- return weston_launcher_open(launcher, path, flags);
-}
-
-static void
-close_restricted(int fd, void *user_data)
-{
- struct udev_input *input = user_data;
- struct weston_launcher *launcher = input->compositor->launcher;
-
- weston_launcher_close(launcher, fd);
-}
-
-const struct libinput_interface libinput_interface = {
- open_restricted,
- close_restricted,
-};
-
-int
-udev_input_enable(struct udev_input *input)
-{
- struct wl_event_loop *loop;
- struct weston_compositor *c = input->compositor;
- int fd;
- struct udev_seat *seat;
- int devices_found = 0;
-
- loop = wl_display_get_event_loop(c->wl_display);
- fd = libinput_get_fd(input->libinput);
- input->libinput_source =
- wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
- libinput_source_dispatch, input);
- if (!input->libinput_source) {
- return -1;
- }
-
- if (input->suspended) {
- if (libinput_resume(input->libinput) != 0) {
- wl_event_source_remove(input->libinput_source);
- input->libinput_source = NULL;
- return -1;
- }
- input->suspended = 0;
- process_events(input);
- }
-
- wl_list_for_each(seat, &input->compositor->seat_list, base.link) {
- evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
-
- if (!wl_list_empty(&seat->devices_list))
- devices_found = 1;
- }
-
- if (devices_found == 0 && !c->require_input) {
- weston_log("warning: no input devices found, but none required "
- "as per configuration.\n");
- return 0;
- }
-
- if (devices_found == 0) {
- weston_log(
- "warning: no input devices on entering Weston. "
- "Possible causes:\n"
- "\t- no permissions to read /dev/input/event*\n"
- "\t- seats misconfigured "
- "(Weston backend option 'seat', "
- "udev device property ID_SEAT)\n");
- return -1;
- }
-
- return 0;
-}
-
-static void
-libinput_log_func(struct libinput *libinput,
- enum libinput_log_priority priority,
- const char *format, va_list args)
-{
- weston_vlog(format, args);
-}
-
-int
-udev_input_init(struct udev_input *input, struct weston_compositor *c,
- struct udev *udev, const char *seat_id,
- udev_configure_device_t configure_device)
-{
- enum libinput_log_priority priority = LIBINPUT_LOG_PRIORITY_INFO;
- const char *log_priority = NULL;
-
- memset(input, 0, sizeof *input);
-
- input->compositor = c;
- input->configure_device = configure_device;
-
- log_priority = getenv("WESTON_LIBINPUT_LOG_PRIORITY");
-
- input->libinput = libinput_udev_create_context(&libinput_interface,
- input, udev);
- if (!input->libinput) {
- return -1;
- }
-
- libinput_log_set_handler(input->libinput, &libinput_log_func);
-
- if (log_priority) {
- if (strcmp(log_priority, "debug") == 0) {
- priority = LIBINPUT_LOG_PRIORITY_DEBUG;
- } else if (strcmp(log_priority, "info") == 0) {
- priority = LIBINPUT_LOG_PRIORITY_INFO;
- } else if (strcmp(log_priority, "error") == 0) {
- priority = LIBINPUT_LOG_PRIORITY_ERROR;
- }
- }
-
- libinput_log_set_priority(input->libinput, priority);
-
- if (libinput_udev_assign_seat(input->libinput, seat_id) != 0) {
- libinput_unref(input->libinput);
- return -1;
- }
-
- process_events(input);
-
- return udev_input_enable(input);
-}
-
-void
-udev_input_destroy(struct udev_input *input)
-{
- struct udev_seat *seat, *next;
-
- if (input->libinput_source)
- wl_event_source_remove(input->libinput_source);
- wl_list_for_each_safe(seat, next, &input->compositor->seat_list, base.link)
- udev_seat_destroy(seat);
- libinput_unref(input->libinput);
-}
-
-static void
-udev_seat_led_update(struct weston_seat *seat_base, enum weston_led leds)
-{
- struct udev_seat *seat = (struct udev_seat *) seat_base;
- struct evdev_device *device;
-
- wl_list_for_each(device, &seat->devices_list, link)
- evdev_led_update(device, leds);
-}
-
-static void
-udev_seat_output_changed(struct udev_seat *seat, struct weston_output *output)
-{
- struct evdev_device *device;
- struct weston_output *found;
-
- wl_list_for_each(device, &seat->devices_list, link) {
- /* If we find any input device without an associated output
- * or an output name to associate with, just tie it with the
- * output we got here - the default assignment.
- */
- if (!device->output_name) {
- if (!device->output)
- evdev_device_set_output(device, output);
-
- continue;
- }
-
- /* Update all devices' output associations, may they gain or
- * lose it.
- */
- found = output_find_by_head_name(output->compositor,
- device->output_name);
- evdev_device_set_output(device, found);
- }
-}
-
-static void
-notify_output_create(struct wl_listener *listener, void *data)
-{
- struct udev_seat *seat = container_of(listener, struct udev_seat,
- output_create_listener);
- struct weston_output *output = data;
-
- udev_seat_output_changed(seat, output);
-}
-
-static void
-notify_output_heads_changed(struct wl_listener *listener, void *data)
-{
- struct udev_seat *seat = container_of(listener, struct udev_seat,
- output_heads_listener);
- struct weston_output *output = data;
-
- udev_seat_output_changed(seat, output);
-}
-
-static struct udev_seat *
-udev_seat_create(struct udev_input *input, const char *seat_name)
-{
- struct weston_compositor *c = input->compositor;
- struct udev_seat *seat;
-
- seat = zalloc(sizeof *seat);
- if (!seat)
- return NULL;
-
- weston_seat_init(&seat->base, c, seat_name);
- seat->base.led_update = udev_seat_led_update;
-
- seat->output_create_listener.notify = notify_output_create;
- wl_signal_add(&c->output_created_signal,
- &seat->output_create_listener);
-
- seat->output_heads_listener.notify = notify_output_heads_changed;
- wl_signal_add(&c->output_heads_changed_signal,
- &seat->output_heads_listener);
-
- wl_list_init(&seat->devices_list);
-
- return seat;
-}
-
-static void
-udev_seat_destroy(struct udev_seat *seat)
-{
- struct weston_keyboard *keyboard =
- weston_seat_get_keyboard(&seat->base);
-
- if (keyboard)
- notify_keyboard_focus_out(&seat->base);
-
- udev_seat_remove_devices(seat);
- weston_seat_release(&seat->base);
- wl_list_remove(&seat->output_create_listener.link);
- wl_list_remove(&seat->output_heads_listener.link);
- free(seat);
-}
-
-struct udev_seat *
-udev_seat_get_named(struct udev_input *input, const char *seat_name)
-{
- struct udev_seat *seat;
-
- wl_list_for_each(seat, &input->compositor->seat_list, base.link) {
- if (strcmp(seat->base.seat_name, seat_name) == 0)
- return seat;
- }
-
- return udev_seat_create(input, seat_name);
-}
diff --git a/libweston/libinput-seat.h b/libweston/libinput-seat.h
deleted file mode 100644
index 315980dc..00000000
--- a/libweston/libinput-seat.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright © 2013 Intel Corporation
- * Copyright © 2013 Jonas Ådahl
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _LIBINPUT_SEAT_H_
-#define _LIBINPUT_SEAT_H_
-
-#include "config.h"
-
-#include <libudev.h>
-
-#include <libweston/libweston.h>
-
-struct libinput_device;
-
-struct udev_seat {
- struct weston_seat base;
- struct wl_list devices_list;
- struct wl_listener output_create_listener;
- struct wl_listener output_heads_listener;
-};
-
-typedef void (*udev_configure_device_t)(struct weston_compositor *compositor,
- struct libinput_device *device);
-
-struct udev_input {
- struct libinput *libinput;
- struct wl_event_source *libinput_source;
- struct weston_compositor *compositor;
- int suspended;
- udev_configure_device_t configure_device;
-};
-
-int
-udev_input_enable(struct udev_input *input);
-void
-udev_input_disable(struct udev_input *input);
-int
-udev_input_init(struct udev_input *input,
- struct weston_compositor *c,
- struct udev *udev,
- const char *seat_id,
- udev_configure_device_t configure_device);
-void
-udev_input_destroy(struct udev_input *input);
-
-struct udev_seat *
-udev_seat_get_named(struct udev_input *u,
- const char *seat_name);
-
-#endif
diff --git a/libweston/libweston-internal.h b/libweston/libweston-internal.h
deleted file mode 100644
index 66c38e86..00000000
--- a/libweston/libweston-internal.h
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2017, 2018 General Electric Company
- * Copyright © 2012, 2017-2019 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef LIBWESTON_INTERNAL_H
-#define LIBWESTON_INTERNAL_H
-
-/*
- * This is the internal (private) part of libweston. All symbols found here
- * are, and should be only (with a few exceptions) used within the internal
- * parts of libweston. Notable exception(s) include a few files in tests/ that
- * need access to these functions, screen-share file from compositor/ and those
- * remoting/. Those will require some further fixing as to avoid including this
- * private header.
- *
- * Eventually, these symbols should reside naturally into their own scope. New
- * features should either provide their own (internal) header or use this one.
- */
-
-
-/* weston_buffer */
-
-void
-weston_buffer_send_server_error(struct weston_buffer *buffer,
- const char *msg);
-void
-weston_buffer_reference(struct weston_buffer_reference *ref,
- struct weston_buffer *buffer);
-
-void
-weston_buffer_release_move(struct weston_buffer_release_reference *dest,
- struct weston_buffer_release_reference *src);
-
-void
-weston_buffer_release_reference(struct weston_buffer_release_reference *ref,
- struct weston_buffer_release *buf_release);
-
-/* weston_bindings */
-void
-weston_binding_list_destroy_all(struct wl_list *list);
-
-/* weston_compositor */
-
-void
-touch_calibrator_mode_changed(struct weston_compositor *compositor);
-
-int
-noop_renderer_init(struct weston_compositor *ec);
-
-void
-weston_compositor_add_head(struct weston_compositor *compositor,
- struct weston_head *head);
-void
-weston_compositor_add_pending_output(struct weston_output *output,
- struct weston_compositor *compositor);
-bool
-weston_compositor_import_dmabuf(struct weston_compositor *compositor,
- struct linux_dmabuf_buffer *buffer);
-bool
-weston_compositor_dmabuf_can_scanout(struct weston_compositor *compositor,
- struct linux_dmabuf_buffer *buffer);
-void
-weston_compositor_offscreen(struct weston_compositor *compositor);
-
-char *
-weston_compositor_print_scene_graph(struct weston_compositor *ec);
-
-void
-weston_compositor_read_presentation_clock(
- const struct weston_compositor *compositor,
- struct timespec *ts);
-
-int
-weston_compositor_run_axis_binding(struct weston_compositor *compositor,
- struct weston_pointer *pointer,
- const struct timespec *time,
- struct weston_pointer_axis_event *event);
-void
-weston_compositor_run_button_binding(struct weston_compositor *compositor,
- struct weston_pointer *pointer,
- const struct timespec *time,
- uint32_t button,
- enum wl_pointer_button_state value);
-int
-weston_compositor_run_debug_binding(struct weston_compositor *compositor,
- struct weston_keyboard *keyboard,
- const struct timespec *time,
- uint32_t key,
- enum wl_keyboard_key_state state);
-void
-weston_compositor_run_key_binding(struct weston_compositor *compositor,
- struct weston_keyboard *keyboard,
- const struct timespec *time,
- uint32_t key,
- enum wl_keyboard_key_state state);
-void
-weston_compositor_run_modifier_binding(struct weston_compositor *compositor,
- struct weston_keyboard *keyboard,
- enum weston_keyboard_modifier modifier,
- enum wl_keyboard_key_state state);
-void
-weston_compositor_run_touch_binding(struct weston_compositor *compositor,
- struct weston_touch *touch,
- const struct timespec *time,
- int touch_type);
-void
-weston_compositor_stack_plane(struct weston_compositor *ec,
- struct weston_plane *plane,
- struct weston_plane *above);
-void
-weston_compositor_set_touch_mode_normal(struct weston_compositor *compositor);
-
-void
-weston_compositor_set_touch_mode_calib(struct weston_compositor *compositor);
-
-int
-weston_compositor_set_presentation_clock(struct weston_compositor *compositor,
- clockid_t clk_id);
-int
-weston_compositor_set_presentation_clock_software(
- struct weston_compositor *compositor);
-void
-weston_compositor_shutdown(struct weston_compositor *ec);
-
-void
-weston_compositor_xkb_destroy(struct weston_compositor *ec);
-
-int
-weston_input_init(struct weston_compositor *compositor);
-
-/* weston_output */
-
-void
-weston_output_disable_planes_incr(struct weston_output *output);
-
-void
-weston_output_disable_planes_decr(struct weston_output *output);
-
-/* weston_plane */
-
-void
-weston_plane_init(struct weston_plane *plane,
- struct weston_compositor *ec,
- int32_t x, int32_t y);
-void
-weston_plane_release(struct weston_plane *plane);
-
-/* weston_seat */
-
-struct clipboard *
-clipboard_create(struct weston_seat *seat);
-
-void
-weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec,
- const char *seat_name);
-
-void
-weston_seat_repick(struct weston_seat *seat);
-
-void
-weston_seat_release(struct weston_seat *seat);
-
-void
-weston_seat_send_selection(struct weston_seat *seat, struct wl_client *client);
-
-void
-weston_seat_init_pointer(struct weston_seat *seat);
-
-int
-weston_seat_init_keyboard(struct weston_seat *seat, struct xkb_keymap *keymap);
-
-void
-weston_seat_init_touch(struct weston_seat *seat);
-
-void
-weston_seat_release_keyboard(struct weston_seat *seat);
-
-void
-weston_seat_release_pointer(struct weston_seat *seat);
-
-void
-weston_seat_release_touch(struct weston_seat *seat);
-
-void
-weston_seat_update_keymap(struct weston_seat *seat, struct xkb_keymap *keymap);
-
-void
-wl_data_device_set_keyboard_focus(struct weston_seat *seat);
-
-/* weston_pointer */
-
-void
-weston_pointer_clamp(struct weston_pointer *pointer,
- wl_fixed_t *fx, wl_fixed_t *fy);
-void
-weston_pointer_set_default_grab(struct weston_pointer *pointer,
- const struct weston_pointer_grab_interface *interface);
-
-void
-weston_pointer_constraint_destroy(struct weston_pointer_constraint *constraint);
-
-/* weston_keyboard */
-bool
-weston_keyboard_has_focus_resource(struct weston_keyboard *keyboard);
-
-/* weston_touch */
-
-struct weston_touch_device *
-weston_touch_create_touch_device(struct weston_touch *touch,
- const char *syspath,
- void *backend_data,
- const struct weston_touch_device_ops *ops);
-
-void
-weston_touch_device_destroy(struct weston_touch_device *device);
-
-bool
-weston_touch_has_focus_resource(struct weston_touch *touch);
-
-int
-weston_touch_start_drag(struct weston_touch *touch,
- struct weston_data_source *source,
- struct weston_surface *icon,
- struct wl_client *client);
-
-
-/* weston_touch_device */
-
-bool
-weston_touch_device_can_calibrate(struct weston_touch_device *device);
-
-/* weston_surface */
-void
-weston_surface_to_buffer_float(struct weston_surface *surface,
- float x, float y, float *bx, float *by);
-pixman_box32_t
-weston_surface_to_buffer_rect(struct weston_surface *surface,
- pixman_box32_t rect);
-
-void
-weston_surface_to_buffer_region(struct weston_surface *surface,
- pixman_region32_t *surface_region,
- pixman_region32_t *buffer_region);
-void
-weston_surface_schedule_repaint(struct weston_surface *surface);
-
-/* weston_spring */
-
-void
-weston_spring_init(struct weston_spring *spring,
- double k, double current, double target);
-int
-weston_spring_done(struct weston_spring *spring);
-
-void
-weston_spring_update(struct weston_spring *spring, const struct timespec *time);
-
-/* weston_view */
-
-void
-weston_view_to_global_fixed(struct weston_view *view,
- wl_fixed_t sx, wl_fixed_t sy,
- wl_fixed_t *x, wl_fixed_t *y);
-void
-weston_view_from_global_float(struct weston_view *view,
- float x, float y, float *vx, float *vy);
-bool
-weston_view_is_opaque(struct weston_view *ev, pixman_region32_t *region);
-
-bool
-weston_view_has_valid_buffer(struct weston_view *ev);
-
-bool
-weston_view_matches_output_entirely(struct weston_view *ev,
- struct weston_output *output);
-void
-weston_view_move_to_plane(struct weston_view *view,
- struct weston_plane *plane);
-
-void
-weston_transformed_coord(int width, int height,
- enum wl_output_transform transform,
- int32_t scale,
- float sx, float sy, float *bx, float *by);
-pixman_box32_t
-weston_transformed_rect(int width, int height,
- enum wl_output_transform transform,
- int32_t scale,
- pixman_box32_t rect);
-void
-weston_transformed_region(int width, int height,
- enum wl_output_transform transform,
- int32_t scale,
- pixman_region32_t *src, pixman_region32_t *dest);
-void
-weston_matrix_transform_region(pixman_region32_t *dest,
- struct weston_matrix *matrix,
- pixman_region32_t *src);
-
-/* protected_surface */
-void
-weston_protected_surface_send_event(struct protected_surface *psurface,
- enum weston_hdcp_protection protection);
-
-/* others */
-int
-wl_data_device_manager_init(struct wl_display *display);
-
-#endif
diff --git a/libweston/linux-dmabuf.c b/libweston/linux-dmabuf.c
deleted file mode 100644
index 796e9826..00000000
--- a/libweston/linux-dmabuf.c
+++ /dev/null
@@ -1,591 +0,0 @@
-/*
- * Copyright © 2014, 2015 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <sys/types.h>
-
-#include <libweston/libweston.h>
-#include "linux-dmabuf.h"
-#include "linux-dmabuf-unstable-v1-server-protocol.h"
-#include "libweston-internal.h"
-
-static void
-linux_dmabuf_buffer_destroy(struct linux_dmabuf_buffer *buffer)
-{
- int i;
-
- for (i = 0; i < buffer->attributes.n_planes; i++) {
- close(buffer->attributes.fd[i]);
- buffer->attributes.fd[i] = -1;
- }
-
- buffer->attributes.n_planes = 0;
- free(buffer);
-}
-
-static void
-destroy_params(struct wl_resource *params_resource)
-{
- struct linux_dmabuf_buffer *buffer;
-
- buffer = wl_resource_get_user_data(params_resource);
-
- if (!buffer)
- return;
-
- linux_dmabuf_buffer_destroy(buffer);
-}
-
-static void
-params_destroy(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-params_add(struct wl_client *client,
- struct wl_resource *params_resource,
- int32_t name_fd,
- uint32_t plane_idx,
- uint32_t offset,
- uint32_t stride,
- uint32_t modifier_hi,
- uint32_t modifier_lo)
-{
- struct linux_dmabuf_buffer *buffer;
-
- buffer = wl_resource_get_user_data(params_resource);
- if (!buffer) {
- wl_resource_post_error(params_resource,
- ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
- "params was already used to create a wl_buffer");
- close(name_fd);
- return;
- }
-
- assert(buffer->params_resource == params_resource);
- assert(!buffer->buffer_resource);
-
- if (plane_idx >= MAX_DMABUF_PLANES) {
- wl_resource_post_error(params_resource,
- ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
- "plane index %u is too high", plane_idx);
- close(name_fd);
- return;
- }
-
- if (buffer->attributes.fd[plane_idx] != -1) {
- wl_resource_post_error(params_resource,
- ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
- "a dmabuf has already been added for plane %u",
- plane_idx);
- close(name_fd);
- return;
- }
-
- buffer->attributes.fd[plane_idx] = name_fd;
- buffer->attributes.offset[plane_idx] = offset;
- buffer->attributes.stride[plane_idx] = stride;
-
- if (wl_resource_get_version(params_resource) < ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION)
- buffer->attributes.modifier[plane_idx] = DRM_FORMAT_MOD_INVALID;
- else
- buffer->attributes.modifier[plane_idx] = ((uint64_t)modifier_hi << 32) |
- modifier_lo;
-
- buffer->attributes.n_planes++;
-}
-
-static void
-linux_dmabuf_wl_buffer_destroy(struct wl_client *client,
- struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static const struct wl_buffer_interface linux_dmabuf_buffer_implementation = {
- linux_dmabuf_wl_buffer_destroy
-};
-
-static void
-destroy_linux_dmabuf_wl_buffer(struct wl_resource *resource)
-{
- struct linux_dmabuf_buffer *buffer;
-
- buffer = wl_resource_get_user_data(resource);
- assert(buffer->buffer_resource == resource);
- assert(!buffer->params_resource);
-
- if (buffer->user_data_destroy_func)
- buffer->user_data_destroy_func(buffer);
-
- linux_dmabuf_buffer_destroy(buffer);
-}
-
-static void
-params_create_common(struct wl_client *client,
- struct wl_resource *params_resource,
- uint32_t buffer_id,
- int32_t width,
- int32_t height,
- uint32_t format,
- uint32_t flags)
-{
- struct linux_dmabuf_buffer *buffer;
- int i;
-
- buffer = wl_resource_get_user_data(params_resource);
-
- if (!buffer) {
- wl_resource_post_error(params_resource,
- ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
- "params was already used to create a wl_buffer");
- return;
- }
-
- assert(buffer->params_resource == params_resource);
- assert(!buffer->buffer_resource);
-
- /* Switch the linux_dmabuf_buffer object from params resource to
- * eventually wl_buffer resource.
- */
- wl_resource_set_user_data(buffer->params_resource, NULL);
- buffer->params_resource = NULL;
-
- if (!buffer->attributes.n_planes) {
- wl_resource_post_error(params_resource,
- ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
- "no dmabuf has been added to the params");
- goto err_out;
- }
-
- /* Check for holes in the dmabufs set (e.g. [0, 1, 3]) */
- for (i = 0; i < buffer->attributes.n_planes; i++) {
- if (buffer->attributes.fd[i] == -1) {
- wl_resource_post_error(params_resource,
- ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
- "no dmabuf has been added for plane %i", i);
- goto err_out;
- }
- }
-
- buffer->attributes.width = width;
- buffer->attributes.height = height;
- buffer->attributes.format = format;
- buffer->attributes.flags = flags;
-
- if (width < 1 || height < 1) {
- wl_resource_post_error(params_resource,
- ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
- "invalid width %d or height %d", width, height);
- goto err_out;
- }
-
- for (i = 0; i < buffer->attributes.n_planes; i++) {
- off_t size;
-
- if ((uint64_t) buffer->attributes.offset[i] + buffer->attributes.stride[i] > UINT32_MAX) {
- wl_resource_post_error(params_resource,
- ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
- "size overflow for plane %i", i);
- goto err_out;
- }
-
- if (i == 0 &&
- (uint64_t) buffer->attributes.offset[i] +
- (uint64_t) buffer->attributes.stride[i] * height > UINT32_MAX) {
- wl_resource_post_error(params_resource,
- ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
- "size overflow for plane %i", i);
- goto err_out;
- }
-
- /* Don't report an error as it might be caused
- * by the kernel not supporting seeking on dmabuf */
- size = lseek(buffer->attributes.fd[i], 0, SEEK_END);
- if (size == -1)
- continue;
-
- if (buffer->attributes.offset[i] >= size) {
- wl_resource_post_error(params_resource,
- ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
- "invalid offset %i for plane %i",
- buffer->attributes.offset[i], i);
- goto err_out;
- }
-
- if (buffer->attributes.offset[i] + buffer->attributes.stride[i] > size) {
- wl_resource_post_error(params_resource,
- ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
- "invalid stride %i for plane %i",
- buffer->attributes.stride[i], i);
- goto err_out;
- }
-
- /* Only valid for first plane as other planes might be
- * sub-sampled according to fourcc format */
- if (i == 0 &&
- buffer->attributes.offset[i] + buffer->attributes.stride[i] * height > size) {
- wl_resource_post_error(params_resource,
- ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
- "invalid buffer stride or height for plane %i", i);
- goto err_out;
- }
- }
-
- if (buffer->direct_display) {
- if (!weston_compositor_dmabuf_can_scanout(buffer->compositor,
- buffer))
- goto err_failed;
-
- goto avoid_gpu_import;
- }
-
- if (!weston_compositor_import_dmabuf(buffer->compositor, buffer))
- goto err_failed;
-
-avoid_gpu_import:
- buffer->buffer_resource = wl_resource_create(client,
- &wl_buffer_interface,
- 1, buffer_id);
- if (!buffer->buffer_resource) {
- wl_resource_post_no_memory(params_resource);
- goto err_buffer;
- }
-
- wl_resource_set_implementation(buffer->buffer_resource,
- &linux_dmabuf_buffer_implementation,
- buffer, destroy_linux_dmabuf_wl_buffer);
-
- /* send 'created' event when the request is not for an immediate
- * import, ie buffer_id is zero */
- if (buffer_id == 0)
- zwp_linux_buffer_params_v1_send_created(params_resource,
- buffer->buffer_resource);
-
- return;
-
-err_buffer:
- if (buffer->user_data_destroy_func)
- buffer->user_data_destroy_func(buffer);
-
-err_failed:
- if (buffer_id == 0)
- zwp_linux_buffer_params_v1_send_failed(params_resource);
- else
- /* since the behavior is left implementation defined by the
- * protocol in case of create_immed failure due to an unknown cause,
- * we choose to treat it as a fatal error and immediately kill the
- * client instead of creating an invalid handle and waiting for it
- * to be used.
- */
- wl_resource_post_error(params_resource,
- ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
- "importing the supplied dmabufs failed");
-
-err_out:
- linux_dmabuf_buffer_destroy(buffer);
-}
-
-static void
-params_create(struct wl_client *client,
- struct wl_resource *params_resource,
- int32_t width,
- int32_t height,
- uint32_t format,
- uint32_t flags)
-{
- params_create_common(client, params_resource, 0, width, height, format,
- flags);
-}
-
-static void
-params_create_immed(struct wl_client *client,
- struct wl_resource *params_resource,
- uint32_t buffer_id,
- int32_t width,
- int32_t height,
- uint32_t format,
- uint32_t flags)
-{
- params_create_common(client, params_resource, buffer_id, width, height,
- format, flags);
-}
-
-static const struct zwp_linux_buffer_params_v1_interface
-zwp_linux_buffer_params_implementation = {
- params_destroy,
- params_add,
- params_create,
- params_create_immed
-};
-
-static void
-linux_dmabuf_destroy(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-linux_dmabuf_create_params(struct wl_client *client,
- struct wl_resource *linux_dmabuf_resource,
- uint32_t params_id)
-{
- struct weston_compositor *compositor;
- struct linux_dmabuf_buffer *buffer;
- uint32_t version;
- int i;
-
- version = wl_resource_get_version(linux_dmabuf_resource);
- compositor = wl_resource_get_user_data(linux_dmabuf_resource);
-
- buffer = zalloc(sizeof *buffer);
- if (!buffer)
- goto err_out;
-
- for (i = 0; i < MAX_DMABUF_PLANES; i++)
- buffer->attributes.fd[i] = -1;
-
- buffer->compositor = compositor;
- buffer->params_resource =
- wl_resource_create(client,
- &zwp_linux_buffer_params_v1_interface,
- version, params_id);
- buffer->direct_display = false;
- if (!buffer->params_resource)
- goto err_dealloc;
-
- wl_resource_set_implementation(buffer->params_resource,
- &zwp_linux_buffer_params_implementation,
- buffer, destroy_params);
-
- return;
-
-err_dealloc:
- free(buffer);
-
-err_out:
- wl_resource_post_no_memory(linux_dmabuf_resource);
-}
-
-/** Get the linux_dmabuf_buffer from a wl_buffer resource
- *
- * If the given wl_buffer resource was created through the linux_dmabuf
- * protocol interface, returns the linux_dmabuf_buffer object. This can
- * be used as a type check for a wl_buffer.
- *
- * \param resource A wl_buffer resource.
- * \return The linux_dmabuf_buffer if it exists, or NULL otherwise.
- */
-WL_EXPORT struct linux_dmabuf_buffer *
-linux_dmabuf_buffer_get(struct wl_resource *resource)
-{
- struct linux_dmabuf_buffer *buffer;
-
- if (!resource)
- return NULL;
-
- if (!wl_resource_instance_of(resource, &wl_buffer_interface,
- &linux_dmabuf_buffer_implementation))
- return NULL;
-
- buffer = wl_resource_get_user_data(resource);
- assert(buffer);
- assert(!buffer->params_resource);
- assert(buffer->buffer_resource == resource);
-
- return buffer;
-}
-
-/** Set renderer-private data
- *
- * Set the user data for the linux_dmabuf_buffer. It is invalid to overwrite
- * a non-NULL user data with a new non-NULL pointer. This is meant to
- * protect against renderers fighting over linux_dmabuf_buffer user data
- * ownership.
- *
- * The renderer-private data is usually set from the
- * weston_renderer::import_dmabuf hook.
- *
- * \param buffer The linux_dmabuf_buffer object to set for.
- * \param data The new renderer-private data pointer.
- * \param func Destructor function to be called for the renderer-private
- * data when the linux_dmabuf_buffer gets destroyed.
- *
- * \sa weston_compositor_import_dmabuf
- */
-WL_EXPORT void
-linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
- void *data,
- dmabuf_user_data_destroy_func func)
-{
- assert(data == NULL || buffer->user_data == NULL);
-
- buffer->user_data = data;
- buffer->user_data_destroy_func = func;
-}
-
-/** Get renderer-private data
- *
- * Get the user data from the linux_dmabuf_buffer.
- *
- * \param buffer The linux_dmabuf_buffer to query.
- * \return Renderer-private data pointer.
- *
- * \sa linux_dmabuf_buffer_set_user_data
- */
-WL_EXPORT void *
-linux_dmabuf_buffer_get_user_data(struct linux_dmabuf_buffer *buffer)
-{
- return buffer->user_data;
-}
-
-static const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_implementation = {
- linux_dmabuf_destroy,
- linux_dmabuf_create_params
-};
-
-static void
-bind_linux_dmabuf(struct wl_client *client,
- void *data, uint32_t version, uint32_t id)
-{
- struct weston_compositor *compositor = data;
- struct wl_resource *resource;
- int *formats = NULL;
- uint64_t *modifiers = NULL;
- int num_formats, num_modifiers;
- uint64_t modifier_invalid = DRM_FORMAT_MOD_INVALID;
- int i, j;
-
- resource = wl_resource_create(client, &zwp_linux_dmabuf_v1_interface,
- version, id);
- if (resource == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_resource_set_implementation(resource, &linux_dmabuf_implementation,
- compositor, NULL);
-
- /*
- * Use EGL_EXT_image_dma_buf_import_modifiers to query and advertise
- * format/modifier codes.
- */
- compositor->renderer->query_dmabuf_formats(compositor, &formats,
- &num_formats);
-
- for (i = 0; i < num_formats; i++) {
- compositor->renderer->query_dmabuf_modifiers(compositor,
- formats[i],
- &modifiers,
- &num_modifiers);
-
- /* send DRM_FORMAT_MOD_INVALID token when no modifiers are supported
- * for this format */
- if (num_modifiers == 0) {
- num_modifiers = 1;
- modifiers = &modifier_invalid;
- }
- for (j = 0; j < num_modifiers; j++) {
- if (version >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) {
- uint32_t modifier_lo = modifiers[j] & 0xFFFFFFFF;
- uint32_t modifier_hi = modifiers[j] >> 32;
- zwp_linux_dmabuf_v1_send_modifier(resource,
- formats[i],
- modifier_hi,
- modifier_lo);
- } else if (modifiers[j] == DRM_FORMAT_MOD_LINEAR ||
- modifiers == &modifier_invalid) {
- zwp_linux_dmabuf_v1_send_format(resource,
- formats[i]);
- }
- }
- if (modifiers != &modifier_invalid)
- free(modifiers);
- }
- free(formats);
-}
-
-/** Advertise linux_dmabuf support
- *
- * Calling this initializes the zwp_linux_dmabuf protocol support, so that
- * the interface will be advertised to clients. Essentially it creates a
- * global. Do not call this function multiple times in the compositor's
- * lifetime. There is no way to deinit explicitly, globals will be reaped
- * when the wl_display gets destroyed.
- *
- * \param compositor The compositor to init for.
- * \return Zero on success, -1 on failure.
- */
-WL_EXPORT int
-linux_dmabuf_setup(struct weston_compositor *compositor)
-{
- if (!wl_global_create(compositor->wl_display,
- &zwp_linux_dmabuf_v1_interface, 3,
- compositor, bind_linux_dmabuf))
- return -1;
-
- return 0;
-}
-
-/** Resolve an internal compositor error by disconnecting the client.
- *
- * This function is used in cases when the dmabuf-based wl_buffer
- * turns out unusable and there is no fallback path. This is used by
- * renderers which are the fallback path in the first place.
- *
- * It is possible the fault is caused by a compositor bug, the underlying
- * graphics stack bug or normal behaviour, or perhaps a client mistake.
- * In any case, the options are to either composite garbage or nothing,
- * or disconnect the client. This is a helper function for the latter.
- *
- * The error is sent as an INVALID_OBJECT error on the client's wl_display.
- *
- * \param buffer The linux_dmabuf_buffer that is unusable.
- * \param msg A custom error message attached to the protocol error.
- */
-WL_EXPORT void
-linux_dmabuf_buffer_send_server_error(struct linux_dmabuf_buffer *buffer,
- const char *msg)
-{
- struct wl_client *client;
- struct wl_resource *display_resource;
- uint32_t id;
-
- assert(buffer->buffer_resource);
- id = wl_resource_get_id(buffer->buffer_resource);
- client = wl_resource_get_client(buffer->buffer_resource);
- display_resource = wl_client_get_object(client, 1);
-
- assert(display_resource);
- wl_resource_post_error(display_resource,
- WL_DISPLAY_ERROR_INVALID_OBJECT,
- "linux_dmabuf server error with "
- "wl_buffer@%u: %s", id, msg);
-}
diff --git a/libweston/linux-dmabuf.h b/libweston/linux-dmabuf.h
deleted file mode 100644
index 926dd9e0..00000000
--- a/libweston/linux-dmabuf.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright © 2014, 2015 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef WESTON_LINUX_DMABUF_H
-#define WESTON_LINUX_DMABUF_H
-
-#include <stdint.h>
-
-#define MAX_DMABUF_PLANES 4
-#ifndef DRM_FORMAT_MOD_INVALID
-#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1)
-#endif
-#ifndef DRM_FORMAT_MOD_LINEAR
-#define DRM_FORMAT_MOD_LINEAR 0
-#endif
-
-struct linux_dmabuf_buffer;
-typedef void (*dmabuf_user_data_destroy_func)(
- struct linux_dmabuf_buffer *buffer);
-
-struct dmabuf_attributes {
- int32_t width;
- int32_t height;
- uint32_t format;
- uint32_t flags; /* enum zlinux_buffer_params_flags */
- int n_planes;
- int fd[MAX_DMABUF_PLANES];
- uint32_t offset[MAX_DMABUF_PLANES];
- uint32_t stride[MAX_DMABUF_PLANES];
- uint64_t modifier[MAX_DMABUF_PLANES];
-};
-
-struct linux_dmabuf_buffer {
- struct wl_resource *buffer_resource;
- struct wl_resource *params_resource;
- struct weston_compositor *compositor;
- struct dmabuf_attributes attributes;
-
- void *user_data;
- dmabuf_user_data_destroy_func user_data_destroy_func;
-
- /* XXX:
- *
- * Add backend private data. This would be for the backend
- * to do all additional imports it might ever use in advance.
- * The basic principle, even if not implemented in drivers today,
- * is that dmabufs are first attached, but the actual allocation
- * is deferred to first use. This would allow the exporter and all
- * attachers to agree on how to allocate.
- *
- * The DRM backend would use this to create drmFBs for each
- * dmabuf_buffer, just in case at some point it would become
- * feasible to scan it out directly. This would improve the
- * possibilities to successfully scan out, avoiding compositing.
- */
-
- /**< marked as scan-out capable, avoids any composition */
- bool direct_display;
-};
-
-int
-linux_dmabuf_setup(struct weston_compositor *compositor);
-
-int
-weston_direct_display_setup(struct weston_compositor *compositor);
-
-struct linux_dmabuf_buffer *
-linux_dmabuf_buffer_get(struct wl_resource *resource);
-
-void
-linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
- void *data,
- dmabuf_user_data_destroy_func func);
-void *
-linux_dmabuf_buffer_get_user_data(struct linux_dmabuf_buffer *buffer);
-
-void
-linux_dmabuf_buffer_send_server_error(struct linux_dmabuf_buffer *buffer,
- const char *msg);
-
-#endif /* WESTON_LINUX_DMABUF_H */
diff --git a/libweston/linux-explicit-synchronization.c b/libweston/linux-explicit-synchronization.c
deleted file mode 100644
index 4b473839..00000000
--- a/libweston/linux-explicit-synchronization.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright © 2018 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <inttypes.h>
-
-#include <libweston/libweston.h>
-#include "linux-explicit-synchronization.h"
-#include "linux-explicit-synchronization-unstable-v1-server-protocol.h"
-#include "linux-sync-file.h"
-#include "shared/fd-util.h"
-#include "libweston-internal.h"
-
-static void
-destroy_linux_buffer_release(struct wl_resource *resource)
-{
- struct weston_buffer_release *buffer_release =
- wl_resource_get_user_data(resource);
-
- fd_clear(&buffer_release->fence_fd);
- free(buffer_release);
-}
-
-static void
-destroy_linux_surface_synchronization(struct wl_resource *resource)
-{
- struct weston_surface *surface =
- wl_resource_get_user_data(resource);
-
- if (surface) {
- fd_clear(&surface->pending.acquire_fence_fd);
- surface->synchronization_resource = NULL;
- }
-}
-
-static void
-linux_surface_synchronization_destroy(struct wl_client *client,
- struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-linux_surface_synchronization_set_acquire_fence(struct wl_client *client,
- struct wl_resource *resource,
- int32_t fd)
-{
- struct weston_surface *surface = wl_resource_get_user_data(resource);
-
- if (!surface) {
- wl_resource_post_error(
- resource,
- ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_NO_SURFACE,
- "surface no longer exists");
- goto err;
- }
-
- if (!linux_sync_file_is_valid(fd)) {
- wl_resource_post_error(
- resource,
- ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_INVALID_FENCE,
- "invalid fence fd");
- goto err;
- }
-
- if (surface->pending.acquire_fence_fd != -1) {
- wl_resource_post_error(
- resource,
- ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_DUPLICATE_FENCE,
- "already have a fence fd");
- goto err;
- }
-
- fd_update(&surface->pending.acquire_fence_fd, fd);
-
- return;
-
-err:
- close(fd);
-}
-
-static void
-linux_surface_synchronization_get_release(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t id)
-{
- struct weston_surface *surface =
- wl_resource_get_user_data(resource);
- struct weston_buffer_release *buffer_release;
-
- if (!surface) {
- wl_resource_post_error(
- resource,
- ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_NO_SURFACE,
- "surface no longer exists");
- return;
- }
-
- if (surface->pending.buffer_release_ref.buffer_release) {
- wl_resource_post_error(
- resource,
- ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_DUPLICATE_RELEASE,
- "already has a buffer release");
- return;
- }
-
- buffer_release = zalloc(sizeof *buffer_release);
- if (buffer_release == NULL)
- goto err_alloc;
-
- buffer_release->fence_fd = -1;
- buffer_release->resource =
- wl_resource_create(client,
- &zwp_linux_buffer_release_v1_interface,
- wl_resource_get_version(resource), id);
- if (!buffer_release->resource)
- goto err_create;
-
- wl_resource_set_implementation(buffer_release->resource, NULL,
- buffer_release,
- destroy_linux_buffer_release);
-
- weston_buffer_release_reference(&surface->pending.buffer_release_ref,
- buffer_release);
-
- return;
-
-err_create:
- free(buffer_release);
-
-err_alloc:
- wl_client_post_no_memory(client);
-
-}
-
-const struct zwp_linux_surface_synchronization_v1_interface
-linux_surface_synchronization_implementation = {
- linux_surface_synchronization_destroy,
- linux_surface_synchronization_set_acquire_fence,
- linux_surface_synchronization_get_release,
-};
-
-static void
-linux_explicit_synchronization_destroy(struct wl_client *client,
- struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-linux_explicit_synchronization_get_synchronization(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t id,
- struct wl_resource *surface_resource)
-{
- struct weston_surface *surface =
- wl_resource_get_user_data(surface_resource);
-
- if (surface->synchronization_resource) {
- wl_resource_post_error(
- resource,
- ZWP_LINUX_EXPLICIT_SYNCHRONIZATION_V1_ERROR_SYNCHRONIZATION_EXISTS,
- "wl_surface@%"PRIu32" already has a synchronization object",
- wl_resource_get_id(surface_resource));
- return;
- }
-
- surface->synchronization_resource =
- wl_resource_create(client,
- &zwp_linux_surface_synchronization_v1_interface,
- wl_resource_get_version(resource), id);
- if (!surface->synchronization_resource) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_resource_set_implementation(surface->synchronization_resource,
- &linux_surface_synchronization_implementation,
- surface,
- destroy_linux_surface_synchronization);
-}
-
-static const struct zwp_linux_explicit_synchronization_v1_interface
-linux_explicit_synchronization_implementation = {
- linux_explicit_synchronization_destroy,
- linux_explicit_synchronization_get_synchronization
-};
-
-static void
-bind_linux_explicit_synchronization(struct wl_client *client,
- void *data, uint32_t version,
- uint32_t id)
-{
- struct weston_compositor *compositor = data;
- struct wl_resource *resource;
-
- resource = wl_resource_create(client,
- &zwp_linux_explicit_synchronization_v1_interface,
- version, id);
- if (resource == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_resource_set_implementation(resource,
- &linux_explicit_synchronization_implementation,
- compositor, NULL);
-}
-
-/** Advertise linux_explicit_synchronization support
- *
- * Calling this initializes the zwp_linux_explicit_synchronization_v1
- * protocol support, so that the interface will be advertised to clients.
- * Essentially it creates a global. Do not call this function multiple times
- * in the compositor's lifetime. There is no way to deinit explicitly, globals
- * will be reaped when the wl_display gets destroyed.
- *
- * \param compositor The compositor to init for.
- * \return Zero on success, -1 on failure.
- */
-WL_EXPORT int
-linux_explicit_synchronization_setup(struct weston_compositor *compositor)
-{
- if (!wl_global_create(compositor->wl_display,
- &zwp_linux_explicit_synchronization_v1_interface,
- 2, compositor,
- bind_linux_explicit_synchronization))
- return -1;
-
- return 0;
-}
-
-/** Resolve an internal compositor error by disconnecting the client.
- *
- * This function is used in cases when explicit synchronization
- * turns out to be unusable and there is no fallback path.
- *
- * It is possible the fault is caused by a compositor bug, the underlying
- * graphics stack bug or normal behaviour, or perhaps a client mistake.
- * In any case, the options are to either composite garbage or nothing,
- * or disconnect the client. This is a helper function for the latter.
- *
- * The error is sent as an INVALID_OBJECT error on the client's wl_display.
- *
- * \param resource The explicit synchronization related resource that is unusable.
- * \param msg A custom error message attached to the protocol error.
- */
-WL_EXPORT void
-linux_explicit_synchronization_send_server_error(struct wl_resource *resource,
- const char *msg)
-{
- uint32_t id = wl_resource_get_id(resource);
- const char *class = wl_resource_get_class(resource);
- struct wl_client *client = wl_resource_get_client(resource);
- struct wl_resource *display_resource = wl_client_get_object(client, 1);
-
- assert(display_resource);
- wl_resource_post_error(display_resource,
- WL_DISPLAY_ERROR_INVALID_OBJECT,
- "linux_explicit_synchronization server error "
- "with %s@%"PRIu32": %s",
- class, id, msg);
-}
diff --git a/libweston/linux-explicit-synchronization.h b/libweston/linux-explicit-synchronization.h
deleted file mode 100644
index 55022879..00000000
--- a/libweston/linux-explicit-synchronization.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright © 2018 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef WESTON_LINUX_EXPLICIT_SYNCHRONIZATION_H
-#define WESTON_LINUX_EXPLICIT_SYNCHRONIZATION_H
-
-struct weston_compositor;
-struct wl_resource;
-
-int
-linux_explicit_synchronization_setup(struct weston_compositor *compositor);
-
-void
-linux_explicit_synchronization_send_server_error(struct wl_resource *resource,
- const char *msg);
-
-#endif /* WESTON_LINUX_EXPLICIT_SYNCHRONIZATION */
diff --git a/libweston/linux-sync-file-uapi.h b/libweston/linux-sync-file-uapi.h
deleted file mode 100644
index cd30665f..00000000
--- a/libweston/linux-sync-file-uapi.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Sync file Linux kernel UAPI */
-
-#ifndef WESTON_LINUX_SYNC_FILE_UAPI_H
-#define WESTON_LINUX_SYNC_FILE_UAPI_H
-
-#include <linux/ioctl.h>
-#include <linux/types.h>
-
-struct sync_fence_info {
- char obj_name[32];
- char driver_name[32];
- __s32 status;
- __u32 flags;
- __u64 timestamp_ns;
-};
-
-struct sync_file_info {
- char name[32];
- __s32 status;
- __u32 flags;
- __u32 num_fences;
- __u32 pad;
-
- __u64 sync_fence_info;
-};
-
-#define SYNC_IOC_MAGIC '>'
-#define SYNC_IOC_FILE_INFO _IOWR(SYNC_IOC_MAGIC, 4, struct sync_file_info)
-
-#endif /* WESTON_LINUX_SYNC_FILE_UAPI_H */
diff --git a/libweston/linux-sync-file.c b/libweston/linux-sync-file.c
deleted file mode 100644
index 9f5313cc..00000000
--- a/libweston/linux-sync-file.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright © 2018 Collabora, Ltd
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <poll.h>
-#include <stddef.h>
-#include <sys/ioctl.h>
-#include <wayland-server-core.h>
-
-#ifdef HAVE_LINUX_SYNC_FILE_H
-#include <linux/sync_file.h>
-#else
-#include "linux-sync-file-uapi.h"
-#endif
-
-#include "linux-sync-file.h"
-#include "shared/timespec-util.h"
-
-/* Check that a file descriptor represents a valid sync file
- *
- * \param fd[in] a file descriptor
- * \return true if fd is a valid sync file, false otherwise
- */
-bool
-linux_sync_file_is_valid(int fd)
-{
- struct sync_file_info file_info = { { 0 } };
-
- if (ioctl(fd, SYNC_IOC_FILE_INFO, &file_info) < 0)
- return false;
-
- return file_info.num_fences > 0;
-}
-
-/* Read the timestamp stored in a sync file
- *
- * \param fd[in] fd a file descriptor for a sync file
- * \param ts[out] the timespec struct to fill with the timestamp
- * \return 0 if a timestamp was read, -1 on error
- */
-WL_EXPORT int
-weston_linux_sync_file_read_timestamp(int fd, struct timespec *ts)
-{
- struct sync_file_info file_info = { { 0 } };
- struct sync_fence_info fence_info = { { 0 } };
-
- assert(ts != NULL);
-
- file_info.sync_fence_info = (uint64_t)(uintptr_t)&fence_info;
- file_info.num_fences = 1;
-
- if (ioctl(fd, SYNC_IOC_FILE_INFO, &file_info) < 0)
- return -1;
-
- timespec_from_nsec(ts, fence_info.timestamp_ns);
-
- return 0;
-}
diff --git a/libweston/linux-sync-file.h b/libweston/linux-sync-file.h
deleted file mode 100644
index 9746d7ba..00000000
--- a/libweston/linux-sync-file.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright © 2018 Collabora, Ltd
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef WESTON_LINUX_SYNC_FILE_H
-#define WESTON_LINUX_SYNC_FILE_H
-
-#include <sys/time.h>
-#include <stdbool.h>
-
-bool
-linux_sync_file_is_valid(int fd);
-
-int
-weston_linux_sync_file_read_timestamp(int fd, struct timespec *ts);
-
-#endif /* WESTON_LINUX_SYNC_FILE_H */
diff --git a/libweston/log.c b/libweston/log.c
deleted file mode 100644
index 6ce9454b..00000000
--- a/libweston/log.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright © 2012 Martin Minarik
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <time.h>
-
-#include <wayland-util.h>
-
-#include <libweston/libweston.h>
-
-/**
- * \defgroup wlog weston-logging
- */
-
-static int
-default_log_handler(const char *fmt, va_list ap);
-
-/** Needs to be set, defaults to default_log_handler
- *
- * \ingroup wlog
- */
-static log_func_t log_handler = default_log_handler;
-
-/** Needs to be set, defaults to default_log_handler
- *
- * \ingroup wlog
- */
-static log_func_t log_continue_handler = default_log_handler;
-
-/** Sentinel log message handler
- *
- * This function is used as the default handler for log messages. It
- * exists only to issue a noisy reminder to the user that a real handler
- * must be installed prior to issuing logging calls. The process is
- * immediately aborted after the reminder is printed.
- *
- * \param fmt The format string. Ignored.
- * \param ap The variadic argument list. Ignored.
- *
- * \ingroup wlog
- */
-static int
-default_log_handler(const char *fmt, va_list ap)
-{
- fprintf(stderr, "weston_log_set_handler() must be called before using of weston_log().\n");
- abort();
-}
-
-/** Install the log handler
- *
- * The given functions will be called to output text as passed to the
- * \a weston_log and \a weston_log_continue functions.
- *
- * \param log The log function. This function will be called when
- * \a weston_log is called, and should begin a new line,
- * with user defined line headers, if any.
- * \param cont The continue log function. This function will be called
- * when \a weston_log_continue is called, and should append
- * its output to the current line, without any header or
- * other content in between.
- *
- * \ingroup wlog
- */
-WL_EXPORT void
-weston_log_set_handler(log_func_t log, log_func_t cont)
-{
- log_handler = log;
- log_continue_handler = cont;
-}
-
-/** weston_vlog calls log_handler
- * \ingroup wlog
- */
-WL_EXPORT int
-weston_vlog(const char *fmt, va_list ap)
-{
- return log_handler(fmt, ap);
-}
-
-/** printf() equivalent in weston compositor.
- *
- * \rststar
- * .. note::
- *
- * Needs :var:`log_handler` to be set-up!
- * \endrststar
- *
- * \ingroup wlog
- */
-WL_EXPORT int
-weston_log(const char *fmt, ...)
-{
- int l;
- va_list argp;
-
- va_start(argp, fmt);
- l = weston_vlog(fmt, argp);
- va_end(argp);
-
- return l;
-}
-
-/** weston_vlog_continue calls log_continue_handler
- *
- * \ingroup wlog
- */
-WL_EXPORT int
-weston_vlog_continue(const char *fmt, va_list argp)
-{
- return log_continue_handler(fmt, argp);
-}
-
-/** weston_log_continue
- *
- * \ingroup wlog
- */
-WL_EXPORT int
-weston_log_continue(const char *fmt, ...)
-{
- int l;
- va_list argp;
-
- va_start(argp, fmt);
- l = weston_vlog_continue(fmt, argp);
- va_end(argp);
-
- return l;
-}
diff --git a/libweston/meson.build b/libweston/meson.build
deleted file mode 100644
index d989b287..00000000
--- a/libweston/meson.build
+++ /dev/null
@@ -1,243 +0,0 @@
-deps_libweston = [
- dep_wayland_server,
- dep_pixman,
- dep_libm,
- dep_libdl,
- dep_libdrm_headers,
- dep_xkbcommon,
- dep_matrix_c
-]
-srcs_libweston = [
- git_version_h,
- 'animation.c',
- 'bindings.c',
- 'clipboard.c',
- 'compositor.c',
- 'content-protection.c',
- 'data-device.c',
- 'input.c',
- 'linux-dmabuf.c',
- 'linux-explicit-synchronization.c',
- 'linux-sync-file.c',
- 'log.c',
- 'noop-renderer.c',
- 'pixel-formats.c',
- 'pixman-renderer.c',
- 'plugin-registry.c',
- 'screenshooter.c',
- 'timeline.c',
- 'touch-calibration.c',
- 'weston-log-wayland.c',
- 'weston-log-file.c',
- 'weston-log-flight-rec.c',
- 'weston-log.c',
- 'weston-direct-display.c',
- 'zoom.c',
- linux_dmabuf_unstable_v1_protocol_c,
- linux_dmabuf_unstable_v1_server_protocol_h,
- linux_explicit_synchronization_unstable_v1_protocol_c,
- linux_explicit_synchronization_unstable_v1_server_protocol_h,
- input_method_unstable_v1_protocol_c,
- input_method_unstable_v1_server_protocol_h,
- input_timestamps_unstable_v1_protocol_c,
- input_timestamps_unstable_v1_server_protocol_h,
- presentation_time_protocol_c,
- presentation_time_server_protocol_h,
- pointer_constraints_unstable_v1_protocol_c,
- pointer_constraints_unstable_v1_server_protocol_h,
- relative_pointer_unstable_v1_protocol_c,
- relative_pointer_unstable_v1_server_protocol_h,
- weston_screenshooter_protocol_c,
- weston_screenshooter_server_protocol_h,
- text_cursor_position_protocol_c,
- text_cursor_position_server_protocol_h,
- text_input_unstable_v1_protocol_c,
- text_input_unstable_v1_server_protocol_h,
- weston_touch_calibration_protocol_c,
- weston_touch_calibration_server_protocol_h,
- weston_content_protection_protocol_c,
- weston_content_protection_server_protocol_h,
- viewporter_protocol_c,
- viewporter_server_protocol_h,
- xdg_output_unstable_v1_protocol_c,
- xdg_output_unstable_v1_server_protocol_h,
- weston_debug_protocol_c,
- weston_debug_server_protocol_h,
- weston_direct_display_protocol_c,
- weston_direct_display_server_protocol_h,
-]
-
-if get_option('renderer-gl')
- dep_egl = dependency('egl', required: false)
- if not dep_egl.found()
- error('libweston + gl-renderer requires egl which was not found. Or, you can use \'-Drenderer-gl=false\'.')
- endif
- deps_libweston += dep_egl
-endif
-
-lib_weston = shared_library(
- 'weston-@0@'.format(libweston_major),
- srcs_libweston,
- include_directories: common_inc,
- install: true,
- version: '0.0.@0@'.format(libweston_revision),
- link_whole: lib_libshared,
- dependencies: deps_libweston
-)
-
-deps_for_libweston_users = [
- dep_wayland_server,
- dep_pixman,
- dep_xkbcommon,
-]
-
-# For external users, like Weston.
-dep_libweston_public = declare_dependency(
- link_with: lib_weston,
- include_directories: public_inc,
- dependencies: deps_for_libweston_users
-)
-
-# For internal users, like the backends.
-dep_libweston_private = declare_dependency(
- link_with: lib_weston,
- include_directories: [ include_directories('.'), public_inc ],
- dependencies: deps_for_libweston_users
-)
-
-# XXX: We should be able to use dep_libweston_private.partial_dependency() instead
-# of this, but a Meson bug makes it not work. It will be fixed with
-# https://github.com/mesonbuild/meson/pull/5167
-# in hopefully Meson 0.51.
-dep_libweston_private_h_deps = []
-foreach d : deps_for_libweston_users
- dep_libweston_private_h_deps += d.partial_dependency(compile_args: true)
-endforeach
-dep_libweston_private_h = declare_dependency(
- include_directories: [ include_directories('.'), public_inc ],
- dependencies: dep_libweston_private_h_deps
-)
-
-pkgconfig.generate(
- lib_weston,
- filebase: 'libweston-@0@'.format(libweston_major),
- name: 'libweston API',
- version: version_weston,
- description: 'Header files for libweston compositors development',
- requires_private: deps_for_libweston_users,
- subdirs: dir_include_libweston
-)
-
-pkgconfig.generate(
- filebase: 'libweston-@0@-protocols'.format(libweston_major),
- name: 'libWeston Protocols',
- version: version_weston,
- description: 'libWeston protocol files',
- variables: [
- 'datarootdir=' + join_paths('${prefix}', get_option('datadir')),
- 'pkgdatadir=' + join_paths('${pc_sysrootdir}${datarootdir}', dir_protocol_libweston)
- ],
- install_dir: dir_data_pc
-)
-
-srcs_session_helper = [
- 'launcher-direct.c',
- 'launcher-util.c',
- 'launcher-weston-launch.c',
-]
-deps_session_helper = [ dep_libweston_private_h ]
-
-if get_option('backend-drm')
- deps_session_helper += dep_libdrm
-endif
-
-systemd_dep = dependency('', required: false)
-if get_option('launcher-logind')
- systemd_dep = dependency('libsystemd', version: '>= 209', required: false)
- if systemd_dep.found()
- config_h.set('HAVE_SYSTEMD_LOGIN_209', '1')
- else
- systemd_dep = dependency('libsystemd-login', version: '>= 198', required: false)
- if not systemd_dep.found()
- error('logind support requires libsystemd or libsystemd-login but neither was found. Or, you can use \'-Dlauncher-logind=false\'')
- endif
- endif
-
- dbus_dep = dependency('dbus-1', version: '>= 1.6', required: false)
- if not dbus_dep.found()
- error('logind support requires dbus-1 >= 1.6 which was not found. Or, you can use \'-Dlauncher-logind=false\'')
- endif
-
- config_h.set('HAVE_DBUS', '1')
- config_h.set('HAVE_SYSTEMD_LOGIN', '1')
-
- srcs_session_helper += [
- 'dbus.c',
- 'launcher-logind.c',
- ]
- deps_session_helper += [
- dbus_dep,
- systemd_dep,
- ]
-endif
-
-lib_session_helper = static_library(
- 'session-helper',
- srcs_session_helper,
- include_directories: common_inc,
- dependencies: deps_session_helper,
- install: false
-)
-dep_session_helper = declare_dependency(link_with: lib_session_helper)
-
-
-lib_libinput_backend = static_library(
- 'libinput-backend',
- [
- 'libinput-device.c',
- 'libinput-seat.c'
- ],
- dependencies: [
- dep_libweston_private,
- dep_libinput,
- dependency('libudev', version: '>= 136')
- ],
- include_directories: common_inc,
- install: false
-)
-dep_libinput_backend = declare_dependency(
- link_with: lib_libinput_backend,
- include_directories: include_directories('.')
-)
-
-dep_vertex_clipping = declare_dependency(
- sources: 'vertex-clipping.c',
- include_directories: include_directories('.')
-)
-
-if get_option('weston-launch')
- dep_pam = cc.find_library('pam')
-
- if not cc.has_function('pam_open_session', dependencies: dep_pam)
- error('pam_open_session not found for weston-launch')
- endif
-
- executable(
- 'weston-launch',
- 'weston-launch.c',
- dependencies: [dep_pam, systemd_dep, dep_libdrm],
- include_directories: common_inc,
- install: true
- )
-
- meson.add_install_script('echo', 'REMINDER: You are installing weston-launch, please make it setuid-root.')
-endif
-
-subdir('renderer-gl')
-subdir('backend-drm')
-subdir('backend-fbdev')
-subdir('backend-headless')
-subdir('backend-rdp')
-subdir('backend-wayland')
-subdir('backend-x11')
-subdir('backend-tdm')
diff --git a/libweston/noop-renderer.c b/libweston/noop-renderer.c
deleted file mode 100644
index d4bd2efe..00000000
--- a/libweston/noop-renderer.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright © 2012 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <libweston/libweston.h>
-
-static int
-noop_renderer_read_pixels(struct weston_output *output,
- pixman_format_code_t format, void *pixels,
- uint32_t x, uint32_t y,
- uint32_t width, uint32_t height)
-{
- return 0;
-}
-
-static void
-noop_renderer_repaint_output(struct weston_output *output,
- pixman_region32_t *output_damage)
-{
-}
-
-static void
-noop_renderer_flush_damage(struct weston_surface *surface)
-{
-}
-
-static void
-noop_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
-{
- struct wl_shm_buffer *shm_buffer;
- uint8_t *data;
- uint32_t size, i, width, height, stride;
- volatile unsigned char unused = 0; /* volatile so it's not optimized out */
-
- if (!buffer)
- return;
-
- shm_buffer = wl_shm_buffer_get(buffer->resource);
-
- if (!shm_buffer) {
- weston_log("No-op renderer supports only SHM buffers\n");
- return;
- }
-
- data = wl_shm_buffer_get_data(shm_buffer);
- stride = wl_shm_buffer_get_stride(shm_buffer);
- width = wl_shm_buffer_get_width(shm_buffer);
- height = wl_shm_buffer_get_height(shm_buffer);
- size = stride * height;
-
- /* Access the buffer data to make sure the buffer's client gets killed
- * if the buffer size is invalid. This makes the bad_buffer test pass.
- * This can be removed if we start reading the buffer contents
- * somewhere else, e.g. in repaint_output(). */
- wl_shm_buffer_begin_access(shm_buffer);
- for (i = 0; i < size; i++)
- unused ^= data[i];
- wl_shm_buffer_end_access(shm_buffer);
-
- buffer->shm_buffer = shm_buffer;
- buffer->width = width;
- buffer->height = height;
-}
-
-static void
-noop_renderer_surface_set_color(struct weston_surface *surface,
- float red, float green, float blue, float alpha)
-{
-}
-
-static void
-noop_renderer_destroy(struct weston_compositor *ec)
-{
- free(ec->renderer);
- ec->renderer = NULL;
-}
-
-WL_EXPORT int
-noop_renderer_init(struct weston_compositor *ec)
-{
- struct weston_renderer *renderer;
-
- renderer = zalloc(sizeof *renderer);
- if (renderer == NULL)
- return -1;
-
- renderer->read_pixels = noop_renderer_read_pixels;
- renderer->repaint_output = noop_renderer_repaint_output;
- renderer->flush_damage = noop_renderer_flush_damage;
- renderer->attach = noop_renderer_attach;
- renderer->surface_set_color = noop_renderer_surface_set_color;
- renderer->destroy = noop_renderer_destroy;
- ec->renderer = renderer;
-
- return 0;
-}
diff --git a/libweston/pixel-formats.c b/libweston/pixel-formats.c
deleted file mode 100644
index 79dc709c..00000000
--- a/libweston/pixel-formats.c
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * Copyright © 2016, 2019 Collabora, Ltd.
- * Copyright (c) 2018 DisplayLink (UK) Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Author: Daniel Stone <daniels@collabora.com>
- */
-
-#include "config.h"
-
-#include <endian.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <unistd.h>
-#include <string.h>
-#include <drm_fourcc.h>
-#include <wayland-client-protocol.h>
-
-#include "shared/helpers.h"
-#include "wayland-util.h"
-#include "pixel-formats.h"
-
-#if ENABLE_EGL
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#define GL_FORMAT(fmt) .gl_format = (fmt)
-#define GL_TYPE(type) .gl_type = (type)
-#define SAMPLER_TYPE(type) .sampler_type = (type)
-#else
-#define GL_FORMAT(fmt) .gl_format = 0
-#define GL_TYPE(type) .gl_type = 0
-#define SAMPLER_TYPE(type) .sampler_type = 0
-#endif
-
-#define DRM_FORMAT(f) .format = DRM_FORMAT_ ## f, .drm_format_name = #f
-#define BITS_RGBA_FIXED(r_, g_, b_, a_) \
- .bits.r = r_, \
- .bits.g = g_, \
- .bits.b = b_, \
- .bits.a = a_, \
- .component_type = PIXEL_COMPONENT_TYPE_FIXED
-
-#include "shared/weston-egl-ext.h"
-
-/**
- * Table of DRM formats supported by Weston; RGB, ARGB and YUV formats are
- * supported. Indexed/greyscale formats, and formats not containing complete
- * colour channels, are not supported.
- */
-static const struct pixel_format_info pixel_format_table[] = {
- {
- DRM_FORMAT(XRGB4444),
- BITS_RGBA_FIXED(4, 4, 4, 0),
- },
- {
- DRM_FORMAT(ARGB4444),
- BITS_RGBA_FIXED(4, 4, 4, 4),
- .opaque_substitute = DRM_FORMAT_XRGB4444,
- },
- {
- DRM_FORMAT(XBGR4444),
- BITS_RGBA_FIXED(4, 4, 4, 0),
- },
- {
- DRM_FORMAT(ABGR4444),
- BITS_RGBA_FIXED(4, 4, 4, 4),
- .opaque_substitute = DRM_FORMAT_XBGR4444,
- },
- {
- DRM_FORMAT(RGBX4444),
- BITS_RGBA_FIXED(4, 4, 4, 0),
-# if __BYTE_ORDER == __LITTLE_ENDIAN
- GL_FORMAT(GL_RGBA),
- GL_TYPE(GL_UNSIGNED_SHORT_4_4_4_4),
-#endif
- },
- {
- DRM_FORMAT(RGBA4444),
- BITS_RGBA_FIXED(4, 4, 4, 4),
- .opaque_substitute = DRM_FORMAT_RGBX4444,
-# if __BYTE_ORDER == __LITTLE_ENDIAN
- GL_FORMAT(GL_RGBA),
- GL_TYPE(GL_UNSIGNED_SHORT_4_4_4_4),
-#endif
- },
- {
- DRM_FORMAT(BGRX4444),
- BITS_RGBA_FIXED(4, 4, 4, 0),
- },
- {
- DRM_FORMAT(BGRA4444),
- BITS_RGBA_FIXED(4, 4, 4, 4),
- .opaque_substitute = DRM_FORMAT_BGRX4444,
- },
- {
- DRM_FORMAT(XRGB1555),
- BITS_RGBA_FIXED(5, 5, 5, 0),
- .depth = 15,
- .bpp = 16,
- },
- {
- DRM_FORMAT(ARGB1555),
- BITS_RGBA_FIXED(5, 5, 5, 1),
- .opaque_substitute = DRM_FORMAT_XRGB1555,
- },
- {
- DRM_FORMAT(XBGR1555),
- BITS_RGBA_FIXED(5, 5, 5, 0),
- },
- {
- DRM_FORMAT(ABGR1555),
- BITS_RGBA_FIXED(5, 5, 5, 1),
- .opaque_substitute = DRM_FORMAT_XBGR1555,
- },
- {
- DRM_FORMAT(RGBX5551),
- BITS_RGBA_FIXED(5, 5, 5, 0),
-# if __BYTE_ORDER == __LITTLE_ENDIAN
- GL_FORMAT(GL_RGBA),
- GL_TYPE(GL_UNSIGNED_SHORT_5_5_5_1),
-#endif
- },
- {
- DRM_FORMAT(RGBA5551),
- BITS_RGBA_FIXED(5, 5, 5, 1),
- .opaque_substitute = DRM_FORMAT_RGBX5551,
-# if __BYTE_ORDER == __LITTLE_ENDIAN
- GL_FORMAT(GL_RGBA),
- GL_TYPE(GL_UNSIGNED_SHORT_5_5_5_1),
-#endif
- },
- {
- DRM_FORMAT(BGRX5551),
- BITS_RGBA_FIXED(5, 5, 5, 0),
- },
- {
- DRM_FORMAT(BGRA5551),
- BITS_RGBA_FIXED(5, 5, 5, 1),
- .opaque_substitute = DRM_FORMAT_BGRX5551,
- },
- {
- DRM_FORMAT(RGB565),
- BITS_RGBA_FIXED(5, 6, 5, 0),
- .depth = 16,
- .bpp = 16,
-# if __BYTE_ORDER == __LITTLE_ENDIAN
- GL_FORMAT(GL_RGB),
- GL_TYPE(GL_UNSIGNED_SHORT_5_6_5),
-#endif
- },
- {
- DRM_FORMAT(BGR565),
- BITS_RGBA_FIXED(5, 6, 5, 0),
- },
- {
- DRM_FORMAT(RGB888),
- BITS_RGBA_FIXED(8, 8, 8, 0),
- },
- {
- DRM_FORMAT(BGR888),
- BITS_RGBA_FIXED(8, 8, 8, 0),
- GL_FORMAT(GL_RGB),
- GL_TYPE(GL_UNSIGNED_BYTE),
- },
- {
- DRM_FORMAT(XRGB8888),
- BITS_RGBA_FIXED(8, 8, 8, 0),
- .depth = 24,
- .bpp = 32,
- GL_FORMAT(GL_BGRA_EXT),
- GL_TYPE(GL_UNSIGNED_BYTE),
- },
- {
- DRM_FORMAT(ARGB8888),
- BITS_RGBA_FIXED(8, 8, 8, 8),
- .opaque_substitute = DRM_FORMAT_XRGB8888,
- .depth = 32,
- .bpp = 32,
- GL_FORMAT(GL_BGRA_EXT),
- GL_TYPE(GL_UNSIGNED_BYTE),
- },
- {
- DRM_FORMAT(XBGR8888),
- BITS_RGBA_FIXED(8, 8, 8, 0),
- GL_FORMAT(GL_RGBA),
- GL_TYPE(GL_UNSIGNED_BYTE),
- },
- {
- DRM_FORMAT(ABGR8888),
- BITS_RGBA_FIXED(8, 8, 8, 8),
- .opaque_substitute = DRM_FORMAT_XBGR8888,
- GL_FORMAT(GL_RGBA),
- GL_TYPE(GL_UNSIGNED_BYTE),
- },
- {
- DRM_FORMAT(RGBX8888),
- BITS_RGBA_FIXED(8, 8, 8, 0),
- },
- {
- DRM_FORMAT(RGBA8888),
- BITS_RGBA_FIXED(8, 8, 8, 8),
- .opaque_substitute = DRM_FORMAT_RGBX8888,
- },
- {
- DRM_FORMAT(BGRX8888),
- BITS_RGBA_FIXED(8, 8, 8, 0),
- },
- {
- DRM_FORMAT(BGRA8888),
- BITS_RGBA_FIXED(8, 8, 8, 8),
- .opaque_substitute = DRM_FORMAT_BGRX8888,
- },
- {
- DRM_FORMAT(XRGB2101010),
- BITS_RGBA_FIXED(10, 10, 10, 0),
- .depth = 30,
- .bpp = 32,
- },
- {
- DRM_FORMAT(ARGB2101010),
- BITS_RGBA_FIXED(10, 10, 10, 2),
- .opaque_substitute = DRM_FORMAT_XRGB2101010,
- },
- {
- DRM_FORMAT(XBGR2101010),
- BITS_RGBA_FIXED(10, 10, 10, 0),
-# if __BYTE_ORDER == __LITTLE_ENDIAN
- GL_FORMAT(GL_RGBA),
- GL_TYPE(GL_UNSIGNED_INT_2_10_10_10_REV_EXT),
-#endif
- },
- {
- DRM_FORMAT(ABGR2101010),
- BITS_RGBA_FIXED(10, 10, 10, 2),
- .opaque_substitute = DRM_FORMAT_XBGR2101010,
-# if __BYTE_ORDER == __LITTLE_ENDIAN
- GL_FORMAT(GL_RGBA),
- GL_TYPE(GL_UNSIGNED_INT_2_10_10_10_REV_EXT),
-#endif
- },
- {
- DRM_FORMAT(RGBX1010102),
- BITS_RGBA_FIXED(10, 10, 10, 0),
- },
- {
- DRM_FORMAT(RGBA1010102),
- BITS_RGBA_FIXED(10, 10, 10, 2),
- .opaque_substitute = DRM_FORMAT_RGBX1010102,
- },
- {
- DRM_FORMAT(BGRX1010102),
- BITS_RGBA_FIXED(10, 10, 10, 0),
- },
- {
- DRM_FORMAT(BGRA1010102),
- BITS_RGBA_FIXED(10, 10, 10, 2),
- .opaque_substitute = DRM_FORMAT_BGRX1010102,
- },
- {
- DRM_FORMAT(YUYV),
- SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL),
- .num_planes = 1,
- .hsub = 2,
- },
- {
- DRM_FORMAT(YVYU),
- SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL),
- .num_planes = 1,
- .chroma_order = ORDER_VU,
- .hsub = 2,
- },
- {
- DRM_FORMAT(UYVY),
- SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL),
- .num_planes = 1,
- .luma_chroma_order = ORDER_CHROMA_LUMA,
- .hsub = 2,
- },
- {
- DRM_FORMAT(VYUY),
- SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL),
- .num_planes = 1,
- .luma_chroma_order = ORDER_CHROMA_LUMA,
- .chroma_order = ORDER_VU,
- .hsub = 2,
- },
- {
- DRM_FORMAT(NV12),
- SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
- .num_planes = 2,
- .hsub = 2,
- .vsub = 2,
- },
- {
- DRM_FORMAT(NV21),
- SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
- .num_planes = 2,
- .chroma_order = ORDER_VU,
- .hsub = 2,
- .vsub = 2,
- },
- {
- DRM_FORMAT(NV16),
- SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
- .num_planes = 2,
- .hsub = 2,
- .vsub = 1,
- },
- {
- DRM_FORMAT(NV61),
- SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
- .num_planes = 2,
- .chroma_order = ORDER_VU,
- .hsub = 2,
- .vsub = 1,
- },
- {
- DRM_FORMAT(NV24),
- SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
- .num_planes = 2,
- },
- {
- DRM_FORMAT(NV42),
- SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
- .num_planes = 2,
- .chroma_order = ORDER_VU,
- },
- {
- DRM_FORMAT(YUV410),
- SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
- .num_planes = 3,
- .hsub = 4,
- .vsub = 4,
- },
- {
- DRM_FORMAT(YVU410),
- SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
- .num_planes = 3,
- .chroma_order = ORDER_VU,
- .hsub = 4,
- .vsub = 4,
- },
- {
- DRM_FORMAT(YUV411),
- SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
- .num_planes = 3,
- .hsub = 4,
- .vsub = 1,
- },
- {
- DRM_FORMAT(YVU411),
- SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
- .num_planes = 3,
- .chroma_order = ORDER_VU,
- .hsub = 4,
- .vsub = 1,
- },
- {
- DRM_FORMAT(YUV420),
- SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
- .num_planes = 3,
- .hsub = 2,
- .vsub = 2,
- },
- {
- DRM_FORMAT(YVU420),
- SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
- .num_planes = 3,
- .chroma_order = ORDER_VU,
- .hsub = 2,
- .vsub = 2,
- },
- {
- DRM_FORMAT(YUV422),
- SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
- .num_planes = 3,
- .hsub = 2,
- .vsub = 1,
- },
- {
- DRM_FORMAT(YVU422),
- SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
- .num_planes = 3,
- .chroma_order = ORDER_VU,
- .hsub = 2,
- .vsub = 1,
- },
- {
- DRM_FORMAT(YUV444),
- SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
- .num_planes = 3,
- },
- {
- DRM_FORMAT(YVU444),
- SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
- .num_planes = 3,
- .chroma_order = ORDER_VU,
- },
-};
-
-WL_EXPORT const struct pixel_format_info *
-pixel_format_get_info_shm(uint32_t format)
-{
- if (format == WL_SHM_FORMAT_XRGB8888)
- return pixel_format_get_info(DRM_FORMAT_XRGB8888);
- else if (format == WL_SHM_FORMAT_ARGB8888)
- return pixel_format_get_info(DRM_FORMAT_ARGB8888);
- else
- return pixel_format_get_info(format);
-}
-
-WL_EXPORT const struct pixel_format_info *
-pixel_format_get_info(uint32_t format)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_LENGTH(pixel_format_table); i++) {
- if (pixel_format_table[i].format == format)
- return &pixel_format_table[i];
- }
-
- return NULL;
-}
-
-WL_EXPORT const struct pixel_format_info *
-pixel_format_get_info_by_drm_name(const char *drm_format_name)
-{
- const struct pixel_format_info *info;
- unsigned int i;
-
- for (i = 0; i < ARRAY_LENGTH(pixel_format_table); i++) {
- info = &pixel_format_table[i];
- if (strcasecmp(info->drm_format_name, drm_format_name) == 0)
- return info;
- }
-
- return NULL;
-}
-
-WL_EXPORT unsigned int
-pixel_format_get_plane_count(const struct pixel_format_info *info)
-{
- return info->num_planes ? info->num_planes : 1;
-}
-
-WL_EXPORT bool
-pixel_format_is_opaque(const struct pixel_format_info *info)
-{
- return !info->opaque_substitute;
-}
-
-WL_EXPORT const struct pixel_format_info *
-pixel_format_get_opaque_substitute(const struct pixel_format_info *info)
-{
- if (!info->opaque_substitute)
- return info;
- else
- return pixel_format_get_info(info->opaque_substitute);
-}
-
-WL_EXPORT const struct pixel_format_info *
-pixel_format_get_info_by_opaque_substitute(uint32_t format)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_LENGTH(pixel_format_table); i++) {
- if (pixel_format_table[i].opaque_substitute == format)
- return &pixel_format_table[i];
- }
-
- return NULL;
-}
-
-WL_EXPORT unsigned int
-pixel_format_width_for_plane(const struct pixel_format_info *info,
- unsigned int plane,
- unsigned int width)
-{
- /* We don't support any formats where the first plane is subsampled. */
- if (plane == 0 || !info->hsub)
- return width;
-
- return width / info->hsub;
-}
-
-WL_EXPORT unsigned int
-pixel_format_height_for_plane(const struct pixel_format_info *info,
- unsigned int plane,
- unsigned int height)
-{
- /* We don't support any formats where the first plane is subsampled. */
- if (plane == 0 || !info->vsub)
- return height;
-
- return height / info->vsub;
-}
diff --git a/libweston/pixel-formats.h b/libweston/pixel-formats.h
deleted file mode 100644
index 3e125260..00000000
--- a/libweston/pixel-formats.h
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright © 2016, 2019 Collabora, Ltd.
- * Copyright (c) 2018 DisplayLink (UK) Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Author: Daniel Stone <daniels@collabora.com>
- */
-
-#include <inttypes.h>
-#include <stdbool.h>
-
-/**
- * Contains information about pixel formats, mapping format codes from
- * wl_shm and drm_fourcc.h (which are deliberately identical, but for the
- * special cases of WL_SHM_ARGB8888 and WL_SHM_XRGB8888) into various
- * sets of information. Helper functions are provided for dealing with these
- * raw structures.
- */
-struct pixel_format_info {
- /** DRM/wl_shm format code */
- uint32_t format;
-
- /** The DRM format name without the DRM_FORMAT_ prefix. */
- const char *drm_format_name;
-
- /** If non-zero, number of planes in base (non-modified) format. */
- int num_planes;
-
- /** If format contains alpha channel, opaque equivalent of format,
- * i.e. alpha channel replaced with X. */
- uint32_t opaque_substitute;
-
- /** How the format should be sampled, expressed in terms of tokens
- * from the EGL_WL_bind_wayland_display extension. If not set,
- * assumed to be either RGB or RGBA, depending on whether or not
- * the format contains an alpha channel. The samplers may still
- * return alpha even for opaque formats; users must manually set
- * the alpha channel to 1.0 (or ignore it) if the format is
- * opaque. */
- uint32_t sampler_type;
-
- /** GL format, if data can be natively/directly uploaded. Note that
- * whilst DRM formats are little-endian unless explicitly specified,
- * (i.e. DRM_FORMAT_ARGB8888 is stored BGRA as sequential bytes in
- * memory), GL uses the sequential byte order, so that format maps to
- * GL_BGRA_EXT plus GL_UNSIGNED_BYTE. To add to the confusion, the
- * explicitly-sized types (e.g. GL_UNSIGNED_SHORT_5_5_5_1) read in
- * machine-endian order, so for these types, the correspondence
- * depends on endianness. */
- int gl_format;
-
- /** GL data type, if data can be natively/directly uploaded. */
- int gl_type;
-
- /** If set, this format can be used with the legacy drmModeAddFB()
- * function (not AddFB2), using this and the bpp member. */
- int depth;
-
- /** See 'depth' member above. */
- int bpp;
-
- /** Horizontal subsampling; if non-zero, divide the width by this
- * member to obtain the number of columns in the source buffer for
- * secondary planes only. Stride is not affected by horizontal
- * subsampling. */
- int hsub;
-
- /** Vertical subsampling; if non-zero, divide the height by this
- * member to obtain the number of rows in the source buffer for
- * secondary planes only. */
- int vsub;
-
- /* Ordering of chroma components. */
- enum {
- ORDER_UV = 0,
- ORDER_VU,
- } chroma_order;
-
- /* If packed YUV (num_planes == 1), ordering of luma/chroma
- * components. */
- enum {
- ORDER_LUMA_CHROMA = 0,
- ORDER_CHROMA_LUMA,
- } luma_chroma_order;
-
- /** How many significant bits each channel has, or zero if N/A. */
- struct {
- int r;
- int g;
- int b;
- int a;
- } bits;
-
- /** How channel bits are interpreted, fixed (uint) or floating-point */
- enum {
- PIXEL_COMPONENT_TYPE_FIXED = 0,
- PIXEL_COMPONENT_TYPE_FLOAT,
- } component_type;
-};
-
-/**
- * Get pixel format information for a DRM format code
- *
- * Given a DRM format code, return a pixel format info structure describing
- * the properties of that format.
- *
- * @param format DRM format code to get info for
- * @returns A pixel format structure (must not be freed), or NULL if the
- * format could not be found
- */
-const struct pixel_format_info *
-pixel_format_get_info(uint32_t format);
-
-/**
- * Get pixel format information for a SHM format code
- *
- * Given a SHM format code, return a DRM pixel format info structure describing
- * the properties of that format.
- *
- * @param format SHM format code to get info for.
- * @returns A pixel format structure (must not be freed), or NULL if the
- * format could not be found.
- */
-const struct pixel_format_info *
-pixel_format_get_info_shm(uint32_t format);
-
-/**
- * Get pixel format information for a named DRM format
- *
- * Given a DRM format name, return a pixel format info structure describing
- * the properties of that format.
- *
- * The DRM format name is the preprocessor token name from drm_fourcc.h
- * without the DRM_FORMAT_ prefix. The search is also case-insensitive.
- * Both "xrgb8888" and "XRGB8888" searches will find DRM_FORMAT_XRGB8888
- * for example.
- *
- * @param drm_format_name DRM format name to get info for (not NULL)
- * @returns A pixel format structure (must not be freed), or NULL if the
- * name could not be found
- */
-const struct pixel_format_info *
-pixel_format_get_info_by_drm_name(const char *drm_format_name);
-
-/**
- * Get number of planes used by a pixel format
- *
- * Given a pixel format info structure, return the number of planes
- * required for a buffer. Note that this is not necessarily identical to
- * the number of samplers required to be bound, as two views into a single
- * plane are sometimes required.
- *
- * @param format Pixel format info structure
- * @returns Number of planes required for the format
- */
-unsigned int
-pixel_format_get_plane_count(const struct pixel_format_info *format);
-
-/**
- * Determine if a pixel format is opaque or contains alpha
- *
- * Returns whether or not the pixel format is opaque, or contains a
- * significant alpha channel. Note that the suggested EGL sampler type may
- * still sample undefined data into the alpha channel; users must consider
- * alpha as 1.0 if the format is opaque, and not rely on the sampler to
- * return this when sampling from the alpha channel.
- *
- * @param format Pixel format info structure
- * @returns True if the format is opaque, or false if it has significant alpha
- */
-bool
-pixel_format_is_opaque(const struct pixel_format_info *format);
-
-/**
- * Get compatible opaque equivalent for a format
- *
- * Given a pixel format info structure, return a format which is wholly
- * compatible with the input format, but opaque, ignoring the alpha channel.
- * If an alpha format is provided, but the content is known to all be opaque,
- * then this can be used as a substitute to avoid blending.
- *
- * If the input format is opaque, this function will return the input format.
- *
- * @param format Pixel format info structure
- * @returns A pixel format info structure for the compatible opaque substitute
- */
-const struct pixel_format_info *
-pixel_format_get_opaque_substitute(const struct pixel_format_info *format);
-
-/**
- * For an opaque format, get the equivalent format with alpha instead of an
- * ignored channel
- *
- * This is the opposite lookup from pixel_format_get_opaque_substitute().
- * Finds the format whose opaque substitute is the given format.
- *
- * If the input format is not opaque or does not have ignored (X) bits, then
- * the search cannot find a match.
- *
- * @param format DRM format code to search for
- * @returns A pixel format info structure for the pixel format whose opaque
- * substitute is the argument, or NULL if no match.
- */
-const struct pixel_format_info *
-pixel_format_get_info_by_opaque_substitute(uint32_t format);
-
-/**
- * Return the effective sampling width for a given plane
- *
- * When horizontal subsampling is effective, a sampler bound to a secondary
- * plane must bind the sampler with a smaller effective width. This function
- * returns the effective width to use for the sampler, i.e. dividing by hsub.
- *
- * If horizontal subsampling is not in effect, this will be equal to the
- * width.
- *
- * @param format Pixel format info structure
- * @param plane Zero-indexed plane number
- * @param width Width of the buffer
- * @returns Effective width for sampling
- */
-unsigned int
-pixel_format_width_for_plane(const struct pixel_format_info *format,
- unsigned int plane,
- unsigned int width);
-
-/**
- * Return the effective sampling height for a given plane
- *
- * When vertical subsampling is in effect, a sampler bound to a secondary
- * plane must bind the sampler with a smaller effective height. This function
- * returns the effective height to use for the sampler, i.e. dividing by vsub.
- *
- * If vertical subsampling is not in effect, this will be equal to the height.
- *
- * @param format Pixel format info structure
- * @param plane Zero-indexed plane number
- * @param height Height of the buffer
- * @returns Effective width for sampling
- */
-unsigned int
-pixel_format_height_for_plane(const struct pixel_format_info *format,
- unsigned int plane,
- unsigned int height);
diff --git a/libweston/pixman-renderer.c b/libweston/pixman-renderer.c
deleted file mode 100644
index cae89741..00000000
--- a/libweston/pixman-renderer.c
+++ /dev/null
@@ -1,968 +0,0 @@
-/*
- * Copyright © 2012 Intel Corporation
- * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
- * Copyright © 2015 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#include "pixman-renderer.h"
-#include "shared/helpers.h"
-
-#include <linux/input.h>
-
-struct pixman_output_state {
- void *shadow_buffer;
- pixman_image_t *shadow_image;
- pixman_image_t *hw_buffer;
- pixman_region32_t *hw_extra_damage;
-};
-
-struct pixman_surface_state {
- struct weston_surface *surface;
-
- pixman_image_t *image;
- struct weston_buffer_reference buffer_ref;
- struct weston_buffer_release_reference buffer_release_ref;
-
- struct wl_listener buffer_destroy_listener;
- struct wl_listener surface_destroy_listener;
- struct wl_listener renderer_destroy_listener;
-};
-
-struct pixman_renderer {
- struct weston_renderer base;
-
- int repaint_debug;
- pixman_image_t *debug_color;
- struct weston_binding *debug_binding;
-
- struct wl_signal destroy_signal;
-};
-
-static inline struct pixman_output_state *
-get_output_state(struct weston_output *output)
-{
- return (struct pixman_output_state *)output->renderer_state;
-}
-
-static int
-pixman_renderer_create_surface(struct weston_surface *surface);
-
-static inline struct pixman_surface_state *
-get_surface_state(struct weston_surface *surface)
-{
- if (!surface->renderer_state)
- pixman_renderer_create_surface(surface);
-
- return (struct pixman_surface_state *)surface->renderer_state;
-}
-
-static inline struct pixman_renderer *
-get_renderer(struct weston_compositor *ec)
-{
- return (struct pixman_renderer *)ec->renderer;
-}
-
-static int
-pixman_renderer_read_pixels(struct weston_output *output,
- pixman_format_code_t format, void *pixels,
- uint32_t x, uint32_t y,
- uint32_t width, uint32_t height)
-{
- struct pixman_output_state *po = get_output_state(output);
- pixman_image_t *out_buf;
-
- if (!po->hw_buffer) {
- errno = ENODEV;
- return -1;
- }
-
- out_buf = pixman_image_create_bits(format,
- width,
- height,
- pixels,
- (PIXMAN_FORMAT_BPP(format) / 8) * width);
-
- pixman_image_composite32(PIXMAN_OP_SRC,
- po->hw_buffer, /* src */
- NULL /* mask */,
- out_buf, /* dest */
- x, y, /* src_x, src_y */
- 0, 0, /* mask_x, mask_y */
- 0, 0, /* dest_x, dest_y */
- pixman_image_get_width (po->hw_buffer), /* width */
- pixman_image_get_height (po->hw_buffer) /* height */);
-
- pixman_image_unref(out_buf);
-
- return 0;
-}
-
-static void
-region_global_to_output(struct weston_output *output, pixman_region32_t *region)
-{
- if (output->zoom.active) {
- weston_matrix_transform_region(region, &output->matrix, region);
- } else {
- pixman_region32_translate(region, -output->x, -output->y);
- weston_transformed_region(output->width, output->height,
- output->transform,
- output->current_scale,
- region, region);
- }
-}
-
-#define D2F(v) pixman_double_to_fixed((double)v)
-
-static void
-weston_matrix_to_pixman_transform(pixman_transform_t *pt,
- const struct weston_matrix *wm)
-{
- /* Pixman supports only 2D transform matrix, but Weston uses 3D, *
- * so we're omitting Z coordinate here. */
- pt->matrix[0][0] = pixman_double_to_fixed(wm->d[0]);
- pt->matrix[0][1] = pixman_double_to_fixed(wm->d[4]);
- pt->matrix[0][2] = pixman_double_to_fixed(wm->d[12]);
- pt->matrix[1][0] = pixman_double_to_fixed(wm->d[1]);
- pt->matrix[1][1] = pixman_double_to_fixed(wm->d[5]);
- pt->matrix[1][2] = pixman_double_to_fixed(wm->d[13]);
- pt->matrix[2][0] = pixman_double_to_fixed(wm->d[3]);
- pt->matrix[2][1] = pixman_double_to_fixed(wm->d[7]);
- pt->matrix[2][2] = pixman_double_to_fixed(wm->d[15]);
-}
-
-static void
-pixman_renderer_compute_transform(pixman_transform_t *transform_out,
- struct weston_view *ev,
- struct weston_output *output)
-{
- struct weston_matrix matrix;
-
- /* Set up the source transformation based on the surface
- position, the output position/transform/scale and the client
- specified buffer transform/scale */
- matrix = output->inverse_matrix;
-
- if (ev->transform.enabled) {
- weston_matrix_multiply(&matrix, &ev->transform.inverse);
- } else {
- weston_matrix_translate(&matrix,
- -ev->geometry.x, -ev->geometry.y, 0);
- }
-
- weston_matrix_multiply(&matrix, &ev->surface->surface_to_buffer_matrix);
-
- weston_matrix_to_pixman_transform(transform_out, &matrix);
-}
-
-static bool
-view_transformation_is_translation(struct weston_view *view)
-{
- if (!view->transform.enabled)
- return true;
-
- if (view->transform.matrix.type <= WESTON_MATRIX_TRANSFORM_TRANSLATE)
- return true;
-
- return false;
-}
-
-static void
-region_intersect_only_translation(pixman_region32_t *result_global,
- pixman_region32_t *global,
- pixman_region32_t *surf,
- struct weston_view *view)
-{
- float view_x, view_y;
-
- assert(view_transformation_is_translation(view));
-
- /* Convert from surface to global coordinates */
- pixman_region32_copy(result_global, surf);
- weston_view_to_global_float(view, 0, 0, &view_x, &view_y);
- pixman_region32_translate(result_global, (int)view_x, (int)view_y);
-
- pixman_region32_intersect(result_global, result_global, global);
-}
-
-static void
-composite_whole(pixman_op_t op,
- pixman_image_t *src,
- pixman_image_t *mask,
- pixman_image_t *dest,
- const pixman_transform_t *transform,
- pixman_filter_t filter)
-{
- int32_t dest_width;
- int32_t dest_height;
-
- dest_width = pixman_image_get_width(dest);
- dest_height = pixman_image_get_height(dest);
-
- pixman_image_set_transform(src, transform);
- pixman_image_set_filter(src, filter, NULL, 0);
-
- pixman_image_composite32(op, src, mask, dest,
- 0, 0, /* src_x, src_y */
- 0, 0, /* mask_x, mask_y */
- 0, 0, /* dest_x, dest_y */
- dest_width, dest_height);
-}
-
-static void
-composite_clipped(pixman_image_t *src,
- pixman_image_t *mask,
- pixman_image_t *dest,
- const pixman_transform_t *transform,
- pixman_filter_t filter,
- pixman_region32_t *src_clip)
-{
- int n_box;
- pixman_box32_t *boxes;
- int32_t dest_width;
- int32_t dest_height;
- int src_stride;
- int bitspp;
- pixman_format_code_t src_format;
- void *src_data;
- int i;
-
- /* Hardcoded to use PIXMAN_OP_OVER, because sampling outside of
- * a Pixman image produces (0,0,0,0) instead of discarding the
- * fragment.
- */
-
- dest_width = pixman_image_get_width(dest);
- dest_height = pixman_image_get_height(dest);
- src_format = pixman_image_get_format(src);
- src_stride = pixman_image_get_stride(src);
- bitspp = PIXMAN_FORMAT_BPP(src_format);
- src_data = pixman_image_get_data(src);
-
- assert(src_format);
-
- /* This would be massive overdraw, except when n_box is 1. */
- boxes = pixman_region32_rectangles(src_clip, &n_box);
- for (i = 0; i < n_box; i++) {
- uint8_t *ptr = src_data;
- pixman_image_t *boximg;
- pixman_transform_t adj = *transform;
-
- ptr += boxes[i].y1 * src_stride;
- ptr += boxes[i].x1 * bitspp / 8;
- boximg = pixman_image_create_bits_no_clear(src_format,
- boxes[i].x2 - boxes[i].x1,
- boxes[i].y2 - boxes[i].y1,
- (uint32_t *)ptr, src_stride);
-
- pixman_transform_translate(&adj, NULL,
- pixman_int_to_fixed(-boxes[i].x1),
- pixman_int_to_fixed(-boxes[i].y1));
- pixman_image_set_transform(boximg, &adj);
-
- pixman_image_set_filter(boximg, filter, NULL, 0);
- pixman_image_composite32(PIXMAN_OP_OVER, boximg, mask, dest,
- 0, 0, /* src_x, src_y */
- 0, 0, /* mask_x, mask_y */
- 0, 0, /* dest_x, dest_y */
- dest_width, dest_height);
-
- pixman_image_unref(boximg);
- }
-
- if (n_box > 1) {
- static bool warned = false;
-
- if (!warned)
- weston_log("Pixman-renderer warning: %dx overdraw\n",
- n_box);
- warned = true;
- }
-}
-
-/** Paint an intersected region
- *
- * \param ev The view to be painted.
- * \param output The output being painted.
- * \param repaint_output The region to be painted in output coordinates.
- * \param source_clip The region of the source image to use, in source image
- * coordinates. If NULL, use the whole source image.
- * \param pixman_op Compositing operator, either SRC or OVER.
- */
-static void
-repaint_region(struct weston_view *ev, struct weston_output *output,
- pixman_region32_t *repaint_output,
- pixman_region32_t *source_clip,
- pixman_op_t pixman_op)
-{
- struct pixman_renderer *pr =
- (struct pixman_renderer *) output->compositor->renderer;
- struct pixman_surface_state *ps = get_surface_state(ev->surface);
- struct pixman_output_state *po = get_output_state(output);
- struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
- pixman_image_t *target_image;
- pixman_transform_t transform;
- pixman_filter_t filter;
- pixman_image_t *mask_image;
- pixman_color_t mask = { 0, };
-
- if (po->shadow_image)
- target_image = po->shadow_image;
- else
- target_image = po->hw_buffer;
-
- /* Clip rendering to the damaged output region */
- pixman_image_set_clip_region32(target_image, repaint_output);
-
- pixman_renderer_compute_transform(&transform, ev, output);
-
- if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
- filter = PIXMAN_FILTER_BILINEAR;
- else
- filter = PIXMAN_FILTER_NEAREST;
-
- if (ps->buffer_ref.buffer)
- wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
-
- if (ev->alpha < 1.0) {
- mask.alpha = 0xffff * ev->alpha;
- mask_image = pixman_image_create_solid_fill(&mask);
- } else {
- mask_image = NULL;
- }
-
- if (source_clip)
- composite_clipped(ps->image, mask_image, target_image,
- &transform, filter, source_clip);
- else
- composite_whole(pixman_op, ps->image, mask_image,
- target_image, &transform, filter);
-
- if (mask_image)
- pixman_image_unref(mask_image);
-
- if (ps->buffer_ref.buffer)
- wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
-
- if (pr->repaint_debug)
- pixman_image_composite32(PIXMAN_OP_OVER,
- pr->debug_color, /* src */
- NULL /* mask */,
- target_image, /* dest */
- 0, 0, /* src_x, src_y */
- 0, 0, /* mask_x, mask_y */
- 0, 0, /* dest_x, dest_y */
- pixman_image_get_width (target_image), /* width */
- pixman_image_get_height (target_image) /* height */);
-
- pixman_image_set_clip_region32(target_image, NULL);
-}
-
-static void
-draw_view_translated(struct weston_view *view, struct weston_output *output,
- pixman_region32_t *repaint_global)
-{
- struct weston_surface *surface = view->surface;
- /* non-opaque region in surface coordinates: */
- pixman_region32_t surface_blend;
- /* region to be painted in output coordinates: */
- pixman_region32_t repaint_output;
-
- pixman_region32_init(&repaint_output);
-
- /* Blended region is whole surface minus opaque region,
- * unless surface alpha forces us to blend all.
- */
- pixman_region32_init_rect(&surface_blend, 0, 0,
- surface->width, surface->height);
-
- if (!(view->alpha < 1.0)) {
- pixman_region32_subtract(&surface_blend, &surface_blend,
- &surface->opaque);
-
- if (pixman_region32_not_empty(&surface->opaque)) {
- region_intersect_only_translation(&repaint_output,
- repaint_global,
- &surface->opaque,
- view);
- region_global_to_output(output, &repaint_output);
-
- repaint_region(view, output, &repaint_output, NULL,
- PIXMAN_OP_SRC);
- }
- }
-
- if (pixman_region32_not_empty(&surface_blend)) {
- region_intersect_only_translation(&repaint_output,
- repaint_global,
- &surface_blend, view);
- region_global_to_output(output, &repaint_output);
-
- repaint_region(view, output, &repaint_output, NULL,
- PIXMAN_OP_OVER);
- }
-
- pixman_region32_fini(&surface_blend);
- pixman_region32_fini(&repaint_output);
-}
-
-static void
-draw_view_source_clipped(struct weston_view *view,
- struct weston_output *output,
- pixman_region32_t *repaint_global)
-{
- struct weston_surface *surface = view->surface;
- pixman_region32_t surf_region;
- pixman_region32_t buffer_region;
- pixman_region32_t repaint_output;
-
- /* Do not bother separating the opaque region from non-opaque.
- * Source clipping requires PIXMAN_OP_OVER in all cases, so painting
- * opaque separately has no benefit.
- */
-
- pixman_region32_init_rect(&surf_region, 0, 0,
- surface->width, surface->height);
- if (view->geometry.scissor_enabled)
- pixman_region32_intersect(&surf_region, &surf_region,
- &view->geometry.scissor);
-
- pixman_region32_init(&buffer_region);
- weston_surface_to_buffer_region(surface, &surf_region, &buffer_region);
-
- pixman_region32_init(&repaint_output);
- pixman_region32_copy(&repaint_output, repaint_global);
- region_global_to_output(output, &repaint_output);
-
- repaint_region(view, output, &repaint_output, &buffer_region,
- PIXMAN_OP_OVER);
-
- pixman_region32_fini(&repaint_output);
- pixman_region32_fini(&buffer_region);
- pixman_region32_fini(&surf_region);
-}
-
-static void
-draw_view(struct weston_view *ev, struct weston_output *output,
- pixman_region32_t *damage) /* in global coordinates */
-{
- struct pixman_surface_state *ps = get_surface_state(ev->surface);
- /* repaint bounding region in global coordinates: */
- pixman_region32_t repaint;
-
- /* No buffer attached */
- if (!ps->image)
- return;
-
- pixman_region32_init(&repaint);
- pixman_region32_intersect(&repaint,
- &ev->transform.boundingbox, damage);
- pixman_region32_subtract(&repaint, &repaint, &ev->clip);
-
- if (!pixman_region32_not_empty(&repaint))
- goto out;
-
- if (view_transformation_is_translation(ev)) {
- /* The simple case: The surface regions opaque, non-opaque,
- * etc. are convertible to global coordinate space.
- * There is no need to use a source clip region.
- * It is possible to paint opaque region as PIXMAN_OP_SRC.
- * Also the boundingbox is accurate rather than an
- * approximation.
- */
- draw_view_translated(ev, output, &repaint);
- } else {
- /* The complex case: the view transformation does not allow
- * converting opaque etc. regions into global coordinate space.
- * Therefore we need source clipping to avoid sampling from
- * unwanted source image areas, unless the source image is
- * to be used whole. Source clipping does not work with
- * PIXMAN_OP_SRC.
- */
- draw_view_source_clipped(ev, output, &repaint);
- }
-
-out:
- pixman_region32_fini(&repaint);
-}
-static void
-repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
-{
- struct weston_compositor *compositor = output->compositor;
- struct weston_view *view;
-
- wl_list_for_each_reverse(view, &compositor->view_list, link)
- if (view->plane == &compositor->primary_plane)
- draw_view(view, output, damage);
-}
-
-static void
-copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
-{
- struct pixman_output_state *po = get_output_state(output);
- pixman_region32_t output_region;
-
- pixman_region32_init(&output_region);
- pixman_region32_copy(&output_region, region);
-
- region_global_to_output(output, &output_region);
-
- pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
- pixman_region32_fini(&output_region);
-
- pixman_image_composite32(PIXMAN_OP_SRC,
- po->shadow_image, /* src */
- NULL /* mask */,
- po->hw_buffer, /* dest */
- 0, 0, /* src_x, src_y */
- 0, 0, /* mask_x, mask_y */
- 0, 0, /* dest_x, dest_y */
- pixman_image_get_width (po->hw_buffer), /* width */
- pixman_image_get_height (po->hw_buffer) /* height */);
-
- pixman_image_set_clip_region32 (po->hw_buffer, NULL);
-}
-
-static void
-pixman_renderer_repaint_output(struct weston_output *output,
- pixman_region32_t *output_damage)
-{
- struct pixman_output_state *po = get_output_state(output);
- pixman_region32_t hw_damage;
-
- if (!po->hw_buffer) {
- po->hw_extra_damage = NULL;
- return;
- }
-
- pixman_region32_init(&hw_damage);
- if (po->hw_extra_damage) {
- pixman_region32_union(&hw_damage,
- po->hw_extra_damage, output_damage);
- po->hw_extra_damage = NULL;
- } else {
- pixman_region32_copy(&hw_damage, output_damage);
- }
-
- if (po->shadow_image) {
- repaint_surfaces(output, output_damage);
- copy_to_hw_buffer(output, &hw_damage);
- } else {
- repaint_surfaces(output, &hw_damage);
- }
- pixman_region32_fini(&hw_damage);
-
- wl_signal_emit(&output->frame_signal, output_damage);
-
- /* Actual flip should be done by caller */
-}
-
-static void
-pixman_renderer_flush_damage(struct weston_surface *surface)
-{
- /* No-op for pixman renderer */
-}
-
-static void
-buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
-{
- struct pixman_surface_state *ps;
-
- ps = container_of(listener, struct pixman_surface_state,
- buffer_destroy_listener);
-
- if (ps->image) {
- pixman_image_unref(ps->image);
- ps->image = NULL;
- }
-
- ps->buffer_destroy_listener.notify = NULL;
-}
-
-static void
-pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
-{
- struct pixman_surface_state *ps = get_surface_state(es);
- struct wl_shm_buffer *shm_buffer;
- pixman_format_code_t pixman_format;
-
- weston_buffer_reference(&ps->buffer_ref, buffer);
- weston_buffer_release_reference(&ps->buffer_release_ref,
- es->buffer_release_ref.buffer_release);
-
- if (ps->buffer_destroy_listener.notify) {
- wl_list_remove(&ps->buffer_destroy_listener.link);
- ps->buffer_destroy_listener.notify = NULL;
- }
-
- if (ps->image) {
- pixman_image_unref(ps->image);
- ps->image = NULL;
- }
-
- if (!buffer)
- return;
-
- shm_buffer = wl_shm_buffer_get(buffer->resource);
-
- if (! shm_buffer) {
- weston_log("Pixman renderer supports only SHM buffers\n");
- weston_buffer_reference(&ps->buffer_ref, NULL);
- weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
- return;
- }
-
- switch (wl_shm_buffer_get_format(shm_buffer)) {
- case WL_SHM_FORMAT_XRGB8888:
- pixman_format = PIXMAN_x8r8g8b8;
- es->is_opaque = true;
- break;
- case WL_SHM_FORMAT_ARGB8888:
- pixman_format = PIXMAN_a8r8g8b8;
- es->is_opaque = false;
- break;
- case WL_SHM_FORMAT_RGB565:
- pixman_format = PIXMAN_r5g6b5;
- es->is_opaque = true;
- break;
- default:
- weston_log("Unsupported SHM buffer format 0x%x\n",
- wl_shm_buffer_get_format(shm_buffer));
- weston_buffer_reference(&ps->buffer_ref, NULL);
- weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
- weston_buffer_send_server_error(buffer,
- "disconnecting due to unhandled buffer type");
- return;
- break;
- }
-
- buffer->shm_buffer = shm_buffer;
- buffer->width = wl_shm_buffer_get_width(shm_buffer);
- buffer->height = wl_shm_buffer_get_height(shm_buffer);
-
- ps->image = pixman_image_create_bits(pixman_format,
- buffer->width, buffer->height,
- wl_shm_buffer_get_data(shm_buffer),
- wl_shm_buffer_get_stride(shm_buffer));
-
- ps->buffer_destroy_listener.notify =
- buffer_state_handle_buffer_destroy;
- wl_signal_add(&buffer->destroy_signal,
- &ps->buffer_destroy_listener);
-}
-
-static void
-pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
-{
- wl_list_remove(&ps->surface_destroy_listener.link);
- wl_list_remove(&ps->renderer_destroy_listener.link);
- if (ps->buffer_destroy_listener.notify) {
- wl_list_remove(&ps->buffer_destroy_listener.link);
- ps->buffer_destroy_listener.notify = NULL;
- }
-
- ps->surface->renderer_state = NULL;
-
- if (ps->image) {
- pixman_image_unref(ps->image);
- ps->image = NULL;
- }
- weston_buffer_reference(&ps->buffer_ref, NULL);
- weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
- free(ps);
-}
-
-static void
-surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
-{
- struct pixman_surface_state *ps;
-
- ps = container_of(listener, struct pixman_surface_state,
- surface_destroy_listener);
-
- pixman_renderer_surface_state_destroy(ps);
-}
-
-static void
-surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
-{
- struct pixman_surface_state *ps;
-
- ps = container_of(listener, struct pixman_surface_state,
- renderer_destroy_listener);
-
- pixman_renderer_surface_state_destroy(ps);
-}
-
-static int
-pixman_renderer_create_surface(struct weston_surface *surface)
-{
- struct pixman_surface_state *ps;
- struct pixman_renderer *pr = get_renderer(surface->compositor);
-
- ps = zalloc(sizeof *ps);
- if (ps == NULL)
- return -1;
-
- surface->renderer_state = ps;
-
- ps->surface = surface;
-
- ps->surface_destroy_listener.notify =
- surface_state_handle_surface_destroy;
- wl_signal_add(&surface->destroy_signal,
- &ps->surface_destroy_listener);
-
- ps->renderer_destroy_listener.notify =
- surface_state_handle_renderer_destroy;
- wl_signal_add(&pr->destroy_signal,
- &ps->renderer_destroy_listener);
-
- return 0;
-}
-
-static void
-pixman_renderer_surface_set_color(struct weston_surface *es,
- float red, float green, float blue, float alpha)
-{
- struct pixman_surface_state *ps = get_surface_state(es);
- pixman_color_t color;
-
- color.red = red * 0xffff;
- color.green = green * 0xffff;
- color.blue = blue * 0xffff;
- color.alpha = alpha * 0xffff;
-
- if (ps->image) {
- pixman_image_unref(ps->image);
- ps->image = NULL;
- }
-
- ps->image = pixman_image_create_solid_fill(&color);
-}
-
-static void
-pixman_renderer_destroy(struct weston_compositor *ec)
-{
- struct pixman_renderer *pr = get_renderer(ec);
-
- wl_signal_emit(&pr->destroy_signal, pr);
- weston_binding_destroy(pr->debug_binding);
- free(pr);
-
- ec->renderer = NULL;
-}
-
-static void
-pixman_renderer_surface_get_content_size(struct weston_surface *surface,
- int *width, int *height)
-{
- struct pixman_surface_state *ps = get_surface_state(surface);
-
- if (ps->image) {
- *width = pixman_image_get_width(ps->image);
- *height = pixman_image_get_height(ps->image);
- } else {
- *width = 0;
- *height = 0;
- }
-}
-
-static int
-pixman_renderer_surface_copy_content(struct weston_surface *surface,
- void *target, size_t size,
- int src_x, int src_y,
- int width, int height)
-{
- const pixman_format_code_t format = PIXMAN_a8b8g8r8;
- const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
- struct pixman_surface_state *ps = get_surface_state(surface);
- pixman_image_t *out_buf;
-
- if (!ps->image)
- return -1;
-
- out_buf = pixman_image_create_bits(format, width, height,
- target, width * bytespp);
-
- pixman_image_set_transform(ps->image, NULL);
- pixman_image_composite32(PIXMAN_OP_SRC,
- ps->image, /* src */
- NULL, /* mask */
- out_buf, /* dest */
- src_x, src_y, /* src_x, src_y */
- 0, 0, /* mask_x, mask_y */
- 0, 0, /* dest_x, dest_y */
- width, height);
-
- pixman_image_unref(out_buf);
-
- return 0;
-}
-
-static void
-debug_binding(struct weston_keyboard *keyboard, const struct timespec *time,
- uint32_t key, void *data)
-{
- struct weston_compositor *ec = data;
- struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
-
- pr->repaint_debug ^= 1;
-
- if (pr->repaint_debug) {
- pixman_color_t red = {
- 0x3fff, 0x0000, 0x0000, 0x3fff
- };
-
- pr->debug_color = pixman_image_create_solid_fill(&red);
- } else {
- pixman_image_unref(pr->debug_color);
- weston_compositor_damage_all(ec);
- }
-}
-
-WL_EXPORT int
-pixman_renderer_init(struct weston_compositor *ec)
-{
- struct pixman_renderer *renderer;
-
- renderer = zalloc(sizeof *renderer);
- if (renderer == NULL)
- return -1;
-
- renderer->repaint_debug = 0;
- renderer->debug_color = NULL;
- renderer->base.read_pixels = pixman_renderer_read_pixels;
- renderer->base.repaint_output = pixman_renderer_repaint_output;
- renderer->base.flush_damage = pixman_renderer_flush_damage;
- renderer->base.attach = pixman_renderer_attach;
- renderer->base.surface_set_color = pixman_renderer_surface_set_color;
- renderer->base.destroy = pixman_renderer_destroy;
- renderer->base.surface_get_content_size =
- pixman_renderer_surface_get_content_size;
- renderer->base.surface_copy_content =
- pixman_renderer_surface_copy_content;
- ec->renderer = &renderer->base;
- ec->capabilities |= WESTON_CAP_ROTATION_ANY;
- ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
-
- renderer->debug_binding =
- weston_compositor_add_debug_binding(ec, KEY_R,
- debug_binding, ec);
-
- wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
-
- wl_signal_init(&renderer->destroy_signal);
-
- return 0;
-}
-
-WL_EXPORT void
-pixman_renderer_output_set_buffer(struct weston_output *output,
- pixman_image_t *buffer)
-{
- struct pixman_output_state *po = get_output_state(output);
-
- if (po->hw_buffer)
- pixman_image_unref(po->hw_buffer);
- po->hw_buffer = buffer;
-
- if (po->hw_buffer) {
- output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
- pixman_image_ref(po->hw_buffer);
- }
-}
-
-WL_EXPORT void
-pixman_renderer_output_set_hw_extra_damage(struct weston_output *output,
- pixman_region32_t *extra_damage)
-{
- struct pixman_output_state *po = get_output_state(output);
-
- po->hw_extra_damage = extra_damage;
-}
-
-WL_EXPORT int
-pixman_renderer_output_create(struct weston_output *output, uint32_t flags)
-{
- struct pixman_output_state *po;
- int w, h;
-
- po = zalloc(sizeof *po);
- if (po == NULL)
- return -1;
-
- if (flags & PIXMAN_RENDERER_OUTPUT_USE_SHADOW) {
- /* set shadow image transformation */
- w = output->current_mode->width;
- h = output->current_mode->height;
-
- po->shadow_buffer = malloc(w * h * 4);
-
- if (!po->shadow_buffer) {
- free(po);
- return -1;
- }
-
- po->shadow_image =
- pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
- po->shadow_buffer, w * 4);
-
- if (!po->shadow_image) {
- free(po->shadow_buffer);
- free(po);
- return -1;
- }
- }
-
- output->renderer_state = po;
-
- return 0;
-}
-
-WL_EXPORT void
-pixman_renderer_output_destroy(struct weston_output *output)
-{
- struct pixman_output_state *po = get_output_state(output);
-
- if (po->shadow_image)
- pixman_image_unref(po->shadow_image);
-
- if (po->hw_buffer)
- pixman_image_unref(po->hw_buffer);
-
- free(po->shadow_buffer);
-
- po->shadow_buffer = NULL;
- po->shadow_image = NULL;
- po->hw_buffer = NULL;
-
- free(po);
-}
diff --git a/libweston/pixman-renderer.h b/libweston/pixman-renderer.h
deleted file mode 100644
index f53ae2a3..00000000
--- a/libweston/pixman-renderer.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <libweston/libweston.h>
-#include "backend.h"
-#include "libweston-internal.h"
-
-int
-pixman_renderer_init(struct weston_compositor *ec);
-
-enum pixman_renderer_output_flags {
- PIXMAN_RENDERER_OUTPUT_USE_SHADOW = (1 << 0),
-};
-
-int
-pixman_renderer_output_create(struct weston_output *output, uint32_t flags);
-
-void
-pixman_renderer_output_set_buffer(struct weston_output *output,
- pixman_image_t *buffer);
-
-void
-pixman_renderer_output_set_hw_extra_damage(struct weston_output *output,
- pixman_region32_t *extra_damage);
-
-void
-pixman_renderer_output_destroy(struct weston_output *output);
diff --git a/libweston/plugin-registry.c b/libweston/plugin-registry.c
deleted file mode 100644
index f5ec6fa5..00000000
--- a/libweston/plugin-registry.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2016 DENSO CORPORATION
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <libweston/libweston.h>
-#include <libweston/plugin-registry.h>
-
-struct weston_plugin_api {
- struct wl_list link; /**< in weston_compositor::plugin_api_list */
-
- char *api_name; /**< The search key */
- const void *vtable; /**< The function table */
- size_t vtable_size; /**< Size of the function table in bytes */
-};
-
-/** Register an implementation of an API
- *
- * \param compositor The compositor instance.
- * \param api_name The API name which other plugins use to find the
- * implementation.
- * \param vtable Pointer to the function table of the API.
- * \param vtable_size Size of the function table in bytes.
- * \return 0 on success, -1 on error, -2 if api_name already registered
- *
- * This call makes the given vtable to be reachable via
- * weston_plugin_api_get(). Calls through the vtable may start happening
- * as soon as the caller returns after success. Argument vtable must not be
- * NULL. Argument api_name must be non-NULL and non-zero length.
- *
- * You can increase the function table size without breaking the ABI.
- * To cater for ABI breaks, it is recommended to have api_name include a
- * version number.
- *
- * A registered API cannot be unregistered. However, calls through a
- * registered API must not be made from the compositor destroy signal handlers.
- */
-WL_EXPORT int
-weston_plugin_api_register(struct weston_compositor *compositor,
- const char *api_name,
- const void *vtable,
- size_t vtable_size)
-{
- struct weston_plugin_api *wpa;
-
- assert(api_name);
- assert(strlen(api_name) > 0);
- assert(vtable);
-
- if (!api_name || !vtable || strlen(api_name) == 0)
- return -1;
-
- wl_list_for_each(wpa, &compositor->plugin_api_list, link)
- if (strcmp(wpa->api_name, api_name) == 0)
- return -2;
-
- wpa = zalloc(sizeof(*wpa));
- if (!wpa)
- return -1;
-
- wpa->api_name = strdup(api_name);
- wpa->vtable = vtable;
- wpa->vtable_size = vtable_size;
-
- if (!wpa->api_name) {
- free(wpa);
-
- return -1;
- }
-
- wl_list_insert(&compositor->plugin_api_list, &wpa->link);
- weston_log("Registered plugin API '%s' of size %zd\n",
- wpa->api_name, wpa->vtable_size);
-
- return 0;
-}
-
-/** Internal function to free registered APIs
- *
- * \param compositor The compositor instance.
- */
-void
-weston_plugin_api_destroy_list(struct weston_compositor *compositor)
-{
- struct weston_plugin_api *wpa, *tmp;
-
- wl_list_for_each_safe(wpa, tmp, &compositor->plugin_api_list, link) {
- free(wpa->api_name);
- wl_list_remove(&wpa->link);
- free(wpa);
- }
-}
-
-/** Fetch the implementation of an API
- *
- * \param compositor The compositor instance.
- * \param api_name The name of the API to search for.
- * \param vtable_size The expected function table size in bytes.
- * \return Pointer to the function table, or NULL on error.
- *
- * Find the function table corresponding to api_name. The vtable_size here
- * must be less or equal to the vtable_size given in the corresponding
- * weston_plugin_api_register() call made by the implementing plugin.
- *
- * Calls can be made through the function table immediately. However, calls
- * must not be made from or after the compositor destroy signal handler.
- */
-WL_EXPORT const void *
-weston_plugin_api_get(struct weston_compositor *compositor,
- const char *api_name,
- size_t vtable_size)
-{
- struct weston_plugin_api *wpa;
-
- assert(api_name);
- if (!api_name)
- return NULL;
-
- wl_list_for_each(wpa, &compositor->plugin_api_list, link) {
- if (strcmp(wpa->api_name, api_name) != 0)
- continue;
-
- if (vtable_size <= wpa->vtable_size)
- return wpa->vtable;
-
- return NULL;
- }
-
- return NULL;
-}
diff --git a/libweston/renderer-gl/egl-glue.c b/libweston/renderer-gl/egl-glue.c
deleted file mode 100644
index d96efeae..00000000
--- a/libweston/renderer-gl/egl-glue.c
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- * Copyright © 2012 Intel Corporation
- * Copyright © 2015, 2019 Collabora, Ltd.
- * Copyright © 2016 NVIDIA Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <assert.h>
-
-#include "shared/helpers.h"
-#include "shared/platform.h"
-
-#include "gl-renderer.h"
-#include "gl-renderer-internal.h"
-#include "pixel-formats.h"
-#include "shared/weston-egl-ext.h"
-
-#include <assert.h>
-
-struct egl_config_print_info {
- const EGLint *attrs;
- unsigned attrs_count;
- const char *prefix;
- const char *separator;
- int field_width;
-};
-
-static const char *
-egl_error_string(EGLint code)
-{
-#define MYERRCODE(x) case x: return #x;
- switch (code) {
- MYERRCODE(EGL_SUCCESS)
- MYERRCODE(EGL_NOT_INITIALIZED)
- MYERRCODE(EGL_BAD_ACCESS)
- MYERRCODE(EGL_BAD_ALLOC)
- MYERRCODE(EGL_BAD_ATTRIBUTE)
- MYERRCODE(EGL_BAD_CONTEXT)
- MYERRCODE(EGL_BAD_CONFIG)
- MYERRCODE(EGL_BAD_CURRENT_SURFACE)
- MYERRCODE(EGL_BAD_DISPLAY)
- MYERRCODE(EGL_BAD_SURFACE)
- MYERRCODE(EGL_BAD_MATCH)
- MYERRCODE(EGL_BAD_PARAMETER)
- MYERRCODE(EGL_BAD_NATIVE_PIXMAP)
- MYERRCODE(EGL_BAD_NATIVE_WINDOW)
- MYERRCODE(EGL_CONTEXT_LOST)
- default:
- return "unknown";
- }
-#undef MYERRCODE
-}
-
-void
-gl_renderer_print_egl_error_state(void)
-{
- EGLint code;
-
- code = eglGetError();
- weston_log("EGL error state: %s (0x%04lx)\n",
- egl_error_string(code), (long)code);
-}
-
-static void
-print_egl_surface_type_bits(FILE *fp, EGLint egl_surface_type)
-{
- const char *sep = "";
- unsigned i;
-
- static const struct {
- EGLint bit;
- const char *str;
- } egl_surf_bits[] = {
- { EGL_WINDOW_BIT, "win" },
- { EGL_PIXMAP_BIT, "pix" },
- { EGL_PBUFFER_BIT, "pbf" },
- { EGL_MULTISAMPLE_RESOLVE_BOX_BIT, "ms_resolve_box" },
- { EGL_SWAP_BEHAVIOR_PRESERVED_BIT, "swap_preserved" },
- };
-
- for (i = 0; i < ARRAY_LENGTH(egl_surf_bits); i++) {
- if (egl_surface_type & egl_surf_bits[i].bit) {
- fprintf(fp, "%s%s", sep, egl_surf_bits[i].str);
- sep = "|";
- }
- }
-}
-
-static const struct egl_config_print_info config_info_ints[] = {
-#define ARRAY(...) ((const EGLint[]) { __VA_ARGS__ })
-
- { ARRAY(EGL_CONFIG_ID), 1, "id: ", "", 3 },
- { ARRAY(EGL_RED_SIZE, EGL_GREEN_SIZE, EGL_BLUE_SIZE, EGL_ALPHA_SIZE), 4,
- "rgba: ", " ", 1 },
- { ARRAY(EGL_BUFFER_SIZE), 1, "buf: ", "", 2 },
- { ARRAY(EGL_DEPTH_SIZE), 1, "dep: ", "", 2 },
- { ARRAY(EGL_STENCIL_SIZE), 1, "stcl: ", "", 1 },
- { ARRAY(EGL_MIN_SWAP_INTERVAL, EGL_MAX_SWAP_INTERVAL), 2,
- "int: ", "-", 1 },
-
-#undef ARRAY
-};
-
-static void
-print_egl_config_ints(FILE *fp, EGLDisplay egldpy, EGLConfig eglconfig)
-{
- unsigned i;
-
- for (i = 0; i < ARRAY_LENGTH(config_info_ints); i++) {
- const struct egl_config_print_info *info = &config_info_ints[i];
- unsigned j;
- const char *sep = "";
-
- fputs(info->prefix, fp);
- for (j = 0; j < info->attrs_count; j++) {
- EGLint value;
-
- if (eglGetConfigAttrib(egldpy, eglconfig,
- info->attrs[j], &value)) {
- fprintf(fp, "%s%*d",
- sep, info->field_width, value);
- } else {
- fprintf(fp, "%s!", sep);
- }
- sep = info->separator;
- }
-
- fputs(" ", fp);
- }
-}
-
-static void
-print_egl_config_info(FILE *fp, EGLDisplay egldpy, EGLConfig eglconfig)
-{
- EGLint value;
-
- print_egl_config_ints(fp, egldpy, eglconfig);
-
- fputs("type: ", fp);
- if (eglGetConfigAttrib(egldpy, eglconfig, EGL_SURFACE_TYPE, &value))
- print_egl_surface_type_bits(fp, value);
- else
- fputs("-", fp);
-
- fputs(" vis_id: ", fp);
- if (eglGetConfigAttrib(egldpy, eglconfig, EGL_NATIVE_VISUAL_ID, &value)) {
- if (value != 0) {
- const struct pixel_format_info *p;
-
- p = pixel_format_get_info(value);
- if (p) {
- fprintf(fp, "%s (0x%x)",
- p->drm_format_name, (unsigned)value);
- } else {
- fprintf(fp, "0x%x", (unsigned)value);
- }
- } else {
- fputs("0", fp);
- }
- } else {
- fputs("-", fp);
- }
-}
-
-static void
-log_all_egl_configs(EGLDisplay egldpy)
-{
- EGLint count = 0;
- EGLConfig *configs;
- int i;
- char *strbuf = NULL;
- size_t strsize = 0;
- FILE *fp;
-
- weston_log("All available EGLConfigs:\n");
-
- if (!eglGetConfigs(egldpy, NULL, 0, &count) || count < 1)
- return;
-
- configs = calloc(count, sizeof *configs);
- if (!configs)
- return;
-
- if (!eglGetConfigs(egldpy, configs, count, &count))
- return;
-
- fp = open_memstream(&strbuf, &strsize);
- if (!fp)
- goto out;
-
- for (i = 0; i < count; i++) {
- print_egl_config_info(fp, egldpy, configs[i]);
- fputc(0, fp);
- fflush(fp);
- weston_log_continue(STAMP_SPACE "%s\n", strbuf);
- rewind(fp);
- }
-
- fclose(fp);
- free(strbuf);
-
-out:
- free(configs);
-}
-
-void
-log_egl_config_info(EGLDisplay egldpy, EGLConfig eglconfig)
-{
- char *strbuf = NULL;
- size_t strsize = 0;
- FILE *fp;
-
- fp = open_memstream(&strbuf, &strsize);
- if (fp) {
- print_egl_config_info(fp, egldpy, eglconfig);
- fclose(fp);
- }
-
- weston_log("Chosen EGL config details: %s\n", strbuf ? strbuf : "?");
- free(strbuf);
-}
-
-static bool
-egl_config_pixel_format_matches(struct gl_renderer *gr,
- EGLConfig config,
- const struct pixel_format_info *pinfo)
-{
- static const EGLint attribs[4] = {
- EGL_ALPHA_SIZE, EGL_RED_SIZE, EGL_GREEN_SIZE, EGL_BLUE_SIZE
- };
- const int *argb[4] = {
- &pinfo->bits.a, &pinfo->bits.r, &pinfo->bits.g, &pinfo->bits.b
- };
- unsigned i;
- EGLint value;
-
- if (gr->platform == EGL_PLATFORM_GBM_KHR) {
- if (!eglGetConfigAttrib(gr->egl_display, config,
- EGL_NATIVE_VISUAL_ID, &value))
- return false;
-
- return ((uint32_t)value) == pinfo->format;
- }
-
- for (i = 0; i < 4; i++) {
- if (!eglGetConfigAttrib(gr->egl_display, config,
- attribs[i], &value))
- return false;
- if (value != *argb[i])
- return false;
- }
-
- return true;
-}
-
-static int
-egl_choose_config(struct gl_renderer *gr,
- const EGLint *attribs,
- const struct pixel_format_info *const *pinfo,
- unsigned pinfo_count,
- EGLConfig *config_out)
-{
- EGLint count = 0;
- EGLint matched = 0;
- EGLConfig *configs;
- unsigned i;
- EGLint j;
- int config_index = -1;
-
- if (!eglGetConfigs(gr->egl_display, NULL, 0, &count) || count < 1) {
- weston_log("No EGL configs to choose from.\n");
- return -1;
- }
- configs = calloc(count, sizeof *configs);
- if (!configs)
- return -1;
-
- if (!eglChooseConfig(gr->egl_display, attribs, configs,
- count, &matched) || !matched) {
- weston_log("No EGL configs with appropriate attributes.\n");
- goto out;
- }
-
- if (pinfo_count == 0)
- config_index = 0;
-
- for (i = 0; config_index == -1 && i < pinfo_count; i++)
- for (j = 0; config_index == -1 && j < matched; j++)
- if (egl_config_pixel_format_matches(gr, configs[j],
- pinfo[i]))
- config_index = j;
-
- if (config_index != -1)
- *config_out = configs[config_index];
-
-out:
- free(configs);
- if (config_index == -1)
- return -1;
-
- if (i > 1)
- weston_log("Unable to use first choice EGL config with"
- " %s, succeeded with alternate %s.\n",
- pinfo[0]->drm_format_name,
- pinfo[i - 1]->drm_format_name);
- return 0;
-}
-
-static bool
-egl_config_is_compatible(struct gl_renderer *gr,
- EGLConfig config,
- EGLint egl_surface_type,
- const struct pixel_format_info *const *pinfo,
- unsigned pinfo_count)
-{
- EGLint value;
- unsigned i;
-
- if (config == EGL_NO_CONFIG_KHR)
- return false;
-
- if (!eglGetConfigAttrib(gr->egl_display, config,
- EGL_SURFACE_TYPE, &value))
- return false;
- if ((value & egl_surface_type) != egl_surface_type)
- return false;
-
- for (i = 0; i < pinfo_count; i++) {
- if (egl_config_pixel_format_matches(gr, config, pinfo[i]))
- return true;
- }
- return false;
-}
-
-/* The caller must free() the string */
-static char *
-explain_egl_config_criteria(EGLint egl_surface_type,
- const struct pixel_format_info *const *pinfo,
- unsigned pinfo_count)
-{
- FILE *fp;
- char *str = NULL;
- size_t size = 0;
- const char *sep;
- unsigned i;
-
- fp = open_memstream(&str, &size);
- if (!fp)
- return NULL;
-
- fputs("{ ", fp);
-
- print_egl_surface_type_bits(fp, egl_surface_type);
- fputs("; ", fp);
-
- sep = "";
- for (i = 0; i < pinfo_count; i++) {
- fprintf(fp, "%s%s", sep, pinfo[i]->drm_format_name);
- sep = ", ";
- }
-
- fputs(" }", fp);
-
- fclose(fp);
-
- return str;
-}
-
-EGLConfig
-gl_renderer_get_egl_config(struct gl_renderer *gr,
- EGLint egl_surface_type,
- const uint32_t *drm_formats,
- unsigned drm_formats_count)
-{
- EGLConfig egl_config;
- const struct pixel_format_info *pinfo[16];
- unsigned pinfo_count;
- unsigned i;
- char *what;
- EGLint config_attribs[] = {
- EGL_SURFACE_TYPE, egl_surface_type,
- EGL_RED_SIZE, 1,
- EGL_GREEN_SIZE, 1,
- EGL_BLUE_SIZE, 1,
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL_NONE
- };
-
- assert(drm_formats_count < ARRAY_LENGTH(pinfo));
- drm_formats_count = MIN(drm_formats_count, ARRAY_LENGTH(pinfo));
-
- for (pinfo_count = 0, i = 0; i < drm_formats_count; i++) {
- pinfo[pinfo_count] = pixel_format_get_info(drm_formats[i]);
- if (!pinfo[pinfo_count]) {
- weston_log("Bad/unknown DRM format code 0x%08x.\n",
- drm_formats[i]);
- continue;
- }
- pinfo_count++;
- }
-
- if (egl_config_is_compatible(gr, gr->egl_config, egl_surface_type,
- pinfo, pinfo_count))
- return gr->egl_config;
-
- if (egl_choose_config(gr, config_attribs, pinfo, pinfo_count,
- &egl_config) < 0) {
- what = explain_egl_config_criteria(egl_surface_type,
- pinfo, pinfo_count);
- weston_log("No EGLConfig matches %s.\n", what);
- free(what);
- log_all_egl_configs(gr->egl_display);
- return EGL_NO_CONFIG_KHR;
- }
-
- /*
- * If we do not have configless context support, all EGLConfigs must
- * be the one and the same, because we use just one GL context for
- * everything.
- */
- if (gr->egl_config != EGL_NO_CONFIG_KHR &&
- egl_config != gr->egl_config) {
- what = explain_egl_config_criteria(egl_surface_type,
- pinfo, pinfo_count);
- weston_log("Found an EGLConfig matching %s but it is not usable"
- " because neither EGL_KHR_no_config_context nor "
- "EGL_MESA_configless_context are supported by EGL.\n",
- what);
- free(what);
- return EGL_NO_CONFIG_KHR;
- }
-
- return egl_config;
-}
-
-static void
-renderer_setup_egl_client_extensions(struct gl_renderer *gr)
-{
- const char *extensions;
-
- extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
- if (!extensions) {
- weston_log("Retrieving EGL client extension string failed.\n");
- return;
- }
-
- if (weston_check_egl_extension(extensions, "EGL_EXT_platform_base"))
- gr->create_platform_window =
- (void *) eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
- else
- weston_log("warning: EGL_EXT_platform_base not supported.\n");
-}
-
-int
-gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
-{
- static const struct {
- char *extension, *entrypoint;
- } swap_damage_ext_to_entrypoint[] = {
- {
- .extension = "EGL_EXT_swap_buffers_with_damage",
- .entrypoint = "eglSwapBuffersWithDamageEXT",
- },
- {
- .extension = "EGL_KHR_swap_buffers_with_damage",
- .entrypoint = "eglSwapBuffersWithDamageKHR",
- },
- };
- struct gl_renderer *gr = get_renderer(ec);
- const char *extensions;
- EGLBoolean ret;
- unsigned i;
-
- gr->create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
- gr->destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
-
- gr->bind_display =
- (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
- gr->unbind_display =
- (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
- gr->query_buffer =
- (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
- gr->set_damage_region =
- (void *) eglGetProcAddress("eglSetDamageRegionKHR");
-
- extensions =
- (const char *) eglQueryString(gr->egl_display, EGL_EXTENSIONS);
- if (!extensions) {
- weston_log("Retrieving EGL extension string failed.\n");
- return -1;
- }
-
- if (weston_check_egl_extension(extensions, "EGL_IMG_context_priority"))
- gr->has_context_priority = true;
-
- if (weston_check_egl_extension(extensions, "EGL_WL_bind_wayland_display"))
- gr->has_bind_display = true;
- if (gr->has_bind_display) {
- assert(gr->bind_display);
- assert(gr->unbind_display);
- assert(gr->query_buffer);
- ret = gr->bind_display(gr->egl_display, ec->wl_display);
- if (!ret)
- gr->has_bind_display = false;
- }
-
- if (weston_check_egl_extension(extensions, "EGL_EXT_buffer_age"))
- gr->has_egl_buffer_age = true;
-
- if (weston_check_egl_extension(extensions, "EGL_KHR_partial_update")) {
- assert(gr->set_damage_region);
- gr->has_egl_partial_update = true;
- }
-
- for (i = 0; i < ARRAY_LENGTH(swap_damage_ext_to_entrypoint); i++) {
- if (weston_check_egl_extension(extensions,
- swap_damage_ext_to_entrypoint[i].extension)) {
- gr->swap_buffers_with_damage =
- (void *) eglGetProcAddress(
- swap_damage_ext_to_entrypoint[i].entrypoint);
- assert(gr->swap_buffers_with_damage);
- break;
- }
- }
-
- if (weston_check_egl_extension(extensions, "EGL_KHR_no_config_context") ||
- weston_check_egl_extension(extensions, "EGL_MESA_configless_context"))
- gr->has_configless_context = true;
-
- if (weston_check_egl_extension(extensions, "EGL_KHR_surfaceless_context"))
- gr->has_surfaceless_context = true;
-
- if (weston_check_egl_extension(extensions, "EGL_EXT_image_dma_buf_import"))
- gr->has_dmabuf_import = true;
-
- if (weston_check_egl_extension(extensions,
- "EGL_EXT_image_dma_buf_import_modifiers")) {
- gr->query_dmabuf_formats =
- (void *) eglGetProcAddress("eglQueryDmaBufFormatsEXT");
- gr->query_dmabuf_modifiers =
- (void *) eglGetProcAddress("eglQueryDmaBufModifiersEXT");
- assert(gr->query_dmabuf_formats);
- assert(gr->query_dmabuf_modifiers);
- gr->has_dmabuf_import_modifiers = true;
- }
-
- if (weston_check_egl_extension(extensions, "EGL_KHR_fence_sync") &&
- weston_check_egl_extension(extensions, "EGL_ANDROID_native_fence_sync")) {
- gr->create_sync =
- (void *) eglGetProcAddress("eglCreateSyncKHR");
- gr->destroy_sync =
- (void *) eglGetProcAddress("eglDestroySyncKHR");
- gr->dup_native_fence_fd =
- (void *) eglGetProcAddress("eglDupNativeFenceFDANDROID");
- assert(gr->create_sync);
- assert(gr->destroy_sync);
- assert(gr->dup_native_fence_fd);
- gr->has_native_fence_sync = true;
- } else {
- weston_log("warning: Disabling render GPU timeline and explicit "
- "synchronization due to missing "
- "EGL_ANDROID_native_fence_sync extension\n");
- }
-
- if (weston_check_egl_extension(extensions, "EGL_KHR_wait_sync")) {
- gr->wait_sync = (void *) eglGetProcAddress("eglWaitSyncKHR");
- assert(gr->wait_sync);
- gr->has_wait_sync = true;
- } else {
- weston_log("warning: Disabling explicit synchronization due"
- "to missing EGL_KHR_wait_sync extension\n");
- }
-
- renderer_setup_egl_client_extensions(gr);
-
- return 0;
-}
diff --git a/libweston/renderer-gl/gl-renderer-internal.h b/libweston/renderer-gl/gl-renderer-internal.h
deleted file mode 100644
index 5f8bac10..00000000
--- a/libweston/renderer-gl/gl-renderer-internal.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright © 2019 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef GL_RENDERER_INTERNAL_H
-#define GL_RENDERER_INTERNAL_H
-
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include "shared/weston-egl-ext.h" /* for PFN* stuff */
-
-struct gl_shader {
- GLuint program;
- GLuint vertex_shader, fragment_shader;
- GLint proj_uniform;
- GLint tex_uniforms[3];
- GLint alpha_uniform;
- GLint color_uniform;
- const char *vertex_source, *fragment_source;
-};
-
-struct gl_renderer {
- struct weston_renderer base;
- bool fragment_shader_debug;
- bool fan_debug;
- struct weston_binding *fragment_binding;
- struct weston_binding *fan_binding;
-
- EGLenum platform;
- EGLDisplay egl_display;
- EGLContext egl_context;
- EGLConfig egl_config;
-
- EGLSurface dummy_surface;
-
- uint32_t gl_version;
-
- struct wl_array vertices;
- struct wl_array vtxcnt;
-
- PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
- PFNEGLCREATEIMAGEKHRPROC create_image;
- PFNEGLDESTROYIMAGEKHRPROC destroy_image;
- PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
- PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC create_platform_window;
-
- bool has_unpack_subimage;
-
- PFNEGLBINDWAYLANDDISPLAYWL bind_display;
- PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
- PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
- bool has_bind_display;
-
- bool has_context_priority;
-
- bool has_egl_image_external;
-
- bool has_egl_buffer_age;
- bool has_egl_partial_update;
- PFNEGLSETDAMAGEREGIONKHRPROC set_damage_region;
-
- bool has_configless_context;
-
- bool has_surfaceless_context;
-
- bool has_dmabuf_import;
- struct wl_list dmabuf_images;
-
- bool has_gl_texture_rg;
-
- struct gl_shader texture_shader_rgba;
- struct gl_shader texture_shader_rgbx;
- struct gl_shader texture_shader_egl_external;
- struct gl_shader texture_shader_y_uv;
- struct gl_shader texture_shader_y_u_v;
- struct gl_shader texture_shader_y_xuxv;
- struct gl_shader texture_shader_xyuv;
- struct gl_shader invert_color_shader;
- struct gl_shader solid_shader;
- struct gl_shader *current_shader;
-
- struct wl_signal destroy_signal;
-
- struct wl_listener output_destroy_listener;
-
- bool has_dmabuf_import_modifiers;
- PFNEGLQUERYDMABUFFORMATSEXTPROC query_dmabuf_formats;
- PFNEGLQUERYDMABUFMODIFIERSEXTPROC query_dmabuf_modifiers;
-
- bool has_native_fence_sync;
- PFNEGLCREATESYNCKHRPROC create_sync;
- PFNEGLDESTROYSYNCKHRPROC destroy_sync;
- PFNEGLDUPNATIVEFENCEFDANDROIDPROC dup_native_fence_fd;
-
- bool has_wait_sync;
- PFNEGLWAITSYNCKHRPROC wait_sync;
-
- void *wl_tbm_server;
-};
-
-static inline struct gl_renderer *
-get_renderer(struct weston_compositor *ec)
-{
- return (struct gl_renderer *)ec->renderer;
-}
-
-void
-gl_renderer_print_egl_error_state(void);
-
-void
-log_egl_config_info(EGLDisplay egldpy, EGLConfig eglconfig);
-
-EGLConfig
-gl_renderer_get_egl_config(struct gl_renderer *gr,
- EGLint egl_surface_type,
- const uint32_t *drm_formats,
- unsigned drm_formats_count);
-
-int
-gl_renderer_setup_egl_extensions(struct weston_compositor *ec);
-
-#endif /* GL_RENDERER_INTERNAL_H */
diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c
deleted file mode 100644
index 967827e6..00000000
--- a/libweston/renderer-gl/gl-renderer.c
+++ /dev/null
@@ -1,3943 +0,0 @@
-/*
- * Copyright © 2012 Intel Corporation
- * Copyright © 2015,2019 Collabora, Ltd.
- * Copyright © 2016 NVIDIA Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <float.h>
-#include <assert.h>
-#include <linux/input.h>
-#include <drm_fourcc.h>
-#include <unistd.h>
-
-#include "linux-sync-file.h"
-#include "timeline.h"
-
-#include "gl-renderer.h"
-#include "gl-renderer-internal.h"
-#include "vertex-clipping.h"
-#include "linux-dmabuf.h"
-#include "linux-dmabuf-unstable-v1-server-protocol.h"
-#include "linux-explicit-synchronization.h"
-#include "pixel-formats.h"
-
-#include "shared/fd-util.h"
-#include "shared/helpers.h"
-#include "shared/platform.h"
-#include "shared/timespec-util.h"
-#include "shared/weston-egl-ext.h"
-
-#ifdef HAVE_TBM
-#include <tbm_bufmgr.h>
-#include <wayland-tbm-server.h>
-#endif
-
-#define GR_GL_VERSION(major, minor) \
- (((uint32_t)(major) << 16) | (uint32_t)(minor))
-
-#define GR_GL_VERSION_INVALID \
- GR_GL_VERSION(0, 0)
-
-#define BUFFER_DAMAGE_COUNT 2
-
-enum gl_border_status {
- BORDER_STATUS_CLEAN = 0,
- BORDER_TOP_DIRTY = 1 << GL_RENDERER_BORDER_TOP,
- BORDER_LEFT_DIRTY = 1 << GL_RENDERER_BORDER_LEFT,
- BORDER_RIGHT_DIRTY = 1 << GL_RENDERER_BORDER_RIGHT,
- BORDER_BOTTOM_DIRTY = 1 << GL_RENDERER_BORDER_BOTTOM,
- BORDER_ALL_DIRTY = 0xf,
- BORDER_SIZE_CHANGED = 0x10
-};
-
-struct gl_border_image {
- GLuint tex;
- int32_t width, height;
- int32_t tex_width;
- void *data;
-};
-
-struct gl_output_state {
- EGLSurface egl_surface;
- pixman_region32_t buffer_damage[BUFFER_DAMAGE_COUNT];
- int buffer_damage_index;
- enum gl_border_status border_damage[BUFFER_DAMAGE_COUNT];
- struct gl_border_image borders[4];
- enum gl_border_status border_status;
-
- struct weston_matrix output_matrix;
-
- EGLSyncKHR begin_render_sync, end_render_sync;
-
- /* struct timeline_render_point::link */
- struct wl_list timeline_render_point_list;
-};
-
-enum buffer_type {
- BUFFER_TYPE_NULL,
- BUFFER_TYPE_SOLID, /* internal solid color surfaces without a buffer */
- BUFFER_TYPE_SHM,
- BUFFER_TYPE_EGL
-};
-
-struct gl_renderer;
-
-struct egl_image {
- struct gl_renderer *renderer;
- EGLImageKHR image;
- int refcount;
-};
-
-enum import_type {
- IMPORT_TYPE_INVALID,
- IMPORT_TYPE_DIRECT,
- IMPORT_TYPE_GL_CONVERSION
-};
-
-struct dmabuf_image {
- struct linux_dmabuf_buffer *dmabuf;
- int num_images;
- struct egl_image *images[3];
- struct wl_list link;
-
- enum import_type import_type;
- GLenum target;
- struct gl_shader *shader;
-};
-
-struct yuv_plane_descriptor {
- int width_divisor;
- int height_divisor;
- uint32_t format;
- int plane_index;
-};
-
-enum texture_type {
- TEXTURE_Y_XUXV_WL,
- TEXTURE_Y_UV_WL,
- TEXTURE_Y_U_V_WL,
- TEXTURE_XYUV_WL
-};
-
-struct yuv_format_descriptor {
- uint32_t format;
- int input_planes;
- int output_planes;
- enum texture_type texture_type;
- struct yuv_plane_descriptor plane[4];
-};
-
-struct gl_surface_state {
- GLfloat color[4];
- struct gl_shader *shader;
-
- GLuint textures[3];
- int num_textures;
- bool needs_full_upload;
- pixman_region32_t texture_damage;
-
- /* These are only used by SHM surfaces to detect when we need
- * to do a full upload to specify a new internal texture
- * format */
- GLenum gl_format[3];
- GLenum gl_pixel_type;
-
- struct egl_image* images[3];
- GLenum target;
- int num_images;
-
- struct weston_buffer_reference buffer_ref;
- struct weston_buffer_release_reference buffer_release_ref;
- enum buffer_type buffer_type;
- int pitch; /* in pixels */
- int height; /* in pixels */
- bool y_inverted;
- bool direct_display;
-
- /* Extension needed for SHM YUV texture */
- int offset[3]; /* offset per plane */
- int hsub[3]; /* horizontal subsampling per plane */
- int vsub[3]; /* vertical subsampling per plane */
-
- struct weston_surface *surface;
-
- /* Whether this surface was used in the current output repaint.
- Used only in the context of a gl_renderer_repaint_output call. */
- bool used_in_output_repaint;
-
- struct wl_listener surface_destroy_listener;
- struct wl_listener renderer_destroy_listener;
-};
-
-enum timeline_render_point_type {
- TIMELINE_RENDER_POINT_TYPE_BEGIN,
- TIMELINE_RENDER_POINT_TYPE_END
-};
-
-struct timeline_render_point {
- struct wl_list link; /* gl_output_state::timeline_render_point_list */
-
- enum timeline_render_point_type type;
- int fd;
- struct weston_output *output;
- struct wl_event_source *event_source;
-};
-
-static PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL;
-
-static inline const char *
-dump_format(uint32_t format, char out[4])
-{
-#if BYTE_ORDER == BIG_ENDIAN
- format = __builtin_bswap32(format);
-#endif
- memcpy(out, &format, 4);
- return out;
-}
-
-static inline struct gl_output_state *
-get_output_state(struct weston_output *output)
-{
- return (struct gl_output_state *)output->renderer_state;
-}
-
-static int
-gl_renderer_create_surface(struct weston_surface *surface);
-
-static inline struct gl_surface_state *
-get_surface_state(struct weston_surface *surface)
-{
- if (!surface->renderer_state)
- gl_renderer_create_surface(surface);
-
- return (struct gl_surface_state *)surface->renderer_state;
-}
-
-static void
-timeline_render_point_destroy(struct timeline_render_point *trp)
-{
- wl_list_remove(&trp->link);
- wl_event_source_remove(trp->event_source);
- close(trp->fd);
- free(trp);
-}
-
-static int
-timeline_render_point_handler(int fd, uint32_t mask, void *data)
-{
- struct timeline_render_point *trp = data;
- const char *tp_name = trp->type == TIMELINE_RENDER_POINT_TYPE_BEGIN ?
- "renderer_gpu_begin" : "renderer_gpu_end";
-
- if (mask & WL_EVENT_READABLE) {
- struct timespec tspec = { 0 };
-
- if (weston_linux_sync_file_read_timestamp(trp->fd,
- &tspec) == 0) {
- TL_POINT(trp->output->compositor, tp_name, TLP_GPU(&tspec),
- TLP_OUTPUT(trp->output), TLP_END);
- }
- }
-
- timeline_render_point_destroy(trp);
-
- return 0;
-}
-
-static EGLSyncKHR
-create_render_sync(struct gl_renderer *gr)
-{
- static const EGLint attribs[] = { EGL_NONE };
-
- if (!gr->has_native_fence_sync)
- return EGL_NO_SYNC_KHR;
-
- return gr->create_sync(gr->egl_display, EGL_SYNC_NATIVE_FENCE_ANDROID,
- attribs);
-}
-
-static void
-timeline_submit_render_sync(struct gl_renderer *gr,
- struct weston_compositor *ec,
- struct weston_output *output,
- EGLSyncKHR sync,
- enum timeline_render_point_type type)
-{
- struct gl_output_state *go;
- struct wl_event_loop *loop;
- int fd;
- struct timeline_render_point *trp;
-
- if (!weston_log_scope_is_enabled(ec->timeline) ||
- !gr->has_native_fence_sync ||
- sync == EGL_NO_SYNC_KHR)
- return;
-
- go = get_output_state(output);
- loop = wl_display_get_event_loop(ec->wl_display);
-
- fd = gr->dup_native_fence_fd(gr->egl_display, sync);
- if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID)
- return;
-
- trp = zalloc(sizeof *trp);
- if (trp == NULL) {
- close(fd);
- return;
- }
-
- trp->type = type;
- trp->fd = fd;
- trp->output = output;
- trp->event_source = wl_event_loop_add_fd(loop, fd,
- WL_EVENT_READABLE,
- timeline_render_point_handler,
- trp);
-
- wl_list_insert(&go->timeline_render_point_list, &trp->link);
-}
-
-static struct egl_image*
-egl_image_create(struct gl_renderer *gr, EGLenum target,
- EGLClientBuffer buffer, const EGLint *attribs)
-{
- struct egl_image *img;
-
- img = zalloc(sizeof *img);
- img->renderer = gr;
- img->refcount = 1;
- img->image = gr->create_image(gr->egl_display, EGL_NO_CONTEXT,
- target, buffer, attribs);
-
- if (img->image == EGL_NO_IMAGE_KHR) {
- free(img);
- return NULL;
- }
-
- return img;
-}
-
-static struct egl_image*
-egl_image_ref(struct egl_image *image)
-{
- image->refcount++;
-
- return image;
-}
-
-static int
-egl_image_unref(struct egl_image *image)
-{
- struct gl_renderer *gr = image->renderer;
-
- assert(image->refcount > 0);
-
- image->refcount--;
- if (image->refcount > 0)
- return image->refcount;
-
- gr->destroy_image(gr->egl_display, image->image);
- free(image);
-
- return 0;
-}
-
-static struct dmabuf_image*
-dmabuf_image_create(void)
-{
- struct dmabuf_image *img;
-
- img = zalloc(sizeof *img);
- wl_list_init(&img->link);
-
- return img;
-}
-
-static void
-dmabuf_image_destroy(struct dmabuf_image *image)
-{
- int i;
-
- for (i = 0; i < image->num_images; ++i)
- egl_image_unref(image->images[i]);
-
- if (image->dmabuf)
- linux_dmabuf_buffer_set_user_data(image->dmabuf, NULL, NULL);
-
- wl_list_remove(&image->link);
- free(image);
-}
-
-#define max(a, b) (((a) > (b)) ? (a) : (b))
-#define min(a, b) (((a) > (b)) ? (b) : (a))
-
-/*
- * Compute the boundary vertices of the intersection of the global coordinate
- * aligned rectangle 'rect', and an arbitrary quadrilateral produced from
- * 'surf_rect' when transformed from surface coordinates into global coordinates.
- * The vertices are written to 'ex' and 'ey', and the return value is the
- * number of vertices. Vertices are produced in clockwise winding order.
- * Guarantees to produce either zero vertices, or 3-8 vertices with non-zero
- * polygon area.
- */
-static int
-calculate_edges(struct weston_view *ev, pixman_box32_t *rect,
- pixman_box32_t *surf_rect, GLfloat *ex, GLfloat *ey)
-{
-
- struct clip_context ctx;
- int i, n;
- GLfloat min_x, max_x, min_y, max_y;
- struct polygon8 surf = {
- { surf_rect->x1, surf_rect->x2, surf_rect->x2, surf_rect->x1 },
- { surf_rect->y1, surf_rect->y1, surf_rect->y2, surf_rect->y2 },
- 4
- };
-
- ctx.clip.x1 = rect->x1;
- ctx.clip.y1 = rect->y1;
- ctx.clip.x2 = rect->x2;
- ctx.clip.y2 = rect->y2;
-
- /* transform surface to screen space: */
- for (i = 0; i < surf.n; i++)
- weston_view_to_global_float(ev, surf.x[i], surf.y[i],
- &surf.x[i], &surf.y[i]);
-
- /* find bounding box: */
- min_x = max_x = surf.x[0];
- min_y = max_y = surf.y[0];
-
- for (i = 1; i < surf.n; i++) {
- min_x = min(min_x, surf.x[i]);
- max_x = max(max_x, surf.x[i]);
- min_y = min(min_y, surf.y[i]);
- max_y = max(max_y, surf.y[i]);
- }
-
- /* First, simple bounding box check to discard early transformed
- * surface rects that do not intersect with the clip region:
- */
- if ((min_x >= ctx.clip.x2) || (max_x <= ctx.clip.x1) ||
- (min_y >= ctx.clip.y2) || (max_y <= ctx.clip.y1))
- return 0;
-
- /* Simple case, bounding box edges are parallel to surface edges,
- * there will be only four edges. We just need to clip the surface
- * vertices to the clip rect bounds:
- */
- if (!ev->transform.enabled)
- return clip_simple(&ctx, &surf, ex, ey);
-
- /* Transformed case: use a general polygon clipping algorithm to
- * clip the surface rectangle with each side of 'rect'.
- * The algorithm is Sutherland-Hodgman, as explained in
- * http://www.codeguru.com/cpp/misc/misc/graphics/article.php/c8965/Polygon-Clipping.htm
- * but without looking at any of that code.
- */
- n = clip_transformed(&ctx, &surf, ex, ey);
-
- if (n < 3)
- return 0;
-
- return n;
-}
-
-static bool
-merge_down(pixman_box32_t *a, pixman_box32_t *b, pixman_box32_t *merge)
-{
- if (a->x1 == b->x1 && a->x2 == b->x2 && a->y1 == b->y2) {
- merge->x1 = a->x1;
- merge->x2 = a->x2;
- merge->y1 = b->y1;
- merge->y2 = a->y2;
- return true;
- }
- return false;
-}
-
-static int
-compress_bands(pixman_box32_t *inrects, int nrects,
- pixman_box32_t **outrects)
-{
- bool merged = false;
- pixman_box32_t *out, merge_rect;
- int i, j, nout;
-
- if (!nrects) {
- *outrects = NULL;
- return 0;
- }
-
- /* nrects is an upper bound - we're not too worried about
- * allocating a little extra
- */
- out = malloc(sizeof(pixman_box32_t) * nrects);
- out[0] = inrects[0];
- nout = 1;
- for (i = 1; i < nrects; i++) {
- for (j = 0; j < nout; j++) {
- merged = merge_down(&inrects[i], &out[j], &merge_rect);
- if (merged) {
- out[j] = merge_rect;
- break;
- }
- }
- if (!merged) {
- out[nout] = inrects[i];
- nout++;
- }
- }
- *outrects = out;
- return nout;
-}
-
-static int
-texture_region(struct weston_view *ev, pixman_region32_t *region,
- pixman_region32_t *surf_region)
-{
- struct gl_surface_state *gs = get_surface_state(ev->surface);
- struct weston_compositor *ec = ev->surface->compositor;
- struct gl_renderer *gr = get_renderer(ec);
- GLfloat *v, inv_width, inv_height;
- unsigned int *vtxcnt, nvtx = 0;
- pixman_box32_t *rects, *surf_rects;
- pixman_box32_t *raw_rects;
- int i, j, k, nrects, nsurf, raw_nrects;
- bool used_band_compression;
- raw_rects = pixman_region32_rectangles(region, &raw_nrects);
- surf_rects = pixman_region32_rectangles(surf_region, &nsurf);
-
- if (raw_nrects < 4) {
- used_band_compression = false;
- nrects = raw_nrects;
- rects = raw_rects;
- } else {
- nrects = compress_bands(raw_rects, raw_nrects, &rects);
- used_band_compression = true;
- }
- /* worst case we can have 8 vertices per rect (ie. clipped into
- * an octagon):
- */
- v = wl_array_add(&gr->vertices, nrects * nsurf * 8 * 4 * sizeof *v);
- vtxcnt = wl_array_add(&gr->vtxcnt, nrects * nsurf * sizeof *vtxcnt);
-
- inv_width = 1.0 / gs->pitch;
- inv_height = 1.0 / gs->height;
-
- for (i = 0; i < nrects; i++) {
- pixman_box32_t *rect = &rects[i];
- for (j = 0; j < nsurf; j++) {
- pixman_box32_t *surf_rect = &surf_rects[j];
- GLfloat sx, sy, bx, by;
- GLfloat ex[8], ey[8]; /* edge points in screen space */
- int n;
-
- /* The transformed surface, after clipping to the clip region,
- * can have as many as eight sides, emitted as a triangle-fan.
- * The first vertex in the triangle fan can be chosen arbitrarily,
- * since the area is guaranteed to be convex.
- *
- * If a corner of the transformed surface falls outside of the
- * clip region, instead of emitting one vertex for the corner
- * of the surface, up to two are emitted for two corresponding
- * intersection point(s) between the surface and the clip region.
- *
- * To do this, we first calculate the (up to eight) points that
- * form the intersection of the clip rect and the transformed
- * surface.
- */
- n = calculate_edges(ev, rect, surf_rect, ex, ey);
- if (n < 3)
- continue;
-
- /* emit edge points: */
- for (k = 0; k < n; k++) {
- weston_view_from_global_float(ev, ex[k], ey[k],
- &sx, &sy);
- /* position: */
- *(v++) = ex[k];
- *(v++) = ey[k];
- /* texcoord: */
- weston_surface_to_buffer_float(ev->surface,
- sx, sy,
- &bx, &by);
- *(v++) = bx * inv_width;
- if (gs->y_inverted) {
- *(v++) = by * inv_height;
- } else {
- *(v++) = (gs->height - by) * inv_height;
- }
- }
-
- vtxcnt[nvtx++] = n;
- }
- }
-
- if (used_band_compression)
- free(rects);
- return nvtx;
-}
-
-static void
-triangle_fan_debug(struct weston_view *view, int first, int count)
-{
- struct weston_compositor *compositor = view->surface->compositor;
- struct gl_renderer *gr = get_renderer(compositor);
- int i;
- GLushort *buffer;
- GLushort *index;
- int nelems;
- static int color_idx = 0;
- static const GLfloat color[][4] = {
- { 1.0, 0.0, 0.0, 1.0 },
- { 0.0, 1.0, 0.0, 1.0 },
- { 0.0, 0.0, 1.0, 1.0 },
- { 1.0, 1.0, 1.0, 1.0 },
- };
-
- nelems = (count - 1 + count - 2) * 2;
-
- buffer = malloc(sizeof(GLushort) * nelems);
- index = buffer;
-
- for (i = 1; i < count; i++) {
- *index++ = first;
- *index++ = first + i;
- }
-
- for (i = 2; i < count; i++) {
- *index++ = first + i - 1;
- *index++ = first + i;
- }
-
- glUseProgram(gr->solid_shader.program);
- glUniform4fv(gr->solid_shader.color_uniform, 1,
- color[color_idx++ % ARRAY_LENGTH(color)]);
- glDrawElements(GL_LINES, nelems, GL_UNSIGNED_SHORT, buffer);
- glUseProgram(gr->current_shader->program);
- free(buffer);
-}
-
-static void
-repaint_region(struct weston_view *ev, pixman_region32_t *region,
- pixman_region32_t *surf_region)
-{
- struct weston_compositor *ec = ev->surface->compositor;
- struct gl_renderer *gr = get_renderer(ec);
- GLfloat *v;
- unsigned int *vtxcnt;
- int i, first, nfans;
-
- /* The final region to be painted is the intersection of
- * 'region' and 'surf_region'. However, 'region' is in the global
- * coordinates, and 'surf_region' is in the surface-local
- * coordinates. texture_region() will iterate over all pairs of
- * rectangles from both regions, compute the intersection
- * polygon for each pair, and store it as a triangle fan if
- * it has a non-zero area (at least 3 vertices, actually).
- */
- nfans = texture_region(ev, region, surf_region);
-
- v = gr->vertices.data;
- vtxcnt = gr->vtxcnt.data;
-
- /* position: */
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[0]);
- glEnableVertexAttribArray(0);
-
- /* texcoord: */
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[2]);
- glEnableVertexAttribArray(1);
-
- for (i = 0, first = 0; i < nfans; i++) {
- glDrawArrays(GL_TRIANGLE_FAN, first, vtxcnt[i]);
- if (gr->fan_debug)
- triangle_fan_debug(ev, first, vtxcnt[i]);
- first += vtxcnt[i];
- }
-
- glDisableVertexAttribArray(1);
- glDisableVertexAttribArray(0);
-
- gr->vertices.size = 0;
- gr->vtxcnt.size = 0;
-}
-
-static int
-use_output(struct weston_output *output)
-{
- static int errored;
- struct gl_output_state *go = get_output_state(output);
- struct gl_renderer *gr = get_renderer(output->compositor);
- EGLBoolean ret;
-
- ret = eglMakeCurrent(gr->egl_display, go->egl_surface,
- go->egl_surface, gr->egl_context);
-
- if (ret == EGL_FALSE) {
- if (errored)
- return -1;
- errored = 1;
- weston_log("Failed to make EGL context current.\n");
- gl_renderer_print_egl_error_state();
- return -1;
- }
-
- return 0;
-}
-
-static int
-shader_init(struct gl_shader *shader, struct gl_renderer *gr,
- const char *vertex_source, const char *fragment_source);
-
-static void
-use_shader(struct gl_renderer *gr, struct gl_shader *shader)
-{
- if (!shader->program) {
- int ret;
-
- ret = shader_init(shader, gr,
- shader->vertex_source,
- shader->fragment_source);
-
- if (ret < 0)
- weston_log("warning: failed to compile shader\n");
- }
-
- if (gr->current_shader == shader)
- return;
- glUseProgram(shader->program);
- gr->current_shader = shader;
-}
-
-static void
-shader_uniforms(struct gl_shader *shader,
- struct weston_view *view,
- struct weston_output *output)
-{
- int i;
- struct gl_surface_state *gs = get_surface_state(view->surface);
- struct gl_output_state *go = get_output_state(output);
-
- glUniformMatrix4fv(shader->proj_uniform,
- 1, GL_FALSE, go->output_matrix.d);
- glUniform4fv(shader->color_uniform, 1, gs->color);
- glUniform1f(shader->alpha_uniform, view->alpha);
-
- for (i = 0; i < gs->num_textures; i++)
- glUniform1i(shader->tex_uniforms[i], i);
-}
-
-static int
-ensure_surface_buffer_is_ready(struct gl_renderer *gr,
- struct gl_surface_state *gs)
-{
- EGLint attribs[] = {
- EGL_SYNC_NATIVE_FENCE_FD_ANDROID,
- -1,
- EGL_NONE
- };
- struct weston_surface *surface = gs->surface;
- struct weston_buffer *buffer = gs->buffer_ref.buffer;
- EGLSyncKHR sync;
- EGLint wait_ret;
- EGLint destroy_ret;
-
- if (!buffer)
- return 0;
-
- if (surface->acquire_fence_fd < 0)
- return 0;
-
- /* We should only get a fence if we support EGLSyncKHR, since
- * we don't advertise the explicit sync protocol otherwise. */
- assert(gr->has_native_fence_sync);
- /* We should only get a fence for non-SHM buffers, since surface
- * commit would have failed otherwise. */
- assert(wl_shm_buffer_get(buffer->resource) == NULL);
-
- attribs[1] = dup(surface->acquire_fence_fd);
- if (attribs[1] == -1) {
- linux_explicit_synchronization_send_server_error(
- gs->surface->synchronization_resource,
- "Failed to dup acquire fence");
- return -1;
- }
-
- sync = gr->create_sync(gr->egl_display,
- EGL_SYNC_NATIVE_FENCE_ANDROID,
- attribs);
- if (sync == EGL_NO_SYNC_KHR) {
- linux_explicit_synchronization_send_server_error(
- gs->surface->synchronization_resource,
- "Failed to create EGLSyncKHR object");
- close(attribs[1]);
- return -1;
- }
-
- wait_ret = gr->wait_sync(gr->egl_display, sync, 0);
- if (wait_ret == EGL_FALSE) {
- linux_explicit_synchronization_send_server_error(
- gs->surface->synchronization_resource,
- "Failed to wait on EGLSyncKHR object");
- /* Continue to try to destroy the sync object. */
- }
-
-
- destroy_ret = gr->destroy_sync(gr->egl_display, sync);
- if (destroy_ret == EGL_FALSE) {
- linux_explicit_synchronization_send_server_error(
- gs->surface->synchronization_resource,
- "Failed to destroy on EGLSyncKHR object");
- }
-
- return (wait_ret == EGL_TRUE && destroy_ret == EGL_TRUE) ? 0 : -1;
-}
-
-
- /* Checks if a view needs to be censored on an output
- * Checks for 2 types of censor requirements
- * - recording_censor: Censor protected view when a
- * protected view is captured.
- * - unprotected_censor: Censor regions of protected views
- * when displayed on an output which has lower protection capability.
- * Returns the originally stored gl_shader if content censoring is required,
- * NULL otherwise.
- */
-static struct gl_shader *
-setup_censor_overrides(struct weston_output *output,
- struct weston_view *ev)
-{
- struct gl_shader *replaced_shader = NULL;
- struct weston_compositor *ec = ev->surface->compositor;
- struct gl_renderer *gr = get_renderer(ec);
- struct gl_surface_state *gs = get_surface_state(ev->surface);
- bool recording_censor =
- (output->disable_planes > 0) &&
- (ev->surface->desired_protection > WESTON_HDCP_DISABLE);
-
- bool unprotected_censor =
- (ev->surface->desired_protection > output->current_protection);
-
- if (gs->direct_display) {
- gs->color[0] = 0.40;
- gs->color[1] = 0.0;
- gs->color[2] = 0.0;
- gs->color[3] = 1.0;
- gs->shader = &gr->solid_shader;
- return gs->shader;
- }
-
- /* When not in enforced mode, the client is notified of the protection */
- /* change, so content censoring is not required */
- if (ev->surface->protection_mode !=
- WESTON_SURFACE_PROTECTION_MODE_ENFORCED)
- return NULL;
-
- if (recording_censor || unprotected_censor) {
- replaced_shader = gs->shader;
- gs->color[0] = 0.40;
- gs->color[1] = 0.0;
- gs->color[2] = 0.0;
- gs->color[3] = 1.0;
- gs->shader = &gr->solid_shader;
- }
-
- return replaced_shader;
-}
-
-static void
-draw_view(struct weston_view *ev, struct weston_output *output,
- pixman_region32_t *damage) /* in global coordinates */
-{
- struct weston_compositor *ec = ev->surface->compositor;
- struct gl_renderer *gr = get_renderer(ec);
- struct gl_surface_state *gs = get_surface_state(ev->surface);
- /* repaint bounding region in global coordinates: */
- pixman_region32_t repaint;
- /* opaque region in surface coordinates: */
- pixman_region32_t surface_opaque;
- /* non-opaque region in surface coordinates: */
- pixman_region32_t surface_blend;
- GLint filter;
- int i;
- struct gl_shader *replaced_shader = NULL;
-
- /* In case of a runtime switch of renderers, we may not have received
- * an attach for this surface since the switch. In that case we don't
- * have a valid buffer or a proper shader set up so skip rendering. */
- if (!gs->shader && !gs->direct_display)
- return;
-
- pixman_region32_init(&repaint);
- pixman_region32_intersect(&repaint,
- &ev->transform.boundingbox, damage);
- pixman_region32_subtract(&repaint, &repaint, &ev->clip);
-
- if (!pixman_region32_not_empty(&repaint))
- goto out;
-
- if (ensure_surface_buffer_is_ready(gr, gs) < 0)
- goto out;
-
- replaced_shader = setup_censor_overrides(output, ev);
-
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-
- if (gr->fan_debug) {
- use_shader(gr, &gr->solid_shader);
- shader_uniforms(&gr->solid_shader, ev, output);
- }
-
- use_shader(gr, gs->shader);
- shader_uniforms(gs->shader, ev, output);
-
- if (ev->transform.enabled || output->zoom.active ||
- output->current_scale != ev->surface->buffer_viewport.buffer.scale)
- filter = GL_LINEAR;
- else
- filter = GL_NEAREST;
-
- for (i = 0; i < gs->num_textures; i++) {
- glActiveTexture(GL_TEXTURE0 + i);
- glBindTexture(gs->target, gs->textures[i]);
- glTexParameteri(gs->target, GL_TEXTURE_MIN_FILTER, filter);
- glTexParameteri(gs->target, GL_TEXTURE_MAG_FILTER, filter);
- }
-
- /* blended region is whole surface minus opaque region: */
- pixman_region32_init_rect(&surface_blend, 0, 0,
- ev->surface->width, ev->surface->height);
- if (ev->geometry.scissor_enabled)
- pixman_region32_intersect(&surface_blend, &surface_blend,
- &ev->geometry.scissor);
- pixman_region32_subtract(&surface_blend, &surface_blend,
- &ev->surface->opaque);
-
- /* XXX: Should we be using ev->transform.opaque here? */
- pixman_region32_init(&surface_opaque);
- if (ev->geometry.scissor_enabled)
- pixman_region32_intersect(&surface_opaque,
- &ev->surface->opaque,
- &ev->geometry.scissor);
- else
- pixman_region32_copy(&surface_opaque, &ev->surface->opaque);
-
- if (pixman_region32_not_empty(&surface_opaque)) {
- if (gs->shader == &gr->texture_shader_rgba) {
- /* Special case for RGBA textures with possibly
- * bad data in alpha channel: use the shader
- * that forces texture alpha = 1.0.
- * Xwayland surfaces need this.
- */
- use_shader(gr, &gr->texture_shader_rgbx);
- shader_uniforms(&gr->texture_shader_rgbx, ev, output);
- }
-
- if (ev->alpha < 1.0)
- glEnable(GL_BLEND);
- else
- glDisable(GL_BLEND);
-
- repaint_region(ev, &repaint, &surface_opaque);
- gs->used_in_output_repaint = true;
- }
-
- if (pixman_region32_not_empty(&surface_blend)) {
- use_shader(gr, gs->shader);
- glEnable(GL_BLEND);
- repaint_region(ev, &repaint, &surface_blend);
- gs->used_in_output_repaint = true;
- }
-
- pixman_region32_fini(&surface_blend);
- pixman_region32_fini(&surface_opaque);
-
-out:
- pixman_region32_fini(&repaint);
-
- if (replaced_shader)
- gs->shader = replaced_shader;
-}
-
-static void
-repaint_views(struct weston_output *output, pixman_region32_t *damage)
-{
- struct weston_compositor *compositor = output->compositor;
- struct weston_view *view;
-
- wl_list_for_each_reverse(view, &compositor->view_list, link)
- if (view->plane == &compositor->primary_plane)
- draw_view(view, output, damage);
-}
-
-static int
-gl_renderer_create_fence_fd(struct weston_output *output);
-
-/* Updates the release fences of surfaces that were used in the current output
- * repaint. Should only be used from gl_renderer_repaint_output, so that the
- * information in gl_surface_state.used_in_output_repaint is accurate.
- */
-static void
-update_buffer_release_fences(struct weston_compositor *compositor,
- struct weston_output *output)
-{
- struct weston_view *view;
-
- wl_list_for_each_reverse(view, &compositor->view_list, link) {
- struct gl_surface_state *gs;
- struct weston_buffer_release *buffer_release;
- int fence_fd;
-
- if (view->plane != &compositor->primary_plane)
- continue;
-
- gs = get_surface_state(view->surface);
- buffer_release = gs->buffer_release_ref.buffer_release;
-
- if (!gs->used_in_output_repaint || !buffer_release)
- continue;
-
- fence_fd = gl_renderer_create_fence_fd(output);
-
- /* If we have a buffer_release then it means we support fences,
- * and we should be able to create the release fence. If we
- * can't, something has gone horribly wrong, so disconnect the
- * client.
- */
- if (fence_fd == -1) {
- linux_explicit_synchronization_send_server_error(
- buffer_release->resource,
- "Failed to create release fence");
- fd_clear(&buffer_release->fence_fd);
- continue;
- }
-
- /* At the moment it is safe to just replace the fence_fd,
- * discarding the previous one:
- *
- * 1. If the previous fence fd represents a sync fence from
- * a previous repaint cycle, that fence fd is now not
- * sufficient to provide the release guarantee and should
- * be replaced.
- *
- * 2. If the fence fd represents a sync fence from another
- * output in the same repaint cycle, it's fine to replace
- * it since we are rendering to all outputs using the same
- * EGL context, so a fence issued for a later output rendering
- * is guaranteed to signal after fences for previous output
- * renderings.
- *
- * Note that the above is only valid if the buffer_release
- * fences only originate from the GL renderer, which guarantees
- * a total order of operations and fences. If we introduce
- * fences from other sources (e.g., plane out-fences), we will
- * need to merge fences instead.
- */
- fd_update(&buffer_release->fence_fd, fence_fd);
- }
-}
-
-static void
-draw_output_border_texture(struct gl_output_state *go,
- enum gl_renderer_border_side side,
- int32_t x, int32_t y,
- int32_t width, int32_t height)
-{
- struct gl_border_image *img = &go->borders[side];
- static GLushort indices [] = { 0, 1, 3, 3, 1, 2 };
-
- if (!img->data) {
- if (img->tex) {
- glDeleteTextures(1, &img->tex);
- img->tex = 0;
- }
-
- return;
- }
-
- if (!img->tex) {
- glGenTextures(1, &img->tex);
- glBindTexture(GL_TEXTURE_2D, img->tex);
-
- glTexParameteri(GL_TEXTURE_2D,
- GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D,
- GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D,
- GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D,
- GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- } else {
- glBindTexture(GL_TEXTURE_2D, img->tex);
- }
-
- if (go->border_status & (1 << side)) {
- glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
- glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
- glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT,
- img->tex_width, img->height, 0,
- GL_BGRA_EXT, GL_UNSIGNED_BYTE, img->data);
- }
-
- GLfloat texcoord[] = {
- 0.0f, 0.0f,
- (GLfloat)img->width / (GLfloat)img->tex_width, 0.0f,
- (GLfloat)img->width / (GLfloat)img->tex_width, 1.0f,
- 0.0f, 1.0f,
- };
-
- GLfloat verts[] = {
- x, y,
- x + width, y,
- x + width, y + height,
- x, y + height
- };
-
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord);
- glEnableVertexAttribArray(0);
- glEnableVertexAttribArray(1);
-
- glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
-
- glDisableVertexAttribArray(1);
- glDisableVertexAttribArray(0);
-}
-
-static int
-output_has_borders(struct weston_output *output)
-{
- struct gl_output_state *go = get_output_state(output);
-
- return go->borders[GL_RENDERER_BORDER_TOP].data ||
- go->borders[GL_RENDERER_BORDER_RIGHT].data ||
- go->borders[GL_RENDERER_BORDER_BOTTOM].data ||
- go->borders[GL_RENDERER_BORDER_LEFT].data;
-}
-
-static void
-draw_output_borders(struct weston_output *output,
- enum gl_border_status border_status)
-{
- struct gl_output_state *go = get_output_state(output);
- struct gl_renderer *gr = get_renderer(output->compositor);
- struct gl_shader *shader = &gr->texture_shader_rgba;
- struct gl_border_image *top, *bottom, *left, *right;
- struct weston_matrix matrix;
- int full_width, full_height;
-
- if (border_status == BORDER_STATUS_CLEAN)
- return; /* Clean. Nothing to do. */
-
- top = &go->borders[GL_RENDERER_BORDER_TOP];
- bottom = &go->borders[GL_RENDERER_BORDER_BOTTOM];
- left = &go->borders[GL_RENDERER_BORDER_LEFT];
- right = &go->borders[GL_RENDERER_BORDER_RIGHT];
-
- full_width = output->current_mode->width + left->width + right->width;
- full_height = output->current_mode->height + top->height + bottom->height;
-
- glDisable(GL_BLEND);
- use_shader(gr, shader);
-
- glViewport(0, 0, full_width, full_height);
-
- weston_matrix_init(&matrix);
- weston_matrix_translate(&matrix, -full_width/2.0, -full_height/2.0, 0);
- weston_matrix_scale(&matrix, 2.0/full_width, -2.0/full_height, 1);
- glUniformMatrix4fv(shader->proj_uniform, 1, GL_FALSE, matrix.d);
-
- glUniform1i(shader->tex_uniforms[0], 0);
- glUniform1f(shader->alpha_uniform, 1);
- glActiveTexture(GL_TEXTURE0);
-
- if (border_status & BORDER_TOP_DIRTY)
- draw_output_border_texture(go, GL_RENDERER_BORDER_TOP,
- 0, 0,
- full_width, top->height);
- if (border_status & BORDER_LEFT_DIRTY)
- draw_output_border_texture(go, GL_RENDERER_BORDER_LEFT,
- 0, top->height,
- left->width, output->current_mode->height);
- if (border_status & BORDER_RIGHT_DIRTY)
- draw_output_border_texture(go, GL_RENDERER_BORDER_RIGHT,
- full_width - right->width, top->height,
- right->width, output->current_mode->height);
- if (border_status & BORDER_BOTTOM_DIRTY)
- draw_output_border_texture(go, GL_RENDERER_BORDER_BOTTOM,
- 0, full_height - bottom->height,
- full_width, bottom->height);
-}
-
-static void
-output_get_border_damage(struct weston_output *output,
- enum gl_border_status border_status,
- pixman_region32_t *damage)
-{
- struct gl_output_state *go = get_output_state(output);
- struct gl_border_image *top, *bottom, *left, *right;
- int full_width, full_height;
-
- if (border_status == BORDER_STATUS_CLEAN)
- return; /* Clean. Nothing to do. */
-
- top = &go->borders[GL_RENDERER_BORDER_TOP];
- bottom = &go->borders[GL_RENDERER_BORDER_BOTTOM];
- left = &go->borders[GL_RENDERER_BORDER_LEFT];
- right = &go->borders[GL_RENDERER_BORDER_RIGHT];
-
- full_width = output->current_mode->width + left->width + right->width;
- full_height = output->current_mode->height + top->height + bottom->height;
- if (border_status & BORDER_TOP_DIRTY)
- pixman_region32_union_rect(damage, damage,
- 0, 0,
- full_width, top->height);
- if (border_status & BORDER_LEFT_DIRTY)
- pixman_region32_union_rect(damage, damage,
- 0, top->height,
- left->width, output->current_mode->height);
- if (border_status & BORDER_RIGHT_DIRTY)
- pixman_region32_union_rect(damage, damage,
- full_width - right->width, top->height,
- right->width, output->current_mode->height);
- if (border_status & BORDER_BOTTOM_DIRTY)
- pixman_region32_union_rect(damage, damage,
- 0, full_height - bottom->height,
- full_width, bottom->height);
-}
-
-static void
-output_get_damage(struct weston_output *output,
- pixman_region32_t *buffer_damage, uint32_t *border_damage)
-{
- struct gl_output_state *go = get_output_state(output);
- struct gl_renderer *gr = get_renderer(output->compositor);
- EGLint buffer_age = 0;
- EGLBoolean ret;
- int i;
-
- if (gr->has_egl_buffer_age) {
- ret = eglQuerySurface(gr->egl_display, go->egl_surface,
- EGL_BUFFER_AGE_EXT, &buffer_age);
- if (ret == EGL_FALSE) {
- weston_log("buffer age query failed.\n");
- gl_renderer_print_egl_error_state();
- }
- }
-
- if (buffer_age == 0 || buffer_age - 1 > BUFFER_DAMAGE_COUNT) {
- pixman_region32_copy(buffer_damage, &output->region);
- *border_damage = BORDER_ALL_DIRTY;
- } else {
- for (i = 0; i < buffer_age - 1; i++)
- *border_damage |= go->border_damage[(go->buffer_damage_index + i) % BUFFER_DAMAGE_COUNT];
-
- if (*border_damage & BORDER_SIZE_CHANGED) {
- /* If we've had a resize, we have to do a full
- * repaint. */
- *border_damage |= BORDER_ALL_DIRTY;
- pixman_region32_copy(buffer_damage, &output->region);
- } else {
- for (i = 0; i < buffer_age - 1; i++)
- pixman_region32_union(buffer_damage,
- buffer_damage,
- &go->buffer_damage[(go->buffer_damage_index + i) % BUFFER_DAMAGE_COUNT]);
- }
- }
-}
-
-static void
-output_rotate_damage(struct weston_output *output,
- pixman_region32_t *output_damage,
- enum gl_border_status border_status)
-{
- struct gl_output_state *go = get_output_state(output);
- struct gl_renderer *gr = get_renderer(output->compositor);
-
- if (!gr->has_egl_buffer_age)
- return;
-
- go->buffer_damage_index += BUFFER_DAMAGE_COUNT - 1;
- go->buffer_damage_index %= BUFFER_DAMAGE_COUNT;
-
- pixman_region32_copy(&go->buffer_damage[go->buffer_damage_index], output_damage);
- go->border_damage[go->buffer_damage_index] = border_status;
-}
-
-/**
- * Given a region in Weston's (top-left-origin) global co-ordinate space,
- * translate it to the co-ordinate space used by GL for our output
- * rendering. This requires shifting it into output co-ordinate space:
- * translating for output offset within the global co-ordinate space,
- * multiplying by output scale to get buffer rather than logical size.
- *
- * Finally, if borders are drawn around the output, we translate the area
- * to account for the border region around the outside, and add any
- * damage if the borders have been redrawn.
- *
- * @param output The output whose co-ordinate space we are after
- * @param global_region The affected region in global co-ordinate space
- * @param[out] rects Y-inverted quads in {x,y,w,h} order; caller must free
- * @param[out] nrects Number of quads (4x number of co-ordinates)
- */
-static void
-pixman_region_to_egl_y_invert(struct weston_output *output,
- struct pixman_region32 *global_region,
- EGLint **rects,
- EGLint *nrects)
-{
- struct gl_output_state *go = get_output_state(output);
- pixman_region32_t transformed;
- struct pixman_box32 *box;
- int buffer_height;
- EGLint *d;
- int i;
-
- /* Translate from global to output co-ordinate space. */
- pixman_region32_init(&transformed);
- pixman_region32_copy(&transformed, global_region);
- pixman_region32_translate(&transformed, -output->x, -output->y);
- weston_transformed_region(output->width, output->height,
- output->transform,
- output->current_scale,
- &transformed, &transformed);
-
- /* If we have borders drawn around the output, shift our output damage
- * to account for borders being drawn around the outside, adding any
- * damage resulting from borders being redrawn. */
- if (output_has_borders(output)) {
- pixman_region32_translate(&transformed,
- go->borders[GL_RENDERER_BORDER_LEFT].width,
- go->borders[GL_RENDERER_BORDER_TOP].height);
- output_get_border_damage(output, go->border_status,
- &transformed);
- }
-
- /* Convert from a Pixman region into {x,y,w,h} quads, flipping in the
- * Y axis to account for GL's lower-left-origin co-ordinate space. */
- box = pixman_region32_rectangles(&transformed, nrects);
- *rects = malloc(*nrects * 4 * sizeof(EGLint));
-
- buffer_height = go->borders[GL_RENDERER_BORDER_TOP].height +
- output->current_mode->height +
- go->borders[GL_RENDERER_BORDER_BOTTOM].height;
-
- d = *rects;
- for (i = 0; i < *nrects; ++i) {
- *d++ = box[i].x1;
- *d++ = buffer_height - box[i].y2;
- *d++ = box[i].x2 - box[i].x1;
- *d++ = box[i].y2 - box[i].y1;
- }
-
- pixman_region32_fini(&transformed);
-}
-
-/* NOTE: We now allow falling back to ARGB gl visuals when XRGB is
- * unavailable, so we're assuming the background has no transparency
- * and that everything with a blend, like drop shadows, will have something
- * opaque (like the background) drawn underneath it.
- *
- * Depending on the underlying hardware, violating that assumption could
- * result in seeing through to another display plane.
- */
-static void
-gl_renderer_repaint_output(struct weston_output *output,
- pixman_region32_t *output_damage)
-{
- struct gl_output_state *go = get_output_state(output);
- struct weston_compositor *compositor = output->compositor;
- struct gl_renderer *gr = get_renderer(compositor);
- EGLBoolean ret;
- static int errored;
- /* areas we've damaged since we last used this buffer */
- pixman_region32_t previous_damage;
- /* total area we need to repaint this time */
- pixman_region32_t total_damage;
- enum gl_border_status border_status = BORDER_STATUS_CLEAN;
- struct weston_view *view;
-
- if (use_output(output) < 0)
- return;
-
- /* Clear the used_in_output_repaint flag, so that we can properly track
- * which surfaces were used in this output repaint. */
- wl_list_for_each_reverse(view, &compositor->view_list, link) {
- if (view->plane == &compositor->primary_plane) {
- struct gl_surface_state *gs =
- get_surface_state(view->surface);
- gs->used_in_output_repaint = false;
- }
- }
-
- if (go->begin_render_sync != EGL_NO_SYNC_KHR)
- gr->destroy_sync(gr->egl_display, go->begin_render_sync);
- if (go->end_render_sync != EGL_NO_SYNC_KHR)
- gr->destroy_sync(gr->egl_display, go->end_render_sync);
-
- go->begin_render_sync = create_render_sync(gr);
-
- /* Calculate the viewport */
- glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width,
- go->borders[GL_RENDERER_BORDER_BOTTOM].height,
- output->current_mode->width,
- output->current_mode->height);
-
- /* Calculate the global GL matrix */
- go->output_matrix = output->matrix;
- weston_matrix_translate(&go->output_matrix,
- -(output->current_mode->width / 2.0),
- -(output->current_mode->height / 2.0), 0);
- weston_matrix_scale(&go->output_matrix,
- 2.0 / output->current_mode->width,
- -2.0 / output->current_mode->height, 1);
-
- /* In fan debug mode, redraw everything to make sure that we clear any
- * fans left over from previous draws on this buffer.
- * This precludes the use of EGL_EXT_swap_buffers_with_damage and
- * EGL_KHR_partial_update, since we damage the whole area. */
- if (gr->fan_debug) {
- pixman_region32_t undamaged;
- pixman_region32_init(&undamaged);
- pixman_region32_subtract(&undamaged, &output->region,
- output_damage);
- gr->fan_debug = false;
- repaint_views(output, &undamaged);
- gr->fan_debug = true;
- pixman_region32_fini(&undamaged);
- }
-
- /* previous_damage covers regions damaged in previous paints since we
- * last used this buffer */
- pixman_region32_init(&previous_damage);
- pixman_region32_init(&total_damage); /* total area to redraw */
-
- /* Update previous_damage using buffer_age (if available), and store
- * current damaged region for future use. */
- output_get_damage(output, &previous_damage, &border_status);
- output_rotate_damage(output, output_damage, go->border_status);
-
- /* Redraw both areas which have changed since we last used this buffer,
- * as well as the areas we now want to repaint, to make sure the
- * buffer is up to date. */
- pixman_region32_union(&total_damage, &previous_damage, output_damage);
- border_status |= go->border_status;
-
- if (gr->has_egl_partial_update && !gr->fan_debug) {
- int n_egl_rects;
- EGLint *egl_rects;
-
- /* For partial_update, we need to pass the region which has
- * changed since we last rendered into this specific buffer;
- * this is total_damage. */
- pixman_region_to_egl_y_invert(output, &total_damage,
- &egl_rects, &n_egl_rects);
- gr->set_damage_region(gr->egl_display, go->egl_surface,
- egl_rects, n_egl_rects);
- free(egl_rects);
- }
-
- repaint_views(output, &total_damage);
-
- pixman_region32_fini(&total_damage);
- pixman_region32_fini(&previous_damage);
-
- draw_output_borders(output, border_status);
-
- wl_signal_emit(&output->frame_signal, output_damage);
-
- go->end_render_sync = create_render_sync(gr);
-
- if (gr->swap_buffers_with_damage && !gr->fan_debug) {
- int n_egl_rects;
- EGLint *egl_rects;
-
- /* For swap_buffers_with_damage, we need to pass the region
- * which has changed since the previous SwapBuffers on this
- * surface - this is output_damage. */
- pixman_region_to_egl_y_invert(output, output_damage,
- &egl_rects, &n_egl_rects);
- ret = gr->swap_buffers_with_damage(gr->egl_display,
- go->egl_surface,
- egl_rects, n_egl_rects);
- free(egl_rects);
- } else {
- ret = eglSwapBuffers(gr->egl_display, go->egl_surface);
- }
-
- if (ret == EGL_FALSE && !errored) {
- errored = 1;
- weston_log("Failed in eglSwapBuffers.\n");
- gl_renderer_print_egl_error_state();
- }
-
- go->border_status = BORDER_STATUS_CLEAN;
-
- /* We have to submit the render sync objects after swap buffers, since
- * the objects get assigned a valid sync file fd only after a gl flush.
- */
- timeline_submit_render_sync(gr, compositor, output,
- go->begin_render_sync,
- TIMELINE_RENDER_POINT_TYPE_BEGIN);
- timeline_submit_render_sync(gr, compositor, output, go->end_render_sync,
- TIMELINE_RENDER_POINT_TYPE_END);
-
- update_buffer_release_fences(compositor, output);
-}
-
-static int
-gl_renderer_read_pixels(struct weston_output *output,
- pixman_format_code_t format, void *pixels,
- uint32_t x, uint32_t y,
- uint32_t width, uint32_t height)
-{
- GLenum gl_format;
- struct gl_output_state *go = get_output_state(output);
-
- x += go->borders[GL_RENDERER_BORDER_LEFT].width;
- y += go->borders[GL_RENDERER_BORDER_BOTTOM].height;
-
- switch (format) {
- case PIXMAN_a8r8g8b8:
- gl_format = GL_BGRA_EXT;
- break;
- case PIXMAN_a8b8g8r8:
- gl_format = GL_RGBA;
- break;
- default:
- return -1;
- }
-
- if (use_output(output) < 0)
- return -1;
-
- glPixelStorei(GL_PACK_ALIGNMENT, 1);
- glReadPixels(x, y, width, height, gl_format,
- GL_UNSIGNED_BYTE, pixels);
-
- return 0;
-}
-
-static GLenum gl_format_from_internal(GLenum internal_format)
-{
- switch (internal_format) {
- case GL_R8_EXT:
- return GL_RED_EXT;
- case GL_RG8_EXT:
- return GL_RG_EXT;
- default:
- return internal_format;
- }
-}
-
-static void
-gl_renderer_flush_damage(struct weston_surface *surface)
-{
- struct gl_renderer *gr = get_renderer(surface->compositor);
- struct gl_surface_state *gs = get_surface_state(surface);
- struct weston_buffer *buffer = gs->buffer_ref.buffer;
- struct weston_view *view;
- bool texture_used;
- pixman_box32_t *rectangles;
- uint8_t *data;
- int i, j, n;
-
- pixman_region32_union(&gs->texture_damage,
- &gs->texture_damage, &surface->damage);
-
- if (!buffer)
- return;
-
- /* Avoid upload, if the texture won't be used this time.
- * We still accumulate the damage in texture_damage, and
- * hold the reference to the buffer, in case the surface
- * migrates back to the primary plane.
- */
- texture_used = false;
- wl_list_for_each(view, &surface->views, surface_link) {
- if (view->plane == &surface->compositor->primary_plane) {
- texture_used = true;
- break;
- }
- }
- if (!texture_used)
- return;
-
- if (!pixman_region32_not_empty(&gs->texture_damage) &&
- !gs->needs_full_upload)
- goto done;
-
- data = wl_shm_buffer_get_data(buffer->shm_buffer);
-
- if (!gr->has_unpack_subimage) {
- wl_shm_buffer_begin_access(buffer->shm_buffer);
- for (j = 0; j < gs->num_textures; j++) {
- glBindTexture(GL_TEXTURE_2D, gs->textures[j]);
- glTexImage2D(GL_TEXTURE_2D, 0,
- gs->gl_format[j],
- gs->pitch / gs->hsub[j],
- buffer->height / gs->vsub[j],
- 0,
- gl_format_from_internal(gs->gl_format[j]),
- gs->gl_pixel_type,
- data + gs->offset[j]);
- }
- wl_shm_buffer_end_access(buffer->shm_buffer);
-
- goto done;
- }
-
- if (gs->needs_full_upload) {
- glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
- glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
- wl_shm_buffer_begin_access(buffer->shm_buffer);
- for (j = 0; j < gs->num_textures; j++) {
- glBindTexture(GL_TEXTURE_2D, gs->textures[j]);
- glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT,
- gs->pitch / gs->hsub[j]);
- glTexImage2D(GL_TEXTURE_2D, 0,
- gs->gl_format[j],
- gs->pitch / gs->hsub[j],
- buffer->height / gs->vsub[j],
- 0,
- gl_format_from_internal(gs->gl_format[j]),
- gs->gl_pixel_type,
- data + gs->offset[j]);
- }
- wl_shm_buffer_end_access(buffer->shm_buffer);
- goto done;
- }
-
- rectangles = pixman_region32_rectangles(&gs->texture_damage, &n);
- wl_shm_buffer_begin_access(buffer->shm_buffer);
- for (i = 0; i < n; i++) {
- pixman_box32_t r;
-
- r = weston_surface_to_buffer_rect(surface, rectangles[i]);
-
- for (j = 0; j < gs->num_textures; j++) {
- glBindTexture(GL_TEXTURE_2D, gs->textures[j]);
- glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT,
- gs->pitch / gs->hsub[j]);
- glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT,
- r.x1 / gs->hsub[j]);
- glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT,
- r.y1 / gs->hsub[j]);
- glTexSubImage2D(GL_TEXTURE_2D, 0,
- r.x1 / gs->hsub[j],
- r.y1 / gs->vsub[j],
- (r.x2 - r.x1) / gs->hsub[j],
- (r.y2 - r.y1) / gs->vsub[j],
- gl_format_from_internal(gs->gl_format[j]),
- gs->gl_pixel_type,
- data + gs->offset[j]);
- }
- }
- wl_shm_buffer_end_access(buffer->shm_buffer);
-
-done:
- pixman_region32_fini(&gs->texture_damage);
- pixman_region32_init(&gs->texture_damage);
- gs->needs_full_upload = false;
-
- weston_buffer_reference(&gs->buffer_ref, NULL);
- weston_buffer_release_reference(&gs->buffer_release_ref, NULL);
-}
-
-static void
-ensure_textures(struct gl_surface_state *gs, int num_textures)
-{
- int i;
-
- if (num_textures <= gs->num_textures)
- return;
-
- for (i = gs->num_textures; i < num_textures; i++) {
- glGenTextures(1, &gs->textures[i]);
- glBindTexture(gs->target, gs->textures[i]);
- glTexParameteri(gs->target,
- GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(gs->target,
- GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- }
- gs->num_textures = num_textures;
- glBindTexture(gs->target, 0);
-}
-
-static void
-gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer,
- struct wl_shm_buffer *shm_buffer)
-{
- struct weston_compositor *ec = es->compositor;
- struct gl_renderer *gr = get_renderer(ec);
- struct gl_surface_state *gs = get_surface_state(es);
- GLenum gl_format[3] = {0, 0, 0};
- GLenum gl_pixel_type;
- int pitch;
- int num_planes;
-
- buffer->shm_buffer = shm_buffer;
- buffer->width = wl_shm_buffer_get_width(shm_buffer);
- buffer->height = wl_shm_buffer_get_height(shm_buffer);
-
- num_planes = 1;
- gs->offset[0] = 0;
- gs->hsub[0] = 1;
- gs->vsub[0] = 1;
-
- switch (wl_shm_buffer_get_format(shm_buffer)) {
- case WL_SHM_FORMAT_XRGB8888:
- gs->shader = &gr->texture_shader_rgbx;
- pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
- gl_format[0] = GL_BGRA_EXT;
- gl_pixel_type = GL_UNSIGNED_BYTE;
- es->is_opaque = true;
- break;
- case WL_SHM_FORMAT_ARGB8888:
- gs->shader = &gr->texture_shader_rgba;
- pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
- gl_format[0] = GL_BGRA_EXT;
- gl_pixel_type = GL_UNSIGNED_BYTE;
- es->is_opaque = false;
- break;
- case WL_SHM_FORMAT_RGB565:
- gs->shader = &gr->texture_shader_rgbx;
- pitch = wl_shm_buffer_get_stride(shm_buffer) / 2;
- gl_format[0] = GL_RGB;
- gl_pixel_type = GL_UNSIGNED_SHORT_5_6_5;
- es->is_opaque = true;
- break;
- case WL_SHM_FORMAT_YUV420:
- gs->shader = &gr->texture_shader_y_u_v;
- pitch = wl_shm_buffer_get_stride(shm_buffer);
- gl_pixel_type = GL_UNSIGNED_BYTE;
- num_planes = 3;
- gs->offset[1] = gs->offset[0] + (pitch / gs->hsub[0]) *
- (buffer->height / gs->vsub[0]);
- gs->hsub[1] = 2;
- gs->vsub[1] = 2;
- gs->offset[2] = gs->offset[1] + (pitch / gs->hsub[1]) *
- (buffer->height / gs->vsub[1]);
- gs->hsub[2] = 2;
- gs->vsub[2] = 2;
- if (gr->has_gl_texture_rg) {
- gl_format[0] = GL_R8_EXT;
- gl_format[1] = GL_R8_EXT;
- gl_format[2] = GL_R8_EXT;
- } else {
- gl_format[0] = GL_LUMINANCE;
- gl_format[1] = GL_LUMINANCE;
- gl_format[2] = GL_LUMINANCE;
- }
- es->is_opaque = true;
- break;
- case WL_SHM_FORMAT_NV12:
- pitch = wl_shm_buffer_get_stride(shm_buffer);
- gl_pixel_type = GL_UNSIGNED_BYTE;
- num_planes = 2;
- gs->offset[1] = gs->offset[0] + (pitch / gs->hsub[0]) *
- (buffer->height / gs->vsub[0]);
- gs->hsub[1] = 2;
- gs->vsub[1] = 2;
- if (gr->has_gl_texture_rg) {
- gs->shader = &gr->texture_shader_y_uv;
- gl_format[0] = GL_R8_EXT;
- gl_format[1] = GL_RG8_EXT;
- } else {
- gs->shader = &gr->texture_shader_y_xuxv;
- gl_format[0] = GL_LUMINANCE;
- gl_format[1] = GL_LUMINANCE_ALPHA;
- }
- es->is_opaque = true;
- break;
- case WL_SHM_FORMAT_YUYV:
- gs->shader = &gr->texture_shader_y_xuxv;
- pitch = wl_shm_buffer_get_stride(shm_buffer) / 2;
- gl_pixel_type = GL_UNSIGNED_BYTE;
- num_planes = 2;
- gs->offset[1] = 0;
- gs->hsub[1] = 2;
- gs->vsub[1] = 1;
- if (gr->has_gl_texture_rg)
- gl_format[0] = GL_RG8_EXT;
- else
- gl_format[0] = GL_LUMINANCE_ALPHA;
- gl_format[1] = GL_BGRA_EXT;
- es->is_opaque = true;
- break;
- default:
- weston_log("warning: unknown shm buffer format: %08x\n",
- wl_shm_buffer_get_format(shm_buffer));
- return;
- }
-
- /* Only allocate a texture if it doesn't match existing one.
- * If a switch from DRM allocated buffer to a SHM buffer is
- * happening, we need to allocate a new texture buffer. */
- if (pitch != gs->pitch ||
- buffer->height != gs->height ||
- gl_format[0] != gs->gl_format[0] ||
- gl_format[1] != gs->gl_format[1] ||
- gl_format[2] != gs->gl_format[2] ||
- gl_pixel_type != gs->gl_pixel_type ||
- gs->buffer_type != BUFFER_TYPE_SHM) {
- gs->pitch = pitch;
- gs->height = buffer->height;
- gs->target = GL_TEXTURE_2D;
- gs->gl_format[0] = gl_format[0];
- gs->gl_format[1] = gl_format[1];
- gs->gl_format[2] = gl_format[2];
- gs->gl_pixel_type = gl_pixel_type;
- gs->buffer_type = BUFFER_TYPE_SHM;
- gs->needs_full_upload = true;
- gs->y_inverted = true;
- gs->direct_display = false;
-
- gs->surface = es;
-
- ensure_textures(gs, num_planes);
- }
-}
-
-static void
-gl_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer,
- uint32_t format)
-{
- struct weston_compositor *ec = es->compositor;
- struct gl_renderer *gr = get_renderer(ec);
- struct gl_surface_state *gs = get_surface_state(es);
- EGLint attribs[3];
- int i, num_planes;
-
- buffer->legacy_buffer = (struct wl_buffer *)buffer->resource;
- gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
- EGL_WIDTH, &buffer->width);
- gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
- EGL_HEIGHT, &buffer->height);
- gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
- EGL_WAYLAND_Y_INVERTED_WL, &buffer->y_inverted);
-
- for (i = 0; i < gs->num_images; i++) {
- egl_image_unref(gs->images[i]);
- gs->images[i] = NULL;
- }
- gs->num_images = 0;
- gs->target = GL_TEXTURE_2D;
- es->is_opaque = false;
- switch (format) {
- case EGL_TEXTURE_RGB:
- es->is_opaque = true;
- /* fallthrough */
- case EGL_TEXTURE_RGBA:
- default:
- num_planes = 1;
- gs->shader = &gr->texture_shader_rgba;
- break;
- case EGL_TEXTURE_EXTERNAL_WL:
- num_planes = 1;
- gs->target = GL_TEXTURE_EXTERNAL_OES;
- gs->shader = &gr->texture_shader_egl_external;
- break;
- case EGL_TEXTURE_Y_UV_WL:
- num_planes = 2;
- gs->shader = &gr->texture_shader_y_uv;
- es->is_opaque = true;
- break;
- case EGL_TEXTURE_Y_U_V_WL:
- num_planes = 3;
- gs->shader = &gr->texture_shader_y_u_v;
- es->is_opaque = true;
- break;
- case EGL_TEXTURE_Y_XUXV_WL:
- num_planes = 2;
- gs->shader = &gr->texture_shader_y_xuxv;
- es->is_opaque = true;
- break;
- }
-
- ensure_textures(gs, num_planes);
- for (i = 0; i < num_planes; i++) {
- attribs[0] = EGL_WAYLAND_PLANE_WL;
- attribs[1] = i;
- attribs[2] = EGL_NONE;
- gs->images[i] = egl_image_create(gr,
- EGL_WAYLAND_BUFFER_WL,
- buffer->legacy_buffer,
- attribs);
- if (!gs->images[i]) {
- weston_log("failed to create img for plane %d\n", i);
- continue;
- }
- gs->num_images++;
-
- glActiveTexture(GL_TEXTURE0 + i);
- glBindTexture(gs->target, gs->textures[i]);
- gr->image_target_texture_2d(gs->target,
- gs->images[i]->image);
- }
-
- gs->pitch = buffer->width;
- gs->height = buffer->height;
- gs->buffer_type = BUFFER_TYPE_EGL;
- gs->y_inverted = buffer->y_inverted;
-}
-
-static void
-gl_renderer_destroy_dmabuf(struct linux_dmabuf_buffer *dmabuf)
-{
- struct dmabuf_image *image = linux_dmabuf_buffer_get_user_data(dmabuf);
-
- dmabuf_image_destroy(image);
-}
-
-static struct egl_image *
-import_simple_dmabuf(struct gl_renderer *gr,
- struct dmabuf_attributes *attributes)
-{
- struct egl_image *image;
- EGLint attribs[50];
- int atti = 0;
- bool has_modifier;
-
- /* This requires the Mesa commit in
- * Mesa 10.3 (08264e5dad4df448e7718e782ad9077902089a07) or
- * Mesa 10.2.7 (55d28925e6109a4afd61f109e845a8a51bd17652).
- * Otherwise Mesa closes the fd behind our back and re-importing
- * will fail.
- * https://bugs.freedesktop.org/show_bug.cgi?id=76188
- */
-
- attribs[atti++] = EGL_WIDTH;
- attribs[atti++] = attributes->width;
- attribs[atti++] = EGL_HEIGHT;
- attribs[atti++] = attributes->height;
- attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
- attribs[atti++] = attributes->format;
-
- if (attributes->modifier[0] != DRM_FORMAT_MOD_INVALID) {
- if (!gr->has_dmabuf_import_modifiers)
- return NULL;
- has_modifier = true;
- } else {
- has_modifier = false;
- }
-
- if (attributes->n_planes > 0) {
- attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
- attribs[atti++] = attributes->fd[0];
- attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
- attribs[atti++] = attributes->offset[0];
- attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
- attribs[atti++] = attributes->stride[0];
- if (has_modifier) {
- attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
- attribs[atti++] = attributes->modifier[0] & 0xFFFFFFFF;
- attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
- attribs[atti++] = attributes->modifier[0] >> 32;
- }
- }
-
- if (attributes->n_planes > 1) {
- attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT;
- attribs[atti++] = attributes->fd[1];
- attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
- attribs[atti++] = attributes->offset[1];
- attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
- attribs[atti++] = attributes->stride[1];
- if (has_modifier) {
- attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT;
- attribs[atti++] = attributes->modifier[1] & 0xFFFFFFFF;
- attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT;
- attribs[atti++] = attributes->modifier[1] >> 32;
- }
- }
-
- if (attributes->n_planes > 2) {
- attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT;
- attribs[atti++] = attributes->fd[2];
- attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
- attribs[atti++] = attributes->offset[2];
- attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
- attribs[atti++] = attributes->stride[2];
- if (has_modifier) {
- attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT;
- attribs[atti++] = attributes->modifier[2] & 0xFFFFFFFF;
- attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT;
- attribs[atti++] = attributes->modifier[2] >> 32;
- }
- }
-
- if (gr->has_dmabuf_import_modifiers) {
- if (attributes->n_planes > 3) {
- attribs[atti++] = EGL_DMA_BUF_PLANE3_FD_EXT;
- attribs[atti++] = attributes->fd[3];
- attribs[atti++] = EGL_DMA_BUF_PLANE3_OFFSET_EXT;
- attribs[atti++] = attributes->offset[3];
- attribs[atti++] = EGL_DMA_BUF_PLANE3_PITCH_EXT;
- attribs[atti++] = attributes->stride[3];
- attribs[atti++] = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT;
- attribs[atti++] = attributes->modifier[3] & 0xFFFFFFFF;
- attribs[atti++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT;
- attribs[atti++] = attributes->modifier[3] >> 32;
- }
- }
-
- attribs[atti++] = EGL_NONE;
-
- image = egl_image_create(gr, EGL_LINUX_DMA_BUF_EXT, NULL,
- attribs);
-
- return image;
-}
-
-/* The kernel header drm_fourcc.h defines the DRM formats below. We duplicate
- * some of the definitions here so that building Weston won't require
- * bleeding-edge kernel headers.
- */
-#ifndef DRM_FORMAT_R8
-#define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */
-#endif
-
-#ifndef DRM_FORMAT_GR88
-#define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */
-#endif
-
-#ifndef DRM_FORMAT_XYUV8888
-#define DRM_FORMAT_XYUV8888 fourcc_code('X', 'Y', 'U', 'V') /* [31:0] X:Y:Cb:Cr 8:8:8:8 little endian */
-#endif
-
-struct yuv_format_descriptor yuv_formats[] = {
- {
- .format = DRM_FORMAT_YUYV,
- .input_planes = 1,
- .output_planes = 2,
- .texture_type = TEXTURE_Y_XUXV_WL,
- {{
- .width_divisor = 1,
- .height_divisor = 1,
- .format = DRM_FORMAT_GR88,
- .plane_index = 0
- }, {
- .width_divisor = 2,
- .height_divisor = 1,
- .format = DRM_FORMAT_ARGB8888,
- .plane_index = 0
- }}
- }, {
- .format = DRM_FORMAT_NV12,
- .input_planes = 2,
- .output_planes = 2,
- .texture_type = TEXTURE_Y_UV_WL,
- {{
- .width_divisor = 1,
- .height_divisor = 1,
- .format = DRM_FORMAT_R8,
- .plane_index = 0
- }, {
- .width_divisor = 2,
- .height_divisor = 2,
- .format = DRM_FORMAT_GR88,
- .plane_index = 1
- }}
- }, {
- .format = DRM_FORMAT_YUV420,
- .input_planes = 3,
- .output_planes = 3,
- .texture_type = TEXTURE_Y_U_V_WL,
- {{
- .width_divisor = 1,
- .height_divisor = 1,
- .format = DRM_FORMAT_R8,
- .plane_index = 0
- }, {
- .width_divisor = 2,
- .height_divisor = 2,
- .format = DRM_FORMAT_R8,
- .plane_index = 1
- }, {
- .width_divisor = 2,
- .height_divisor = 2,
- .format = DRM_FORMAT_R8,
- .plane_index = 2
- }}
- }, {
- .format = DRM_FORMAT_YUV444,
- .input_planes = 3,
- .output_planes = 3,
- .texture_type = TEXTURE_Y_U_V_WL,
- {{
- .width_divisor = 1,
- .height_divisor = 1,
- .format = DRM_FORMAT_R8,
- .plane_index = 0
- }, {
- .width_divisor = 1,
- .height_divisor = 1,
- .format = DRM_FORMAT_R8,
- .plane_index = 1
- }, {
- .width_divisor = 1,
- .height_divisor = 1,
- .format = DRM_FORMAT_R8,
- .plane_index = 2
- }}
- }, {
- .format = DRM_FORMAT_XYUV8888,
- .input_planes = 1,
- .output_planes = 1,
- .texture_type = TEXTURE_XYUV_WL,
- {{
- .width_divisor = 1,
- .height_divisor = 1,
- .format = DRM_FORMAT_XBGR8888,
- .plane_index = 0
- }}
- }
-};
-
-static struct egl_image *
-import_dmabuf_single_plane(struct gl_renderer *gr,
- const struct dmabuf_attributes *attributes,
- struct yuv_plane_descriptor *descriptor)
-{
- struct dmabuf_attributes plane;
- struct egl_image *image;
- char fmt[4];
-
- plane.width = attributes->width / descriptor->width_divisor;
- plane.height = attributes->height / descriptor->height_divisor;
- plane.format = descriptor->format;
- plane.n_planes = 1;
- plane.fd[0] = attributes->fd[descriptor->plane_index];
- plane.offset[0] = attributes->offset[descriptor->plane_index];
- plane.stride[0] = attributes->stride[descriptor->plane_index];
- plane.modifier[0] = attributes->modifier[descriptor->plane_index];
-
- image = import_simple_dmabuf(gr, &plane);
- if (!image) {
- weston_log("Failed to import plane %d as %.4s\n",
- descriptor->plane_index,
- dump_format(descriptor->format, fmt));
- return NULL;
- }
-
- return image;
-}
-
-static bool
-import_yuv_dmabuf(struct gl_renderer *gr,
- struct dmabuf_image *image)
-{
- unsigned i;
- int j;
- int ret;
- struct yuv_format_descriptor *format = NULL;
- struct dmabuf_attributes *attributes = &image->dmabuf->attributes;
- char fmt[4];
-
- for (i = 0; i < ARRAY_LENGTH(yuv_formats); ++i) {
- if (yuv_formats[i].format == attributes->format) {
- format = &yuv_formats[i];
- break;
- }
- }
-
- if (!format) {
- weston_log("Error during import, and no known conversion for format "
- "%.4s in the renderer\n",
- dump_format(attributes->format, fmt));
- return false;
- }
-
- if (attributes->n_planes != format->input_planes) {
- weston_log("%.4s dmabuf must contain %d plane%s (%d provided)\n",
- dump_format(format->format, fmt),
- format->input_planes,
- (format->input_planes > 1) ? "s" : "",
- attributes->n_planes);
- return false;
- }
-
- for (j = 0; j < format->output_planes; ++j) {
- image->images[j] = import_dmabuf_single_plane(gr, attributes,
- &format->plane[j]);
- if (!image->images[j]) {
- while (j) {
- ret = egl_image_unref(image->images[--j]);
- assert(ret == 0);
- }
- return false;
- }
- }
-
- image->num_images = format->output_planes;
-
- switch (format->texture_type) {
- case TEXTURE_Y_XUXV_WL:
- image->shader = &gr->texture_shader_y_xuxv;
- break;
- case TEXTURE_Y_UV_WL:
- image->shader = &gr->texture_shader_y_uv;
- break;
- case TEXTURE_Y_U_V_WL:
- image->shader = &gr->texture_shader_y_u_v;
- break;
- case TEXTURE_XYUV_WL:
- image->shader = &gr->texture_shader_xyuv;
- break;
- default:
- assert(false);
- }
-
- return true;
-}
-
-static GLenum
-choose_texture_target(struct dmabuf_attributes *attributes)
-{
- if (attributes->n_planes > 1)
- return GL_TEXTURE_EXTERNAL_OES;
-
- switch (attributes->format & ~DRM_FORMAT_BIG_ENDIAN) {
- case DRM_FORMAT_YUYV:
- case DRM_FORMAT_YVYU:
- case DRM_FORMAT_UYVY:
- case DRM_FORMAT_VYUY:
- case DRM_FORMAT_AYUV:
- case DRM_FORMAT_XYUV8888:
- return GL_TEXTURE_EXTERNAL_OES;
- default:
- return GL_TEXTURE_2D;
- }
-}
-
-static struct dmabuf_image *
-import_dmabuf(struct gl_renderer *gr,
- struct linux_dmabuf_buffer *dmabuf)
-{
- struct egl_image *egl_image;
- struct dmabuf_image *image;
-
- image = dmabuf_image_create();
- image->dmabuf = dmabuf;
-
- egl_image = import_simple_dmabuf(gr, &dmabuf->attributes);
- if (egl_image) {
- image->num_images = 1;
- image->images[0] = egl_image;
- image->import_type = IMPORT_TYPE_DIRECT;
- image->target = choose_texture_target(&dmabuf->attributes);
-
- switch (image->target) {
- case GL_TEXTURE_2D:
- image->shader = &gr->texture_shader_rgba;
- break;
- default:
- image->shader = &gr->texture_shader_egl_external;
- }
- } else {
- if (!import_yuv_dmabuf(gr, image)) {
- dmabuf_image_destroy(image);
- return NULL;
- }
- image->import_type = IMPORT_TYPE_GL_CONVERSION;
- image->target = GL_TEXTURE_2D;
- }
-
- return image;
-}
-
-static void
-gl_renderer_query_dmabuf_formats(struct weston_compositor *wc,
- int **formats, int *num_formats)
-{
- struct gl_renderer *gr = get_renderer(wc);
- static const int fallback_formats[] = {
- DRM_FORMAT_ARGB8888,
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_YUYV,
- DRM_FORMAT_NV12,
- DRM_FORMAT_YUV420,
- DRM_FORMAT_YUV444,
- DRM_FORMAT_XYUV8888,
- };
- bool fallback = false;
- EGLint num;
-
- assert(gr->has_dmabuf_import);
-
- if (!gr->has_dmabuf_import_modifiers ||
- !gr->query_dmabuf_formats(gr->egl_display, 0, NULL, &num)) {
- num = gr->has_gl_texture_rg ? ARRAY_LENGTH(fallback_formats) : 2;
- fallback = true;
- }
-
- *formats = calloc(num, sizeof(int));
- if (*formats == NULL) {
- *num_formats = 0;
- return;
- }
-
- if (fallback) {
- memcpy(*formats, fallback_formats, num * sizeof(int));
- *num_formats = num;
- return;
- }
-
- if (!gr->query_dmabuf_formats(gr->egl_display, num, *formats, &num)) {
- *num_formats = 0;
- free(*formats);
- return;
- }
-
- *num_formats = num;
-}
-
-static void
-gl_renderer_query_dmabuf_modifiers(struct weston_compositor *wc, int format,
- uint64_t **modifiers,
- int *num_modifiers)
-{
- struct gl_renderer *gr = get_renderer(wc);
- int num;
-
- assert(gr->has_dmabuf_import);
-
- if (!gr->has_dmabuf_import_modifiers ||
- !gr->query_dmabuf_modifiers(gr->egl_display, format, 0, NULL,
- NULL, &num) ||
- num == 0) {
- *num_modifiers = 0;
- return;
- }
-
- *modifiers = calloc(num, sizeof(uint64_t));
- if (*modifiers == NULL) {
- *num_modifiers = 0;
- return;
- }
- if (!gr->query_dmabuf_modifiers(gr->egl_display, format,
- num, *modifiers, NULL, &num)) {
- *num_modifiers = 0;
- free(*modifiers);
- return;
- }
-
- *num_modifiers = num;
-}
-
-static bool
-gl_renderer_import_dmabuf(struct weston_compositor *ec,
- struct linux_dmabuf_buffer *dmabuf)
-{
- struct gl_renderer *gr = get_renderer(ec);
- struct dmabuf_image *image;
- int i;
-
- assert(gr->has_dmabuf_import);
-
- for (i = 0; i < dmabuf->attributes.n_planes; i++) {
- /* return if EGL doesn't support import modifiers */
- if (dmabuf->attributes.modifier[i] != DRM_FORMAT_MOD_INVALID)
- if (!gr->has_dmabuf_import_modifiers)
- return false;
-
- /* return if modifiers passed are unequal */
- if (dmabuf->attributes.modifier[i] !=
- dmabuf->attributes.modifier[0])
- return false;
- }
-
- /* reject all flags we do not recognize or handle */
- if (dmabuf->attributes.flags & ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT)
- return false;
-
- image = import_dmabuf(gr, dmabuf);
- if (!image)
- return false;
-
- wl_list_insert(&gr->dmabuf_images, &image->link);
- linux_dmabuf_buffer_set_user_data(dmabuf, image,
- gl_renderer_destroy_dmabuf);
-
- return true;
-}
-
-static bool
-import_known_dmabuf(struct gl_renderer *gr,
- struct dmabuf_image *image)
-{
- switch (image->import_type) {
- case IMPORT_TYPE_DIRECT:
- image->images[0] = import_simple_dmabuf(gr, &image->dmabuf->attributes);
- if (!image->images[0])
- return false;
- image->num_images = 1;
- break;
-
- case IMPORT_TYPE_GL_CONVERSION:
- if (!import_yuv_dmabuf(gr, image))
- return false;
- break;
-
- default:
- weston_log("Invalid import type for dmabuf\n");
- return false;
- }
-
- return true;
-}
-
-static bool
-dmabuf_is_opaque(struct linux_dmabuf_buffer *dmabuf)
-{
- const struct pixel_format_info *info;
-
- info = pixel_format_get_info(dmabuf->attributes.format &
- ~DRM_FORMAT_BIG_ENDIAN);
- if (!info)
- return false;
-
- return pixel_format_is_opaque(info);
-}
-
-#ifdef HAVE_TBM
-static bool
-tbm_surface_is_opaque(tbm_surface_h tsurface)
-{
- const struct pixel_format_info *info;
-
- /* format of tbm surface use fourcc */
- info = pixel_format_get_info(tbm_surface_get_format(tsurface) &
- ~DRM_FORMAT_BIG_ENDIAN);
- if (!info)
- return false;
-
- return pixel_format_is_opaque(info);
-}
-
-static void
-gl_renderer_attach_tbm_surface(struct weston_surface *surface,
- struct weston_buffer *buffer,
- tbm_surface_h tsurface)
-{
- struct gl_renderer *gr = get_renderer(surface->compositor);
- struct gl_surface_state *gs = get_surface_state(surface);
- tbm_format format;
- int num_planes = 1;
- int i;
-
- buffer->width = tbm_surface_get_width(tsurface);
- buffer->height = tbm_surface_get_height(tsurface);
- /* how to know it? */
- buffer->y_inverted = true;
-
- for (i = 0; i < gs->num_images; i++)
- egl_image_unref(gs->images[i]);
- gs->num_images = 0;
-
- gs->target = GL_TEXTURE_2D;
- gs->pitch = buffer->width;
- gs->height = buffer->height;
- gs->buffer_type = BUFFER_TYPE_EGL;
- gs->y_inverted = buffer->y_inverted;
- surface->is_opaque = tbm_surface_is_opaque(tsurface);
-
- format = tbm_surface_get_format(tsurface);
- switch(format) {
- case TBM_FORMAT_ARGB8888:
- case TBM_FORMAT_XRGB8888:
- gs->shader = &gr->texture_shader_rgba;
- break;
- default:
- gs->shader = &gr->texture_shader_egl_external;
- break;
- }
-
-#ifndef EGL_NATIVE_SURFACE_TIZEN
-#define EGL_NATIVE_SURFACE_TIZEN 0x32A1
-#endif
-
- ensure_textures(gs, num_planes);
- for (i = 0; i < num_planes; i++) {
- gs->images[i] = egl_image_create(gr,
- EGL_NATIVE_SURFACE_TIZEN,
- (void *)tsurface,
- NULL);
- if (!gs->images[i]) {
- weston_log("failed to create img for plane %d\n", i);
- continue;
- }
- gs->num_images++;
-
- glActiveTexture(GL_TEXTURE0 + i);
- glBindTexture(gs->target, gs->textures[i]);
- gr->image_target_texture_2d(gs->target,
- gs->images[i]->image);
- }
-}
-#endif
-
-static void
-gl_renderer_attach_dmabuf(struct weston_surface *surface,
- struct weston_buffer *buffer,
- struct linux_dmabuf_buffer *dmabuf)
-{
- struct gl_renderer *gr = get_renderer(surface->compositor);
- struct gl_surface_state *gs = get_surface_state(surface);
- struct dmabuf_image *image;
- int i;
- int ret;
-
- if (!gr->has_dmabuf_import) {
- linux_dmabuf_buffer_send_server_error(dmabuf,
- "EGL dmabuf import not supported");
- return;
- }
-
- buffer->width = dmabuf->attributes.width;
- buffer->height = dmabuf->attributes.height;
-
- /*
- * GL-renderer uses the OpenGL convention of texture coordinates, where
- * the origin is at bottom-left. Because dmabuf buffers have the origin
- * at top-left, we must invert the Y_INVERT flag to get the image right.
- */
- buffer->y_inverted =
- !(dmabuf->attributes.flags & ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT);
-
- for (i = 0; i < gs->num_images; i++)
- egl_image_unref(gs->images[i]);
- gs->num_images = 0;
-
- gs->pitch = buffer->width;
- gs->height = buffer->height;
- gs->buffer_type = BUFFER_TYPE_EGL;
- gs->y_inverted = buffer->y_inverted;
- gs->direct_display = dmabuf->direct_display;
- surface->is_opaque = dmabuf_is_opaque(dmabuf);
-
- /*
- * We try to always hold an imported EGLImage from the dmabuf
- * to prevent the client from preventing re-imports. But, we also
- * need to re-import every time the contents may change because
- * GL driver's caching may need flushing.
- *
- * Here we release the cache reference which has to be final.
- */
- if (dmabuf->direct_display)
- return;
-
- image = linux_dmabuf_buffer_get_user_data(dmabuf);
-
- /* The dmabuf_image should have been created during the import */
- assert(image != NULL);
-
- for (i = 0; i < image->num_images; ++i) {
- ret = egl_image_unref(image->images[i]);
- assert(ret == 0);
- }
-
- if (!import_known_dmabuf(gr, image)) {
- linux_dmabuf_buffer_send_server_error(dmabuf, "EGL dmabuf import failed");
- return;
- }
-
- gs->num_images = image->num_images;
- for (i = 0; i < gs->num_images; ++i)
- gs->images[i] = egl_image_ref(image->images[i]);
-
- gs->target = image->target;
- ensure_textures(gs, gs->num_images);
- for (i = 0; i < gs->num_images; ++i) {
- glActiveTexture(GL_TEXTURE0 + i);
- glBindTexture(gs->target, gs->textures[i]);
- gr->image_target_texture_2d(gs->target, gs->images[i]->image);
- }
-
- gs->shader = image->shader;
-}
-
-static void
-gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
-{
- struct weston_compositor *ec = es->compositor;
- struct gl_renderer *gr = get_renderer(ec);
- struct gl_surface_state *gs = get_surface_state(es);
- struct wl_shm_buffer *shm_buffer;
- struct linux_dmabuf_buffer *dmabuf;
- EGLint format;
- int i;
-#ifdef HAVE_TBM
- tbm_surface_h tsurface;
-#endif
-
- weston_buffer_reference(&gs->buffer_ref, buffer);
- weston_buffer_release_reference(&gs->buffer_release_ref,
- es->buffer_release_ref.buffer_release);
-
- if (!buffer) {
- for (i = 0; i < gs->num_images; i++) {
- egl_image_unref(gs->images[i]);
- gs->images[i] = NULL;
- }
- gs->num_images = 0;
- glDeleteTextures(gs->num_textures, gs->textures);
- gs->num_textures = 0;
- gs->buffer_type = BUFFER_TYPE_NULL;
- gs->y_inverted = true;
- gs->direct_display = false;
- es->is_opaque = false;
- return;
- }
-
- shm_buffer = wl_shm_buffer_get(buffer->resource);
-
- if (shm_buffer)
- gl_renderer_attach_shm(es, buffer, shm_buffer);
-#ifdef HAVE_TBM
- else if ((tsurface = wayland_tbm_server_get_surface(gr->wl_tbm_server, buffer->resource)))
- gl_renderer_attach_tbm_surface(es, buffer, tsurface);
-#endif
- else if (gr->has_bind_display &&
- gr->query_buffer(gr->egl_display, (void *)buffer->resource,
- EGL_TEXTURE_FORMAT, &format))
- gl_renderer_attach_egl(es, buffer, format);
- else if ((dmabuf = linux_dmabuf_buffer_get(buffer->resource)))
- gl_renderer_attach_dmabuf(es, buffer, dmabuf);
- else {
- weston_log("unhandled buffer type!\n");
- if (gr->has_bind_display) {
- weston_log("eglQueryWaylandBufferWL failed\n");
- gl_renderer_print_egl_error_state();
- }
- weston_buffer_reference(&gs->buffer_ref, NULL);
- weston_buffer_release_reference(&gs->buffer_release_ref, NULL);
- gs->buffer_type = BUFFER_TYPE_NULL;
- gs->y_inverted = true;
- es->is_opaque = false;
- weston_buffer_send_server_error(buffer,
- "disconnecting due to unhandled buffer type");
- }
-}
-
-static void
-gl_renderer_surface_set_color(struct weston_surface *surface,
- float red, float green, float blue, float alpha)
-{
- struct gl_surface_state *gs = get_surface_state(surface);
- struct gl_renderer *gr = get_renderer(surface->compositor);
-
- gs->color[0] = red;
- gs->color[1] = green;
- gs->color[2] = blue;
- gs->color[3] = alpha;
- gs->buffer_type = BUFFER_TYPE_SOLID;
- gs->pitch = 1;
- gs->height = 1;
-
- gs->shader = &gr->solid_shader;
-}
-
-static void
-gl_renderer_surface_get_content_size(struct weston_surface *surface,
- int *width, int *height)
-{
- struct gl_surface_state *gs = get_surface_state(surface);
-
- if (gs->buffer_type == BUFFER_TYPE_NULL) {
- *width = 0;
- *height = 0;
- } else {
- *width = gs->pitch;
- *height = gs->height;
- }
-}
-
-static uint32_t
-pack_color(pixman_format_code_t format, float *c)
-{
- uint8_t r = round(c[0] * 255.0f);
- uint8_t g = round(c[1] * 255.0f);
- uint8_t b = round(c[2] * 255.0f);
- uint8_t a = round(c[3] * 255.0f);
-
- switch (format) {
- case PIXMAN_a8b8g8r8:
- return (a << 24) | (b << 16) | (g << 8) | r;
- default:
- assert(0);
- return 0;
- }
-}
-
-static int
-gl_renderer_surface_copy_content(struct weston_surface *surface,
- void *target, size_t size,
- int src_x, int src_y,
- int width, int height)
-{
- static const GLfloat verts[4 * 2] = {
- 0.0f, 0.0f,
- 1.0f, 0.0f,
- 1.0f, 1.0f,
- 0.0f, 1.0f
- };
- static const GLfloat projmat_normal[16] = { /* transpose */
- 2.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 2.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 1.0f, 0.0f,
- -1.0f, -1.0f, 0.0f, 1.0f
- };
- static const GLfloat projmat_yinvert[16] = { /* transpose */
- 2.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, -2.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 1.0f, 0.0f,
- -1.0f, 1.0f, 0.0f, 1.0f
- };
- const pixman_format_code_t format = PIXMAN_a8b8g8r8;
- const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
- const GLenum gl_format = GL_RGBA; /* PIXMAN_a8b8g8r8 little-endian */
- struct gl_renderer *gr = get_renderer(surface->compositor);
- struct gl_surface_state *gs = get_surface_state(surface);
- int cw, ch;
- GLuint fbo;
- GLuint tex;
- GLenum status;
- const GLfloat *proj;
- int i;
-
- gl_renderer_surface_get_content_size(surface, &cw, &ch);
-
- switch (gs->buffer_type) {
- case BUFFER_TYPE_NULL:
- return -1;
- case BUFFER_TYPE_SOLID:
- *(uint32_t *)target = pack_color(format, gs->color);
- return 0;
- case BUFFER_TYPE_SHM:
- gl_renderer_flush_damage(surface);
- /* fall through */
- case BUFFER_TYPE_EGL:
- break;
- }
-
- glGenTextures(1, &tex);
- glBindTexture(GL_TEXTURE_2D, tex);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cw, ch,
- 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- glBindTexture(GL_TEXTURE_2D, 0);
-
- glGenFramebuffers(1, &fbo);
- glBindFramebuffer(GL_FRAMEBUFFER, fbo);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, tex, 0);
-
- status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- if (status != GL_FRAMEBUFFER_COMPLETE) {
- weston_log("%s: fbo error: %#x\n", __func__, status);
- glDeleteFramebuffers(1, &fbo);
- glDeleteTextures(1, &tex);
- return -1;
- }
-
- glViewport(0, 0, cw, ch);
- glDisable(GL_BLEND);
- use_shader(gr, gs->shader);
- if (gs->y_inverted)
- proj = projmat_normal;
- else
- proj = projmat_yinvert;
-
- glUniformMatrix4fv(gs->shader->proj_uniform, 1, GL_FALSE, proj);
- glUniform1f(gs->shader->alpha_uniform, 1.0f);
-
- for (i = 0; i < gs->num_textures; i++) {
- glUniform1i(gs->shader->tex_uniforms[i], i);
-
- glActiveTexture(GL_TEXTURE0 + i);
- glBindTexture(gs->target, gs->textures[i]);
- glTexParameteri(gs->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(gs->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- }
-
- /* position: */
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts);
- glEnableVertexAttribArray(0);
-
- /* texcoord: */
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, verts);
- glEnableVertexAttribArray(1);
-
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-
- glDisableVertexAttribArray(1);
- glDisableVertexAttribArray(0);
-
- glPixelStorei(GL_PACK_ALIGNMENT, bytespp);
- glReadPixels(src_x, src_y, width, height, gl_format,
- GL_UNSIGNED_BYTE, target);
-
- glDeleteFramebuffers(1, &fbo);
- glDeleteTextures(1, &tex);
-
- return 0;
-}
-
-static void
-surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr)
-{
- int i;
-
- wl_list_remove(&gs->surface_destroy_listener.link);
- wl_list_remove(&gs->renderer_destroy_listener.link);
-
- gs->surface->renderer_state = NULL;
-
- glDeleteTextures(gs->num_textures, gs->textures);
-
- for (i = 0; i < gs->num_images; i++)
- egl_image_unref(gs->images[i]);
-
- weston_buffer_reference(&gs->buffer_ref, NULL);
- weston_buffer_release_reference(&gs->buffer_release_ref, NULL);
- pixman_region32_fini(&gs->texture_damage);
- free(gs);
-}
-
-static void
-surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
-{
- struct gl_surface_state *gs;
- struct gl_renderer *gr;
-
- gs = container_of(listener, struct gl_surface_state,
- surface_destroy_listener);
-
- gr = get_renderer(gs->surface->compositor);
-
- surface_state_destroy(gs, gr);
-}
-
-static void
-surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
-{
- struct gl_surface_state *gs;
- struct gl_renderer *gr;
-
- gr = data;
-
- gs = container_of(listener, struct gl_surface_state,
- renderer_destroy_listener);
-
- surface_state_destroy(gs, gr);
-}
-
-static int
-gl_renderer_create_surface(struct weston_surface *surface)
-{
- struct gl_surface_state *gs;
- struct gl_renderer *gr = get_renderer(surface->compositor);
-
- gs = zalloc(sizeof *gs);
- if (gs == NULL)
- return -1;
-
- /* A buffer is never attached to solid color surfaces, yet
- * they still go through texcoord computations. Do not divide
- * by zero there.
- */
- gs->pitch = 1;
- gs->y_inverted = true;
- gs->direct_display = false;
-
- gs->surface = surface;
-
- pixman_region32_init(&gs->texture_damage);
- surface->renderer_state = gs;
-
- gs->surface_destroy_listener.notify =
- surface_state_handle_surface_destroy;
- wl_signal_add(&surface->destroy_signal,
- &gs->surface_destroy_listener);
-
- gs->renderer_destroy_listener.notify =
- surface_state_handle_renderer_destroy;
- wl_signal_add(&gr->destroy_signal,
- &gs->renderer_destroy_listener);
-
- if (surface->buffer_ref.buffer) {
- gl_renderer_attach(surface, surface->buffer_ref.buffer);
- gl_renderer_flush_damage(surface);
- }
-
- return 0;
-}
-
-static const char vertex_shader[] =
- "uniform mat4 proj;\n"
- "attribute vec2 position;\n"
- "attribute vec2 texcoord;\n"
- "varying vec2 v_texcoord;\n"
- "void main()\n"
- "{\n"
- " gl_Position = proj * vec4(position, 0.0, 1.0);\n"
- " v_texcoord = texcoord;\n"
- "}\n";
-
-/* Declare common fragment shader uniforms */
-#define FRAGMENT_CONVERT_YUV \
- " y *= alpha;\n" \
- " u *= alpha;\n" \
- " v *= alpha;\n" \
- " gl_FragColor.r = y + 1.59602678 * v;\n" \
- " gl_FragColor.g = y - 0.39176229 * u - 0.81296764 * v;\n" \
- " gl_FragColor.b = y + 2.01723214 * u;\n" \
- " gl_FragColor.a = alpha;\n"
-
-static const char fragment_debug[] =
- " gl_FragColor = vec4(0.0, 0.3, 0.0, 0.2) + gl_FragColor * 0.8;\n";
-
-static const char fragment_brace[] =
- "}\n";
-
-static const char texture_fragment_shader_rgba[] =
- "precision mediump float;\n"
- "varying vec2 v_texcoord;\n"
- "uniform sampler2D tex;\n"
- "uniform float alpha;\n"
- "void main()\n"
- "{\n"
- " gl_FragColor = alpha * texture2D(tex, v_texcoord)\n;"
- ;
-
-static const char texture_fragment_shader_rgbx[] =
- "precision mediump float;\n"
- "varying vec2 v_texcoord;\n"
- "uniform sampler2D tex;\n"
- "uniform float alpha;\n"
- "void main()\n"
- "{\n"
- " gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb\n;"
- " gl_FragColor.a = alpha;\n"
- ;
-
-static const char texture_fragment_shader_egl_external[] =
- "#extension GL_OES_EGL_image_external : require\n"
- "precision mediump float;\n"
- "varying vec2 v_texcoord;\n"
- "uniform samplerExternalOES tex;\n"
- "uniform float alpha;\n"
- "void main()\n"
- "{\n"
- " gl_FragColor = alpha * texture2D(tex, v_texcoord)\n;"
- ;
-
-static const char texture_fragment_shader_y_uv[] =
- "precision mediump float;\n"
- "uniform sampler2D tex;\n"
- "uniform sampler2D tex1;\n"
- "varying vec2 v_texcoord;\n"
- "uniform float alpha;\n"
- "void main() {\n"
- " float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"
- " float u = texture2D(tex1, v_texcoord).r - 0.5;\n"
- " float v = texture2D(tex1, v_texcoord).g - 0.5;\n"
- FRAGMENT_CONVERT_YUV
- ;
-
-static const char texture_fragment_shader_y_u_v[] =
- "precision mediump float;\n"
- "uniform sampler2D tex;\n"
- "uniform sampler2D tex1;\n"
- "uniform sampler2D tex2;\n"
- "varying vec2 v_texcoord;\n"
- "uniform float alpha;\n"
- "void main() {\n"
- " float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"
- " float u = texture2D(tex1, v_texcoord).x - 0.5;\n"
- " float v = texture2D(tex2, v_texcoord).x - 0.5;\n"
- FRAGMENT_CONVERT_YUV
- ;
-
-static const char texture_fragment_shader_y_xuxv[] =
- "precision mediump float;\n"
- "uniform sampler2D tex;\n"
- "uniform sampler2D tex1;\n"
- "varying vec2 v_texcoord;\n"
- "uniform float alpha;\n"
- "void main() {\n"
- " float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"
- " float u = texture2D(tex1, v_texcoord).g - 0.5;\n"
- " float v = texture2D(tex1, v_texcoord).a - 0.5;\n"
- FRAGMENT_CONVERT_YUV
- ;
-
-static const char texture_fragment_shader_xyuv[] =
- "precision mediump float;\n"
- "uniform sampler2D tex;\n"
- "varying vec2 v_texcoord;\n"
- "uniform float alpha;\n"
- "void main() {\n"
- " float y = 1.16438356 * (texture2D(tex, v_texcoord).b - 0.0625);\n"
- " float u = texture2D(tex, v_texcoord).g - 0.5;\n"
- " float v = texture2D(tex, v_texcoord).r - 0.5;\n"
- FRAGMENT_CONVERT_YUV
- ;
-
-static const char solid_fragment_shader[] =
- "precision mediump float;\n"
- "uniform vec4 color;\n"
- "uniform float alpha;\n"
- "void main()\n"
- "{\n"
- " gl_FragColor = alpha * color\n;"
- ;
-
-static int
-compile_shader(GLenum type, int count, const char **sources)
-{
- GLuint s;
- char msg[512];
- GLint status;
-
- s = glCreateShader(type);
- glShaderSource(s, count, sources, NULL);
- glCompileShader(s);
- glGetShaderiv(s, GL_COMPILE_STATUS, &status);
- if (!status) {
- glGetShaderInfoLog(s, sizeof msg, NULL, msg);
- weston_log("shader info: %s\n", msg);
- return GL_NONE;
- }
-
- return s;
-}
-
-static int
-shader_init(struct gl_shader *shader, struct gl_renderer *renderer,
- const char *vertex_source, const char *fragment_source)
-{
- char msg[512];
- GLint status;
- int count;
- const char *sources[3];
-
- shader->vertex_shader =
- compile_shader(GL_VERTEX_SHADER, 1, &vertex_source);
-
- if (renderer->fragment_shader_debug) {
- sources[0] = fragment_source;
- sources[1] = fragment_debug;
- sources[2] = fragment_brace;
- count = 3;
- } else {
- sources[0] = fragment_source;
- sources[1] = fragment_brace;
- count = 2;
- }
-
- shader->fragment_shader =
- compile_shader(GL_FRAGMENT_SHADER, count, sources);
-
- shader->program = glCreateProgram();
- glAttachShader(shader->program, shader->vertex_shader);
- glAttachShader(shader->program, shader->fragment_shader);
- glBindAttribLocation(shader->program, 0, "position");
- glBindAttribLocation(shader->program, 1, "texcoord");
-
- glLinkProgram(shader->program);
- glGetProgramiv(shader->program, GL_LINK_STATUS, &status);
- if (!status) {
- glGetProgramInfoLog(shader->program, sizeof msg, NULL, msg);
- weston_log("link info: %s\n", msg);
- return -1;
- }
-
- shader->proj_uniform = glGetUniformLocation(shader->program, "proj");
- shader->tex_uniforms[0] = glGetUniformLocation(shader->program, "tex");
- shader->tex_uniforms[1] = glGetUniformLocation(shader->program, "tex1");
- shader->tex_uniforms[2] = glGetUniformLocation(shader->program, "tex2");
- shader->alpha_uniform = glGetUniformLocation(shader->program, "alpha");
- shader->color_uniform = glGetUniformLocation(shader->program, "color");
-
- return 0;
-}
-
-static void
-shader_release(struct gl_shader *shader)
-{
- glDeleteShader(shader->vertex_shader);
- glDeleteShader(shader->fragment_shader);
- glDeleteProgram(shader->program);
-
- shader->vertex_shader = 0;
- shader->fragment_shader = 0;
- shader->program = 0;
-}
-
-static void
-log_extensions(const char *name, const char *extensions)
-{
- const char *p, *end;
- int l;
- int len;
-
- l = weston_log("%s:", name);
- p = extensions;
- while (*p) {
- end = strchrnul(p, ' ');
- len = end - p;
- if (l + len > 78)
- l = weston_log_continue("\n" STAMP_SPACE "%.*s",
- len, p);
- else
- l += weston_log_continue(" %.*s", len, p);
- for (p = end; isspace(*p); p++)
- ;
- }
- weston_log_continue("\n");
-}
-
-static void
-log_egl_info(EGLDisplay egldpy)
-{
- const char *str;
-
- str = eglQueryString(egldpy, EGL_VERSION);
- weston_log("EGL version: %s\n", str ? str : "(null)");
-
- str = eglQueryString(egldpy, EGL_VENDOR);
- weston_log("EGL vendor: %s\n", str ? str : "(null)");
-
- str = eglQueryString(egldpy, EGL_CLIENT_APIS);
- weston_log("EGL client APIs: %s\n", str ? str : "(null)");
-
- str = eglQueryString(egldpy, EGL_EXTENSIONS);
- log_extensions("EGL extensions", str ? str : "(null)");
-}
-
-static void
-log_gl_info(void)
-{
- const char *str;
-
- str = (char *)glGetString(GL_VERSION);
- weston_log("GL version: %s\n", str ? str : "(null)");
-
- str = (char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
- weston_log("GLSL version: %s\n", str ? str : "(null)");
-
- str = (char *)glGetString(GL_VENDOR);
- weston_log("GL vendor: %s\n", str ? str : "(null)");
-
- str = (char *)glGetString(GL_RENDERER);
- weston_log("GL renderer: %s\n", str ? str : "(null)");
-
- str = (char *)glGetString(GL_EXTENSIONS);
- log_extensions("GL extensions", str ? str : "(null)");
-}
-
-static void
-gl_renderer_output_set_border(struct weston_output *output,
- enum gl_renderer_border_side side,
- int32_t width, int32_t height,
- int32_t tex_width, unsigned char *data)
-{
- struct gl_output_state *go = get_output_state(output);
-
- if (go->borders[side].width != width ||
- go->borders[side].height != height)
- /* In this case, we have to blow everything and do a full
- * repaint. */
- go->border_status |= BORDER_SIZE_CHANGED | BORDER_ALL_DIRTY;
-
- if (data == NULL) {
- width = 0;
- height = 0;
- }
-
- go->borders[side].width = width;
- go->borders[side].height = height;
- go->borders[side].tex_width = tex_width;
- go->borders[side].data = data;
- go->border_status |= 1 << side;
-}
-
-static int
-gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface);
-
-static EGLSurface
-gl_renderer_create_window_surface(struct gl_renderer *gr,
- EGLNativeWindowType window_for_legacy,
- void *window_for_platform,
- const uint32_t *drm_formats,
- unsigned drm_formats_count)
-{
- EGLSurface egl_surface = EGL_NO_SURFACE;
- EGLConfig egl_config;
-
- egl_config = gl_renderer_get_egl_config(gr, EGL_WINDOW_BIT,
- drm_formats, drm_formats_count);
- if (egl_config == EGL_NO_CONFIG_KHR)
- return EGL_NO_SURFACE;
-
- log_egl_config_info(gr->egl_display, egl_config);
-
- if (gr->create_platform_window)
- egl_surface = gr->create_platform_window(gr->egl_display,
- egl_config,
- window_for_platform,
- NULL);
- else
- egl_surface = eglCreateWindowSurface(gr->egl_display,
- egl_config,
- window_for_legacy, NULL);
-
- return egl_surface;
-}
-
-static int
-gl_renderer_output_create(struct weston_output *output,
- EGLSurface surface)
-{
- struct gl_output_state *go;
- int i;
-
- go = zalloc(sizeof *go);
- if (go == NULL)
- return -1;
-
- go->egl_surface = surface;
-
- for (i = 0; i < BUFFER_DAMAGE_COUNT; i++)
- pixman_region32_init(&go->buffer_damage[i]);
-
- wl_list_init(&go->timeline_render_point_list);
-
- go->begin_render_sync = EGL_NO_SYNC_KHR;
- go->end_render_sync = EGL_NO_SYNC_KHR;
-
- output->renderer_state = go;
-
- return 0;
-}
-
-static int
-gl_renderer_output_window_create(struct weston_output *output,
- EGLNativeWindowType window_for_legacy,
- void *window_for_platform,
- const uint32_t *drm_formats,
- unsigned drm_formats_count)
-{
- struct weston_compositor *ec = output->compositor;
- struct gl_renderer *gr = get_renderer(ec);
- EGLSurface egl_surface = EGL_NO_SURFACE;
- int ret = 0;
-
- egl_surface = gl_renderer_create_window_surface(gr,
- window_for_legacy,
- window_for_platform,
- drm_formats,
- drm_formats_count);
- if (egl_surface == EGL_NO_SURFACE) {
- weston_log("failed to create egl surface\n");
- return -1;
- }
-
- ret = gl_renderer_output_create(output, egl_surface);
- if (ret < 0)
- weston_platform_destroy_egl_surface(gr->egl_display, egl_surface);
-
- return ret;
-}
-
-static int
-gl_renderer_output_pbuffer_create(struct weston_output *output,
- int width,
- int height,
- const uint32_t *drm_formats,
- unsigned drm_formats_count)
-{
- struct gl_renderer *gr = get_renderer(output->compositor);
- EGLConfig pbuffer_config;
- EGLSurface egl_surface;
- int ret;
- EGLint pbuffer_attribs[] = {
- EGL_WIDTH, width,
- EGL_HEIGHT, height,
- EGL_NONE
- };
-
- pbuffer_config = gl_renderer_get_egl_config(gr, EGL_PBUFFER_BIT,
- drm_formats,
- drm_formats_count);
- if (pbuffer_config == EGL_NO_CONFIG_KHR) {
- weston_log("failed to choose EGL config for PbufferSurface\n");
- return -1;
- }
-
- log_egl_config_info(gr->egl_display, pbuffer_config);
-
- egl_surface = eglCreatePbufferSurface(gr->egl_display, pbuffer_config,
- pbuffer_attribs);
- if (egl_surface == EGL_NO_SURFACE) {
- weston_log("failed to create egl surface\n");
- gl_renderer_print_egl_error_state();
- return -1;
- }
-
- ret = gl_renderer_output_create(output, egl_surface);
- if (ret < 0)
- eglDestroySurface(gr->egl_display, egl_surface);
-
- return ret;
-}
-
-static void
-gl_renderer_output_destroy(struct weston_output *output)
-{
- struct gl_renderer *gr = get_renderer(output->compositor);
- struct gl_output_state *go = get_output_state(output);
- struct timeline_render_point *trp, *tmp;
- int i;
-
- for (i = 0; i < 2; i++)
- pixman_region32_fini(&go->buffer_damage[i]);
-
- eglMakeCurrent(gr->egl_display,
- EGL_NO_SURFACE, EGL_NO_SURFACE,
- EGL_NO_CONTEXT);
-
- weston_platform_destroy_egl_surface(gr->egl_display, go->egl_surface);
-
- if (!wl_list_empty(&go->timeline_render_point_list))
- weston_log("warning: discarding pending timeline render"
- "objects at output destruction");
-
- wl_list_for_each_safe(trp, tmp, &go->timeline_render_point_list, link)
- timeline_render_point_destroy(trp);
-
- if (go->begin_render_sync != EGL_NO_SYNC_KHR)
- gr->destroy_sync(gr->egl_display, go->begin_render_sync);
- if (go->end_render_sync != EGL_NO_SYNC_KHR)
- gr->destroy_sync(gr->egl_display, go->end_render_sync);
-
- free(go);
-}
-
-static int
-gl_renderer_create_fence_fd(struct weston_output *output)
-{
- struct gl_output_state *go = get_output_state(output);
- struct gl_renderer *gr = get_renderer(output->compositor);
- int fd;
-
- if (go->end_render_sync == EGL_NO_SYNC_KHR)
- return -1;
-
- fd = gr->dup_native_fence_fd(gr->egl_display, go->end_render_sync);
- if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID)
- return -1;
-
- return fd;
-}
-
-static void
-gl_renderer_destroy(struct weston_compositor *ec)
-{
- struct gl_renderer *gr = get_renderer(ec);
- struct dmabuf_image *image, *next;
-
- wl_signal_emit(&gr->destroy_signal, gr);
-
- if (gr->has_bind_display)
- gr->unbind_display(gr->egl_display, ec->wl_display);
-
- /* Work around crash in egl_dri2.c's dri2_make_current() - when does this apply? */
- eglMakeCurrent(gr->egl_display,
- EGL_NO_SURFACE, EGL_NO_SURFACE,
- EGL_NO_CONTEXT);
-
-
- wl_list_for_each_safe(image, next, &gr->dmabuf_images, link)
- dmabuf_image_destroy(image);
-
- if (gr->dummy_surface != EGL_NO_SURFACE)
- weston_platform_destroy_egl_surface(gr->egl_display,
- gr->dummy_surface);
-
- eglTerminate(gr->egl_display);
- eglReleaseThread();
-
- wl_list_remove(&gr->output_destroy_listener.link);
-
- wl_array_release(&gr->vertices);
- wl_array_release(&gr->vtxcnt);
-
- if (gr->fragment_binding)
- weston_binding_destroy(gr->fragment_binding);
- if (gr->fan_binding)
- weston_binding_destroy(gr->fan_binding);
-
- free(gr);
-}
-
-/** Checks whether a platform EGL client extension is supported
- *
- * \param ec The weston compositor
- * \param extension_suffix The EGL client extension suffix
- * \return 1 if supported, 0 if using fallbacks, -1 unsupported
- *
- * This function checks whether a specific platform_* extension is supported
- * by EGL.
- *
- * The extension suffix should be the suffix of the platform extension (that
- * specifies a platform argument as defined in EGL_EXT_platform_base). For
- * example, passing "foo" will check whether either "EGL_KHR_platform_foo",
- * "EGL_EXT_platform_foo", or "EGL_MESA_platform_foo" is supported.
- *
- * The return value is 1:
- * - if the supplied EGL client extension is supported.
- * The return value is 0:
- * - if the platform_base client extension isn't supported so will
- * fallback to eglGetDisplay and friends.
- * The return value is -1:
- * - if the supplied EGL client extension is not supported.
- */
-static int
-gl_renderer_supports(struct weston_compositor *ec,
- const char *extension_suffix)
-{
- static const char *extensions = NULL;
- char s[64];
-
- if (!extensions) {
- extensions = (const char *) eglQueryString(
- EGL_NO_DISPLAY, EGL_EXTENSIONS);
-
- if (!extensions)
- return 0;
-
- log_extensions("EGL client extensions",
- extensions);
- }
-
- if (!weston_check_egl_extension(extensions, "EGL_EXT_platform_base"))
- return 0;
-
- snprintf(s, sizeof s, "EGL_KHR_platform_%s", extension_suffix);
- if (weston_check_egl_extension(extensions, s))
- return 1;
-
- snprintf(s, sizeof s, "EGL_EXT_platform_%s", extension_suffix);
- if (weston_check_egl_extension(extensions, s))
- return 1;
-
- snprintf(s, sizeof s, "EGL_MESA_platform_%s", extension_suffix);
- if (weston_check_egl_extension(extensions, s))
- return 1;
-
- /* at this point we definitely have some platform extensions but
- * haven't found the supplied platform, so chances are it's
- * not supported. */
-
- return -1;
-}
-
-static const char *
-platform_to_extension(EGLenum platform)
-{
- switch (platform) {
- case EGL_PLATFORM_GBM_KHR:
- return "gbm";
- case EGL_PLATFORM_WAYLAND_KHR:
- return "wayland";
- case EGL_PLATFORM_X11_KHR:
- return "x11";
- case EGL_PLATFORM_SURFACELESS_MESA:
- return "surfaceless";
- default:
- assert(0 && "bad EGL platform enum");
- }
-}
-
-static void
-output_handle_destroy(struct wl_listener *listener, void *data)
-{
- struct gl_renderer *gr;
- struct weston_output *output = data;
-
- gr = container_of(listener, struct gl_renderer,
- output_destroy_listener);
-
- if (wl_list_empty(&output->compositor->output_list))
- eglMakeCurrent(gr->egl_display, gr->dummy_surface,
- gr->dummy_surface, gr->egl_context);
-}
-
-static int
-gl_renderer_create_pbuffer_surface(struct gl_renderer *gr) {
- EGLConfig pbuffer_config;
- static const EGLint pbuffer_attribs[] = {
- EGL_WIDTH, 10,
- EGL_HEIGHT, 10,
- EGL_NONE
- };
-
- pbuffer_config = gl_renderer_get_egl_config(gr, EGL_PBUFFER_BIT,
- NULL, 0);
- if (pbuffer_config == EGL_NO_CONFIG_KHR) {
- weston_log("failed to choose EGL config for PbufferSurface\n");
- return -1;
- }
-
- gr->dummy_surface = eglCreatePbufferSurface(gr->egl_display,
- pbuffer_config,
- pbuffer_attribs);
-
- if (gr->dummy_surface == EGL_NO_SURFACE) {
- weston_log("failed to create PbufferSurface\n");
- return -1;
- }
-
- return 0;
-}
-
-static int
-gl_renderer_display_create(struct weston_compositor *ec,
- EGLenum platform,
- void *native_display,
- EGLint egl_surface_type,
- const uint32_t *drm_formats,
- unsigned drm_formats_count)
-{
- struct gl_renderer *gr;
- EGLint major, minor;
- int supports = 0;
-
- if (platform) {
- supports = gl_renderer_supports(
- ec, platform_to_extension(platform));
- if (supports < 0)
- return -1;
- }
-
- /* Surfaceless is unusable without platform_base extension */
- if (supports == 0 && platform == EGL_PLATFORM_SURFACELESS_MESA)
- return -1;
-
- gr = zalloc(sizeof *gr);
- if (gr == NULL)
- return -1;
-
- gr->base.read_pixels = gl_renderer_read_pixels;
- gr->base.repaint_output = gl_renderer_repaint_output;
- gr->base.flush_damage = gl_renderer_flush_damage;
- gr->base.attach = gl_renderer_attach;
- gr->base.surface_set_color = gl_renderer_surface_set_color;
- gr->base.destroy = gl_renderer_destroy;
- gr->base.surface_get_content_size =
- gl_renderer_surface_get_content_size;
- gr->base.surface_copy_content = gl_renderer_surface_copy_content;
- gr->platform = platform;
- gr->egl_display = NULL;
-
- /* extension_suffix is supported */
- if (supports) {
- if (!get_platform_display) {
- get_platform_display = (void *) eglGetProcAddress(
- "eglGetPlatformDisplayEXT");
- }
-
- /* also wrap this in the supports check because
- * eglGetProcAddress can return non-NULL and still not
- * support the feature at runtime, so ensure the
- * appropriate extension checks have been done. */
- if (get_platform_display && platform) {
- gr->egl_display = get_platform_display(platform,
- native_display,
- NULL);
- }
- }
-
- if (!gr->egl_display) {
- weston_log("warning: either no EGL_EXT_platform_base "
- "support or specific platform support; "
- "falling back to eglGetDisplay.\n");
- gr->egl_display = eglGetDisplay(native_display);
- }
-
- if (gr->egl_display == EGL_NO_DISPLAY) {
- weston_log("failed to create display\n");
- goto fail;
- }
-
- if (!eglInitialize(gr->egl_display, &major, &minor)) {
- weston_log("failed to initialize display\n");
- goto fail_with_error;
- }
-
- log_egl_info(gr->egl_display);
-
- ec->renderer = &gr->base;
-
- if (gl_renderer_setup_egl_extensions(ec) < 0)
- goto fail_with_error;
-
- if (!gr->has_configless_context) {
- if (!gr->has_surfaceless_context)
- egl_surface_type |= EGL_PBUFFER_BIT;
-
- gr->egl_config = gl_renderer_get_egl_config(gr,
- egl_surface_type,
- drm_formats,
- drm_formats_count);
- if (gr->egl_config == EGL_NO_CONFIG_KHR) {
- weston_log("failed to choose EGL config\n");
- goto fail_terminate;
- }
- }
-
- ec->capabilities |= WESTON_CAP_ROTATION_ANY;
- ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
- ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
- if (gr->has_native_fence_sync && gr->has_wait_sync)
- ec->capabilities |= WESTON_CAP_EXPLICIT_SYNC;
-
- wl_list_init(&gr->dmabuf_images);
- if (gr->has_dmabuf_import) {
- gr->base.import_dmabuf = gl_renderer_import_dmabuf;
- gr->base.query_dmabuf_formats =
- gl_renderer_query_dmabuf_formats;
- gr->base.query_dmabuf_modifiers =
- gl_renderer_query_dmabuf_modifiers;
- }
-
- if (gr->has_surfaceless_context) {
- weston_log("EGL_KHR_surfaceless_context available\n");
- gr->dummy_surface = EGL_NO_SURFACE;
- } else {
- weston_log("EGL_KHR_surfaceless_context unavailable. "
- "Trying PbufferSurface\n");
-
- if (gl_renderer_create_pbuffer_surface(gr) < 0)
- goto fail_with_error;
- }
-
- wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
- wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_YUV420);
- wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_NV12);
- wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_YUYV);
-
- wl_signal_init(&gr->destroy_signal);
-
- if (gl_renderer_setup(ec, gr->dummy_surface) < 0) {
- if (gr->dummy_surface != EGL_NO_SURFACE)
- weston_platform_destroy_egl_surface(gr->egl_display,
- gr->dummy_surface);
- goto fail_with_error;
- }
-
-#ifdef HAVE_TBM
- tbm_bufmgr bufmgr;
-
- gr->wl_tbm_server = wayland_tbm_server_init(ec->wl_display, NULL, -1, -1);
- if (!gr->wl_tbm_server) {
- weston_log("Fail to init wayland_tbm_server\n");
- goto fail_with_error;
- }
-
- bufmgr = wayland_tbm_server_get_bufmgr(gr->wl_tbm_server);
- if (!bufmgr) {
- weston_log("Fail to get bufmgr\n");
- wayland_tbm_server_deinit(gr->wl_tbm_server);
- goto fail_with_error;
- }
-
- tbm_bufmgr_bind_native_display(bufmgr, (void *)ec->wl_display);
-#endif
- return 0;
-
-fail_with_error:
- gl_renderer_print_egl_error_state();
-fail_terminate:
- eglTerminate(gr->egl_display);
-fail:
- free(gr);
- return -1;
-}
-
-static int
-compile_shaders(struct weston_compositor *ec)
-{
- struct gl_renderer *gr = get_renderer(ec);
-
- gr->texture_shader_rgba.vertex_source = vertex_shader;
- gr->texture_shader_rgba.fragment_source = texture_fragment_shader_rgba;
-
- gr->texture_shader_rgbx.vertex_source = vertex_shader;
- gr->texture_shader_rgbx.fragment_source = texture_fragment_shader_rgbx;
-
- gr->texture_shader_egl_external.vertex_source = vertex_shader;
- gr->texture_shader_egl_external.fragment_source =
- texture_fragment_shader_egl_external;
-
- gr->texture_shader_y_uv.vertex_source = vertex_shader;
- gr->texture_shader_y_uv.fragment_source = texture_fragment_shader_y_uv;
-
- gr->texture_shader_y_u_v.vertex_source = vertex_shader;
- gr->texture_shader_y_u_v.fragment_source =
- texture_fragment_shader_y_u_v;
-
- gr->texture_shader_y_xuxv.vertex_source = vertex_shader;
- gr->texture_shader_y_xuxv.fragment_source =
- texture_fragment_shader_y_xuxv;
-
- gr->texture_shader_xyuv.vertex_source = vertex_shader;
- gr->texture_shader_xyuv.fragment_source = texture_fragment_shader_xyuv;
-
- gr->solid_shader.vertex_source = vertex_shader;
- gr->solid_shader.fragment_source = solid_fragment_shader;
-
- return 0;
-}
-
-static void
-fragment_debug_binding(struct weston_keyboard *keyboard,
- const struct timespec *time,
- uint32_t key, void *data)
-{
- struct weston_compositor *ec = data;
- struct gl_renderer *gr = get_renderer(ec);
- struct weston_output *output;
-
- gr->fragment_shader_debug = !gr->fragment_shader_debug;
-
- shader_release(&gr->texture_shader_rgba);
- shader_release(&gr->texture_shader_rgbx);
- shader_release(&gr->texture_shader_egl_external);
- shader_release(&gr->texture_shader_y_uv);
- shader_release(&gr->texture_shader_y_u_v);
- shader_release(&gr->texture_shader_y_xuxv);
- shader_release(&gr->texture_shader_xyuv);
- shader_release(&gr->solid_shader);
-
- /* Force use_shader() to call glUseProgram(), since we need to use
- * the recompiled version of the shader. */
- gr->current_shader = NULL;
-
- wl_list_for_each(output, &ec->output_list, link)
- weston_output_damage(output);
-}
-
-static void
-fan_debug_repaint_binding(struct weston_keyboard *keyboard,
- const struct timespec *time,
- uint32_t key, void *data)
-{
- struct weston_compositor *compositor = data;
- struct gl_renderer *gr = get_renderer(compositor);
-
- gr->fan_debug = !gr->fan_debug;
- weston_compositor_damage_all(compositor);
-}
-
-static uint32_t
-get_gl_version(void)
-{
- const char *version;
- int major, minor;
-
- version = (const char *) glGetString(GL_VERSION);
- if (version &&
- (sscanf(version, "%d.%d", &major, &minor) == 2 ||
- sscanf(version, "OpenGL ES %d.%d", &major, &minor) == 2)) {
- return GR_GL_VERSION(major, minor);
- }
-
- return GR_GL_VERSION_INVALID;
-}
-
-static int
-gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
-{
- struct gl_renderer *gr = get_renderer(ec);
- const char *extensions;
- EGLBoolean ret;
-
- EGLint context_attribs[16] = {
- EGL_CONTEXT_CLIENT_VERSION, 0,
- };
- unsigned int nattr = 2;
-
- if (!eglBindAPI(EGL_OPENGL_ES_API)) {
- weston_log("failed to bind EGL_OPENGL_ES_API\n");
- gl_renderer_print_egl_error_state();
- return -1;
- }
-
- /*
- * Being the compositor we require minimum output latency,
- * so request a high priority context for ourselves - that should
- * reschedule all of our rendering and its dependencies to be completed
- * first. If the driver doesn't permit us to create a high priority
- * context, it will fallback to the default priority (MEDIUM).
- */
- if (gr->has_context_priority) {
- context_attribs[nattr++] = EGL_CONTEXT_PRIORITY_LEVEL_IMG;
- context_attribs[nattr++] = EGL_CONTEXT_PRIORITY_HIGH_IMG;
- }
-
- assert(nattr < ARRAY_LENGTH(context_attribs));
- context_attribs[nattr] = EGL_NONE;
-
- /* try to create an OpenGLES 3 context first */
- context_attribs[1] = 3;
- gr->egl_context = eglCreateContext(gr->egl_display, gr->egl_config,
- EGL_NO_CONTEXT, context_attribs);
- if (gr->egl_context == NULL) {
- /* and then fallback to OpenGLES 2 */
- context_attribs[1] = 2;
- gr->egl_context = eglCreateContext(gr->egl_display,
- gr->egl_config,
- EGL_NO_CONTEXT,
- context_attribs);
- if (gr->egl_context == NULL) {
- weston_log("failed to create context\n");
- gl_renderer_print_egl_error_state();
- return -1;
- }
- }
-
- if (gr->has_context_priority) {
- EGLint value = EGL_CONTEXT_PRIORITY_MEDIUM_IMG;
-
- eglQueryContext(gr->egl_display, gr->egl_context,
- EGL_CONTEXT_PRIORITY_LEVEL_IMG, &value);
-
- if (value != EGL_CONTEXT_PRIORITY_HIGH_IMG) {
- weston_log("Failed to obtain a high priority context.\n");
- /* Not an error, continue on as normal */
- }
- }
-
- ret = eglMakeCurrent(gr->egl_display, egl_surface,
- egl_surface, gr->egl_context);
- if (ret == EGL_FALSE) {
- weston_log("Failed to make EGL context current.\n");
- gl_renderer_print_egl_error_state();
- return -1;
- }
-
- gr->gl_version = get_gl_version();
- if (gr->gl_version == GR_GL_VERSION_INVALID) {
- weston_log("warning: failed to detect GLES version, "
- "defaulting to 2.0.\n");
- gr->gl_version = GR_GL_VERSION(2, 0);
- }
-
- log_gl_info();
-
- gr->image_target_texture_2d =
- (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
-
- extensions = (const char *) glGetString(GL_EXTENSIONS);
- if (!extensions) {
- weston_log("Retrieving GL extension string failed.\n");
- return -1;
- }
-
- if (!weston_check_egl_extension(extensions, "GL_EXT_texture_format_BGRA8888")) {
- weston_log("GL_EXT_texture_format_BGRA8888 not available\n");
- return -1;
- }
-
- if (weston_check_egl_extension(extensions, "GL_EXT_read_format_bgra"))
- ec->read_format = PIXMAN_a8r8g8b8;
- else
- ec->read_format = PIXMAN_a8b8g8r8;
-
- if (gr->gl_version >= GR_GL_VERSION(3, 0) ||
- weston_check_egl_extension(extensions, "GL_EXT_unpack_subimage"))
- gr->has_unpack_subimage = true;
-
- if (gr->gl_version >= GR_GL_VERSION(3, 0) ||
- weston_check_egl_extension(extensions, "GL_EXT_texture_rg"))
- gr->has_gl_texture_rg = true;
-
- if (weston_check_egl_extension(extensions, "GL_OES_EGL_image_external"))
- gr->has_egl_image_external = true;
-
- glActiveTexture(GL_TEXTURE0);
-
- if (compile_shaders(ec))
- return -1;
-
- gr->fragment_binding =
- weston_compositor_add_debug_binding(ec, KEY_S,
- fragment_debug_binding,
- ec);
- gr->fan_binding =
- weston_compositor_add_debug_binding(ec, KEY_F,
- fan_debug_repaint_binding,
- ec);
-
- gr->output_destroy_listener.notify = output_handle_destroy;
- wl_signal_add(&ec->output_destroyed_signal,
- &gr->output_destroy_listener);
-
- weston_log("GL ES 2 renderer features:\n");
- weston_log_continue(STAMP_SPACE "read-back format: %s\n",
- ec->read_format == PIXMAN_a8r8g8b8 ? "BGRA" : "RGBA");
- weston_log_continue(STAMP_SPACE "wl_shm sub-image to texture: %s\n",
- gr->has_unpack_subimage ? "yes" : "no");
- weston_log_continue(STAMP_SPACE "EGL Wayland extension: %s\n",
- gr->has_bind_display ? "yes" : "no");
-
-
- return 0;
-}
-
-WL_EXPORT struct gl_renderer_interface gl_renderer_interface = {
- .display_create = gl_renderer_display_create,
- .output_window_create = gl_renderer_output_window_create,
- .output_pbuffer_create = gl_renderer_output_pbuffer_create,
- .output_destroy = gl_renderer_output_destroy,
- .output_set_border = gl_renderer_output_set_border,
- .create_fence_fd = gl_renderer_create_fence_fd,
-};
diff --git a/libweston/renderer-gl/gl-renderer.h b/libweston/renderer-gl/gl-renderer.h
deleted file mode 100644
index 2bca2d00..00000000
--- a/libweston/renderer-gl/gl-renderer.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright © 2012 John Kåre Alsaker
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdint.h>
-
-#include <libweston/libweston.h>
-#include "backend.h"
-#include "libweston-internal.h"
-
-#ifdef ENABLE_EGL
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-#else
-
-typedef int EGLint;
-typedef int EGLenum;
-typedef void *EGLDisplay;
-typedef void *EGLSurface;
-typedef void *EGLConfig;
-typedef intptr_t EGLNativeDisplayType;
-typedef intptr_t EGLNativeWindowType;
-#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0)
-#define EGL_PBUFFER_BIT 0x0001
-#define EGL_WINDOW_BIT 0x0004
-
-#endif /* ENABLE_EGL */
-
-enum gl_renderer_border_side {
- GL_RENDERER_BORDER_TOP = 0,
- GL_RENDERER_BORDER_LEFT = 1,
- GL_RENDERER_BORDER_RIGHT = 2,
- GL_RENDERER_BORDER_BOTTOM = 3,
-};
-
-struct gl_renderer_interface {
- /**
- * Initialize GL-renderer with the given EGL platform and native display
- *
- * \param ec The weston_compositor where to initialize.
- * \param platform The EGL platform identifier.
- * \param native_display The native display corresponding to the given
- * EGL platform.
- * \param egl_surface_type EGL_SURFACE_TYPE bits for the base EGLConfig.
- * \param drm_formats Array of DRM pixel formats that are acceptable
- * for the base EGLConfig.
- * \param drm_formats_count The drm_formats array length.
- * \return 0 on success, -1 on failure.
- *
- * This function creates an EGLDisplay and initializes it. It also
- * creates the GL ES context and sets it up. It attempts GL ES 3.0
- * and falls back to GL ES 2.0 if 3.0 is not supported.
- *
- * If \c platform is zero or EGL_EXT_platform_base is not supported,
- * choosing the platform is left for the EGL implementation. Otherwise
- * the given platform is used explicitly if the EGL implementation
- * advertises it. Without the advertisement this function fails.
- *
- * If neither EGL_KHR_no_config_context or EGL_MESA_configless_context
- * are supported, the arguments egl_surface_type, drm_formats, and
- * drm_formats_count are used to find a so called base EGLConfig. The
- * GL context is created with the base EGLConfig, and outputs will be
- * required to use the same config as well. If one or both of the
- * extensions are supported, these arguments are unused, and each
- * output can use a different EGLConfig (pixel format).
- *
- * The first format in drm_formats that matches any EGLConfig
- * determines which EGLConfig is chosen. On EGL GBM platform, the
- * pixel format must match exactly. On other platforms, it is enough
- * that each R, G, B, A channel has the same number of bits as in the
- * DRM format.
- */
- int (*display_create)(struct weston_compositor *ec,
- EGLenum platform,
- void *native_display,
- EGLint egl_surface_type,
- const uint32_t *drm_formats,
- unsigned drm_formats_count);
-
- /**
- * Attach GL-renderer to the output with a native window
- *
- * \param output The output to create a rendering surface for.
- * \param window_for_legacy Native window handle for
- * eglCreateWindowSurface().
- * \param window_for_platform Native window handle for
- * eglCreatePlatformWindowSurface().
- * \param drm_formats Array of DRM pixel formats that are acceptable.
- * \param drm_formats_count The drm_formats array length.
- * \return 0 on success, -1 on failure.
- *
- * This function creates the renderer data structures needed to repaint
- * the output. The repaint results will be directed to the given native
- * window.
- *
- * If EGL_EXT_platform_base is supported then \c window_for_platform is
- * used, otherwise \c window_for_legacy is used. This is because the
- * handle on X11 platform is different between the two.
- *
- * The first format in drm_formats that matches any EGLConfig
- * determines which EGLConfig is chosen. See \c display_create about
- * how the matching works and the possible limitations.
- *
- * This function should be used only if \c display_create was called
- * with \c EGL_WINDOW_BIT in \c egl_surface_type.
- */
- int (*output_window_create)(struct weston_output *output,
- EGLNativeWindowType window_for_legacy,
- void *window_for_platform,
- const uint32_t *drm_formats,
- unsigned drm_formats_count);
-
- /**
- * Attach GL-renderer to the output with internal pixel storage
- *
- * \param output The output to create a rendering surface for.
- * \param width Width of the rendering surface in pixels.
- * \param height Height of the rendering surface in pixels.
- * \param drm_formats Array of DRM pixel formats that are acceptable.
- * \param drm_formats_count The drm_formats array length.
- * \return 0 on success, -1 on failure.
- *
- * This function creates the renderer data structures needed to repaint
- * the output. The repaint results will be kept internal and can only
- * be accessed through e.g. screen capture.
- *
- * The first format in drm_formats that matches any EGLConfig
- * determines which EGLConfig is chosen. See \c display_create about
- * how the matching works and the possible limitations.
- *
- * This function should be used only if \c display_create was called
- * with \c EGL_PBUFFER_BIT in \c egl_surface_type.
- */
- int (*output_pbuffer_create)(struct weston_output *output,
- int width,
- int height,
- const uint32_t *drm_formats,
- unsigned drm_formats_count);
-
- void (*output_destroy)(struct weston_output *output);
-
- /* Sets the output border.
- *
- * The side specifies the side for which we are setting the border.
- * The width and height are the width and height of the border.
- * The tex_width patemeter specifies the width of the actual
- * texture; this may be larger than width if the data is not
- * tightly packed.
- *
- * The top and bottom textures will extend over the sides to the
- * full width of the bordered window. The right and left edges,
- * however, will extend only to the top and bottom of the
- * compositor surface. This is demonstrated by the picture below:
- *
- * +-----------------------+
- * | TOP |
- * +-+-------------------+-+
- * | | | |
- * |L| |R|
- * |E| |I|
- * |F| |G|
- * |T| |H|
- * | | |T|
- * | | | |
- * +-+-------------------+-+
- * | BOTTOM |
- * +-----------------------+
- */
- void (*output_set_border)(struct weston_output *output,
- enum gl_renderer_border_side side,
- int32_t width, int32_t height,
- int32_t tex_width, unsigned char *data);
-
- /* Create fence sync FD to wait for GPU rendering.
- *
- * Return FD on success, -1 on failure or unsupported
- * EGL_ANDROID_native_fence_sync extension.
- */
- int (*create_fence_fd)(struct weston_output *output);
-};
diff --git a/libweston/renderer-gl/meson.build b/libweston/renderer-gl/meson.build
deleted file mode 100644
index 2d0d3938..00000000
--- a/libweston/renderer-gl/meson.build
+++ /dev/null
@@ -1,51 +0,0 @@
-if not get_option('renderer-gl')
- subdir_done()
-endif
-
-config_h.set('ENABLE_EGL', '1')
-
-srcs_renderer_gl = [
- 'egl-glue.c',
- 'gl-renderer.c',
- linux_dmabuf_unstable_v1_protocol_c,
- linux_dmabuf_unstable_v1_server_protocol_h,
-]
-
-deps_renderer_gl = [
- dep_libm,
- dep_pixman,
- dep_libweston_private,
- dep_libdrm_headers,
- dep_vertex_clipping
-]
-
-foreach name : [ 'egl', 'glesv2' ]
- d = dependency(name, required: false)
- if not d.found()
- error('gl-renderer requires @0@ which was not found. Or, you can use \'-Drenderer-gl=false\'.'.format(name))
- endif
- deps_renderer_gl += d
-endforeach
-
-if get_option('backend-tdm')
- foreach name : [ 'libtbm', 'wayland-tbm-server' ]
- d = dependency(name, required: false)
- if not d.found()
- error('backend-tdm of gl-renderer requires @0@ which was not found. Or, you can use \'-Dbackend-tdm=false\'.'.format(name))
- endif
- deps_renderer_gl += d
- endforeach
-
- config_h.set('HAVE_TBM', '1')
-endif
-
-plugin_gl = shared_library(
- 'gl-renderer',
- srcs_renderer_gl,
- include_directories: common_inc,
- dependencies: deps_renderer_gl,
- name_prefix: '',
- install: true,
- install_dir: dir_module_libweston
-)
-env_modmap += 'gl-renderer.so=@0@;'.format(plugin_gl.full_path())
diff --git a/libweston/screenshooter.c b/libweston/screenshooter.c
deleted file mode 100644
index 4ea519bd..00000000
--- a/libweston/screenshooter.c
+++ /dev/null
@@ -1,494 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <linux/input.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/uio.h>
-
-#include <libweston/libweston.h>
-#include "shared/helpers.h"
-#include "shared/timespec-util.h"
-#include "backend.h"
-#include "libweston-internal.h"
-
-#include "wcap/wcap-decode.h"
-
-struct screenshooter_frame_listener {
- struct wl_listener listener;
- struct weston_buffer *buffer;
- struct weston_output *output;
- weston_screenshooter_done_func_t done;
- void *data;
-};
-
-static void
-copy_bgra_yflip(uint8_t *dst, uint8_t *src, int height, int stride)
-{
- uint8_t *end;
-
- end = dst + height * stride;
- while (dst < end) {
- memcpy(dst, src, stride);
- dst += stride;
- src -= 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;
- uint32_t *src = vsrc;
- uint32_t *end = dst + bytes / 4;
-
- while (dst < end) {
- uint32_t v = *src++;
- /* A R G B */
- uint32_t tmp = v & 0xff00ff00;
- tmp |= (v >> 16) & 0x000000ff;
- tmp |= (v << 16) & 0x00ff0000;
- *dst++ = tmp;
- }
-}
-
-static void
-copy_rgba_yflip(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
-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 = l->output;
- struct weston_compositor *compositor = output->compositor;
- int32_t stride;
- uint8_t *pixels, *d, *s;
-
- weston_output_disable_planes_decr(output);
- wl_list_remove(&listener->link);
- stride = l->buffer->width * (PIXMAN_FORMAT_BPP(compositor->read_format) / 8);
- pixels = malloc(stride * l->buffer->height);
-
- if (pixels == NULL) {
- l->done(l->data, WESTON_SCREENSHOOTER_NO_MEMORY);
- free(l);
- return;
- }
-
- compositor->renderer->read_pixels(output,
- compositor->read_format, pixels,
- 0, 0, output->current_mode->width,
- output->current_mode->height);
-
- stride = wl_shm_buffer_get_stride(l->buffer->shm_buffer);
-
- d = wl_shm_buffer_get_data(l->buffer->shm_buffer);
- s = pixels + stride * (l->buffer->height - 1);
-
- wl_shm_buffer_begin_access(l->buffer->shm_buffer);
-
- switch (compositor->read_format) {
- case PIXMAN_a8r8g8b8:
- case PIXMAN_x8r8g8b8:
- if (compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP)
- copy_bgra_yflip(d, s, output->current_mode->height, stride);
- else
- copy_bgra(d, pixels, output->current_mode->height, stride);
- break;
- case PIXMAN_x8b8g8r8:
- case PIXMAN_a8b8g8r8:
- if (compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP)
- copy_rgba_yflip(d, s, output->current_mode->height, stride);
- else
- copy_rgba(d, pixels, output->current_mode->height, stride);
- break;
- default:
- break;
- }
-
- wl_shm_buffer_end_access(l->buffer->shm_buffer);
-
- l->done(l->data, WESTON_SCREENSHOOTER_SUCCESS);
- free(pixels);
- free(l);
-}
-
-WL_EXPORT int
-weston_screenshooter_shoot(struct weston_output *output,
- struct weston_buffer *buffer,
- weston_screenshooter_done_func_t done, void *data)
-{
- struct screenshooter_frame_listener *l;
-
- if (!wl_shm_buffer_get(buffer->resource)) {
- done(data, WESTON_SCREENSHOOTER_BAD_BUFFER);
- return -1;
- }
-
- buffer->shm_buffer = wl_shm_buffer_get(buffer->resource);
- buffer->width = wl_shm_buffer_get_width(buffer->shm_buffer);
- buffer->height = wl_shm_buffer_get_height(buffer->shm_buffer);
-
- if (buffer->width < output->current_mode->width ||
- buffer->height < output->current_mode->height) {
- done(data, WESTON_SCREENSHOOTER_BAD_BUFFER);
- return -1;
- }
-
- l = malloc(sizeof *l);
- if (l == NULL) {
- done(data, WESTON_SCREENSHOOTER_NO_MEMORY);
- return -1;
- }
-
- l->buffer = buffer;
- l->output = output;
- l->done = done;
- l->data = data;
- l->listener.notify = screenshooter_frame_notify;
- wl_signal_add(&output->frame_signal, &l->listener);
- weston_output_disable_planes_incr(output);
- weston_output_damage(output);
-
- return 0;
-}
-
-struct weston_recorder {
- struct weston_output *output;
- uint32_t *frame, *rect;
- uint32_t *tmpbuf;
- uint32_t total;
- int fd;
- struct wl_listener frame_listener;
- int count, destroying;
-};
-
-static uint32_t *
-output_run(uint32_t *p, uint32_t delta, int run)
-{
- int i;
-
- while (run > 0) {
- if (run <= 0xe0) {
- *p++ = delta | ((run - 1) << 24);
- break;
- }
-
- i = 24 - __builtin_clz(run);
- *p++ = delta | ((i + 0xe0) << 24);
- run -= 1 << (7 + i);
- }
-
- return p;
-}
-
-static uint32_t
-component_delta(uint32_t next, uint32_t prev)
-{
- unsigned char dr, dg, db;
-
- dr = (next >> 16) - (prev >> 16);
- dg = (next >> 8) - (prev >> 8);
- db = (next >> 0) - (prev >> 0);
-
- return (dr << 16) | (dg << 8) | (db << 0);
-}
-
-static void
-weston_recorder_destroy(struct weston_recorder *recorder);
-
-static void
-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 = recorder->output;
- struct weston_compositor *compositor = output->compositor;
- uint32_t msecs = timespec_to_msec(&output->frame_time);
- pixman_box32_t *r;
- pixman_region32_t damage, transformed_damage;
- int i, j, k, n, width, height, run, stride;
- uint32_t delta, prev, *d, *s, *p, next;
- struct {
- uint32_t msecs;
- 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_init(&transformed_damage);
- pixman_region32_intersect(&damage, &output->region, data);
- pixman_region32_translate(&damage, -output->x, -output->y);
- weston_transformed_region(output->width, output->height,
- output->transform, output->current_scale,
- &damage, &transformed_damage);
- pixman_region32_fini(&damage);
-
- r = pixman_region32_rectangles(&transformed_damage, &n);
- if (n == 0) {
- pixman_region32_fini(&transformed_damage);
- return;
- }
-
- header.msecs = msecs;
- header.nrects = n;
- v[0].iov_base = &header;
- v[0].iov_len = sizeof header;
- v[1].iov_base = r;
- v[1].iov_len = n * sizeof *r;
- recorder->total += writev(recorder->fd, v, 2);
- stride = output->current_mode->width;
-
- for (i = 0; i < n; i++) {
- width = r[i].x2 - r[i].x1;
- height = r[i].y2 - r[i].y1;
-
- if (do_yflip)
- y_orig = output->current_mode->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);
-
- p = outbuf;
- run = prev = 0; /* quiet gcc */
- for (j = 0; j < height; j++) {
- if (do_yflip)
- s = recorder->rect + width * j;
- else
- s = recorder->rect + width * (height - j - 1);
- y_orig = r[i].y2 - j - 1;
- d = recorder->frame + stride * y_orig + r[i].x1;
-
- for (k = 0; k < width; k++) {
- next = *s++;
- delta = component_delta(next, *d);
- *d++ = next;
- if (run == 0 || delta == prev) {
- run++;
- } else {
- p = output_run(p, prev, run);
- run = 1;
- }
- prev = delta;
- }
- }
-
- p = output_run(p, prev, run);
-
- recorder->total += write(recorder->fd,
- 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 - outbuf) * 4,
- (float) (p - outbuf) / (width * height),
- recorder->total / 1024 / 1024);
-#endif
- }
-
- pixman_region32_fini(&transformed_damage);
- recorder->count++;
-
- if (recorder->destroying)
- weston_recorder_destroy(recorder);
-}
-
-static void
-weston_recorder_free(struct weston_recorder *recorder)
-{
- if (recorder == NULL)
- return;
-
- free(recorder->tmpbuf);
- free(recorder->rect);
- free(recorder->frame);
- free(recorder);
-}
-
-static struct weston_recorder *
-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 = zalloc(sizeof *recorder);
- if (recorder == NULL) {
- weston_log("%s: out of memory\n", __func__);
- return NULL;
- }
-
- stride = output->current_mode->width;
- size = stride * 4 * output->current_mode->height;
- recorder->frame = zalloc(size);
- recorder->rect = malloc(size);
- recorder->output = output;
-
- if ((recorder->frame == NULL) || (recorder->rect == NULL)) {
- weston_log("%s: out of memory\n", __func__);
- goto err_recorder;
- }
-
- if (!do_yflip) {
- recorder->tmpbuf = malloc(size);
- if (recorder->tmpbuf == NULL) {
- weston_log("%s: out of memory\n", __func__);
- goto err_recorder;
- }
- }
-
- header.magic = WCAP_HEADER_MAGIC;
-
- switch (compositor->read_format) {
- case PIXMAN_x8r8g8b8:
- case PIXMAN_a8r8g8b8:
- header.format = WCAP_FORMAT_XRGB8888;
- break;
- case PIXMAN_a8b8g8r8:
- header.format = WCAP_FORMAT_XBGR8888;
- break;
- default:
- weston_log("unknown recorder format\n");
- goto err_recorder;
- }
-
- recorder->fd = open(filename,
- O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
-
- if (recorder->fd < 0) {
- weston_log("problem opening output file %s: %s\n", filename,
- strerror(errno));
- goto err_recorder;
- }
-
- header.width = output->current_mode->width;
- header.height = output->current_mode->height;
- recorder->total += write(recorder->fd, &header, sizeof header);
-
- recorder->frame_listener.notify = weston_recorder_frame_notify;
- wl_signal_add(&output->frame_signal, &recorder->frame_listener);
- weston_output_disable_planes_incr(output);
- weston_output_damage(output);
-
- return recorder;
-
-err_recorder:
- weston_recorder_free(recorder);
- return NULL;
-}
-
-static void
-weston_recorder_destroy(struct weston_recorder *recorder)
-{
- wl_list_remove(&recorder->frame_listener.link);
- close(recorder->fd);
- weston_output_disable_planes_decr(recorder->output);
- weston_recorder_free(recorder);
-}
-
-WL_EXPORT struct weston_recorder *
-weston_recorder_start(struct weston_output *output, const char *filename)
-{
- struct wl_listener *listener;
-
- listener = wl_signal_get(&output->frame_signal,
- weston_recorder_frame_notify);
- if (listener) {
- weston_log("a recorder on output %s is already running\n",
- output->name);
- return NULL;
- }
-
- weston_log("starting recorder for output %s, file %s\n",
- output->name, filename);
- return weston_recorder_create(output, filename);
-}
-
-WL_EXPORT void
-weston_recorder_stop(struct weston_recorder *recorder)
-{
- weston_log("stopping recorder, total file size %dM, %d frames\n",
- recorder->total / (1024 * 1024), recorder->count);
-
- recorder->destroying = 1;
- weston_output_schedule_repaint(recorder->output);
-}
diff --git a/libweston/spring-tool.c b/libweston/spring-tool.c
deleted file mode 100644
index b032d737..00000000
--- a/libweston/spring-tool.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright © 2011 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdint.h>
-#include <inttypes.h>
-
-#include "config.h"
-
-#include <libweston/libweston.h>
-#include "shared/timespec-util.h"
-
-WL_EXPORT void
-weston_view_geometry_dirty(struct weston_view *view)
-{
-}
-
-WL_EXPORT int
-weston_log(const char *fmt, ...)
-{
- return 0;
-}
-
-WL_EXPORT void
-weston_view_schedule_repaint(struct weston_view *view)
-{
-}
-
-WL_EXPORT void
-weston_compositor_schedule_repaint(struct weston_compositor *compositor)
-{
-}
-
-int
-main(int argc, char *argv[])
-{
- const double k = 300.0;
- const double current = 0.5;
- const double target = 1.0;
- const double friction = 1400;
-
- struct weston_spring spring;
- struct timespec time = { 0 };
-
- weston_spring_init(&spring, k, current, target);
- spring.friction = friction;
- spring.previous = 0.48;
- spring.timestamp = (struct timespec) { 0 };
-
- while (!weston_spring_done(&spring)) {
- printf("\t%" PRId64 "\t%f\n",
- timespec_to_msec(&time), spring.current);
- weston_spring_update(&spring, &time);
- timespec_add_msec(&time, &time, 16);
- }
-
- return 0;
-}
diff --git a/libweston/timeline.c b/libweston/timeline.c
deleted file mode 100644
index 9da8b5e3..00000000
--- a/libweston/timeline.c
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
- * Copyright © 2014 Pekka Paalanen <pq@iki.fi>
- * Copyright © 2014, 2019 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <time.h>
-#include <assert.h>
-
-#include <libweston/libweston.h>
-#include <libweston/weston-log.h>
-#include "timeline.h"
-#include "weston-log-internal.h"
-
-/**
- * Timeline itself is not a subscriber but a scope (a producer of data), and it
- * re-routes the data it produces to all the subscriptions (and implicitly
- * to the subscribers) using a subscription iteration to go through all of them.
- *
- * Public API:
- * * weston_timeline_refresh_subscription_objects() - allows outside parts of
- * libweston notify/signal timeline code about the fact that underlying object
- * has suffered some modifications and needs to re-emit the object ID.
- * * weston_log_timeline_point() - which will disseminate data to all
- * subscriptions
- *
- * Do note that only weston_timeline_refresh_subscription_objects()
- * is exported in libweston.
- *
- * Destruction of the objects assigned to each underlying objects happens in
- * two places: one in the logging framework callback of the log scope
- * ('destroy_subscription'), and secondly, when the object itself gets
- * destroyed.
- *
- * timeline_emit_context - For each subscription this object will be created to
- * store a buffer when the object itself will be written and a subscription,
- * which will be used to force the object ID if there is a need to do so (the
- * underlying object has been refreshed, or better said has suffered some
- * modification). Data written to a subscription will be flushed before the
- * data written to the FILE *.
- *
- * @param cur a FILE *
- * @param subscription a pointer to an already created subscription
- *
- * @ingroup internal-log
- * @sa weston_timeline_point
- */
-struct timeline_emit_context {
- FILE *cur;
- struct weston_log_subscription *subscription;
-};
-
-/** Create a timeline subscription and hang it off the subscription
- *
- * Called when the subscription is created.
- *
- * @ingroup internal-log
- */
-void
-weston_timeline_create_subscription(struct weston_log_subscription *sub,
- void *user_data)
-{
- struct weston_timeline_subscription *tl_sub = zalloc(sizeof(*tl_sub));
- if (!tl_sub)
- return;
-
- wl_list_init(&tl_sub->objects);
-
- /* attach this timeline_subscription to it */
- weston_log_subscription_set_data(sub, tl_sub);
-}
-
-static void
-weston_timeline_destroy_subscription_object(struct weston_timeline_subscription_object *sub_obj)
-{
- /* remove the notify listener */
- wl_list_remove(&sub_obj->destroy_listener.link);
- sub_obj->destroy_listener.notify = NULL;
-
- wl_list_remove(&sub_obj->subscription_link);
- free(sub_obj);
-}
-
-/** Destroy the timeline subscription and all timeline subscription objects
- * associated with it.
- *
- * Called when (before) the subscription is destroyed.
- *
- * @ingroup internal-log
- */
-void
-weston_timeline_destroy_subscription(struct weston_log_subscription *sub,
- void *user_data)
-{
- struct weston_timeline_subscription *tl_sub =
- weston_log_subscription_get_data(sub);
- struct weston_timeline_subscription_object *sub_obj, *tmp_sub_obj;
-
- if (!tl_sub)
- return;
-
- wl_list_for_each_safe(sub_obj, tmp_sub_obj,
- &tl_sub->objects, subscription_link)
- weston_timeline_destroy_subscription_object(sub_obj);
-
- free(tl_sub);
-}
-
-static bool
-weston_timeline_check_object_refresh(struct weston_timeline_subscription_object *obj)
-{
- if (obj->force_refresh == true) {
- obj->force_refresh = false;
- return true;
- }
- return false;
-}
-
-static struct weston_timeline_subscription_object *
-weston_timeline_subscription_search(struct weston_timeline_subscription *tl_sub,
- void *object)
-{
- struct weston_timeline_subscription_object *sub_obj;
-
- wl_list_for_each(sub_obj, &tl_sub->objects, subscription_link)
- if (sub_obj->object == object)
- return sub_obj;
-
- return NULL;
-}
-
-static struct weston_timeline_subscription_object *
-weston_timeline_subscription_object_create(void *object,
- struct weston_timeline_subscription *tm_sub)
-{
- struct weston_timeline_subscription_object *sub_obj;
-
- sub_obj = zalloc(sizeof(*sub_obj));
- sub_obj->id = ++tm_sub->next_id;
- sub_obj->object = object;
-
- /* when the object is created so that it has the chance to display the
- * object ID, we set the refresh status; it will only be re-freshed by
- * the backend (or part parts) when the underlying objects has suffered
- * modifications */
- sub_obj->force_refresh = true;
-
- wl_list_insert(&tm_sub->objects, &sub_obj->subscription_link);
-
- return sub_obj;
-}
-
-static void
-weston_timeline_destroy_subscription_object_notify(struct wl_listener *listener, void *data)
-{
- struct weston_timeline_subscription_object *sub_obj;
-
- sub_obj = wl_container_of(listener, sub_obj, destroy_listener);
- weston_timeline_destroy_subscription_object(sub_obj);
-}
-
-static struct weston_timeline_subscription_object *
-weston_timeline_subscription_output_ensure(struct weston_timeline_subscription *tl_sub,
- struct weston_output *output)
-{
- struct weston_timeline_subscription_object *sub_obj;
-
- sub_obj = weston_timeline_subscription_search(tl_sub, output);
- if (!sub_obj) {
- sub_obj = weston_timeline_subscription_object_create(output, tl_sub);
-
- sub_obj->destroy_listener.notify =
- weston_timeline_destroy_subscription_object_notify;
- wl_signal_add(&output->destroy_signal,
- &sub_obj->destroy_listener);
- }
- return sub_obj;
-}
-
-static struct weston_timeline_subscription_object *
-weston_timeline_subscription_surface_ensure(struct weston_timeline_subscription *tl_sub,
- struct weston_surface *surface)
-{
- struct weston_timeline_subscription_object *sub_obj;
-
- sub_obj = weston_timeline_subscription_search(tl_sub, surface);
- if (!sub_obj) {
- sub_obj = weston_timeline_subscription_object_create(surface, tl_sub);
-
- sub_obj->destroy_listener.notify =
- weston_timeline_destroy_subscription_object_notify;
- wl_signal_add(&surface->destroy_signal,
- &sub_obj->destroy_listener);
- }
-
- return sub_obj;
-}
-
-static void
-fprint_quoted_string(struct weston_log_subscription *sub, const char *str)
-{
- if (!str) {
- weston_log_subscription_printf(sub, "null");
- return;
- }
-
- weston_log_subscription_printf(sub, "\"%s\"", str);
-}
-
-static void
-emit_weston_output_print_id(struct weston_log_subscription *sub,
- struct weston_timeline_subscription_object *sub_obj,
- const char *name)
-{
- if (!weston_timeline_check_object_refresh(sub_obj))
- return;
-
- weston_log_subscription_printf(sub, "{ \"id\":%u, "
- "\"type\":\"weston_output\", \"name\":", sub_obj->id);
- fprint_quoted_string(sub, name);
- weston_log_subscription_printf(sub, " }\n");
-}
-
-static int
-emit_weston_output(struct timeline_emit_context *ctx, void *obj)
-{
- struct weston_log_subscription *sub = ctx->subscription;
- struct weston_output *output = obj;
- struct weston_timeline_subscription_object *sub_obj;
- struct weston_timeline_subscription *tl_sub;
-
- tl_sub = weston_log_subscription_get_data(sub);
- sub_obj = weston_timeline_subscription_output_ensure(tl_sub, output);
- emit_weston_output_print_id(sub, sub_obj, output->name);
-
- assert(sub_obj->id != 0);
- fprintf(ctx->cur, "\"wo\":%u", sub_obj->id);
-
- return 1;
-}
-
-
-static void
-check_weston_surface_description(struct weston_log_subscription *sub,
- struct weston_surface *s,
- struct weston_timeline_subscription *tm_sub,
- struct weston_timeline_subscription_object *sub_obj)
-{
- struct weston_surface *mains;
- char d[512];
- char mainstr[32];
-
- if (!weston_timeline_check_object_refresh(sub_obj))
- return;
-
- mains = weston_surface_get_main_surface(s);
- if (mains != s) {
- struct weston_timeline_subscription_object *new_sub_obj;
-
- new_sub_obj = weston_timeline_subscription_surface_ensure(tm_sub, mains);
- check_weston_surface_description(sub, mains, tm_sub, new_sub_obj);
- if (snprintf(mainstr, sizeof(mainstr), ", \"main_surface\":%u",
- new_sub_obj->id) < 0)
- mainstr[0] = '\0';
- } else {
- mainstr[0] = '\0';
- }
-
- if (!s->get_label || s->get_label(s, d, sizeof(d)) < 0)
- d[0] = '\0';
-
- weston_log_subscription_printf(sub, "{ \"id\":%u, "
- "\"type\":\"weston_surface\", \"desc\":",
- sub_obj->id);
- fprint_quoted_string(sub, d[0] ? d : NULL);
- weston_log_subscription_printf(sub, "%s }\n", mainstr);
-}
-
-static int
-emit_weston_surface(struct timeline_emit_context *ctx, void *obj)
-{
- struct weston_log_subscription *sub = ctx->subscription;
- struct weston_surface *surface = obj;
- struct weston_timeline_subscription_object *sub_obj;
- struct weston_timeline_subscription *tl_sub;
-
- tl_sub = weston_log_subscription_get_data(sub);
- sub_obj = weston_timeline_subscription_surface_ensure(tl_sub, surface);
- check_weston_surface_description(sub, surface, tl_sub, sub_obj);
-
- assert(sub_obj->id != 0);
- fprintf(ctx->cur, "\"ws\":%u", sub_obj->id);
-
- return 1;
-}
-
-static int
-emit_vblank_timestamp(struct timeline_emit_context *ctx, void *obj)
-{
- struct timespec *ts = obj;
-
- fprintf(ctx->cur, "\"vblank\":[%" PRId64 ", %ld]",
- (int64_t)ts->tv_sec, ts->tv_nsec);
-
- return 1;
-}
-
-static int
-emit_gpu_timestamp(struct timeline_emit_context *ctx, void *obj)
-{
- struct timespec *ts = obj;
-
- fprintf(ctx->cur, "\"gpu\":[%" PRId64 ", %ld]",
- (int64_t)ts->tv_sec, ts->tv_nsec);
-
- return 1;
-}
-
-static struct weston_timeline_subscription_object *
-weston_timeline_get_subscription_object(struct weston_log_subscription *sub,
- void *object)
-{
- struct weston_timeline_subscription *tl_sub;
-
- tl_sub = weston_log_subscription_get_data(sub);
- if (!tl_sub)
- return NULL;
-
- return weston_timeline_subscription_search(tl_sub, object);
-}
-
-/** Sets (on) the timeline subscription object refresh status.
- *
- * This function 'notifies' timeline to print the object ID. The timeline code
- * will reset it back, so there's no need for users to do anything about it.
- *
- * Can be used from outside libweston.
- *
- * @param wc a weston_compositor instance
- * @param object the underyling object
- *
- * @ingroup log
- */
-WL_EXPORT void
-weston_timeline_refresh_subscription_objects(struct weston_compositor *wc,
- void *object)
-{
- struct weston_log_subscription *sub = NULL;
-
- while ((sub = weston_log_subscription_iterate(wc->timeline, sub))) {
- struct weston_timeline_subscription_object *sub_obj;
-
- sub_obj = weston_timeline_get_subscription_object(sub, object);
- if (sub_obj)
- sub_obj->force_refresh = true;
- }
-}
-
-typedef int (*type_func)(struct timeline_emit_context *ctx, void *obj);
-
-static const type_func type_dispatch[] = {
- [TLT_OUTPUT] = emit_weston_output,
- [TLT_SURFACE] = emit_weston_surface,
- [TLT_VBLANK] = emit_vblank_timestamp,
- [TLT_GPU] = emit_gpu_timestamp,
-};
-
-/** Disseminates the message to all subscriptions of the scope \c
- * timeline_scope
- *
- * The TL_POINT() is a wrapper over this function, but it uses the weston_compositor
- * instance to pass the timeline scope.
- *
- * @param timeline_scope the timeline scope
- * @param name the name of the timeline point. Interpretable by the tool reading
- * the output (wesgr).
- *
- * @ingroup log
- */
-WL_EXPORT void
-weston_timeline_point(struct weston_log_scope *timeline_scope,
- const char *name, ...)
-{
- struct timespec ts;
- enum timeline_type otype;
- void *obj;
- char buf[512];
- struct weston_log_subscription *sub = NULL;
-
- if (!weston_log_scope_is_enabled(timeline_scope))
- return;
-
- clock_gettime(CLOCK_MONOTONIC, &ts);
-
- while ((sub = weston_log_subscription_iterate(timeline_scope, sub))) {
- va_list argp;
- struct timeline_emit_context ctx = {};
-
- memset(buf, 0, sizeof(buf));
- ctx.cur = fmemopen(buf, sizeof(buf), "w");
- ctx.subscription = sub;
-
- if (!ctx.cur) {
- weston_log("Timeline error in fmemopen, closing.\n");
- return;
- }
-
- fprintf(ctx.cur, "{ \"T\":[%" PRId64 ", %ld], \"N\":\"%s\"",
- (int64_t)ts.tv_sec, ts.tv_nsec, name);
-
- va_start(argp, name);
- while (1) {
- otype = va_arg(argp, enum timeline_type);
- if (otype == TLT_END)
- break;
-
- obj = va_arg(argp, void *);
- if (type_dispatch[otype]) {
- fprintf(ctx.cur, ", ");
- type_dispatch[otype](&ctx, obj);
- }
- }
- va_end(argp);
-
- fprintf(ctx.cur, " }\n");
- fflush(ctx.cur);
- if (ferror(ctx.cur)) {
- weston_log("Timeline error in constructing entry, closing.\n");
- } else {
- weston_log_subscription_printf(ctx.subscription, "%s", buf);
- }
-
- fclose(ctx.cur);
-
- }
-}
diff --git a/libweston/timeline.h b/libweston/timeline.h
deleted file mode 100644
index aaed7431..00000000
--- a/libweston/timeline.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright © 2014 Pekka Paalanen <pq@iki.fi>
- * Copyright © 2014, 2019 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef WESTON_TIMELINE_H
-#define WESTON_TIMELINE_H
-
-#include <wayland-util.h>
-#include <stdbool.h>
-
-#include <libweston/weston-log.h>
-#include <wayland-server-core.h>
-
-enum timeline_type {
- TLT_END = 0,
- TLT_OUTPUT,
- TLT_SURFACE,
- TLT_VBLANK,
- TLT_GPU,
-};
-
-/** Timeline subscription created for each subscription
- *
- * Created automatically by weston_log_scope::new_subscription and
- * destroyed by weston_log_scope::destroy_subscription.
- *
- * @ingroup internal-log
- */
-struct weston_timeline_subscription {
- unsigned int next_id;
- struct wl_list objects; /**< weston_timeline_subscription_object::subscription_link */
-};
-
-/**
- * Created when object is first seen for a particular timeline subscription
- * Destroyed when the subscription got destroyed or object was destroyed
- *
- * @ingroup internal-log
- */
-struct weston_timeline_subscription_object {
- void *object; /**< points to the object */
- unsigned int id;
- bool force_refresh;
- struct wl_list subscription_link; /**< weston_timeline_subscription::objects */
- struct wl_listener destroy_listener;
-};
-
-#define TYPEVERIFY(type, arg) ({ \
- typeof(arg) tmp___ = (arg); \
- (void)((type)0 == tmp___); \
- tmp___; })
-
-/**
- * Should be used as the last argument when using TL_POINT macro
- *
- * @ingroup log
- */
-#define TLP_END TLT_END, NULL
-
-#define TLP_OUTPUT(o) TLT_OUTPUT, TYPEVERIFY(struct weston_output *, (o))
-#define TLP_SURFACE(s) TLT_SURFACE, TYPEVERIFY(struct weston_surface *, (s))
-#define TLP_VBLANK(t) TLT_VBLANK, TYPEVERIFY(const struct timespec *, (t))
-#define TLP_GPU(t) TLT_GPU, TYPEVERIFY(const struct timespec *, (t))
-
-/** This macro is used to add timeline points.
- *
- * Use TLP_END when done for the vargs.
- *
- * @param ec weston_compositor instance
- *
- * @ingroup log
- */
-#define TL_POINT(ec, ...) do { \
- weston_timeline_point(ec->timeline, __VA_ARGS__); \
-} while (0)
-
-void
-weston_timeline_point(struct weston_log_scope *timeline_scope,
- const char *name, ...);
-
-#endif /* WESTON_TIMELINE_H */
diff --git a/libweston/touch-calibration.c b/libweston/touch-calibration.c
deleted file mode 100644
index 187c8987..00000000
--- a/libweston/touch-calibration.c
+++ /dev/null
@@ -1,717 +0,0 @@
-/*
- * Copyright 2017-2018 Collabora, Ltd.
- * Copyright 2017-2018 General Electric Company
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <string.h>
-#include <wayland-server.h>
-
-#include "shared/helpers.h"
-#include "shared/string-helpers.h"
-#include <libweston/zalloc.h>
-#include "shared/timespec-util.h"
-#include <libweston/libweston.h>
-#include "libweston-internal.h"
-
-#include "weston-touch-calibration-server-protocol.h"
-
-struct weston_touch_calibrator {
- struct wl_resource *resource;
-
- struct weston_compositor *compositor;
-
- struct weston_surface *surface;
- struct wl_listener surface_destroy_listener;
- struct wl_listener surface_commit_listener;
-
- struct weston_touch_device *device;
- struct wl_listener device_destroy_listener;
-
- struct weston_output *output;
- struct wl_listener output_destroy_listener;
-
- struct weston_view *view;
-
- /** The calibration procedure has been cancelled. */
- bool calibration_cancelled;
-
- /** The current touch sequence has been cancelled. */
- bool touch_cancelled;
-};
-
-static struct weston_touch_calibrator *
-calibrator_from_device(struct weston_touch_device *device)
-{
- return device->aggregate->seat->compositor->touch_calibrator;
-}
-
-static uint32_t
-wire_uint_from_double(double c)
-{
- assert(c >= 0.0);
- assert(c <= 1.0);
-
- return round(c * 0xffffffff);
-}
-
-static bool
-normalized_is_valid(const struct weston_point2d_device_normalized *p)
-{
- return p->x >= 0.0 && p->x <= 1.0 &&
- p->y >= 0.0 && p->y <= 1.0;
-}
-
-WL_EXPORT void
-notify_touch_calibrator(struct weston_touch_device *device,
- const struct timespec *time, int32_t slot,
- const struct weston_point2d_device_normalized *norm,
- int touch_type)
-{
- struct weston_touch_calibrator *calibrator;
- struct wl_resource *res;
- uint32_t msecs;
- uint32_t x = 0;
- uint32_t y = 0;
-
- calibrator = calibrator_from_device(device);
- if (!calibrator)
- return;
-
- res = calibrator->resource;
-
- /* Ignore any touch events coming from another device */
- if (device != calibrator->device) {
- if (touch_type == WL_TOUCH_DOWN)
- weston_touch_calibrator_send_invalid_touch(res);
- return;
- }
-
- /* Ignore all events if we have sent 'cancel' event until all
- * touches (on the seat) are up.
- */
- if (calibrator->touch_cancelled) {
- if (calibrator->device->aggregate->num_tp == 0) {
- assert(touch_type == WL_TOUCH_UP);
- calibrator->touch_cancelled = false;
- }
- return;
- }
-
- msecs = timespec_to_msec(time);
- if (touch_type != WL_TOUCH_UP) {
- if (normalized_is_valid(norm)) {
- x = wire_uint_from_double(norm->x);
- y = wire_uint_from_double(norm->y);
- } else {
- /* Coordinates are out of bounds */
- if (touch_type == WL_TOUCH_MOTION) {
- weston_touch_calibrator_send_cancel(res);
- calibrator->touch_cancelled = true;
- }
- weston_touch_calibrator_send_invalid_touch(res);
- return;
- }
- }
-
- switch (touch_type) {
- case WL_TOUCH_UP:
- weston_touch_calibrator_send_up(res, msecs, slot);
- break;
- case WL_TOUCH_DOWN:
- weston_touch_calibrator_send_down(res, msecs, slot, x, y);
- break;
- case WL_TOUCH_MOTION:
- weston_touch_calibrator_send_motion(res, msecs, slot, x, y);
- break;
- default:
- return;
- }
-}
-
-WL_EXPORT void
-notify_touch_calibrator_frame(struct weston_touch_device *device)
-{
- struct weston_touch_calibrator *calibrator;
-
- calibrator = calibrator_from_device(device);
- if (!calibrator)
- return;
-
- weston_touch_calibrator_send_frame(calibrator->resource);
-}
-
-WL_EXPORT void
-notify_touch_calibrator_cancel(struct weston_touch_device *device)
-{
- struct weston_touch_calibrator *calibrator;
-
- calibrator = calibrator_from_device(device);
- if (!calibrator)
- return;
-
- weston_touch_calibrator_send_cancel(calibrator->resource);
-}
-
-static void
-map_calibrator(struct weston_touch_calibrator *calibrator)
-{
- struct weston_compositor *c = calibrator->compositor;
- struct weston_touch_device *device = calibrator->device;
- static const struct weston_touch_device_matrix identity = {
- .m = { 1, 0, 0, 0, 1, 0}
- };
-
- assert(!calibrator->view);
- assert(calibrator->output);
- assert(calibrator->surface);
- assert(calibrator->surface->resource);
-
- calibrator->view = weston_view_create(calibrator->surface);
- if (!calibrator->view) {
- wl_resource_post_no_memory(calibrator->surface->resource);
- return;
- }
-
- weston_layer_entry_insert(&c->calibrator_layer.view_list,
- &calibrator->view->layer_link);
-
- weston_view_set_position(calibrator->view,
- calibrator->output->x,
- calibrator->output->y);
- calibrator->view->output = calibrator->surface->output;
- calibrator->view->is_mapped = true;
-
- calibrator->surface->output = calibrator->output;
- calibrator->surface->is_mapped = true;
-
- weston_output_schedule_repaint(calibrator->output);
-
- device->ops->get_calibration(device, &device->saved_calibration);
- device->ops->set_calibration(device, &identity);
-}
-
-static void
-unmap_calibrator(struct weston_touch_calibrator *calibrator)
-{
- struct weston_touch_device *device = calibrator->device;
-
- wl_list_remove(&calibrator->surface_commit_listener.link);
- wl_list_init(&calibrator->surface_commit_listener.link);
-
- if (!calibrator->view)
- return;
-
- weston_view_destroy(calibrator->view);
- calibrator->view = NULL;
- weston_surface_unmap(calibrator->surface);
-
- /* Reload saved calibration */
- if (device)
- device->ops->set_calibration(device,
- &device->saved_calibration);
-}
-
-void
-touch_calibrator_mode_changed(struct weston_compositor *compositor)
-{
- struct weston_touch_calibrator *calibrator;
-
- calibrator = compositor->touch_calibrator;
- if (!calibrator)
- return;
-
- if (calibrator->calibration_cancelled)
- return;
-
- if (compositor->touch_mode == WESTON_TOUCH_MODE_CALIB)
- map_calibrator(calibrator);
-}
-
-static void
-touch_calibrator_surface_committed(struct wl_listener *listener, void *data)
-{
- struct weston_touch_calibrator *calibrator =
- container_of(listener, struct weston_touch_calibrator,
- surface_commit_listener);
- struct weston_surface *surface = calibrator->surface;
-
- wl_list_remove(&calibrator->surface_commit_listener.link);
- wl_list_init(&calibrator->surface_commit_listener.link);
-
- if (surface->width != calibrator->output->width ||
- surface->height != calibrator->output->height) {
- wl_resource_post_error(calibrator->resource,
- WESTON_TOUCH_CALIBRATOR_ERROR_BAD_SIZE,
- "calibrator surface size does not match");
- return;
- }
-
- weston_compositor_set_touch_mode_calib(calibrator->compositor);
- /* results in call to touch_calibrator_mode_changed() */
-}
-
-static void
-touch_calibrator_convert(struct wl_client *client,
- struct wl_resource *resource,
- int32_t x,
- int32_t y,
- uint32_t coordinate_id)
-{
- struct weston_touch_calibrator *calibrator;
- struct wl_resource *coordinate_resource;
- struct weston_output *output;
- struct weston_surface *surface;
- uint32_t version;
- struct weston_vector p = { { 0.0, 0.0, 0.0, 1.0 } };
- struct weston_point2d_device_normalized norm;
-
- version = wl_resource_get_version(resource);
- calibrator = wl_resource_get_user_data(resource);
- surface = calibrator->surface;
- output = calibrator->output;
-
- coordinate_resource =
- wl_resource_create(client, &weston_touch_coordinate_interface,
- version, coordinate_id);
- if (!coordinate_resource) {
- wl_client_post_no_memory(client);
- return;
- }
-
- if (calibrator->calibration_cancelled) {
- weston_touch_coordinate_send_result(coordinate_resource, 0, 0);
- wl_resource_destroy(coordinate_resource);
- return;
- }
-
- if (!surface || !surface->is_mapped) {
- wl_resource_post_error(resource,
- WESTON_TOUCH_CALIBRATOR_ERROR_NOT_MAPPED,
- "calibrator surface is not mapped");
- return;
- }
- assert(calibrator->view);
- assert(output);
-
- if (x < 0 || y < 0 || x >= surface->width || y >= surface->height) {
- wl_resource_post_error(resource,
- WESTON_TOUCH_CALIBRATOR_ERROR_BAD_COORDINATES,
- "convert(%d, %d) input is out of bounds",
- x, y);
- return;
- }
-
- /* Convert from surface-local coordinates into global, from global
- * into output-raw, do perspective division and normalize.
- */
- weston_view_to_global_float(calibrator->view, x, y, &p.f[0], &p.f[1]);
- weston_matrix_transform(&output->matrix, &p);
- norm.x = p.f[0] / (p.f[3] * output->current_mode->width);
- norm.y = p.f[1] / (p.f[3] * output->current_mode->height);
-
- if (!normalized_is_valid(&norm)) {
- wl_resource_post_error(resource,
- WESTON_TOUCH_CALIBRATOR_ERROR_BAD_COORDINATES,
- "convert(%d, %d) output is out of bounds",
- x, y);
- return;
- }
-
- weston_touch_coordinate_send_result(coordinate_resource,
- wire_uint_from_double(norm.x),
- wire_uint_from_double(norm.y));
- wl_resource_destroy(coordinate_resource);
-}
-
-static void
-destroy_touch_calibrator(struct wl_resource *resource)
-{
- struct weston_touch_calibrator *calibrator;
-
- calibrator = wl_resource_get_user_data(resource);
-
- calibrator->compositor->touch_calibrator = NULL;
-
- weston_compositor_set_touch_mode_normal(calibrator->compositor);
-
- if (calibrator->surface) {
- unmap_calibrator(calibrator);
- weston_surface_set_role(calibrator->surface, NULL,
- calibrator->surface->resource, 0);
- wl_list_remove(&calibrator->surface_destroy_listener.link);
- wl_list_remove(&calibrator->surface_commit_listener.link);
- }
-
- if (calibrator->device)
- wl_list_remove(&calibrator->device_destroy_listener.link);
-
- if (calibrator->output)
- wl_list_remove(&calibrator->output_destroy_listener.link);
-
- free(calibrator);
-}
-
-static void
-touch_calibrator_destroy(struct wl_client *client,
- struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static const struct weston_touch_calibrator_interface
-touch_calibrator_implementation = {
- touch_calibrator_destroy,
- touch_calibrator_convert
-};
-
-static void
-touch_calibrator_cancel_calibration(struct weston_touch_calibrator *calibrator)
-{
- weston_touch_calibrator_send_cancel_calibration(calibrator->resource);
- calibrator->calibration_cancelled = true;
-
- if (calibrator->surface)
- unmap_calibrator(calibrator);
-}
-
-static void
-touch_calibrator_output_destroyed(struct wl_listener *listener, void *data)
-{
- struct weston_touch_calibrator *calibrator =
- container_of(listener, struct weston_touch_calibrator,
- output_destroy_listener);
-
- assert(calibrator->output == data);
- calibrator->output = NULL;
-
- touch_calibrator_cancel_calibration(calibrator);
-}
-
-static void
-touch_calibrator_device_destroyed(struct wl_listener *listener, void *data)
-{
- struct weston_touch_calibrator *calibrator =
- container_of(listener, struct weston_touch_calibrator,
- device_destroy_listener);
-
- assert(calibrator->device == data);
- calibrator->device = NULL;
-
- touch_calibrator_cancel_calibration(calibrator);
-}
-
-static void
-touch_calibrator_surface_destroyed(struct wl_listener *listener, void *data)
-{
- struct weston_touch_calibrator *calibrator =
- container_of(listener, struct weston_touch_calibrator,
- surface_destroy_listener);
-
- assert(calibrator->surface->resource == data);
-
- unmap_calibrator(calibrator);
- calibrator->surface = NULL;
-}
-
-static void
-touch_calibration_destroy(struct wl_client *client,
- struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static struct weston_touch_device *
-weston_compositor_find_touch_device_by_syspath(
- struct weston_compositor *compositor,
- const char *syspath)
-{
- struct weston_seat *seat;
- struct weston_touch *touch;
- struct weston_touch_device *device;
-
- if (!syspath)
- return NULL;
-
- wl_list_for_each(seat, &compositor->seat_list, link) {
- touch = weston_seat_get_touch(seat);
- if (!touch)
- continue;
-
- wl_list_for_each(device, &touch->device_list, link) {
- if (strcmp(device->syspath, syspath) == 0)
- return device;
- }
- }
-
- return NULL;
-}
-
-static void
-touch_calibration_create_calibrator(
- struct wl_client *client,
- struct wl_resource *touch_calibration_resource,
- struct wl_resource *surface_resource,
- const char *syspath,
- uint32_t calibrator_id)
-{
- struct weston_compositor *compositor;
- struct weston_touch_calibrator *calibrator;
- struct weston_touch_device *device;
- struct weston_output *output = NULL;
- struct weston_surface *surface;
- uint32_t version;
- int ret;
-
- version = wl_resource_get_version(touch_calibration_resource);
- compositor = wl_resource_get_user_data(touch_calibration_resource);
-
- if (compositor->touch_calibrator != NULL) {
- wl_resource_post_error(touch_calibration_resource,
- WESTON_TOUCH_CALIBRATION_ERROR_ALREADY_EXISTS,
- "a calibrator has already been created");
- return;
- }
-
- calibrator = zalloc(sizeof *calibrator);
- if (!calibrator) {
- wl_client_post_no_memory(client);
- return;
- }
-
- calibrator->compositor = compositor;
- calibrator->resource = wl_resource_create(client,
- &weston_touch_calibrator_interface,
- version, calibrator_id);
- if (!calibrator->resource) {
- wl_client_post_no_memory(client);
- goto err_dealloc;
- }
-
- surface = wl_resource_get_user_data(surface_resource);
- assert(surface);
- ret = weston_surface_set_role(surface, "weston_touch_calibrator",
- touch_calibration_resource,
- WESTON_TOUCH_CALIBRATION_ERROR_INVALID_SURFACE);
- if (ret < 0)
- goto err_destroy_resource;
-
- calibrator->surface_destroy_listener.notify =
- touch_calibrator_surface_destroyed;
- wl_resource_add_destroy_listener(surface->resource,
- &calibrator->surface_destroy_listener);
- calibrator->surface = surface;
-
- calibrator->surface_commit_listener.notify =
- touch_calibrator_surface_committed;
- wl_signal_add(&surface->commit_signal,
- &calibrator->surface_commit_listener);
-
- device = weston_compositor_find_touch_device_by_syspath(compositor,
- syspath);
- if (device) {
- output = device->ops->get_output(device);
- if (weston_touch_device_can_calibrate(device) && output)
- calibrator->device = device;
- }
-
- if (!calibrator->device) {
- wl_resource_post_error(touch_calibration_resource,
- WESTON_TOUCH_CALIBRATION_ERROR_INVALID_DEVICE,
- "the given touch device '%s' is not valid",
- syspath ?: "");
- goto err_unlink_surface;
- }
-
- calibrator->device_destroy_listener.notify =
- touch_calibrator_device_destroyed;
- wl_signal_add(&calibrator->device->destroy_signal,
- &calibrator->device_destroy_listener);
-
- wl_resource_set_implementation(calibrator->resource,
- &touch_calibrator_implementation,
- calibrator, destroy_touch_calibrator);
-
- assert(output);
- calibrator->output_destroy_listener.notify =
- touch_calibrator_output_destroyed;
- wl_signal_add(&output->destroy_signal,
- &calibrator->output_destroy_listener);
- calibrator->output = output;
-
- weston_touch_calibrator_send_configure(calibrator->resource,
- output->width,
- output->height);
-
- compositor->touch_calibrator = calibrator;
-
- return;
-
-err_unlink_surface:
- wl_list_remove(&calibrator->surface_commit_listener.link);
- wl_list_remove(&calibrator->surface_destroy_listener.link);
-
-err_destroy_resource:
- wl_resource_destroy(calibrator->resource);
-
-err_dealloc:
- free(calibrator);
-}
-
-static void
-touch_calibration_save(struct wl_client *client,
- struct wl_resource *touch_calibration_resource,
- const char *device_name,
- struct wl_array *matrix_data)
-{
- struct weston_touch_device *device;
- struct weston_compositor *compositor;
- struct weston_touch_device_matrix calibration;
- struct weston_touch_calibrator *calibrator;
- int i = 0;
- float *c;
-
- compositor = wl_resource_get_user_data(touch_calibration_resource);
-
- device = weston_compositor_find_touch_device_by_syspath(compositor,
- device_name);
- if (!device || !weston_touch_device_can_calibrate(device)) {
- wl_resource_post_error(touch_calibration_resource,
- WESTON_TOUCH_CALIBRATION_ERROR_INVALID_DEVICE,
- "the given device is not valid");
- return;
- }
-
- wl_array_for_each(c, matrix_data) {
- calibration.m[i++] = *c;
- }
-
- /* If calibration can't be saved, don't set it as current */
- if (compositor->touch_calibration_save &&
- compositor->touch_calibration_save(compositor, device,
- &calibration) < 0)
- return;
-
- /* If calibrator is still mapped, the compositor will use
- * saved_calibration when going back to normal touch handling.
- * Continuing calibrating after save request is undefined. */
- calibrator = compositor->touch_calibrator;
- if (calibrator &&
- calibrator->surface &&
- weston_surface_is_mapped(calibrator->surface))
- device->saved_calibration = calibration;
- else
- device->ops->set_calibration(device, &calibration);
-}
-
-static const struct weston_touch_calibration_interface
-touch_calibration_implementation = {
- touch_calibration_destroy,
- touch_calibration_create_calibrator,
- touch_calibration_save
-};
-
-static void
-bind_touch_calibration(struct wl_client *client,
- void *data, uint32_t version, uint32_t id)
-{
- struct weston_compositor *compositor = data;
- struct wl_resource *resource;
- struct weston_touch_device *device;
- struct weston_seat *seat;
- struct weston_touch *touch;
- const char *name;
-
- resource = wl_resource_create(client,
- &weston_touch_calibration_interface,
- version, id);
- if (resource == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_resource_set_implementation(resource,
- &touch_calibration_implementation,
- compositor, NULL);
-
- wl_list_for_each(seat, &compositor->seat_list, link) {
- touch = weston_seat_get_touch(seat);
- if (!touch)
- continue;
-
- wl_list_for_each(device, &touch->device_list, link) {
- if (!weston_touch_device_can_calibrate(device))
- continue;
-
- name = device->ops->get_calibration_head_name(device);
- if (!name)
- continue;
-
- weston_touch_calibration_send_touch_device(resource,
- device->syspath, name);
- }
- }
-}
-
-/** Advertise touch_calibration support
- *
- * \param compositor The compositor to init for.
- * \param save The callback function for saving a new calibration, or NULL.
- * \return Zero on success, -1 on failure or if already enabled.
- *
- * Calling this initializes the weston_touch_calibration protocol support,
- * so that the interface will be advertised to clients. It is recommended
- * to use some mechanism, e.g. wl_display_set_global_filter(), to restrict
- * access to the interface.
- *
- * There is no way to disable this once enabled.
- *
- * If the save callback is NULL, a new calibration provided by a client will
- * always be accepted. If the save callback is not NULL, it must return
- * success for the new calibration to be accepted.
- */
-WL_EXPORT int
-weston_compositor_enable_touch_calibrator(struct weston_compositor *compositor,
- weston_touch_calibration_save_func save)
-{
- if (compositor->touch_calibration)
- return -1;
-
- compositor->touch_calibration = wl_global_create(compositor->wl_display,
- &weston_touch_calibration_interface, 1,
- compositor, bind_touch_calibration);
- if (!compositor->touch_calibration)
- return -1;
-
- compositor->touch_calibration_save = save;
- weston_layer_init(&compositor->calibrator_layer, compositor);
-
- /* needs to be stacked above everything except lock screen and cursor,
- * otherwise the position value is arbitrary */
- weston_layer_set_position(&compositor->calibrator_layer,
- WESTON_LAYER_POSITION_TOP_UI + 120);
-
- return 0;
-}
diff --git a/libweston/vertex-clipping.c b/libweston/vertex-clipping.c
deleted file mode 100644
index a71e7336..00000000
--- a/libweston/vertex-clipping.c
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright © 2012 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include <assert.h>
-#include <float.h>
-#include <math.h>
-
-#include "vertex-clipping.h"
-
-float
-float_difference(float a, float b)
-{
- /* http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/ */
- static const float max_diff = 4.0f * FLT_MIN;
- static const float max_rel_diff = 4.0e-5;
- float diff = a - b;
- float adiff = fabsf(diff);
-
- if (adiff <= max_diff)
- return 0.0f;
-
- a = fabsf(a);
- b = fabsf(b);
- if (adiff <= (a > b ? a : b) * max_rel_diff)
- return 0.0f;
-
- return diff;
-}
-
-/* A line segment (p1x, p1y)-(p2x, p2y) intersects the line x = x_arg.
- * Compute the y coordinate of the intersection.
- */
-static float
-clip_intersect_y(float p1x, float p1y, float p2x, float p2y,
- float x_arg)
-{
- float a;
- float diff = float_difference(p1x, p2x);
-
- /* Practically vertical line segment, yet the end points have already
- * been determined to be on different sides of the line. Therefore
- * the line segment is part of the line and intersects everywhere.
- * Return the end point, so we use the whole line segment.
- */
- if (diff == 0.0f)
- return p2y;
-
- a = (x_arg - p2x) / diff;
- return p2y + (p1y - p2y) * a;
-}
-
-/* A line segment (p1x, p1y)-(p2x, p2y) intersects the line y = y_arg.
- * Compute the x coordinate of the intersection.
- */
-static float
-clip_intersect_x(float p1x, float p1y, float p2x, float p2y,
- float y_arg)
-{
- float a;
- float diff = float_difference(p1y, p2y);
-
- /* Practically horizontal line segment, yet the end points have already
- * been determined to be on different sides of the line. Therefore
- * the line segment is part of the line and intersects everywhere.
- * Return the end point, so we use the whole line segment.
- */
- if (diff == 0.0f)
- return p2x;
-
- a = (y_arg - p2y) / diff;
- return p2x + (p1x - p2x) * a;
-}
-
-enum path_transition {
- PATH_TRANSITION_OUT_TO_OUT = 0,
- PATH_TRANSITION_OUT_TO_IN = 1,
- PATH_TRANSITION_IN_TO_OUT = 2,
- PATH_TRANSITION_IN_TO_IN = 3,
-};
-
-static void
-clip_append_vertex(struct clip_context *ctx, float x, float y)
-{
- *ctx->vertices.x++ = x;
- *ctx->vertices.y++ = y;
-}
-
-static enum path_transition
-path_transition_left_edge(struct clip_context *ctx, float x, float y)
-{
- return ((ctx->prev.x >= ctx->clip.x1) << 1) | (x >= ctx->clip.x1);
-}
-
-static enum path_transition
-path_transition_right_edge(struct clip_context *ctx, float x, float y)
-{
- return ((ctx->prev.x < ctx->clip.x2) << 1) | (x < ctx->clip.x2);
-}
-
-static enum path_transition
-path_transition_top_edge(struct clip_context *ctx, float x, float y)
-{
- return ((ctx->prev.y >= ctx->clip.y1) << 1) | (y >= ctx->clip.y1);
-}
-
-static enum path_transition
-path_transition_bottom_edge(struct clip_context *ctx, float x, float y)
-{
- return ((ctx->prev.y < ctx->clip.y2) << 1) | (y < ctx->clip.y2);
-}
-
-static void
-clip_polygon_leftright(struct clip_context *ctx,
- enum path_transition transition,
- float x, float y, float clip_x)
-{
- float yi;
-
- switch (transition) {
- case PATH_TRANSITION_IN_TO_IN:
- clip_append_vertex(ctx, x, y);
- break;
- case PATH_TRANSITION_IN_TO_OUT:
- yi = clip_intersect_y(ctx->prev.x, ctx->prev.y, x, y, clip_x);
- clip_append_vertex(ctx, clip_x, yi);
- break;
- case PATH_TRANSITION_OUT_TO_IN:
- yi = clip_intersect_y(ctx->prev.x, ctx->prev.y, x, y, clip_x);
- clip_append_vertex(ctx, clip_x, yi);
- clip_append_vertex(ctx, x, y);
- break;
- case PATH_TRANSITION_OUT_TO_OUT:
- /* nothing */
- break;
- default:
- assert(0 && "bad enum path_transition");
- }
-
- ctx->prev.x = x;
- ctx->prev.y = y;
-}
-
-static void
-clip_polygon_topbottom(struct clip_context *ctx,
- enum path_transition transition,
- float x, float y, float clip_y)
-{
- float xi;
-
- switch (transition) {
- case PATH_TRANSITION_IN_TO_IN:
- clip_append_vertex(ctx, x, y);
- break;
- case PATH_TRANSITION_IN_TO_OUT:
- xi = clip_intersect_x(ctx->prev.x, ctx->prev.y, x, y, clip_y);
- clip_append_vertex(ctx, xi, clip_y);
- break;
- case PATH_TRANSITION_OUT_TO_IN:
- xi = clip_intersect_x(ctx->prev.x, ctx->prev.y, x, y, clip_y);
- clip_append_vertex(ctx, xi, clip_y);
- clip_append_vertex(ctx, x, y);
- break;
- case PATH_TRANSITION_OUT_TO_OUT:
- /* nothing */
- break;
- default:
- assert(0 && "bad enum path_transition");
- }
-
- ctx->prev.x = x;
- ctx->prev.y = y;
-}
-
-static void
-clip_context_prepare(struct clip_context *ctx, const struct polygon8 *src,
- float *dst_x, float *dst_y)
-{
- ctx->prev.x = src->x[src->n - 1];
- ctx->prev.y = src->y[src->n - 1];
- ctx->vertices.x = dst_x;
- ctx->vertices.y = dst_y;
-}
-
-static int
-clip_polygon_left(struct clip_context *ctx, const struct polygon8 *src,
- float *dst_x, float *dst_y)
-{
- enum path_transition trans;
- int i;
-
- if (src->n < 2)
- return 0;
-
- clip_context_prepare(ctx, src, dst_x, dst_y);
- for (i = 0; i < src->n; i++) {
- trans = path_transition_left_edge(ctx, src->x[i], src->y[i]);
- clip_polygon_leftright(ctx, trans, src->x[i], src->y[i],
- ctx->clip.x1);
- }
- return ctx->vertices.x - dst_x;
-}
-
-static int
-clip_polygon_right(struct clip_context *ctx, const struct polygon8 *src,
- float *dst_x, float *dst_y)
-{
- enum path_transition trans;
- int i;
-
- if (src->n < 2)
- return 0;
-
- clip_context_prepare(ctx, src, dst_x, dst_y);
- for (i = 0; i < src->n; i++) {
- trans = path_transition_right_edge(ctx, src->x[i], src->y[i]);
- clip_polygon_leftright(ctx, trans, src->x[i], src->y[i],
- ctx->clip.x2);
- }
- return ctx->vertices.x - dst_x;
-}
-
-static int
-clip_polygon_top(struct clip_context *ctx, const struct polygon8 *src,
- float *dst_x, float *dst_y)
-{
- enum path_transition trans;
- int i;
-
- if (src->n < 2)
- return 0;
-
- clip_context_prepare(ctx, src, dst_x, dst_y);
- for (i = 0; i < src->n; i++) {
- trans = path_transition_top_edge(ctx, src->x[i], src->y[i]);
- clip_polygon_topbottom(ctx, trans, src->x[i], src->y[i],
- ctx->clip.y1);
- }
- return ctx->vertices.x - dst_x;
-}
-
-static int
-clip_polygon_bottom(struct clip_context *ctx, const struct polygon8 *src,
- float *dst_x, float *dst_y)
-{
- enum path_transition trans;
- int i;
-
- if (src->n < 2)
- return 0;
-
- clip_context_prepare(ctx, src, dst_x, dst_y);
- for (i = 0; i < src->n; i++) {
- trans = path_transition_bottom_edge(ctx, src->x[i], src->y[i]);
- clip_polygon_topbottom(ctx, trans, src->x[i], src->y[i],
- ctx->clip.y2);
- }
- return ctx->vertices.x - dst_x;
-}
-
-#define max(a, b) (((a) > (b)) ? (a) : (b))
-#define min(a, b) (((a) > (b)) ? (b) : (a))
-#define clip(x, a, b) min(max(x, a), b)
-
-int
-clip_simple(struct clip_context *ctx,
- struct polygon8 *surf,
- float *ex,
- float *ey)
-{
- int i;
- for (i = 0; i < surf->n; i++) {
- ex[i] = clip(surf->x[i], ctx->clip.x1, ctx->clip.x2);
- ey[i] = clip(surf->y[i], ctx->clip.y1, ctx->clip.y2);
- }
- return surf->n;
-}
-
-int
-clip_transformed(struct clip_context *ctx,
- struct polygon8 *surf,
- float *ex,
- float *ey)
-{
- struct polygon8 polygon;
- int i, n;
-
- polygon.n = clip_polygon_left(ctx, surf, polygon.x, polygon.y);
- surf->n = clip_polygon_right(ctx, &polygon, surf->x, surf->y);
- polygon.n = clip_polygon_top(ctx, surf, polygon.x, polygon.y);
- surf->n = clip_polygon_bottom(ctx, &polygon, surf->x, surf->y);
-
- /* Get rid of duplicate vertices */
- ex[0] = surf->x[0];
- ey[0] = surf->y[0];
- n = 1;
- for (i = 1; i < surf->n; i++) {
- if (float_difference(ex[n - 1], surf->x[i]) == 0.0f &&
- float_difference(ey[n - 1], surf->y[i]) == 0.0f)
- continue;
- ex[n] = surf->x[i];
- ey[n] = surf->y[i];
- n++;
- }
- if (float_difference(ex[n - 1], surf->x[0]) == 0.0f &&
- float_difference(ey[n - 1], surf->y[0]) == 0.0f)
- n--;
-
- return n;
-}
diff --git a/libweston/vertex-clipping.h b/libweston/vertex-clipping.h
deleted file mode 100644
index 0c699021..00000000
--- a/libweston/vertex-clipping.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright © 2012 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#ifndef _WESTON_VERTEX_CLIPPING_H
-#define _WESTON_VERTEX_CLIPPING_H
-
-struct polygon8 {
- float x[8];
- float y[8];
- int n;
-};
-
-struct clip_context {
- struct {
- float x;
- float y;
- } prev;
-
- struct {
- float x1, y1;
- float x2, y2;
- } clip;
-
- struct {
- float *x;
- float *y;
- } vertices;
-};
-
-float
-float_difference(float a, float b);
-
-int
-clip_simple(struct clip_context *ctx,
- struct polygon8 *surf,
- float *ex,
- float *ey);
-
-int
-clip_transformed(struct clip_context *ctx,
- struct polygon8 *surf,
- float *ex,
- float *ey);\
-
-#endif
diff --git a/libweston/weston-direct-display.c b/libweston/weston-direct-display.c
deleted file mode 100644
index bf25b5a3..00000000
--- a/libweston/weston-direct-display.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright © 2019 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <sys/types.h>
-
-#include <libweston/libweston.h>
-#include "linux-dmabuf.h"
-#include "weston-direct-display-server-protocol.h"
-#include "libweston-internal.h"
-
-static void
-direct_display_enable(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *dmabuf_res)
-{
- struct linux_dmabuf_buffer *dmabuf;
-
- dmabuf = wl_resource_get_user_data(dmabuf_res);
- assert(dmabuf);
- dmabuf->direct_display = true;
-}
-
-static void
-direct_display_destroy(struct wl_client *client,
- struct wl_resource *global_resource)
-{
- wl_resource_destroy(global_resource);
-}
-
-static const struct weston_direct_display_v1_interface
- weston_direct_display_interface_v1 = {
- direct_display_enable,
- direct_display_destroy,
-};
-
-static void
-bind_direct_display(struct wl_client *client, void *data,
- uint32_t version, uint32_t id)
-{
- struct wl_resource *resource;
- struct weston_compositor *ec = data;
-
- resource = wl_resource_create(client,
- &weston_direct_display_v1_interface,
- version, id);
- if (!resource) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_resource_set_implementation(resource,
- &weston_direct_display_interface_v1,
- ec, NULL);
-}
-
-WL_EXPORT int
-weston_direct_display_setup(struct weston_compositor *ec)
-{
- if (!wl_global_create(ec->wl_display,
- &weston_direct_display_v1_interface, 1,
- ec, bind_direct_display))
- return -1;
-
- return 0;
-}
diff --git a/libweston/weston-launch.c b/libweston/weston-launch.c
deleted file mode 100644
index 8a711b4a..00000000
--- a/libweston/weston-launch.c
+++ /dev/null
@@ -1,874 +0,0 @@
-/*
- * Copyright © 2012 Benjamin Franzke
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <poll.h>
-#include <errno.h>
-
-#include <getopt.h>
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/socket.h>
-#include <sys/signalfd.h>
-#include <signal.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <linux/vt.h>
-#include <linux/major.h>
-#include <linux/kd.h>
-
-#include <pwd.h>
-#include <grp.h>
-#include <security/pam_appl.h>
-
-#ifdef HAVE_SYSTEMD_LOGIN
-#include <systemd/sd-login.h>
-#endif
-
-#include "weston-launch.h"
-
-#define DRM_MAJOR 226
-
-#ifndef KDSKBMUTE
-#define KDSKBMUTE 0x4B51
-#endif
-
-#ifndef EVIOCREVOKE
-#define EVIOCREVOKE _IOW('E', 0x91, int)
-#endif
-
-#define MAX_ARGV_SIZE 256
-
-#ifdef BUILD_DRM_COMPOSITOR
-
-#include <xf86drm.h>
-
-#else
-
-static inline int
-drmDropMaster(int drm_fd)
-{
- return 0;
-}
-
-static inline int
-drmSetMaster(int drm_fd)
-{
- return 0;
-}
-
-#endif
-
-/* major()/minor() */
-#ifdef MAJOR_IN_MKDEV
-# include <sys/mkdev.h>
-#endif
-#ifdef MAJOR_IN_SYSMACROS
-# include <sys/sysmacros.h>
-#endif
-
-struct weston_launch {
- struct pam_conv pc;
- pam_handle_t *ph;
- int tty;
- int ttynr;
- int sock[2];
- int drm_fd;
- int last_input_fd;
- int kb_mode;
- struct passwd *pw;
-
- int signalfd;
-
- pid_t child;
- int verbose;
- char *new_user;
-};
-
-union cmsg_data { unsigned char b[4]; int fd; };
-
-static gid_t *
-read_groups(int *ngroups)
-{
- int n;
- gid_t *groups;
-
- n = getgroups(0, NULL);
-
- if (n < 0) {
- fprintf(stderr, "Unable to retrieve groups: %s\n",
- strerror(errno));
- return NULL;
- }
-
- groups = malloc(n * sizeof(gid_t));
- if (!groups)
- return NULL;
-
- if (getgroups(n, groups) < 0) {
- fprintf(stderr, "Unable to retrieve groups: %s\n",
- strerror(errno));
- free(groups);
- return NULL;
- }
-
- *ngroups = n;
- return groups;
-}
-
-static bool
-weston_launch_allowed(struct weston_launch *wl)
-{
- struct group *gr;
- gid_t *groups;
- int ngroups;
-#ifdef HAVE_SYSTEMD_LOGIN
- char *session, *seat;
- int err;
-#endif
-
- if (getuid() == 0)
- return true;
-
- gr = getgrnam("weston-launch");
- if (gr) {
- groups = read_groups(&ngroups);
- if (groups && ngroups > 0) {
- while (ngroups--) {
- if (groups[ngroups] == gr->gr_gid) {
- free(groups);
- return true;
- }
- }
- free(groups);
- }
- }
-
-#ifdef HAVE_SYSTEMD_LOGIN
- err = sd_pid_get_session(getpid(), &session);
- if (err == 0 && session) {
- if (sd_session_is_active(session) &&
- sd_session_get_seat(session, &seat) == 0) {
- free(seat);
- free(session);
- return true;
- }
- free(session);
- }
-#endif
-
- return false;
-}
-
-static int
-pam_conversation_fn(int msg_count,
- const struct pam_message **messages,
- struct pam_response **responses,
- void *user_data)
-{
- return PAM_SUCCESS;
-}
-
-static int
-setup_pam(struct weston_launch *wl)
-{
- int err;
-
- wl->pc.conv = pam_conversation_fn;
- wl->pc.appdata_ptr = wl;
-
- err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
- if (err != PAM_SUCCESS) {
- fprintf(stderr, "failed to start pam transaction: %d: %s\n",
- err, pam_strerror(wl->ph, err));
- return -1;
- }
-
- err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
- if (err != PAM_SUCCESS) {
- fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
- err, pam_strerror(wl->ph, err));
- return -1;
- }
-
- err = pam_open_session(wl->ph, 0);
- if (err != PAM_SUCCESS) {
- fprintf(stderr, "failed to open pam session: %d: %s\n",
- err, pam_strerror(wl->ph, err));
- return -1;
- }
-
- return 0;
-}
-
-static int
-setup_launcher_socket(struct weston_launch *wl)
-{
- if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, wl->sock) < 0) {
- fprintf(stderr, "weston: socketpair failed: %s\n",
- strerror(errno));
- return -1;
- }
-
- if (fcntl(wl->sock[0], F_SETFD, FD_CLOEXEC) < 0) {
- fprintf(stderr, "weston: fcntl failed: %s\n",
- strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-static int
-setup_signals(struct weston_launch *wl)
-{
- int ret;
- sigset_t mask;
- struct sigaction sa;
-
- memset(&sa, 0, sizeof sa);
- sa.sa_handler = SIG_DFL;
- sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
- ret = sigaction(SIGCHLD, &sa, NULL);
- assert(ret == 0);
-
- sa.sa_handler = SIG_IGN;
- sa.sa_flags = 0;
- sigaction(SIGHUP, &sa, NULL);
-
- ret = sigemptyset(&mask);
- assert(ret == 0);
- sigaddset(&mask, SIGCHLD);
- sigaddset(&mask, SIGINT);
- sigaddset(&mask, SIGTERM);
- sigaddset(&mask, SIGUSR1);
- sigaddset(&mask, SIGUSR2);
- ret = sigprocmask(SIG_BLOCK, &mask, NULL);
- assert(ret == 0);
-
- wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
- if (wl->signalfd < 0)
- return -errno;
-
- return 0;
-}
-
-static void
-setenv_fd(const char *env, int fd)
-{
- char buf[32];
-
- snprintf(buf, sizeof buf, "%d", fd);
- setenv(env, buf, 1);
-}
-
-static int
-send_reply(struct weston_launch *wl, int reply)
-{
- int len;
-
- do {
- len = send(wl->sock[0], &reply, sizeof reply, 0);
- } while (len < 0 && errno == EINTR);
-
- return len;
-}
-
-static int
-handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
-{
- int fd = -1, ret = -1;
- char control[CMSG_SPACE(sizeof(fd))];
- struct cmsghdr *cmsg;
- struct stat s;
- struct msghdr nmsg;
- struct iovec iov;
- struct weston_launcher_open *message;
- union cmsg_data *data;
-
- message = msg->msg_iov->iov_base;
- if ((size_t)len < sizeof(*message))
- goto err0;
-
- /* Ensure path is null-terminated */
- ((char *) message)[len-1] = '\0';
-
- fd = open(message->path, message->flags);
- if (fd < 0) {
- fprintf(stderr, "Error opening device %s: %s\n",
- message->path, strerror(errno));
- goto err0;
- }
-
- if (fstat(fd, &s) < 0) {
- close(fd);
- fd = -1;
- fprintf(stderr, "Failed to stat %s\n", message->path);
- goto err0;
- }
-
- if (major(s.st_rdev) != INPUT_MAJOR &&
- major(s.st_rdev) != DRM_MAJOR) {
- close(fd);
- fd = -1;
- fprintf(stderr, "Device %s is not an input or drm device\n",
- message->path);
- goto err0;
- }
-
-err0:
- memset(&nmsg, 0, sizeof nmsg);
- nmsg.msg_iov = &iov;
- nmsg.msg_iovlen = 1;
- if (fd != -1) {
- nmsg.msg_control = control;
- nmsg.msg_controllen = sizeof control;
- cmsg = CMSG_FIRSTHDR(&nmsg);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
- data = (union cmsg_data *) CMSG_DATA(cmsg);
- data->fd = fd;
- nmsg.msg_controllen = cmsg->cmsg_len;
- ret = 0;
- }
- iov.iov_base = &ret;
- iov.iov_len = sizeof ret;
-
- if (wl->verbose)
- fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
- message->path, ret, fd);
- do {
- len = sendmsg(wl->sock[0], &nmsg, 0);
- } while (len < 0 && errno == EINTR);
-
- if (len < 0)
- return -1;
-
- if (fd != -1 && major(s.st_rdev) == DRM_MAJOR)
- wl->drm_fd = fd;
- if (fd != -1 && major(s.st_rdev) == INPUT_MAJOR &&
- wl->last_input_fd < fd)
- wl->last_input_fd = fd;
-
- return 0;
-}
-
-static int
-handle_socket_msg(struct weston_launch *wl)
-{
- char control[CMSG_SPACE(sizeof(int))];
- char buf[BUFSIZ];
- struct msghdr msg;
- struct iovec iov;
- int ret = -1;
- ssize_t len;
- struct weston_launcher_message *message;
-
- memset(&msg, 0, sizeof(msg));
- iov.iov_base = buf;
- iov.iov_len = sizeof buf;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = control;
- msg.msg_controllen = sizeof control;
-
- do {
- len = recvmsg(wl->sock[0], &msg, 0);
- } while (len < 0 && errno == EINTR);
-
- if (len < 1)
- return -1;
-
- message = (void *) buf;
- switch (message->opcode) {
- case WESTON_LAUNCHER_OPEN:
- ret = handle_open(wl, &msg, len);
- break;
- }
-
- return ret;
-}
-
-static void
-quit(struct weston_launch *wl, int status)
-{
- struct vt_mode mode = { 0 };
- int err;
-
- close(wl->signalfd);
- close(wl->sock[0]);
-
- if (wl->new_user) {
- err = pam_close_session(wl->ph, 0);
- if (err)
- fprintf(stderr, "pam_close_session failed: %d: %s\n",
- err, pam_strerror(wl->ph, err));
- pam_end(wl->ph, err);
- }
-
- if (ioctl(wl->tty, KDSKBMUTE, 0) &&
- ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
- fprintf(stderr, "failed to restore keyboard mode: %s\n",
- strerror(errno));
-
- if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
- fprintf(stderr, "failed to set KD_TEXT mode on tty: %s\n",
- strerror(errno));
-
- /* We have to drop master before we switch the VT back in
- * VT_AUTO, so we don't risk switching to a VT with another
- * display server, that will then fail to set drm master. */
- drmDropMaster(wl->drm_fd);
-
- mode.mode = VT_AUTO;
- if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
- fprintf(stderr, "could not reset vt handling\n");
-
- exit(status);
-}
-
-static void
-close_input_fds(struct weston_launch *wl)
-{
- struct stat s;
- int fd;
-
- for (fd = 3; fd <= wl->last_input_fd; fd++) {
- if (fstat(fd, &s) == 0 && major(s.st_rdev) == INPUT_MAJOR) {
- /* EVIOCREVOKE may fail if the kernel doesn't
- * support it, but all we can do is ignore it. */
- ioctl(fd, EVIOCREVOKE, 0);
- close(fd);
- }
- }
-}
-
-static int
-handle_signal(struct weston_launch *wl)
-{
- struct signalfd_siginfo sig;
- int pid, status, ret;
-
- if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
- fprintf(stderr, "weston: reading signalfd failed: %s\n",
- strerror(errno));
- return -1;
- }
-
- switch (sig.ssi_signo) {
- case SIGCHLD:
- pid = waitpid(-1, &status, 0);
- if (pid == wl->child) {
- wl->child = 0;
- if (WIFEXITED(status))
- ret = WEXITSTATUS(status);
- else if (WIFSIGNALED(status))
- /*
- * If weston dies because of signal N, we
- * return 10+N. This is distinct from
- * weston-launch dying because of a signal
- * (128+N).
- */
- ret = 10 + WTERMSIG(status);
- else
- ret = 0;
- quit(wl, ret);
- }
- break;
- case SIGTERM:
- case SIGINT:
- if (!wl->child)
- break;
-
- if (wl->verbose)
- fprintf(stderr, "weston-launch: sending %s to pid %d\n",
- strsignal(sig.ssi_signo), wl->child);
-
- kill(wl->child, sig.ssi_signo);
- break;
- case SIGUSR1:
- send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
- close_input_fds(wl);
- drmDropMaster(wl->drm_fd);
- ioctl(wl->tty, VT_RELDISP, 1);
- break;
- case SIGUSR2:
- ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
- drmSetMaster(wl->drm_fd);
- send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
- break;
- default:
- return -1;
- }
-
- return 0;
-}
-
-static int
-setup_tty(struct weston_launch *wl, const char *tty)
-{
- struct stat buf;
- struct vt_mode mode = { 0 };
- char *t;
-
- if (!wl->new_user) {
- wl->tty = STDIN_FILENO;
- } else if (tty) {
- t = ttyname(STDIN_FILENO);
- if (t && strcmp(t, tty) == 0)
- wl->tty = STDIN_FILENO;
- else
- wl->tty = open(tty, O_RDWR | O_NOCTTY);
- } else {
- int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
- char filename[16];
-
- if (tty0 < 0) {
- fprintf(stderr, "weston: could not open tty0: %s\n",
- strerror(errno));
- return -1;
- }
-
- if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
- {
- fprintf(stderr, "weston: failed to find non-opened console: %s\n",
- strerror(errno));
- return -1;
- }
-
- snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
- wl->tty = open(filename, O_RDWR | O_NOCTTY);
- close(tty0);
- }
-
- if (wl->tty < 0) {
- fprintf(stderr, "weston: failed to open tty: %s\n",
- strerror(errno));
- return -1;
- }
-
- if (fstat(wl->tty, &buf) == -1 ||
- major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0) {
- fprintf(stderr, "weston: weston-launch must be run from a virtual terminal\n");
- return -1;
- }
-
- if (tty) {
- if (fstat(wl->tty, &buf) < 0) {
- fprintf(stderr, "weston: stat %s failed: %s\n", tty,
- strerror(errno));
- return -1;
- }
-
- if (major(buf.st_rdev) != TTY_MAJOR) {
- fprintf(stderr,
- "weston: invalid tty device: %s\n", tty);
- return -1;
- }
-
- wl->ttynr = minor(buf.st_rdev);
- }
-
- if (ioctl(wl->tty, KDGKBMODE, &wl->kb_mode)) {
- fprintf(stderr,
- "weston: failed to get current keyboard mode: %s",
- strerror(errno));
- return -1;
- }
-
- if (ioctl(wl->tty, KDSKBMUTE, 1) &&
- ioctl(wl->tty, KDSKBMODE, K_OFF)) {
- fprintf(stderr,
- "weston: failed to set K_OFF keyboard mode: %s\n",
- strerror(errno));
- return -1;
- }
-
- if (ioctl(wl->tty, KDSETMODE, KD_GRAPHICS)) {
- fprintf(stderr,
- "weston: failed to set KD_GRAPHICS mode on tty: %s\n",
- strerror(errno));
- return -1;
- }
-
- mode.mode = VT_PROCESS;
- mode.relsig = SIGUSR1;
- mode.acqsig = SIGUSR2;
- if (ioctl(wl->tty, VT_SETMODE, &mode) < 0) {
- fprintf(stderr,
- "weston: failed to take control of vt handling %s\n",
- strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-static int
-setup_session(struct weston_launch *wl, char **child_argv)
-{
- char **env;
- char *term;
- int i;
-
- if (wl->tty != STDIN_FILENO) {
- if (setsid() < 0) {
- fprintf(stderr, "weston: setsid failed %s\n",
- strerror(errno));
- exit(EXIT_FAILURE);
- }
- if (ioctl(wl->tty, TIOCSCTTY, 0) < 0) {
- fprintf(stderr, "TIOCSCTTY failed - tty is in use %s\n",
- strerror(errno));
- exit(EXIT_FAILURE);
- }
- }
-
- term = getenv("TERM");
- clearenv();
- if (term)
- setenv("TERM", term, 1);
- setenv("USER", wl->pw->pw_name, 1);
- setenv("LOGNAME", wl->pw->pw_name, 1);
- setenv("HOME", wl->pw->pw_dir, 1);
- setenv("SHELL", wl->pw->pw_shell, 1);
-
- env = pam_getenvlist(wl->ph);
- if (env) {
- for (i = 0; env[i]; ++i) {
- if (putenv(env[i]) != 0)
- fprintf(stderr, "putenv %s failed\n", env[i]);
- }
- free(env);
- }
-
- /*
- * We open a new session, so it makes sense
- * to run a new login shell
- */
- child_argv[0] = "/bin/sh";
- child_argv[1] = "-l";
- child_argv[2] = "-c";
- child_argv[3] = "exec " BINDIR "/weston \"$@\"";
- child_argv[4] = "weston";
- return 5;
-}
-
-static void
-drop_privileges(struct weston_launch *wl)
-{
- if (setgid(wl->pw->pw_gid) < 0 ||
-#ifdef HAVE_INITGROUPS
- initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
-#endif
- setuid(wl->pw->pw_uid) < 0) {
- fprintf(stderr, "weston: dropping privileges failed %s\n",
- strerror(errno));
- exit(EXIT_FAILURE);
- }
-}
-
-static void
-launch_compositor(struct weston_launch *wl, int argc, char *argv[])
-{
- char *child_argv[MAX_ARGV_SIZE];
- sigset_t mask;
- int o, i;
-
- if (wl->verbose)
- printf("weston-launch: spawned weston with pid: %d\n", getpid());
- if (wl->new_user) {
- o = setup_session(wl, child_argv);
- } else {
- child_argv[0] = BINDIR "/weston";
- o = 1;
- }
- for (i = 0; i < argc; ++i)
- child_argv[o + i] = argv[i];
- child_argv[o + i] = NULL;
-
- if (geteuid() == 0)
- drop_privileges(wl);
-
- setenv_fd("WESTON_TTY_FD", wl->tty);
- setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
-
- unsetenv("DISPLAY");
-
- /* Do not give our signal mask to the new process. */
- sigemptyset(&mask);
- sigaddset(&mask, SIGTERM);
- sigaddset(&mask, SIGCHLD);
- sigaddset(&mask, SIGINT);
- sigprocmask(SIG_UNBLOCK, &mask, NULL);
-
-
- execv(child_argv[0], child_argv);
- fprintf(stderr, "weston: exec failed: %s\n", strerror(errno));
- exit(EXIT_FAILURE);
-}
-
-static void
-help(const char *name)
-{
- fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
- fprintf(stderr, " -u, --user Start session as specified username,\n"
- " e.g. -u joe, requires root.\n");
- fprintf(stderr, " -t, --tty Start session on alternative tty,\n"
- " e.g. -t /dev/tty4, requires -u option.\n");
- fprintf(stderr, " -v, --verbose Be verbose\n");
- fprintf(stderr, " -h, --help Display this help message\n");
-}
-
-int
-main(int argc, char *argv[])
-{
- struct weston_launch wl;
- int i, c;
- char *tty = NULL;
- struct option opts[] = {
- { "user", required_argument, NULL, 'u' },
- { "tty", required_argument, NULL, 't' },
- { "verbose", no_argument, NULL, 'v' },
- { "help", no_argument, NULL, 'h' },
- { 0, 0, NULL, 0 }
- };
-
- memset(&wl, 0, sizeof wl);
-
- while ((c = getopt_long(argc, argv, "u:t:vh", opts, &i)) != -1) {
- switch (c) {
- case 'u':
- wl.new_user = optarg;
- if (getuid() != 0) {
- fprintf(stderr, "weston: Permission denied. -u allowed for root only\n");
- exit(EXIT_FAILURE);
- }
- break;
- case 't':
- tty = optarg;
- break;
- case 'v':
- wl.verbose = 1;
- break;
- case 'h':
- help("weston-launch");
- exit(EXIT_FAILURE);
- default:
- exit(EXIT_FAILURE);
- }
- }
-
- if ((argc - optind) > (MAX_ARGV_SIZE - 6)) {
- fprintf(stderr,
- "weston: Too many arguments to pass to weston: %s\n",
- strerror(E2BIG));
- exit(EXIT_FAILURE);
- }
-
- if (tty && !wl.new_user) {
- fprintf(stderr, "weston: -t/--tty option requires -u/--user option as well\n");
- exit(EXIT_FAILURE);
- }
-
- if (wl.new_user)
- wl.pw = getpwnam(wl.new_user);
- else
- wl.pw = getpwuid(getuid());
- if (wl.pw == NULL) {
- fprintf(stderr, "weston: failed to get username: %s\n",
- strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- if (!weston_launch_allowed(&wl)) {
- fprintf(stderr, "Permission denied. You should either:\n"
-#ifdef HAVE_SYSTEMD_LOGIN
- " - run from an active and local (systemd) session.\n"
-#else
- " - enable systemd session support for weston-launch.\n"
-#endif
- " - or add yourself to the 'weston-launch' group.\n");
- exit(EXIT_FAILURE);
- }
-
- if (setup_tty(&wl, tty) < 0)
- exit(EXIT_FAILURE);
-
- if (wl.new_user && setup_pam(&wl) < 0)
- exit(EXIT_FAILURE);
-
- if (setup_launcher_socket(&wl) < 0)
- exit(EXIT_FAILURE);
-
- if (setup_signals(&wl) < 0)
- exit(EXIT_FAILURE);
-
- wl.child = fork();
- if (wl.child == -1) {
- fprintf(stderr, "weston: fork failed %s\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- if (wl.child == 0)
- launch_compositor(&wl, argc - optind, argv + optind);
-
- close(wl.sock[1]);
- if (wl.tty != STDIN_FILENO)
- close(wl.tty);
-
- while (1) {
- struct pollfd fds[2];
- int n;
-
- fds[0].fd = wl.sock[0];
- fds[0].events = POLLIN;
- fds[1].fd = wl.signalfd;
- fds[1].events = POLLIN;
-
- n = poll(fds, 2, -1);
- if (n < 0) {
- fprintf(stderr, "poll failed: %s\n", strerror(errno));
- return -1;
- }
- if (fds[0].revents & POLLIN)
- handle_socket_msg(&wl);
- if (fds[1].revents)
- handle_signal(&wl);
- }
-
- return 0;
-}
diff --git a/libweston/weston-launch.h b/libweston/weston-launch.h
deleted file mode 100644
index 819321c8..00000000
--- a/libweston/weston-launch.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright © 2012 Benjamin Franzke
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _WESTON_LAUNCH_H_
-#define _WESTON_LAUNCH_H_
-
-enum weston_launcher_opcode {
- WESTON_LAUNCHER_OPEN,
-};
-
-enum weston_launcher_event {
- WESTON_LAUNCHER_SUCCESS,
- WESTON_LAUNCHER_ACTIVATE,
- WESTON_LAUNCHER_DEACTIVATE
-};
-
-struct weston_launcher_message {
- int opcode;
-};
-
-struct weston_launcher_open {
- struct weston_launcher_message header;
- int flags;
- char path[0];
-};
-
-int
-weston_environment_get_fd(const char *env);
-
-#endif
diff --git a/libweston/weston-log-file.c b/libweston/weston-log-file.c
deleted file mode 100644
index 2cdb247d..00000000
--- a/libweston/weston-log-file.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright © 2019 Collabora Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <libweston/weston-log.h>
-#include "shared/helpers.h"
-#include <libweston/libweston.h>
-
-#include "weston-log-internal.h"
-
-#include <stdio.h>
-
-/** File type of stream
- */
-struct weston_debug_log_file {
- struct weston_log_subscriber base;
- FILE *file;
-};
-
-static struct weston_debug_log_file *
-to_weston_debug_log_file(struct weston_log_subscriber *sub)
-{
- return container_of(sub, struct weston_debug_log_file, base);
-}
-
-static void
-weston_log_file_write(struct weston_log_subscriber *sub,
- const char *data, size_t len)
-{
- struct weston_debug_log_file *stream = to_weston_debug_log_file(sub);
- fwrite(data, len, 1, stream->file);
-}
-
-/** Creates a file type of subscriber
- *
- * Should be destroyed using weston_log_subscriber_destroy_log()
- *
- * @param dump_to if specified, used for writing data to
- * @returns a weston_log_subscriber object or NULL in case of failure
- *
- * @sa weston_log_subscriber_destroy_log
- *
- */
-WL_EXPORT struct weston_log_subscriber *
-weston_log_subscriber_create_log(FILE *dump_to)
-{
- struct weston_debug_log_file *file = zalloc(sizeof(*file));
-
- if (!file)
- return NULL;
-
- if (dump_to)
- file->file = dump_to;
- else
- file->file = stderr;
-
-
- file->base.write = weston_log_file_write;
- file->base.destroy = NULL;
- file->base.complete = NULL;
-
- wl_list_init(&file->base.subscription_list);
-
- return &file->base;
-}
-
-/** Destroy the subscriber created with weston_log_subscriber_create_log
- *
- * @param subscriber the weston_log_subscriber object to destroy
- *
- */
-WL_EXPORT void
-weston_log_subscriber_destroy_log(struct weston_log_subscriber *subscriber)
-{
- struct weston_debug_log_file *file = to_weston_debug_log_file(subscriber);
- free(file);
-}
diff --git a/libweston/weston-log-flight-rec.c b/libweston/weston-log-flight-rec.c
deleted file mode 100644
index 31ea3045..00000000
--- a/libweston/weston-log-flight-rec.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright © 2019 Collabora Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <libweston/weston-log.h>
-#include "shared/helpers.h"
-#include <libweston/libweston.h>
-
-#include "weston-log-internal.h"
-
-#include <assert.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/time.h>
-
-struct weston_ring_buffer {
- uint32_t append_pos; /**< where in the buffer we are */
- uint32_t size; /**< max length of the ring buffer */
- char *buf; /**< the buffer itself */
- FILE *file; /**< where to write in case we need to dump the buf */
- bool overlap; /**< in case buff overlaps, hint from where to print buf contents */
-};
-
-/** allows easy access to the ring buffer in case of a core dump
- */
-WL_EXPORT struct weston_ring_buffer *weston_primary_flight_recorder_ring_buffer = NULL;
-
-/** A black box type of stream, used to aggregate data continuously, and
- * when needed, to dump its contents for inspection.
- */
-struct weston_debug_log_flight_recorder {
- struct weston_log_subscriber base;
- struct weston_ring_buffer rb;
-};
-
-static void
-weston_ring_buffer_init(struct weston_ring_buffer *rb, size_t size, char *buf)
-{
- rb->append_pos = 0;
- rb->size = size - 1;
- rb->buf = buf;
- rb->overlap = false;
- rb->file = stderr;
-}
-
-static struct weston_debug_log_flight_recorder *
-to_flight_recorder(struct weston_log_subscriber *sub)
-{
- return container_of(sub, struct weston_debug_log_flight_recorder, base);
-}
-
-static void
-weston_log_flight_recorder_adjust_end(struct weston_ring_buffer *rb,
- size_t bytes_to_advance)
-{
- if (rb->append_pos == rb->size - bytes_to_advance)
- rb->append_pos = 0;
- else
- rb->append_pos += bytes_to_advance;
-}
-
-static void
-weston_log_flight_recorder_write_chunks(struct weston_ring_buffer *rb,
- const char *data, size_t len)
-{
- /* no of chunks that matches our buffer size */
- size_t nr_chunks = len / rb->size;
-
- /* bytes left that do not fill entire buffer */
- size_t bytes_left_last_chunk = len % rb->size;
- const char *c_data = data;
-
- /* might overlap multiple times, memcpy is redundant,
- * that's why we don't even modify append_pos */
- while (nr_chunks-- > 0) {
- memcpy(&rb->buf[rb->append_pos], c_data, rb->size);
- c_data += rb->size;
- }
-
- if (bytes_left_last_chunk)
- memcpy(&rb->buf[rb->append_pos], c_data, bytes_left_last_chunk);
-
- /* adjust append_pos */
- weston_log_flight_recorder_adjust_end(rb, bytes_left_last_chunk);
-}
-
-static void
-weston_log_flight_recorder_write_chunks_overlap(struct weston_ring_buffer *rb,
- const char *data, size_t len)
-{
- size_t transfer_remains =
- (rb->append_pos + len) - rb->size;
- size_t transfer_to_end = len - transfer_remains;
- const char *c_data = data;
-
- /* transfer what remains until the end of the buffer */
- memcpy(&rb->buf[rb->append_pos], c_data, transfer_to_end);
- c_data += transfer_to_end;
-
- /* reset append_pos as we filled up the buffer */
- rb->append_pos = 0;
-
- /* transfer what remains */
- weston_log_flight_recorder_write_chunks(rb, c_data, transfer_remains);
- rb->overlap = true;
-}
-
-static void
-weston_log_flight_recorder_write_data(struct weston_ring_buffer *rb,
- const char *data, size_t len)
-{
- /*
- * If append_pos is at the beginning of the buffer, we determine if we
- * should do it in chunks, and if there are any bytes left we transfer
- * those as well.
- *
- * If the append_pos is somewhere inside the buffer we determine how
- * many bytes we need to transfer between we reach the end and overlap,
- * then we proceed as in the first step.
- */
- if (rb->append_pos == 0)
- weston_log_flight_recorder_write_chunks(rb, data, len);
- else
- weston_log_flight_recorder_write_chunks_overlap(rb, data, len);
-}
-
-static void
-weston_log_flight_recorder_write(struct weston_log_subscriber *sub,
- const char *data, size_t len)
-{
- struct weston_debug_log_flight_recorder *flight_rec =
- to_flight_recorder(sub);
- struct weston_ring_buffer *rb = &flight_rec->rb;
-
- /* in case the data is bigger than the size of the buf */
- if (rb->size < len) {
- weston_log_flight_recorder_write_data(rb, data, len);
- } else {
- /* if we can transfer it without wrapping it do it at once */
- if (rb->append_pos <= rb->size - len) {
- memcpy(&rb->buf[rb->append_pos], data, len);
-
- /*
- * adjust append_pos, take care of the situation were
- * to fill up the entire buf
- */
- weston_log_flight_recorder_adjust_end(rb, len);
- } else {
- weston_log_flight_recorder_write_data(rb, data, len);
- }
- }
-
-}
-
-static void
-weston_log_flight_recorder_map_memory(struct weston_debug_log_flight_recorder *flight_rec)
-{
- size_t i = 0;
-
- for (i = 0; i < flight_rec->rb.size; i++)
- flight_rec->rb.buf[i] = 0xff;
-}
-
-static void
-weston_log_subscriber_display_flight_rec_data(struct weston_ring_buffer *rb,
- FILE *file)
-{
- FILE *file_d = stderr;
- if (file)
- file_d = file;
-
- if (!rb->overlap) {
- if (rb->append_pos)
- fwrite(rb->buf, sizeof(char), rb->append_pos, file_d);
- else
- fwrite(rb->buf, sizeof(char), rb->size, file_d);
- } else {
- /* from append_pos to size */
- fwrite(&rb->buf[rb->append_pos], sizeof(char),
- rb->size - rb->append_pos, file_d);
- /* from 0 to append_pos */
- fwrite(rb->buf, sizeof(char), rb->append_pos, file_d);
- }
-}
-
-WL_EXPORT void
-weston_log_subscriber_display_flight_rec(struct weston_log_subscriber *sub)
-{
- struct weston_debug_log_flight_recorder *flight_rec =
- to_flight_recorder(sub);
- struct weston_ring_buffer *rb = &flight_rec->rb;
-
- weston_log_subscriber_display_flight_rec_data(rb, rb->file);
-}
-
-/** Create a flight recorder type of subscriber
- *
- * Allocates both the flight recorder and the underlying ring buffer. Use
- * weston_log_subscriber_destroy_flight_rec() to clean-up.
- *
- * @param size specify the maximum size (in bytes) of the backing storage
- * for the flight recorder
- * @returns a weston_log_subscriber object or NULL in case of failure
- */
-WL_EXPORT struct weston_log_subscriber *
-weston_log_subscriber_create_flight_rec(size_t size)
-{
- struct weston_debug_log_flight_recorder *flight_rec;
- char *weston_rb;
-
- assert("Can't create more than one flight recorder." &&
- !weston_primary_flight_recorder_ring_buffer);
-
- flight_rec = zalloc(sizeof(*flight_rec));
- if (!flight_rec)
- return NULL;
-
- flight_rec->base.write = weston_log_flight_recorder_write;
- flight_rec->base.destroy = NULL;
- flight_rec->base.complete = NULL;
- wl_list_init(&flight_rec->base.subscription_list);
-
- weston_rb = zalloc(sizeof(char) * size);
- if (!weston_rb) {
- free(flight_rec);
- return NULL;
- }
-
- weston_ring_buffer_init(&flight_rec->rb, size, weston_rb);
- weston_primary_flight_recorder_ring_buffer = &flight_rec->rb;
-
- /* write some data to the rb such that the memory gets mapped */
- weston_log_flight_recorder_map_memory(flight_rec);
-
- return &flight_rec->base;
-}
-
-/** Destroys the weston_log_subscriber object created with
- * weston_log_subscriber_create_flight_rec()
- *
- * @param sub the weston_log_subscriber object
- *
- */
-WL_EXPORT void
-weston_log_subscriber_destroy_flight_rec(struct weston_log_subscriber *sub)
-{
- struct weston_debug_log_flight_recorder *flight_rec = to_flight_recorder(sub);
- free(flight_rec->rb.buf);
- free(flight_rec);
-}
-
-/** Retrieve flight recorder ring buffer contents, could be useful when
- * implementing an assert()-like wrapper.
- *
- * @param file a FILE type already opened. Can also pass stderr/stdout under gdb
- * if the program is loaded into memory.
- *
- * Uses the global exposed weston_primary_flight_recorder_ring_buffer.
- *
- */
-WL_EXPORT void
-weston_log_flight_recorder_display_buffer(FILE *file)
-{
- if (!weston_primary_flight_recorder_ring_buffer)
- return;
-
- weston_log_subscriber_display_flight_rec_data(weston_primary_flight_recorder_ring_buffer,
- file);
-}
diff --git a/libweston/weston-log-internal.h b/libweston/weston-log-internal.h
deleted file mode 100644
index ba5b51ce..00000000
--- a/libweston/weston-log-internal.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright © 2019 Collabora Ltd
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#ifndef WESTON_LOG_INTERNAL_H
-#define WESTON_LOG_INTERNAL_H
-
-#include "wayland-util.h"
-
-struct weston_log_subscription;
-
-/** Subscriber allows each type of stream to customize or to provide its own
- * methods to manipulate the underlying storage. It follows also an
- * object-oriented approach, contains the ops callbacks and a list of
- * subcriptions of type weston_log_subscription. Each subscription created will
- * be both added to this subscription list and that of the weston_log_scope.
- *
- * A kind of stream can inherit the subscriber class and provide its own callbacks:
- * @code
- * struct weston_log_data_stream {
- * struct weston_log_subscriber base;
- * struct weston_data_stream opaque;
- * };
- * @endcode
- *
- * Passing the base class will require container retrieval type of methods
- * to be allowed to reach the opaque type (i.e., container_of()).
- *
- * @ingroup internal-log
- *
- */
-struct weston_log_subscriber {
- /** write the data pointed by @param data */
- void (*write)(struct weston_log_subscriber *sub, const char *data, size_t len);
- /** For the type of streams that required additional destroy operation
- * for destroying the stream */
- void (*destroy)(struct weston_log_subscriber *sub);
- /** For the type of streams that can inform the 'consumer' part that
- * write operation has been terminated/finished and should close the
- * stream.
- */
- void (*complete)(struct weston_log_subscriber *sub);
- struct wl_list subscription_list; /**< weston_log_subscription::owner_link */
-};
-
-void
-weston_log_subscription_create(struct weston_log_subscriber *owner,
- struct weston_log_scope *scope);
-
-void
-weston_log_subscription_destroy(struct weston_log_subscription *sub);
-
-struct weston_log_subscription *
-weston_log_subscriber_get_only_subscription(struct weston_log_subscriber *subscriber);
-
-void
-weston_log_subscription_add(struct weston_log_scope *scope,
- struct weston_log_subscription *sub);
-void
-weston_log_subscription_remove(struct weston_log_subscription *sub);
-
-
-void
-weston_log_bind_weston_debug(struct wl_client *client,
- void *data, uint32_t version, uint32_t id);
-
-struct weston_log_scope *
-weston_log_get_scope(struct weston_log_context *log_ctx, const char *name);
-
-void
-weston_log_run_cb_new_subscription(struct weston_log_subscription *sub);
-
-void
-weston_debug_protocol_advertise_scopes(struct weston_log_context *log_ctx,
- struct wl_resource *res);
-int
-weston_log_ctx_compositor_setup(struct weston_compositor *compositor,
- struct weston_log_context *log_ctx);
-
-int
-weston_vlog(const char *fmt, va_list ap);
-int
-weston_vlog_continue(const char *fmt, va_list ap);
-
-void *
-weston_log_subscription_get_data(struct weston_log_subscription *sub);
-
-void
-weston_log_subscription_set_data(struct weston_log_subscription *sub, void *data);
-
-void
-weston_timeline_create_subscription(struct weston_log_subscription *sub,
- void *user_data);
-
-void
-weston_timeline_destroy_subscription(struct weston_log_subscription *sub,
- void *user_data);
-
-#endif /* WESTON_LOG_INTERNAL_H */
diff --git a/libweston/weston-log-wayland.c b/libweston/weston-log-wayland.c
deleted file mode 100644
index 43fc2885..00000000
--- a/libweston/weston-log-wayland.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright © 2019 Collabora Ltd
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <libweston/weston-log.h>
-#include "shared/helpers.h"
-#include <libweston/libweston.h>
-
-#include "weston-log-internal.h"
-#include "weston-debug-server-protocol.h"
-
-#include <assert.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/time.h>
-
-/** A debug stream created by a client
- *
- * A client provides a file descriptor for the server to write debug messages
- * into. A weston_log_debug_wayland is associated to one weston_log_scope via the
- * scope name, and the scope provides the messages. There can be several
- * streams for the same scope, all streams getting the same messages.
- *
- * The following is specific to weston-debug protocol.
- * Subscription/unsubscription takes place in the stream_create(), respectively
- * in stream_destroy().
- */
-struct weston_log_debug_wayland {
- struct weston_log_subscriber base;
- int fd; /**< client provided fd */
- struct wl_resource *resource; /**< weston_debug_stream_v1 object */
-};
-
-static struct weston_log_debug_wayland *
-to_weston_log_debug_wayland(struct weston_log_subscriber *sub)
-{
- return container_of(sub, struct weston_log_debug_wayland, base);
-}
-
-static void
-stream_close_unlink(struct weston_log_debug_wayland *stream)
-{
- if (stream->fd != -1)
- close(stream->fd);
- stream->fd = -1;
-}
-
-static void WL_PRINTF(2, 3)
-stream_close_on_failure(struct weston_log_debug_wayland *stream,
- const char *fmt, ...)
-{
- char *msg;
- va_list ap;
- int ret;
-
- stream_close_unlink(stream);
-
- va_start(ap, fmt);
- ret = vasprintf(&msg, fmt, ap);
- va_end(ap);
-
- if (ret > 0) {
- weston_debug_stream_v1_send_failure(stream->resource, msg);
- free(msg);
- } else {
- weston_debug_stream_v1_send_failure(stream->resource,
- "MEMFAIL");
- }
-}
-
-/** Write data into a specific debug stream
- *
- * \param sub The subscriber's stream to write into; must not be NULL.
- * \param[in] data Pointer to the data to write.
- * \param len Number of bytes to write.
- *
- * Writes the given data (binary verbatim) into the debug stream.
- * If \c len is zero or negative, the write is silently dropped.
- *
- * Writing is continued until all data has been written or
- * a write fails. If the write fails due to a signal, it is re-tried.
- * Otherwise on failure, the stream is closed and
- * \c weston_debug_stream_v1.failure event is sent to the client.
- *
- * \memberof weston_log_debug_wayland
- */
-static void
-weston_log_debug_wayland_write(struct weston_log_subscriber *sub,
- const char *data, size_t len)
-{
- ssize_t len_ = len;
- ssize_t ret;
- int e;
- struct weston_log_debug_wayland *stream = to_weston_log_debug_wayland(sub);
-
- if (stream->fd == -1)
- return;
-
- while (len_ > 0) {
- ret = write(stream->fd, data, len_);
- e = errno;
- if (ret < 0) {
- if (e == EINTR)
- continue;
-
- stream_close_on_failure(stream,
- "Error writing %zd bytes: %s (%d)",
- len_, strerror(e), e);
- break;
- }
-
- len_ -= ret;
- data += ret;
- }
-}
-
-/** Close the debug stream and send success event
- *
- * \param sub Subscriber's stream to close.
- *
- * Closes the debug stream and sends \c weston_debug_stream_v1.complete
- * event to the client. This tells the client the debug information dump
- * is complete.
- *
- * \memberof weston_log_debug_wayland
- */
-static void
-weston_log_debug_wayland_complete(struct weston_log_subscriber *sub)
-{
- struct weston_log_debug_wayland *stream = to_weston_log_debug_wayland(sub);
-
- stream_close_unlink(stream);
- weston_debug_stream_v1_send_complete(stream->resource);
-}
-
-static void
-weston_log_debug_wayland_to_destroy(struct weston_log_subscriber *sub)
-{
- struct weston_log_debug_wayland *stream = to_weston_log_debug_wayland(sub);
- stream_close_on_failure(stream, "debug name removed");
-}
-
-static struct weston_log_debug_wayland *
-stream_create(struct weston_log_context *log_ctx, const char *name,
- int32_t streamfd, struct wl_resource *stream_resource)
-{
- struct weston_log_debug_wayland *stream;
- struct weston_log_scope *scope;
-
- stream = zalloc(sizeof *stream);
- if (!stream)
- return NULL;
-
- stream->fd = streamfd;
- stream->resource = stream_resource;
-
- stream->base.write = weston_log_debug_wayland_write;
- stream->base.destroy = weston_log_debug_wayland_to_destroy;
- stream->base.complete = weston_log_debug_wayland_complete;
- wl_list_init(&stream->base.subscription_list);
-
- scope = weston_log_get_scope(log_ctx, name);
- if (scope) {
- weston_log_subscription_create(&stream->base, scope);
- } else {
- stream_close_on_failure(stream,
- "Debug stream name '%s' is unknown.",
- name);
- }
-
- return stream;
-}
-
-static void
-stream_destroy(struct wl_resource *stream_resource)
-{
- struct weston_log_debug_wayland *stream;
- struct weston_log_subscription *sub = NULL;
-
- stream = wl_resource_get_user_data(stream_resource);
-
- if (stream->fd != -1)
- close(stream->fd);
-
- sub = weston_log_subscriber_get_only_subscription(&stream->base);
-
- /* we can have a zero subscription if clients tried to subscribe
- * to a non-existent scope */
- if (sub)
- weston_log_subscription_destroy(sub);
-
- free(stream);
-}
-
-static void
-weston_debug_stream_destroy(struct wl_client *client,
- struct wl_resource *stream_resource)
-{
- wl_resource_destroy(stream_resource);
-}
-
-static const struct weston_debug_stream_v1_interface
- weston_debug_stream_impl = {
- weston_debug_stream_destroy
-};
-
-static void
-weston_debug_destroy(struct wl_client *client,
- struct wl_resource *global_resource)
-{
- wl_resource_destroy(global_resource);
-}
-
-static void
-weston_debug_subscribe(struct wl_client *client,
- struct wl_resource *global_resource,
- const char *name,
- int32_t streamfd,
- uint32_t new_stream_id)
-{
- struct weston_log_context *log_ctx;
- struct wl_resource *stream_resource;
- uint32_t version;
- struct weston_log_debug_wayland *stream;
-
- log_ctx = wl_resource_get_user_data(global_resource);
- version = wl_resource_get_version(global_resource);
-
- stream_resource = wl_resource_create(client,
- &weston_debug_stream_v1_interface,
- version, new_stream_id);
- if (!stream_resource)
- goto fail;
-
- stream = stream_create(log_ctx, name, streamfd, stream_resource);
- if (!stream)
- goto fail;
-
- wl_resource_set_implementation(stream_resource,
- &weston_debug_stream_impl,
- stream, stream_destroy);
- return;
-
-fail:
- close(streamfd);
- wl_client_post_no_memory(client);
-}
-
-static const struct weston_debug_v1_interface weston_debug_impl = {
- weston_debug_destroy,
- weston_debug_subscribe
-};
-
-void
-weston_log_bind_weston_debug(struct wl_client *client,
- void *data, uint32_t version, uint32_t id)
-{
- struct weston_log_context *log_ctx = data;
- struct wl_resource *resource;
-
- resource = wl_resource_create(client,
- &weston_debug_v1_interface,
- version, id);
- if (!resource) {
- wl_client_post_no_memory(client);
- return;
- }
- wl_resource_set_implementation(resource, &weston_debug_impl,
- log_ctx, NULL);
-
- weston_debug_protocol_advertise_scopes(log_ctx, resource);
-}
diff --git a/libweston/weston-log.c b/libweston/weston-log.c
deleted file mode 100644
index b2c4597c..00000000
--- a/libweston/weston-log.c
+++ /dev/null
@@ -1,962 +0,0 @@
-/*
- * Copyright © 2017 Pekka Paalanen <pq@iki.fi>
- * Copyright © 2018 Zodiac Inflight Innovations
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <libweston/weston-log.h>
-#include "shared/helpers.h"
-#include <libweston/libweston.h>
-
-#include "weston-log-internal.h"
-#include "weston-debug-server-protocol.h"
-
-#include <assert.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/time.h>
-
-/**
- * @defgroup log Public Logging/Debugging API
- * @defgroup internal-log Private/Internal Logging/Debugging API
- * @defgroup debug-protocol weston-debug protocol specific
- */
-
-/** Main weston-log context
- *
- * One per weston_compositor. Stores list of scopes created and a list pending
- * subscriptions.
- *
- * A pending subscription is a subscription to a scope which hasn't been
- * created. When the scope is finally created the pending subscription will be
- * removed from the pending subscription list, but not before was added in the
- * scope's subscription list and that of the subscriber list.
- *
- * Pending subscriptions only make sense for other types of streams, other than
- * those created by weston-debug protocol. In the case of the weston-debug
- * protocol, the subscription processes is done automatically whenever a client
- * connects and subscribes to a scope which was previously advertised by the
- * compositor.
- *
- * @ingroup internal-log
- */
-struct weston_log_context {
- struct wl_global *global;
- struct wl_list scope_list; /**< weston_log_scope::compositor_link */
- struct wl_list pending_subscription_list; /**< weston_log_subscription::source_link */
-};
-
-/** weston-log message scope
- *
- * This is used for scoping logging/debugging messages. Clients can subscribe
- * to only the scopes they are interested in. A scope is identified by its name
- * (also referred to as debug stream name).
- *
- * @ingroup log
- */
-struct weston_log_scope {
- char *name;
- char *desc;
- weston_log_scope_cb new_subscription;
- weston_log_scope_cb destroy_subscription;
- void *user_data;
- struct wl_list compositor_link;
- struct wl_list subscription_list; /**< weston_log_subscription::source_link */
-};
-
-/** Ties a subscriber to a scope
- *
- * A subscription is created each time we'd want to subscribe to a scope. From
- * the stream type we can retrieve the subscriber and from the subscriber we
- * reach each of the streams callbacks. See also weston_log_subscriber object.
- *
- * When a subscription has been created we store it in the scope's subscription
- * list and in the subscriber's subscription list. The subscription might be a
- * pending subscription until the scope for which there's was a subscribe has
- * been created. The scope creation will take of looking through the pending
- * subscription list.
- *
- * A subscription can reached from a subscriber subscription list by using the
- * streams base class.
- *
- * @ingroup internal-log
- */
-struct weston_log_subscription {
- struct weston_log_subscriber *owner;
- struct wl_list owner_link; /**< weston_log_subscriber::subscription_list */
-
- char *scope_name;
- struct weston_log_scope *source;
- struct wl_list source_link; /**< weston_log_scope::subscription_list or
- weston_log_context::pending_subscription_list */
-
- void *data;
-};
-
-static struct weston_log_subscription *
-find_pending_subscription(struct weston_log_context *log_ctx,
- const char *scope_name)
-{
- struct weston_log_subscription *sub;
-
- wl_list_for_each(sub, &log_ctx->pending_subscription_list, source_link)
- if (!strcmp(sub->scope_name, scope_name))
- return sub;
-
- return NULL;
-}
-
-/** Create a pending subscription and add it the list of pending subscriptions
- *
- * @param owner a subscriber represented by weston_log_subscriber object
- * @param scope_name the name of the scope (which we don't have in the list of scopes)
- * @param log_ctx the logging context used to add the pending subscription
- *
- * @memberof weston_log_subscription
- */
-static void
-weston_log_subscription_create_pending(struct weston_log_subscriber *owner,
- const char *scope_name,
- struct weston_log_context *log_ctx)
-{
- assert(owner);
- assert(scope_name);
- struct weston_log_subscription *sub = zalloc(sizeof(*sub));
-
- if (!sub)
- return;
-
- sub->scope_name = strdup(scope_name);
- sub->owner = owner;
-
- wl_list_insert(&log_ctx->pending_subscription_list, &sub->source_link);
-}
-
-/** Destroys the pending subscription created previously with
- * weston_log_subscription_create_pending()
- *
- * @param sub the weston_log_subscription object to remove from the list
- * of subscriptions and to destroy the subscription
- *
- * @memberof weston_log_subscription
- */
-static void
-weston_log_subscription_destroy_pending(struct weston_log_subscription *sub)
-{
- assert(sub);
- /* pending subsriptions do not have a source */
- wl_list_remove(&sub->source_link);
- free(sub->scope_name);
- free(sub);
-}
-
-/** Write to the stream's subscription
- *
- * @memberof weston_log_subscription
- */
-static void
-weston_log_subscription_write(struct weston_log_subscription *sub,
- const char *data, size_t len)
-{
- if (sub->owner && sub->owner->write)
- sub->owner->write(sub->owner, data, len);
-}
-
-/** Write a formatted string to the stream's subscription
- *
- * @memberof weston_log_subscription
- */
-static void
-weston_log_subscription_vprintf(struct weston_log_subscription *sub,
- const char *fmt, va_list ap)
-{
- static const char oom[] = "Out of memory";
- char *str;
- int len;
-
- if (!weston_log_scope_is_enabled(sub->source))
- return;
-
- len = vasprintf(&str, fmt, ap);
- if (len >= 0) {
- weston_log_subscription_write(sub, str, len);
- free(str);
- } else {
- weston_log_subscription_write(sub, oom, sizeof oom - 1);
- }
-}
-
-void
-weston_log_subscription_set_data(struct weston_log_subscription *sub, void *data)
-{
- /* don't allow data to already be set */
- assert(!sub->data);
- sub->data = data;
-}
-
-void *
-weston_log_subscription_get_data(struct weston_log_subscription *sub)
-{
- return sub->data;
-}
-
-/** Creates a new subscription using the subscriber by \c owner.
- *
- * The subscription created is added to the \c owner subscription list.
- * Destroying the subscription using weston_log_subscription_destroy() will
- * remove the link from the subscription list and free storage alloc'ed.
- *
- * Note that this adds the subscription to the scope's subscription list
- * hence the \c scope required argument.
- *
- * @param owner the subscriber owner, must be created before creating a
- * subscription
- * @param scope the scope in order to add the subscription to the scope's
- * subscription list
- * @returns a weston_log_subscription object in case of success, or NULL
- * otherwise
- *
- * @sa weston_log_subscription_destroy, weston_log_subscription_remove,
- * weston_log_subscription_add
- * @memberof weston_log_subscription
- */
-void
-weston_log_subscription_create(struct weston_log_subscriber *owner,
- struct weston_log_scope *scope)
-{
- struct weston_log_subscription *sub;
- assert(owner);
- assert(scope);
- assert(scope->name);
-
- sub = zalloc(sizeof(*sub));
- if (!sub)
- return;
-
- sub->owner = owner;
- sub->scope_name = strdup(scope->name);
-
- wl_list_insert(&sub->owner->subscription_list, &sub->owner_link);
-
- weston_log_subscription_add(scope, sub);
- weston_log_run_cb_new_subscription(sub);
-}
-
-/** Destroys the subscription
- *
- * Removes the subscription from the scopes subscription list and from
- * subscriber's subscription list. It destroys the subscription afterwads.
- *
- * @memberof weston_log_subscription
- */
-void
-weston_log_subscription_destroy(struct weston_log_subscription *sub)
-{
- assert(sub);
-
- if (sub->source->destroy_subscription)
- sub->source->destroy_subscription(sub, sub->source->user_data);
-
- if (sub->owner)
- wl_list_remove(&sub->owner_link);
-
- weston_log_subscription_remove(sub);
- free(sub->scope_name);
- free(sub);
-}
-
-/** Retrieve a subscription by using the subscriber
- *
- * This is useful when trying to find a subscription from the subscriber by
- * having only access to the stream.
- *
- * @param subscriber the subscriber in question
- * @returns a weston_log_subscription object
- *
- * @memberof weston_log_subscription
- */
-struct weston_log_subscription *
-weston_log_subscriber_get_only_subscription(struct weston_log_subscriber *subscriber)
-{
- struct weston_log_subscription *sub;
- /* unlikely, but can happen */
- if (wl_list_length(&subscriber->subscription_list) == 0)
- return NULL;
-
- assert(wl_list_length(&subscriber->subscription_list) == 1);
-
- return wl_container_of(subscriber->subscription_list.prev,
- sub, owner_link);
-}
-
-/** Adds the subscription \c sub to the subscription list of the
- * scope.
- *
- * This should used when the scope has been created, and the subscription \c
- * sub has be created before calling this function.
- *
- * @param scope the scope
- * @param sub the subscription, it must be created before, see
- * weston_log_subscription_create()
- *
- * @memberof weston_log_subscription
- */
-void
-weston_log_subscription_add(struct weston_log_scope *scope,
- struct weston_log_subscription *sub)
-{
- assert(scope);
- assert(sub);
- /* don't allow subscriptions to have a source already! */
- assert(!sub->source);
-
- sub->source = scope;
- wl_list_insert(&scope->subscription_list, &sub->source_link);
-}
-
-/** Removes the subscription from the scope's subscription list
- *
- * @memberof weston_log_subscription
- */
-void
-weston_log_subscription_remove(struct weston_log_subscription *sub)
-{
- assert(sub);
- if (sub->source)
- wl_list_remove(&sub->source_link);
- sub->source = NULL;
-}
-
-/** Look-up the scope from the scope list stored in the log context, by
- * matching against the \c name.
- *
- * @param log_ctx
- * @param name the scope name, see weston_compositor_add_log_scope()
- * @returns NULL if none found, or a pointer to a weston_log_scope
- *
- * @ingroup internal-log
- */
-struct weston_log_scope *
-weston_log_get_scope(struct weston_log_context *log_ctx, const char *name)
-{
- struct weston_log_scope *scope;
- wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
- if (strcmp(name, scope->name) == 0)
- return scope;
- return NULL;
-}
-
-/** Wrapper to invoke the weston_log_scope_cb. Allows to call the cb
- * new_subscription of a log scope.
- *
- * @ingroup internal-log
- */
-void
-weston_log_run_cb_new_subscription(struct weston_log_subscription *sub)
-{
- if (sub->source->new_subscription)
- sub->source->new_subscription(sub, sub->source->user_data);
-}
-
-/** Advertise the log scope name and the log scope description
- *
- * This is only used by the weston-debug protocol!
- *
- * @ingroup internal-log
- */
-void
-weston_debug_protocol_advertise_scopes(struct weston_log_context *log_ctx,
- struct wl_resource *res)
-{
- struct weston_log_scope *scope;
- wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
- weston_debug_v1_send_available(res, scope->name, scope->desc);
-}
-
-/**
- * Connect weston_compositor structure to weston_log_context structure.
- *
- * \param compositor
- * \param log_ctx
- * \return 0 on success, -1 on failure
- *
- * Sets weston_compositor::weston_log_ctx.
- *
- * @ingroup log
- */
-int
-weston_log_ctx_compositor_setup(struct weston_compositor *compositor,
- struct weston_log_context *log_ctx)
-{
- assert(!compositor->weston_log_ctx);
- assert(log_ctx);
-
- compositor->weston_log_ctx = log_ctx;
- return 0;
-}
-
-/** Creates weston_log_context structure
- *
- * \return NULL in case of failure, or a weston_log_context object in case of
- * success
- *
- * weston_log_context is a singleton for each weston_compositor.
- * @ingroup log
- *
- */
-WL_EXPORT struct weston_log_context *
-weston_log_ctx_compositor_create(void)
-{
- struct weston_log_context *log_ctx;
-
- log_ctx = zalloc(sizeof *log_ctx);
- if (!log_ctx)
- return NULL;
-
- wl_list_init(&log_ctx->scope_list);
- wl_list_init(&log_ctx->pending_subscription_list);
-
- return log_ctx;
-}
-
-/** Destroy weston_log_context structure
- *
- * \param compositor The libweston compositor whose weston-debug to tear down.
- *
- * Clears weston_compositor::weston_log_ctx.
- * @ingroup log
- *
- */
-WL_EXPORT void
-weston_log_ctx_compositor_destroy(struct weston_compositor *compositor)
-{
- struct weston_log_context *log_ctx = compositor->weston_log_ctx;
- struct weston_log_scope *scope;
- struct weston_log_subscription *pending_sub, *pending_sub_tmp;
-
- if (log_ctx->global)
- wl_global_destroy(log_ctx->global);
-
- wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
- fprintf(stderr, "Internal warning: debug scope '%s' has not been destroyed.\n",
- scope->name);
-
- /* Remove head to not crash if scope removed later. */
- wl_list_remove(&log_ctx->scope_list);
-
- /* Remove any pending subscription(s) which nobody subscribed to */
- wl_list_for_each_safe(pending_sub, pending_sub_tmp,
- &log_ctx->pending_subscription_list, source_link) {
- weston_log_subscription_destroy_pending(pending_sub);
- }
-
- /* pending_subscription_list should be empty at this point */
-
- free(log_ctx);
-
- compositor->weston_log_ctx = NULL;
-}
-
-/** Enable weston-debug protocol extension
- *
- * \param compositor The libweston compositor where to enable.
- *
- * This enables the weston_debug_v1 Wayland protocol extension which any client
- * can use to get debug messages from the compositor.
- *
- * WARNING: This feature should not be used in production. If a client
- * provides a file descriptor that blocks writes, it will block the whole
- * compositor indefinitely.
- *
- * There is no control on which client is allowed to subscribe to debug
- * messages. Any and all clients are allowed.
- *
- * The debug extension is disabled by default, and once enabled, cannot be
- * disabled again.
- *
- * @ingroup debug-protocol
- */
-WL_EXPORT void
-weston_compositor_enable_debug_protocol(struct weston_compositor *compositor)
-{
- struct weston_log_context *log_ctx = compositor->weston_log_ctx;
- assert(log_ctx);
- if (log_ctx->global)
- return;
-
- log_ctx->global = wl_global_create(compositor->wl_display,
- &weston_debug_v1_interface, 1,
- log_ctx, weston_log_bind_weston_debug);
- if (!log_ctx->global)
- return;
-
- fprintf(stderr, "WARNING: debug protocol has been enabled. "
- "This is a potential denial-of-service attack vector and "
- "information leak.\n");
-}
-
-/** Determine if the debug protocol has been enabled
- *
- * \param wc The libweston compositor to verify if debug protocol has been
- * enabled
- *
- * @ingroup debug-protocol
- */
-WL_EXPORT bool
-weston_compositor_is_debug_protocol_enabled(struct weston_compositor *wc)
-{
- return wc->weston_log_ctx->global != NULL;
-}
-
-/** Register a new stream name, creating a log scope.
- *
- * @param log_ctx The weston_log_context where to add.
- * @param name The debug stream/scope name; must not be NULL.
- * @param description The log scope description for humans; must not be NULL.
- * @param new_subscription Optional callback when a client subscribes to this
- * scope.
- * @param destroy_subscription Optional callback when a client destroys the
- * subscription.
- * @param user_data Optional user data pointer for the callback.
- * @returns A valid pointer on success, NULL on failure.
- *
- * This function is used to create a log scope. All debug message printing
- * happens for a scope, which allows clients to subscribe to the kind of debug
- * messages they want by \c name. For the weston-debug protocol,
- * subscription for the scope will happen automatically but for other types of
- * streams, weston_log_subscribe() should be called as to create a subscription
- * and tie it to the scope created by this function.
- *
- * \p name must be unique in the weston_compositor instance. \p name
- * and \p description must both be provided. In case of the weston-debug
- * protocol, the description is printed when a client asks for a list of
- * supported log scopes.
- *
- * \p new_subscription, if not NULL, is called when a client subscribes to the log
- * scope creating a debug stream. This is for log scopes that need to print
- * messages as a response to a client appearing, e.g. printing a list of
- * windows on demand or a static preamble. The argument \p user_data is
- * passed in to the callback and is otherwise unused.
- *
- * For one-shot debug streams, \c new_subscription should finally call
- * weston_log_subscription_complete() to close the stream and tell the client
- * the printing is complete. Otherwise the client expects more data to be
- * written. The complete callback in weston_log_subscriber should be installed
- * to trigger it and it is set-up automatically for the weston-debug protocol.
- *
- * As subscription can take place before creating the scope, any pending
- * subscriptions to scope added by weston_log_subscribe(), will be checked
- * against the scope being created and if found will be added to the scope's
- * subscription list.
- *
- * The log scope must be destroyed using weston_compositor_log_scope_destroy()
- * before destroying the weston_compositor.
- *
- * @memberof weston_log_scope
- * @sa weston_log_scope_cb, weston_log_subscribe
- */
-WL_EXPORT struct weston_log_scope *
-weston_compositor_add_log_scope(struct weston_log_context *log_ctx,
- const char *name,
- const char *description,
- weston_log_scope_cb new_subscription,
- weston_log_scope_cb destroy_subscription,
- void *user_data)
-{
- struct weston_log_scope *scope;
- struct weston_log_subscription *pending_sub = NULL;
-
- if (!name || !description) {
- fprintf(stderr, "Error: cannot add a debug scope without name or description.\n");
- return NULL;
- }
-
- if (!log_ctx) {
- fprintf(stderr, "Error: cannot add debug scope '%s', infra not initialized.\n",
- name);
- return NULL;
- }
-
- if (weston_log_get_scope(log_ctx, name)){
- fprintf(stderr, "Error: debug scope named '%s' is already registered.\n",
- name);
- return NULL;
- }
-
- scope = zalloc(sizeof *scope);
- if (!scope) {
- fprintf(stderr, "Error adding debug scope '%s': out of memory.\n",
- name);
- return NULL;
- }
-
- scope->name = strdup(name);
- scope->desc = strdup(description);
- scope->new_subscription = new_subscription;
- scope->destroy_subscription = destroy_subscription;
- scope->user_data = user_data;
- wl_list_init(&scope->subscription_list);
-
- if (!scope->name || !scope->desc) {
- fprintf(stderr, "Error adding debug scope '%s': out of memory.\n",
- name);
- free(scope->name);
- free(scope->desc);
- free(scope);
- return NULL;
- }
-
- wl_list_insert(log_ctx->scope_list.prev, &scope->compositor_link);
-
- /* check if there are any pending subscriptions to this scope */
- while ((pending_sub = find_pending_subscription(log_ctx, scope->name)) != NULL) {
- weston_log_subscription_create(pending_sub->owner, scope);
-
- /* remove it from pending */
- weston_log_subscription_destroy_pending(pending_sub);
- }
-
-
- return scope;
-}
-
-/** Destroy a log scope
- *
- * @param scope The log scope to destroy; may be NULL.
- *
- * Destroys the log scope, calling each stream's destroy callback if one was
- * installed/created.
- *
- * @memberof weston_log_scope
- */
-WL_EXPORT void
-weston_compositor_log_scope_destroy(struct weston_log_scope *scope)
-{
- struct weston_log_subscription *sub, *sub_tmp;
-
- if (!scope)
- return;
-
- wl_list_for_each_safe(sub, sub_tmp, &scope->subscription_list, source_link) {
- /* destroy each subscription */
- if (sub->owner->destroy)
- sub->owner->destroy(sub->owner);
-
- weston_log_subscription_destroy(sub);
- }
-
- wl_list_remove(&scope->compositor_link);
- free(scope->name);
- free(scope->desc);
- free(scope);
-}
-
-/** Are there any active subscriptions to the scope?
- *
- * \param scope The log scope to check; may be NULL.
- * \return True if any streams are open for this scope, false otherwise.
- *
- * As printing some debugging messages may be relatively expensive, one
- * can use this function to determine if there is a need to gather the
- * debugging information at all. If this function returns false, all
- * printing for this scope is dropped, so gathering the information is
- * pointless.
- *
- * The return value of this function should not be stored, as new clients
- * may subscribe to the debug scope later.
- *
- * If the given scope is NULL, this function will always return false,
- * making it safe to use in teardown or destroy code, provided the
- * scope is initialized to NULL before creation and set to NULL after
- * destruction.
- *
- * \memberof weston_log_scope
- */
-WL_EXPORT bool
-weston_log_scope_is_enabled(struct weston_log_scope *scope)
-{
- if (!scope)
- return false;
-
- return !wl_list_empty(&scope->subscription_list);
-}
-
-/** Close the stream's complete callback if one was installed/created.
- *
- * @ingroup log
- */
-WL_EXPORT void
-weston_log_subscription_complete(struct weston_log_subscription *sub)
-{
- if (sub->owner && sub->owner->complete)
- sub->owner->complete(sub->owner);
-}
-
-/** Close the log scope.
- *
- * @param scope The log scope to complete; may be NULL.
- *
- * Complete the log scope, calling each stream's complete callback if one was
- * installed/created. This can be useful to signal the reading end that the
- * data has been transmited and should no longer expect that written over the
- * stream. Particularly useful for the weston-debug protocol.
- *
- * @memberof weston_log_scope
- * @sa weston_compositor_add_log_scope, weston_compositor_log_scope_destroy
- */
-WL_EXPORT void
-weston_log_scope_complete(struct weston_log_scope *scope)
-{
- struct weston_log_subscription *sub;
-
- if (!scope)
- return;
-
- wl_list_for_each(sub, &scope->subscription_list, source_link)
- weston_log_subscription_complete(sub);
-}
-
-/** Write log data for a scope
- *
- * \param scope The debug scope to write for; may be NULL, in which case
- * nothing will be written.
- * \param[in] data Pointer to the data to write.
- * \param len Number of bytes to write.
- *
- * Writes the given data to all subscribed clients' streams.
- *
- * \memberof weston_log_scope
- */
-WL_EXPORT void
-weston_log_scope_write(struct weston_log_scope *scope,
- const char *data, size_t len)
-{
- struct weston_log_subscription *sub;
-
- if (!scope)
- return;
-
- wl_list_for_each(sub, &scope->subscription_list, source_link)
- weston_log_subscription_write(sub, data, len);
-}
-
-/** Write a formatted string for a scope (varargs)
- *
- * \param scope The log scope to write for; may be NULL, in which case
- * nothing will be written.
- * \param fmt Printf-style format string.
- * \param ap Formatting arguments.
- *
- * Writes to formatted string to all subscribed clients' streams.
- *
- * The behavioral details for each stream are the same as for
- * weston_debug_stream_write().
- *
- * \memberof weston_log_scope
- */
-WL_EXPORT int
-weston_log_scope_vprintf(struct weston_log_scope *scope,
- const char *fmt, va_list ap)
-{
- static const char oom[] = "Out of memory";
- char *str;
- int len = 0;
-
- if (!weston_log_scope_is_enabled(scope))
- return len;
-
- len = vasprintf(&str, fmt, ap);
- if (len >= 0) {
- weston_log_scope_write(scope, str, len);
- free(str);
- } else {
- weston_log_scope_write(scope, oom, sizeof oom - 1);
- }
-
- return len;
-}
-
-/** Write a formatted string for a scope
- *
- * \param scope The log scope to write for; may be NULL, in which case
- * nothing will be written.
- * \param fmt Printf-style format string and arguments.
- *
- * Writes to formatted string to all subscribed clients' streams.
- *
- * The behavioral details for each stream are the same as for
- * weston_debug_stream_write().
- *
- * \memberof weston_log_scope
- */
-WL_EXPORT int
-weston_log_scope_printf(struct weston_log_scope *scope,
- const char *fmt, ...)
-{
- va_list ap;
- int len;
-
- va_start(ap, fmt);
- len = weston_log_scope_vprintf(scope, fmt, ap);
- va_end(ap);
-
- return len;
-}
-
-/** Write a formatted string for a subscription
- *
- * \param sub The subscription to write for; may be NULL, in which case
- * nothing will be written.
- * \param fmt Printf-style format string and arguments.
- *
- * Writes to formatted string to the stream that created the subscription.
- *
- * @ingroup log
- */
-WL_EXPORT void
-weston_log_subscription_printf(struct weston_log_subscription *sub,
- const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- weston_log_subscription_vprintf(sub, fmt, ap);
- va_end(ap);
-}
-
-/** Write debug scope name and current time into string
- *
- * \param[in] scope debug scope; may be NULL
- * \param[out] buf Buffer to store the string.
- * \param len Available size in the buffer in bytes.
- * \return \c buf
- *
- * Reads the current local wall-clock time and formats it into a string.
- * and append the debug scope name to it, if a scope is available.
- * The string is NUL-terminated, even if truncated.
- *
- * @memberof weston_log_scope
- */
-WL_EXPORT char *
-weston_log_scope_timestamp(struct weston_log_scope *scope,
- char *buf, size_t len)
-{
- struct timeval tv;
- struct tm *bdt;
- char string[128];
- size_t ret = 0;
-
- gettimeofday(&tv, NULL);
-
- bdt = localtime(&tv.tv_sec);
- if (bdt)
- ret = strftime(string, sizeof string,
- "%Y-%m-%d %H:%M:%S", bdt);
-
- if (ret > 0) {
- snprintf(buf, len, "[%s.%03ld][%s]", string,
- tv.tv_usec / 1000,
- (scope) ? scope->name : "no scope");
- } else {
- snprintf(buf, len, "[?][%s]",
- (scope) ? scope->name : "no scope");
- }
-
- return buf;
-}
-
-/** Subscribe to a scope
- *
- * Creates a subscription which is used to subscribe the \p subscriber
- * to the scope \c scope_name.
- *
- * If \c scope_name has already been created (using
- * weston_compositor_add_log_scope) the subscription will take place
- * immediately, otherwise we store the subscription into a pending list. See
- * also weston_compositor_add_log_scope().
- *
- * @param log_ctx the log context, used for accessing pending list
- * @param subscriber the subscriber, which has to be created before
- * @param scope_name the scope name. In case the scope is not created
- * we temporarily store the subscription in the pending list.
- *
- * @ingroup log
- */
-WL_EXPORT void
-weston_log_subscribe(struct weston_log_context *log_ctx,
- struct weston_log_subscriber *subscriber,
- const char *scope_name)
-{
- assert(log_ctx);
- assert(subscriber);
- assert(scope_name);
-
- struct weston_log_scope *scope;
-
- scope = weston_log_get_scope(log_ctx, scope_name);
- if (scope)
- weston_log_subscription_create(subscriber, scope);
- else
- /*
- * if we don't have already as scope for it, add it to pending
- * subscription list
- */
- weston_log_subscription_create_pending(subscriber, scope_name, log_ctx);
-}
-
-/** Iterate over all subscriptions in a scope
- *
- * @param scope the scope for which you want to iterate
- * @param sub_iter the iterator, use NULL to start from the 'head'
- * @returns the next subscription from the log scope
- *
- * This is (quite) useful when 'log_scope' and 'log_subscription' are opaque. Do note
- * that \c sub_iter needs to be NULL-initialized before calling this function.
- *
- */
-WL_EXPORT struct weston_log_subscription *
-weston_log_subscription_iterate(struct weston_log_scope *scope,
- struct weston_log_subscription *sub_iter)
-{
- struct wl_list *list = &scope->subscription_list;
- struct wl_list *node;
-
- /* go to the next item in the list or if not set starts with the head */
- if (sub_iter)
- node = sub_iter->source_link.next;
- else
- node = list->next;
-
- assert(node);
- assert(!sub_iter || node != &sub_iter->source_link);
-
- /* if we're at the end */
- if (node == list)
- return NULL;
-
- return container_of(node, struct weston_log_subscription, source_link);
-}
diff --git a/libweston/zoom.c b/libweston/zoom.c
deleted file mode 100644
index 064d6a84..00000000
--- a/libweston/zoom.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright © 2012 Scott Moreau
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdbool.h>
-
-#include <libweston/libweston.h>
-#include "backend.h"
-#include "libweston-internal.h"
-#include "text-cursor-position-server-protocol.h"
-#include "shared/helpers.h"
-
-static void
-weston_zoom_frame_z(struct weston_animation *animation,
- struct weston_output *output,
- const struct timespec *time)
-{
- if (animation->frame_counter <= 1)
- output->zoom.spring_z.timestamp = *time;
-
- weston_spring_update(&output->zoom.spring_z, time);
-
- if (output->zoom.spring_z.current > output->zoom.max_level)
- output->zoom.spring_z.current = output->zoom.max_level;
- else if (output->zoom.spring_z.current < 0.0)
- output->zoom.spring_z.current = 0.0;
-
- if (weston_spring_done(&output->zoom.spring_z)) {
- if (output->zoom.active && output->zoom.level <= 0.0) {
- output->zoom.active = false;
- output->zoom.seat = NULL;
- weston_output_disable_planes_decr(output);
- wl_list_remove(&output->zoom.motion_listener.link);
- }
- output->zoom.spring_z.current = output->zoom.level;
- wl_list_remove(&animation->link);
- wl_list_init(&animation->link);
- }
-
- output->dirty = 1;
- weston_output_damage(output);
-}
-
-static void
-zoom_area_center_from_point(struct weston_output *output,
- double *x, double *y)
-{
- float level = output->zoom.spring_z.current;
-
- *x = (*x - output->x) * level + output->width / 2.;
- *y = (*y - output->y) * level + output->height / 2.;
-}
-
-static void
-weston_output_update_zoom_transform(struct weston_output *output)
-{
- double x = output->zoom.current.x; /* global pointer coords */
- double y = output->zoom.current.y;
- float level;
-
- level = output->zoom.spring_z.current;
-
- if (!output->zoom.active || level > output->zoom.max_level ||
- level == 0.0f)
- return;
-
- zoom_area_center_from_point(output, &x, &y);
-
- output->zoom.trans_x = x - output->width / 2;
- output->zoom.trans_y = y - output->height / 2;
-
- if (output->zoom.trans_x < 0)
- output->zoom.trans_x = 0;
- if (output->zoom.trans_y < 0)
- output->zoom.trans_y = 0;
- if (output->zoom.trans_x > level * output->width)
- output->zoom.trans_x = level * output->width;
- if (output->zoom.trans_y > level * output->height)
- output->zoom.trans_y = level * output->height;
-}
-
-static void
-weston_zoom_transition(struct weston_output *output)
-{
- if (output->zoom.level != output->zoom.spring_z.current) {
- output->zoom.spring_z.target = output->zoom.level;
- if (wl_list_empty(&output->zoom.animation_z.link)) {
- output->zoom.animation_z.frame_counter = 0;
- wl_list_insert(output->animation_list.prev,
- &output->zoom.animation_z.link);
- }
- }
-
- output->dirty = 1;
- weston_output_damage(output);
-}
-
-WL_EXPORT void
-weston_output_update_zoom(struct weston_output *output)
-{
- struct weston_seat *seat = output->zoom.seat;
- struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
- if (!pointer)
- return;
-
- assert(output->zoom.active);
-
- output->zoom.current.x = wl_fixed_to_double(pointer->x);
- output->zoom.current.y = wl_fixed_to_double(pointer->y);
-
- weston_zoom_transition(output);
- weston_output_update_zoom_transform(output);
-}
-
-static void
-motion(struct wl_listener *listener, void *data)
-{
- struct weston_output_zoom *zoom =
- container_of(listener, struct weston_output_zoom, motion_listener);
- struct weston_output *output =
- container_of(zoom, struct weston_output, zoom);
-
- weston_output_update_zoom(output);
-}
-
-WL_EXPORT void
-weston_output_activate_zoom(struct weston_output *output,
- struct weston_seat *seat)
-{
- struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
- if (!pointer || output->zoom.active)
- return;
-
- output->zoom.active = true;
- output->zoom.seat = seat;
- weston_output_disable_planes_incr(output);
- wl_signal_add(&pointer->motion_signal,
- &output->zoom.motion_listener);
-}
-
-WL_EXPORT void
-weston_output_init_zoom(struct weston_output *output)
-{
- output->zoom.active = false;
- output->zoom.seat = NULL;
- output->zoom.increment = 0.07;
- output->zoom.max_level = 0.95;
- output->zoom.level = 0.0;
- output->zoom.trans_x = 0.0;
- output->zoom.trans_y = 0.0;
- weston_spring_init(&output->zoom.spring_z, 250.0, 0.0, 0.0);
- output->zoom.spring_z.friction = 1000;
- output->zoom.animation_z.frame = weston_zoom_frame_z;
- wl_list_init(&output->zoom.animation_z.link);
- output->zoom.motion_listener.notify = motion;
-}