Control: tags -1 moreinfo confirmed

On 2023-04-28 11:26:00 +0200, Jochen Sprickerhof wrote:
> Package: release.debian.org
> Severity: normal
> User: [email protected]
> Usertags: unblock
> X-Debbugs-Cc: [email protected], Birger Schacht 
> <[email protected]>
> Control: affects -1 + src:xdg-desktop-portal-wlr
> 
> Please unblock package xdg-desktop-portal-wlr
> 
> [ Reason ]
> Latest Chromium in testing fails to screen share with
> xdg-desktop-portal-wlr. This is fixed with xdg-desktop-portal-wlr 0.7.0.

ACK. Please remove the moreinfo tag once the package is available in
unstable.

Cheers

> 
> [ Impact ]
> Wayland Chromium users would not be able to share their screen.
> 
> [ Tests ]
> Only manually tests that screen share works with Chromium and Firefox.
> 
> [ Risks ]
> Small no package depend on xdg-desktop-portal-wlr.
> 
> [ Checklist ]
>   [X] all changes are documented in the d/changelog
>   [X] I reviewed all changes and I approve them
>   [X] attach debdiff against the package in testing
> 
> [ Other info ]
> I think it is better to import the new upstream version instead of
> trying to extract single patches as changes are mostly for fixing this
> issue.
> 
> unblock xdg-desktop-portal-wlr/0.7.0-1

> diff -Nru xdg-desktop-portal-wlr-0.6.0/debian/changelog 
> xdg-desktop-portal-wlr-0.7.0/debian/changelog
> --- xdg-desktop-portal-wlr-0.6.0/debian/changelog     2022-07-02 
> 10:11:20.000000000 +0200
> +++ xdg-desktop-portal-wlr-0.7.0/debian/changelog     2023-04-28 
> 10:59:18.000000000 +0200
> @@ -1,3 +1,11 @@
> +xdg-desktop-portal-wlr (0.7.0-1) unstable; urgency=medium
> +
> +  * Team upload
> +  * New upstream release.
> +    - fixes screen sharing with latest chromium. (Closes: #1034735)
> +
> + -- Jochen Sprickerhof <[email protected]>  Fri, 28 Apr 2023 10:59:18 +0200
> +
>  xdg-desktop-portal-wlr (0.6.0-1) unstable; urgency=medium
>  
>    * New upstream release
> diff -Nru xdg-desktop-portal-wlr-0.6.0/include/screencast_common.h 
> xdg-desktop-portal-wlr-0.7.0/include/screencast_common.h
> --- xdg-desktop-portal-wlr-0.6.0/include/screencast_common.h  2022-06-09 
> 11:25:25.000000000 +0200
> +++ xdg-desktop-portal-wlr-0.7.0/include/screencast_common.h  2023-04-15 
> 10:32:26.000000000 +0200
> @@ -11,7 +11,8 @@
>  
>  // this seems to be right based on
>  // 
> https://github.com/flatpak/xdg-desktop-portal/blob/309a1fc0cf2fb32cceb91dbc666d20cf0a3202c2/src/screen-cast.c#L955
> -#define XDP_CAST_PROTO_VER 2
> +#define XDP_CAST_PROTO_VER 4
> +#define XDP_CAST_DATA_VER 1
>  
>  enum cursor_modes {
>    HIDDEN = 1,
> @@ -24,6 +25,12 @@
>    WINDOW = 2,
>  };
>  
> +enum persist_modes {
> +  PERSIST_NONE = 0,
> +  PERSIST_TRANSIENT = 1,
> +  PERSIST_PERMANENT = 2,
> +};
> +
>  enum buffer_type {
>    WL_SHM = 0,
>    DMABUF = 1,
> @@ -60,7 +67,8 @@
>       bool y_invert;
>       uint64_t tv_sec;
>       uint32_t tv_nsec;
> -     struct xdpw_frame_damage damage;
> +     struct xdpw_frame_damage damage[4];
> +     uint32_t damage_count;
>       struct xdpw_buffer *xdpw_buffer;
>       struct pw_buffer *pw_buffer;
>  };
> @@ -116,7 +124,6 @@
>       struct wl_list output_list;
>       struct wl_registry *registry;
>       struct zwlr_screencopy_manager_v1 *screencopy_manager;
> -     struct zxdg_output_manager_v1 *xdg_output_manager;
>       struct wl_shm *shm;
>       struct zwp_linux_dmabuf_v1 *linux_dmabuf;
>       struct zwp_linux_dmabuf_feedback_v1 *linux_dmabuf_feedback;
> @@ -130,6 +137,16 @@
>       struct wl_list screencast_instances;
>  };
>  
> +struct xdpw_screencast_target {
> +     struct xdpw_wlr_output *output;
> +     bool with_cursor;
> +};
> +
> +struct xdpw_screencast_restore_data {
> +     uint32_t version;
> +     const char *output_name;
> +};
> +
>  struct xdpw_screencast_instance {
>       // list
>       struct wl_list link;
> @@ -154,11 +171,10 @@
>  
>       // wlroots
>       struct zwlr_screencopy_frame_v1 *frame_callback;
> -     struct xdpw_wlr_output *target_output;
> +     struct xdpw_screencast_target *target;
>       uint32_t max_framerate;
>       struct zwlr_screencopy_frame_v1 *wlr_frame;
>       struct xdpw_screencopy_frame_info screencopy_frame_info[2];
> -     bool with_cursor;
>       int err;
>       bool quit;
>       bool teardown;
> @@ -168,17 +184,23 @@
>       struct fps_limit_state fps_limit;
>  };
>  
> +struct xdpw_screencast_session_data {
> +     struct xdpw_screencast_instance *screencast_instance;
> +     uint32_t cursor_mode;
> +     uint32_t persist_mode;
> +};
> +
>  struct xdpw_wlr_output {
>       struct wl_list link;
>       uint32_t id;
>       struct wl_output *output;
> -     struct zxdg_output_v1 *xdg_output;
>       char *make;
>       char *model;
>       char *name;
>       int width;
>       int height;
>       float framerate;
> +     enum wl_output_transform transformation;
>  };
>  
>  void randname(char *buf);
> @@ -195,4 +217,6 @@
>  
>  enum xdpw_chooser_types get_chooser_type(const char *chooser_type);
>  const char *chooser_type_str(enum xdpw_chooser_types chooser_type);
> +
> +struct xdpw_frame_damage merge_damage(struct xdpw_frame_damage *damage1, 
> struct xdpw_frame_damage *damage2);
>  #endif /* SCREENCAST_COMMON_H */
> diff -Nru xdg-desktop-portal-wlr-0.6.0/include/screenshot_common.h 
> xdg-desktop-portal-wlr-0.7.0/include/screenshot_common.h
> --- xdg-desktop-portal-wlr-0.6.0/include/screenshot_common.h  1970-01-01 
> 01:00:00.000000000 +0100
> +++ xdg-desktop-portal-wlr-0.7.0/include/screenshot_common.h  2023-04-15 
> 10:32:26.000000000 +0200
> @@ -0,0 +1,6 @@
> +#ifndef SCREENSHOT_COMMON_H
> +#define SCREENSHOT_COMMON_H
> +
> +#define XDP_SHOT_PROTO_VER 1
> +
> +#endif
> diff -Nru xdg-desktop-portal-wlr-0.6.0/include/wlr_screencast.h 
> xdg-desktop-portal-wlr-0.7.0/include/wlr_screencast.h
> --- xdg-desktop-portal-wlr-0.6.0/include/wlr_screencast.h     2022-06-09 
> 11:25:25.000000000 +0200
> +++ xdg-desktop-portal-wlr-0.7.0/include/wlr_screencast.h     2023-04-15 
> 10:32:26.000000000 +0200
> @@ -3,15 +3,13 @@
>  
>  #include "screencast_common.h"
>  
> -#define WL_OUTPUT_VERSION 1
> +#define WL_OUTPUT_VERSION 4
>  
>  #define SC_MANAGER_VERSION 3
>  #define SC_MANAGER_VERSION_MIN 2
>  
>  #define WL_SHM_VERSION 1
>  
> -#define XDG_OUTPUT_MANAGER_VERSION 3
> -
>  #define LINUX_DMABUF_VERSION 4
>  #define LINUX_DMABUF_VERSION_MIN 3
>  
> @@ -20,12 +18,9 @@
>  int xdpw_wlr_screencopy_init(struct xdpw_state *state);
>  void xdpw_wlr_screencopy_finish(struct xdpw_screencast_context *ctx);
>  
> -struct xdpw_wlr_output *xdpw_wlr_output_find_by_name(struct wl_list 
> *output_list,
> -     const char *name);
> -struct xdpw_wlr_output *xdpw_wlr_output_first(struct wl_list *output_list);
> -struct xdpw_wlr_output *xdpw_wlr_output_find(struct xdpw_screencast_context 
> *ctx,
> -     struct wl_output *out, uint32_t id);
> -struct xdpw_wlr_output *xdpw_wlr_output_chooser(struct 
> xdpw_screencast_context *ctx);
> +bool xdpw_wlr_target_chooser(struct xdpw_screencast_context *ctx, struct 
> xdpw_screencast_target *target);
> +bool xdpw_wlr_target_from_data(struct xdpw_screencast_context *ctx, struct 
> xdpw_screencast_target *target,
> +             struct xdpw_screencast_restore_data *data);
>  
>  void xdpw_wlr_frame_finish(struct xdpw_screencast_instance *cast);
>  void xdpw_wlr_frame_start(struct xdpw_screencast_instance *cast);
> diff -Nru xdg-desktop-portal-wlr-0.6.0/include/xdpw.h 
> xdg-desktop-portal-wlr-0.7.0/include/xdpw.h
> --- xdg-desktop-portal-wlr-0.6.0/include/xdpw.h       2022-06-09 
> 11:25:25.000000000 +0200
> +++ xdg-desktop-portal-wlr-0.7.0/include/xdpw.h       2023-04-15 
> 10:32:26.000000000 +0200
> @@ -11,6 +11,7 @@
>  #endif
>  
>  #include "screencast_common.h"
> +#include "screenshot_common.h"
>  #include "config.h"
>  
>  struct xdpw_state {
> @@ -22,6 +23,7 @@
>       uint32_t screencast_source_types; // bitfield of enum source_types
>       uint32_t screencast_cursor_modes; // bitfield of enum cursor_modes
>       uint32_t screencast_version;
> +     uint32_t screenshot_version;
>       struct xdpw_config *config;
>       int timer_poll_fd;
>       struct wl_list timers;
> @@ -36,7 +38,7 @@
>       struct wl_list link;
>       sd_bus_slot *slot;
>       char *session_handle;
> -     struct xdpw_screencast_instance *screencast_instance;
> +     struct xdpw_screencast_session_data screencast_data;
>  };
>  
>  typedef void (*xdpw_event_loop_timer_func_t)(void *data);
> diff -Nru xdg-desktop-portal-wlr-0.6.0/meson.build 
> xdg-desktop-portal-wlr-0.7.0/meson.build
> --- xdg-desktop-portal-wlr-0.6.0/meson.build  2022-06-09 11:25:25.000000000 
> +0200
> +++ xdg-desktop-portal-wlr-0.7.0/meson.build  2023-04-15 10:32:26.000000000 
> +0200
> @@ -1,7 +1,7 @@
>  project(
>       'xdg-desktop-portal-wlr',
>       'c',
> -     version: '0.6.0',
> +     version: '0.7.0',
>       license: 'MIT',
>       meson_version: '>=0.58.0',
>       default_options: ['c_std=c11', 'warning_level=2', 'werror=true'],
> @@ -23,7 +23,7 @@
>  inc = include_directories('include')
>  
>  rt = cc.find_library('rt')
> -pipewire = dependency('libpipewire-0.3', version: '>= 0.3.41')
> +pipewire = dependency('libpipewire-0.3', version: '>= 0.3.62')
>  wayland_client = dependency('wayland-client')
>  wayland_protos = dependency('wayland-protocols', version: '>=1.24')
>  iniparser = dependency('inih')
> @@ -36,12 +36,6 @@
>       epoll = dependency('epoll-shim')
>  endif
>  
> -if pipewire.version() == '0.3.49'
> -        add_project_arguments(cc.get_supported_arguments([
> -                '-D_GNU_SOURCE',
> -        ]), language: 'c')
> -endif
> -
>  if get_option('sd-bus-provider') == 'auto'
>       assert(get_option('auto_features').auto(), 'sd-bus-provider must not be 
> set to auto since auto_features != auto')
>       sdbus = dependency('libsystemd',
> @@ -136,7 +130,7 @@
>       install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal', 
> 'portals'),
>  )
>  
> -scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 
> 1.9.7')
> +scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 
> 1.9.7', native: true)
>  if scdoc.found()
>       man_pages = ['xdg-desktop-portal-wlr.5.scd']
>       foreach src : man_pages
> diff -Nru xdg-desktop-portal-wlr-0.6.0/README.md 
> xdg-desktop-portal-wlr-0.7.0/README.md
> --- xdg-desktop-portal-wlr-0.6.0/README.md    2022-06-09 11:25:25.000000000 
> +0200
> +++ xdg-desktop-portal-wlr-0.7.0/README.md    2023-04-15 10:32:26.000000000 
> +0200
> @@ -1,6 +1,6 @@
>  # xdg-desktop-portal-wlr
>  
> -[![builds.sr.ht 
> status](https://builds.sr.ht/~emersion/xdg-desktop-portal-wlr/commits.svg)](https://builds.sr.ht/~emersion/xdg-desktop-portal-wlr/commits?)
> +[![builds.sr.ht 
> status](https://builds.sr.ht/~emersion/xdg-desktop-portal-wlr/commits/master.svg)](https://builds.sr.ht/~emersion/xdg-desktop-portal-wlr/commits/master?)
>  
>  [xdg-desktop-portal] backend for wlroots
>  
> diff -Nru xdg-desktop-portal-wlr-0.6.0/src/core/main.c 
> xdg-desktop-portal-wlr-0.7.0/src/core/main.c
> --- xdg-desktop-portal-wlr-0.6.0/src/core/main.c      2022-06-09 
> 11:25:25.000000000 +0200
> +++ xdg-desktop-portal-wlr-0.7.0/src/core/main.c      2023-04-15 
> 10:32:26.000000000 +0200
> @@ -119,12 +119,18 @@
>               .screencast_source_types = MONITOR,
>               .screencast_cursor_modes = HIDDEN | EMBEDDED,
>               .screencast_version = XDP_CAST_PROTO_VER,
> +             .screenshot_version = XDP_SHOT_PROTO_VER,
>               .config = &config,
>       };
>  
>       wl_list_init(&state.xdpw_sessions);
>  
> -     xdpw_screenshot_init(&state);
> +     ret = xdpw_screenshot_init(&state);
> +     if (ret < 0) {
> +             logprint(ERROR, "xdpw: failed to initialize screenshot");
> +             goto error;
> +     }
> +
>       ret = xdpw_screencast_init(&state);
>       if (ret < 0) {
>               logprint(ERROR, "xdpw: failed to initialize screencast");
> diff -Nru xdg-desktop-portal-wlr-0.6.0/src/core/session.c 
> xdg-desktop-portal-wlr-0.7.0/src/core/session.c
> --- xdg-desktop-portal-wlr-0.6.0/src/core/session.c   2022-06-09 
> 11:25:25.000000000 +0200
> +++ xdg-desktop-portal-wlr-0.7.0/src/core/session.c   2023-04-15 
> 10:32:26.000000000 +0200
> @@ -61,7 +61,7 @@
>       if (!sess) {
>               return;
>       }
> -     struct xdpw_screencast_instance *cast = sess->screencast_instance;
> +     struct xdpw_screencast_instance *cast = 
> sess->screencast_data.screencast_instance;
>       if (cast) {
>               assert(cast->refcount > 0);
>               --cast->refcount;
> diff -Nru xdg-desktop-portal-wlr-0.6.0/src/screencast/pipewire_screencast.c 
> xdg-desktop-portal-wlr-0.7.0/src/screencast/pipewire_screencast.c
> --- xdg-desktop-portal-wlr-0.6.0/src/screencast/pipewire_screencast.c 
> 2022-06-09 11:25:25.000000000 +0200
> +++ xdg-desktop-portal-wlr-0.7.0/src/screencast/pipewire_screencast.c 
> 2023-04-15 10:32:26.000000000 +0200
> @@ -1,10 +1,12 @@
>  #include "pipewire_screencast.h"
>  
>  #include <pipewire/pipewire.h>
> +#include <spa/buffer/meta.h>
>  #include <spa/utils/result.h>
>  #include <spa/param/props.h>
>  #include <spa/param/format-utils.h>
>  #include <spa/param/video/format-utils.h>
> +#include <spa/pod/dynamic.h>
>  #include <sys/mman.h>
>  #include <unistd.h>
>  #include <assert.h>
> @@ -139,7 +141,7 @@
>       return ret;
>  }
>  
> -static uint32_t build_formats(struct spa_pod_builder *b, struct 
> xdpw_screencast_instance *cast,
> +static uint32_t build_formats(struct spa_pod_builder *b[static 2], struct 
> xdpw_screencast_instance *cast,
>               const struct spa_pod *params[static 2]) {
>       uint32_t param_count;
>       uint32_t modifier_count;
> @@ -148,17 +150,20 @@
>       if (!cast->avoid_dmabufs &&
>                       build_modifierlist(cast, 
> cast->screencopy_frame_info[DMABUF].format, &modifiers, &modifier_count) && 
> modifier_count > 0) {
>               param_count = 2;
> -             params[0] = build_format(b, 
> xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[DMABUF].format),
> +             params[0] = build_format(b[0], 
> xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[DMABUF].format),
>                               cast->screencopy_frame_info[DMABUF].width, 
> cast->screencopy_frame_info[DMABUF].height, cast->framerate,
>                               modifiers, modifier_count);
> -             params[1] = build_format(b, 
> xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[WL_SHM].format),
> +             assert(params[0] != NULL);
> +             params[1] = build_format(b[1], 
> xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[WL_SHM].format),
>                               cast->screencopy_frame_info[WL_SHM].width, 
> cast->screencopy_frame_info[WL_SHM].height, cast->framerate,
>                               NULL, 0);
> +             assert(params[1] != NULL);
>       } else {
>               param_count = 1;
> -             params[0] = build_format(b, 
> xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[WL_SHM].format),
> +             params[0] = build_format(b[0], 
> xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[WL_SHM].format),
>                               cast->screencopy_frame_info[WL_SHM].width, 
> cast->screencopy_frame_info[WL_SHM].height, cast->framerate,
>                               NULL, 0);
> +             assert(params[0] != NULL);
>       }
>       free(modifiers);
>       return param_count;
> @@ -196,10 +201,9 @@
>       logprint(TRACE, "pipewire: stream parameters changed");
>       struct xdpw_screencast_instance *cast = data;
>       struct pw_stream *stream = cast->stream;
> -     uint8_t params_buffer[1024];
> -     struct spa_pod_builder b =
> -             SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
> -     const struct spa_pod *params[3];
> +     uint8_t params_buffer[3][1024];
> +     struct spa_pod_dynamic_builder b[3];
> +     const struct spa_pod *params[4];
>       uint32_t blocks;
>       uint32_t data_type;
>  
> @@ -207,6 +211,10 @@
>               return;
>       }
>  
> +     spa_pod_dynamic_builder_init(&b[0], params_buffer[0], 
> sizeof(params_buffer[0]), 2048);
> +     spa_pod_dynamic_builder_init(&b[1], params_buffer[1], 
> sizeof(params_buffer[1]), 2048);
> +     spa_pod_dynamic_builder_init(&b[2], params_buffer[2], 
> sizeof(params_buffer[2]), 2048);
> +
>       spa_format_video_raw_parse(param, &cast->pwr_format);
>       cast->framerate = (uint32_t)(cast->pwr_format.max_framerate.num / 
> cast->pwr_format.max_framerate.denom);
>  
> @@ -224,6 +232,7 @@
>                       uint32_t flags = GBM_BO_USE_RENDERING;
>                       uint64_t modifier;
>                       uint32_t n_params;
> +                     struct spa_pod_builder *builder[2] = {&b[0].b, &b[1].b};
>  
>                       struct gbm_bo *bo = 
> gbm_bo_create_with_modifiers2(cast->ctx->gbm,
>                               
> cast->screencopy_frame_info[cast->buffer_type].width, 
> cast->screencopy_frame_info[cast->buffer_type].height,
> @@ -241,6 +250,9 @@
>                                       flags = 
> cast->ctx->state->config->screencast_conf.force_mod_linear ?
>                                               GBM_BO_USE_RENDERING | 
> GBM_BO_USE_LINEAR : GBM_BO_USE_RENDERING;
>                                       break;
> +                             case DRM_FORMAT_MOD_LINEAR:
> +                                     flags = GBM_BO_USE_RENDERING | 
> GBM_BO_USE_LINEAR;
> +                                     break;
>                               default:
>                                       continue;
>                               }
> @@ -257,18 +269,24 @@
>                       logprint(WARN, "pipewire: unable to allocate a dmabuf. 
> Falling back to shm");
>                       cast->avoid_dmabufs = true;
>  
> -                     n_params = build_formats(&b, cast, &params[0]);
> +                     n_params = build_formats(builder, cast, &params[0]);
>                       pw_stream_update_params(stream, params, n_params);
> +                     spa_pod_dynamic_builder_clean(&b[0]);
> +                     spa_pod_dynamic_builder_clean(&b[1]);
> +                     spa_pod_dynamic_builder_clean(&b[2]);
>                       return;
>  
>  fixate_format:
> -                     params[0] = fixate_format(&b, 
> xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[cast->buffer_type].format),
> +                     params[0] = fixate_format(&b[2].b, 
> xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[cast->buffer_type].format),
>                                       
> cast->screencopy_frame_info[cast->buffer_type].width, 
> cast->screencopy_frame_info[cast->buffer_type].height, cast->framerate, 
> &modifier);
>  
> -                     n_params = build_formats(&b, cast, &params[1]);
> +                     n_params = build_formats(builder, cast, &params[1]);
>                       n_params++;
>  
>                       pw_stream_update_params(stream, params, n_params);
> +                     spa_pod_dynamic_builder_clean(&b[0]);
> +                     spa_pod_dynamic_builder_clean(&b[1]);
> +                     spa_pod_dynamic_builder_clean(&b[2]);
>                       return;
>               }
>  
> @@ -291,20 +309,37 @@
>       logprint(DEBUG, "pipewire: size: (%u, %u)", 
> cast->pwr_format.size.width, cast->pwr_format.size.height);
>       logprint(DEBUG, "pipewire: max_framerate: (%u / %u)", 
> cast->pwr_format.max_framerate.num, cast->pwr_format.max_framerate.denom);
>  
> -     params[0] = build_buffer(&b, blocks, 
> cast->screencopy_frame_info[cast->buffer_type].size,
> +     params[0] = build_buffer(&b[0].b, blocks, 
> cast->screencopy_frame_info[cast->buffer_type].size,
>                       cast->screencopy_frame_info[cast->buffer_type].stride, 
> data_type);
>  
> -     params[1] = spa_pod_builder_add_object(&b,
> +     params[1] = spa_pod_builder_add_object(&b[1].b,
>               SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
>               SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header),
>               SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct 
> spa_meta_header)));
>  
> -     pw_stream_update_params(stream, params, 2);
> +     params[2] = spa_pod_builder_add_object(&b[1].b,
> +             SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
> +             SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoTransform),
> +             SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct 
> spa_meta_videotransform)));
> +
> +     params[3] = spa_pod_builder_add_object(&b[2].b,
> +             SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
> +             SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoDamage),
> +             SPA_PARAM_META_size, SPA_POD_CHOICE_RANGE_Int(
> +                     sizeof(struct spa_meta_region) * 4,
> +                     sizeof(struct spa_meta_region) * 1,
> +                     sizeof(struct spa_meta_region) * 4));
> +
> +     pw_stream_update_params(stream, params, 4);
> +     spa_pod_dynamic_builder_clean(&b[0]);
> +     spa_pod_dynamic_builder_clean(&b[1]);
> +     spa_pod_dynamic_builder_clean(&b[2]);
>  }
>  
>  static void pwr_handle_stream_add_buffer(void *data, struct pw_buffer 
> *buffer) {
>       struct xdpw_screencast_instance *cast = data;
>       struct spa_data *d;
> +     enum spa_data_type t;
>  
>       logprint(DEBUG, "pipewire: add buffer event handle");
>  
> @@ -313,17 +348,17 @@
>       // Select buffer type from negotiation result
>       if ((d[0].type & (1u << SPA_DATA_MemFd)) > 0) {
>               assert(cast->buffer_type == WL_SHM);
> -             d[0].type = SPA_DATA_MemFd;
> +             t = SPA_DATA_MemFd;
>       } else if ((d[0].type & (1u << SPA_DATA_DmaBuf)) > 0) {
>               assert(cast->buffer_type == DMABUF);
> -             d[0].type = SPA_DATA_DmaBuf;
> +             t = SPA_DATA_DmaBuf;
>       } else {
>               logprint(ERROR, "pipewire: unsupported buffer type");
>               cast->err = 1;
>               return;
>       }
>  
> -     logprint(TRACE, "pipewire: selected buffertype %u", d[0].type);
> +     logprint(TRACE, "pipewire: selected buffertype %u", t);
>  
>       struct xdpw_buffer *xdpw_buffer = xdpw_buffer_create(cast, 
> cast->buffer_type, &cast->screencopy_frame_info[cast->buffer_type]);
>       if (xdpw_buffer == NULL) {
> @@ -336,6 +371,7 @@
>  
>       assert(xdpw_buffer->plane_count >= 0 && buffer->buffer->n_datas == 
> (uint32_t)xdpw_buffer->plane_count);
>       for (uint32_t plane = 0; plane < buffer->buffer->n_datas; plane++) {
> +             d[plane].type = t;
>               d[plane].maxsize = xdpw_buffer->size[plane];
>               d[plane].mapoffset = 0;
>               d[plane].chunk->size = xdpw_buffer->size[plane];
> @@ -419,6 +455,44 @@
>               logprint(TRACE, "pipewire: timestamp %"PRId64, h->pts);
>       }
>  
> +     struct spa_meta_videotransform *vt;
> +     if ((vt = spa_buffer_find_meta_data(spa_buf, SPA_META_VideoTransform, 
> sizeof(*vt)))) {
> +             vt->transform = cast->target->output->transformation;
> +             logprint(TRACE, "pipewire: transformation %u", vt->transform);
> +     }
> +
> +     struct spa_meta *damage;
> +     if ((damage = spa_buffer_find_meta(spa_buf, SPA_META_VideoDamage))) {
> +             struct spa_region *d_region = spa_meta_first(damage);
> +             uint32_t damage_counter = 0;
> +             do {
> +                     if (damage_counter >= cast->current_frame.damage_count) 
> {
> +                             *d_region = SPA_REGION(0, 0, 0, 0);
> +                             logprint(TRACE, "pipewire: end damage %u %u,%u 
> (%ux%u)", damage_counter,
> +                                             d_region->position.x, 
> d_region->position.y, d_region->size.width, d_region->size.height);
> +                             break;
> +                     }
> +                     *d_region = 
> SPA_REGION(cast->current_frame.damage[damage_counter].x,
> +                             cast->current_frame.damage[damage_counter].y,
> +                             
> cast->current_frame.damage[damage_counter].width,
> +                             
> cast->current_frame.damage[damage_counter].height);
> +                     logprint(TRACE, "pipewire: damage %u %u,%u (%ux%u)", 
> damage_counter,
> +                                     d_region->position.x, 
> d_region->position.y, d_region->size.width, d_region->size.height);
> +                     damage_counter++;
> +             } while (spa_meta_check(d_region + 1, damage) && d_region++);
> +
> +             if (damage_counter < cast->current_frame.damage_count) {
> +                     struct xdpw_frame_damage damage =
> +                             {d_region->position.x, d_region->position.x, 
> d_region->size.width, d_region->size.height};
> +                     for (; damage_counter < 
> cast->current_frame.damage_count; damage_counter++) {
> +                             damage = merge_damage(&damage, 
> &cast->current_frame.damage[damage_counter]);
> +                     }
> +                     *d_region = SPA_REGION(damage.x, damage.y, 
> damage.width, damage.height);
> +                     logprint(TRACE, "pipewire: collected damage %u %u,%u 
> (%ux%u)", damage_counter,
> +                                     d_region->position.x, 
> d_region->position.y, d_region->size.width, d_region->size.height);
> +             }
> +     }
> +
>       if (buffer_corrupt) {
>               for (uint32_t plane = 0; plane < spa_buf->n_datas; plane++) {
>                       d[plane].chunk->flags = SPA_CHUNK_FLAG_CORRUPTED;
> @@ -453,14 +527,18 @@
>  void pwr_update_stream_param(struct xdpw_screencast_instance *cast) {
>       logprint(TRACE, "pipewire: stream update parameters");
>       struct pw_stream *stream = cast->stream;
> -     uint8_t params_buffer[1024];
> -     struct spa_pod_builder b =
> -             SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
> +     uint8_t params_buffer[2][1024];
> +     struct spa_pod_dynamic_builder b[2];
> +     spa_pod_dynamic_builder_init(&b[0], params_buffer[0], 
> sizeof(params_buffer[0]), 2048);
> +     spa_pod_dynamic_builder_init(&b[1], params_buffer[1], 
> sizeof(params_buffer[1]), 2048);
>       const struct spa_pod *params[2];
>  
> -     uint32_t n_params = build_formats(&b, cast, params);
> +     struct spa_pod_builder *builder[2] = {&b[0].b, &b[1].b};
> +     uint32_t n_params = build_formats(builder, cast, params);
>  
>       pw_stream_update_params(stream, params, n_params);
> +     spa_pod_dynamic_builder_clean(&b[0]);
> +     spa_pod_dynamic_builder_clean(&b[1]);
>  }
>  
>  void xdpw_pwr_stream_create(struct xdpw_screencast_instance *cast) {
> @@ -469,8 +547,10 @@
>  
>       pw_loop_enter(state->pw_loop);
>  
> -     uint8_t buffer[1024];
> -     struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
> +     uint8_t buffer[2][1024];
> +     struct spa_pod_dynamic_builder b[2];
> +     spa_pod_dynamic_builder_init(&b[0], buffer[0], sizeof(buffer[0]), 2048);
> +     spa_pod_dynamic_builder_init(&b[1], buffer[1], sizeof(buffer[1]), 2048);
>       const struct spa_pod *params[2];
>  
>       char name[] = "xdpw-stream-XXXXXX";
> @@ -486,7 +566,10 @@
>       }
>       cast->pwr_stream_state = false;
>  
> -     uint32_t param_count = build_formats(&b, cast, params);
> +     struct spa_pod_builder *builder[2] = {&b[0].b, &b[1].b};
> +     uint32_t param_count = build_formats(builder, cast, params);
> +     spa_pod_dynamic_builder_clean(&b[0]);
> +     spa_pod_dynamic_builder_clean(&b[1]);
>  
>       pw_stream_add_listener(cast->stream, &cast->stream_listener,
>               &pwr_stream_events, cast);
> diff -Nru xdg-desktop-portal-wlr-0.6.0/src/screencast/screencast.c 
> xdg-desktop-portal-wlr-0.7.0/src/screencast/screencast.c
> --- xdg-desktop-portal-wlr-0.6.0/src/screencast/screencast.c  2022-06-09 
> 11:25:25.000000000 +0200
> +++ xdg-desktop-portal-wlr-0.7.0/src/screencast/screencast.c  2023-04-15 
> 10:32:26.000000000 +0200
> @@ -48,7 +48,7 @@
>  }
>  
>  void xdpw_screencast_instance_init(struct xdpw_screencast_context *ctx,
> -             struct xdpw_screencast_instance *cast, struct xdpw_wlr_output 
> *out, bool with_cursor) {
> +             struct xdpw_screencast_instance *cast, struct 
> xdpw_screencast_target *target) {
>  
>       // only run exec_before if there's no other instance running that 
> already ran it
>       if (wl_list_empty(&ctx->screencast_instances)) {
> @@ -60,15 +60,14 @@
>       }
>  
>       cast->ctx = ctx;
> -     cast->target_output = out;
> +     cast->target = target;
>       if (ctx->state->config->screencast_conf.max_fps > 0) {
> -             cast->max_framerate = 
> ctx->state->config->screencast_conf.max_fps < (uint32_t)out->framerate ?
> -                     ctx->state->config->screencast_conf.max_fps : 
> (uint32_t)out->framerate;
> +             cast->max_framerate = 
> ctx->state->config->screencast_conf.max_fps < 
> (uint32_t)target->output->framerate ?
> +                     ctx->state->config->screencast_conf.max_fps : 
> (uint32_t)target->output->framerate;
>       } else {
> -             cast->max_framerate = (uint32_t)out->framerate;
> +             cast->max_framerate = (uint32_t)target->output->framerate;
>       }
>       cast->framerate = cast->max_framerate;
> -     cast->with_cursor = with_cursor;
>       cast->refcount = 1;
>       cast->node_id = SPA_ID_INVALID;
>       cast->avoid_dmabufs = false;
> @@ -93,6 +92,7 @@
>               }
>       }
>  
> +     free(cast->target);
>       wl_list_remove(&cast->link);
>       xdpw_pwr_stream_destroy(cast);
>       assert(wl_list_length(&cast->buffer_list) == 0);
> @@ -102,13 +102,14 @@
>  void xdpw_screencast_instance_teardown(struct xdpw_screencast_instance 
> *cast) {
>       struct xdpw_session *sess, *tmp;
>       wl_list_for_each_safe(sess, tmp, &cast->ctx->state->xdpw_sessions, 
> link) {
> -             if (sess->screencast_instance == cast) {
> +             if (sess->screencast_data.screencast_instance == cast) {
>                       xdpw_session_destroy(sess);
>               }
>       }
>  }
>  
> -bool setup_outputs(struct xdpw_screencast_context *ctx, struct xdpw_session 
> *sess, bool with_cursor) {
> +bool setup_target(struct xdpw_screencast_context *ctx, struct xdpw_session 
> *sess, struct xdpw_screencast_restore_data *data) {
> +     bool target_initialized = false;
>  
>       struct xdpw_wlr_output *output, *tmp_o;
>       wl_list_for_each_reverse_safe(output, tmp_o, &ctx->output_list, link) {
> @@ -116,29 +117,57 @@
>                       output->make, output->model, output->id, output->name);
>       }
>  
> -     struct xdpw_wlr_output *out;
> -     out = xdpw_wlr_output_chooser(ctx);
> -     if (!out) {
> +     struct xdpw_screencast_target *target = calloc(1, sizeof(struct 
> xdpw_screencast_target));
> +     if (!target) {
> +             logprint(ERROR, "wlroots: unable to allocate target");
> +             return false;
> +     }
> +     target->with_cursor = sess->screencast_data.cursor_mode == EMBEDDED;
> +     if (data) {
> +             target_initialized = xdpw_wlr_target_from_data(ctx, target, 
> data);
> +     }
> +     if (!target_initialized) {
> +             target_initialized = xdpw_wlr_target_chooser(ctx, target);
> +             //TODO: Chooser option to confirm the persist mode
> +             const char *env_persist_str = getenv("XDPW_PERSIST_MODE");
> +             if (env_persist_str) {
> +                     if (strcmp(env_persist_str, "transient") == 0) {
> +                             sess->screencast_data.persist_mode = 
> sess->screencast_data.persist_mode > PERSIST_TRANSIENT
> +                                     ? PERSIST_TRANSIENT : 
> sess->screencast_data.persist_mode;
> +                     } else if (strcmp(env_persist_str, "permanent") == 0) {
> +                             sess->screencast_data.persist_mode = 
> sess->screencast_data.persist_mode > PERSIST_PERMANENT
> +                                     ? PERSIST_PERMANENT : 
> sess->screencast_data.persist_mode;
> +                     } else {
> +                             sess->screencast_data.persist_mode = 
> PERSIST_NONE;
> +                     }
> +
> +             } else {
> +                     sess->screencast_data.persist_mode = PERSIST_NONE;
> +             }
> +     }
> +     if (!target_initialized) {
>               logprint(ERROR, "wlroots: no output found");
> +             free(target);
>               return false;
>       }
> +     assert(target->output);
>  
>       // Disable screencast sharing to avoid sharing between dmabuf and shm 
> capable clients
>       /*
>       struct xdpw_screencast_instance *cast, *tmp_c;
>       wl_list_for_each_reverse_safe(cast, tmp_c, &ctx->screencast_instances, 
> link) {
>               logprint(INFO, "xdpw: existing screencast instance: %d %s 
> cursor",
> -                     cast->target_output->id,
> -                     cast->with_cursor ? "with" : "without");
> +                     cast->target->output->id,
> +                     cast->target->with_cursor ? "with" : "without");
>  
> -             if (cast->target_output->id == out->id && cast->with_cursor == 
> with_cursor) {
> +             if (cast->target->output->id == target->output->id && 
> cast->target->with_cursor == target->with_cursor) {
>                       if (cast->refcount == 0) {
>                               logprint(DEBUG,
>                                       "xdpw: matching cast instance found, "
>                                       "but is already scheduled for 
> destruction, skipping");
>                       }
>                       else {
> -                             sess->screencast_instance = cast;
> +                             sess->screencast_data.screencast_instance = 
> cast;
>                               ++cast->refcount;
>                       }
>                       logprint(INFO, "xdpw: screencast instance %p now has %d 
> references",
> @@ -147,13 +176,12 @@
>       }
>       */
>  
> -     if (!sess->screencast_instance) {
> -             sess->screencast_instance = calloc(1, sizeof(struct 
> xdpw_screencast_instance));
> -             xdpw_screencast_instance_init(ctx, sess->screencast_instance,
> -                     out, with_cursor);
> +     if (!sess->screencast_data.screencast_instance) {
> +             sess->screencast_data.screencast_instance = calloc(1, 
> sizeof(struct xdpw_screencast_instance));
> +             xdpw_screencast_instance_init(ctx, 
> sess->screencast_data.screencast_instance, target);
>       }
>       logprint(INFO, "wlroots: output: %s",
> -             sess->screencast_instance->target_output->name);
> +             
> sess->screencast_data.screencast_instance->target->output->name);
>  
>       return true;
>  
> @@ -276,9 +304,6 @@
>  
>       logprint(INFO, "dbus: select sources method invoked");
>  
> -     // default to embedded cursor mode if not specified
> -     bool cursor_embedded = true;
> -
>       char *request_handle, *session_handle, *app_id;
>       ret = sd_bus_message_read(msg, "oos", &request_handle, &session_handle, 
> &app_id);
>       if (ret < 0) {
> @@ -293,8 +318,26 @@
>       logprint(INFO, "dbus: session_handle: %s", session_handle);
>       logprint(INFO, "dbus: app_id: %s", app_id);
>  
> +     sess = NULL;
> +     wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) 
> {
> +             if (strcmp(sess->session_handle, session_handle) == 0) {
> +                             logprint(DEBUG, "dbus: select sources: found 
> matching session %s", sess->session_handle);
> +                             break;
> +             }
> +     }
> +     if (!sess) {
> +             logprint(WARN, "dbus: select sources: no matching session %s 
> found", sess->session_handle);
> +             goto error;
> +     }
> +
> +     // default to embedded cursor mode if not specified
> +     sess->screencast_data.cursor_mode = EMBEDDED;
> +     // default to no persist if not specified
> +     sess->screencast_data.persist_mode = PERSIST_NONE;
> +
>       char *key;
>       int innerRet = 0;
> +     struct xdpw_screencast_restore_data restore_data = {0};
>       while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
>               innerRet = sd_bus_message_read(msg, "s", &key);
>               if (innerRet < 0) {
> @@ -314,16 +357,87 @@
>                       }
>                       logprint(INFO, "dbus: option types:%x", mask);
>               } else if (strcmp(key, "cursor_mode") == 0) {
> -                     uint32_t cursor_mode;
> -                     sd_bus_message_read(msg, "v", "u", &cursor_mode);
> -                     if (cursor_mode & HIDDEN) {
> -                             cursor_embedded = false;
> -                     }
> -                     if (cursor_mode & METADATA) {
> +                     sd_bus_message_read(msg, "v", "u", 
> &sess->screencast_data.cursor_mode);
> +                     if (sess->screencast_data.cursor_mode & METADATA) {
>                               logprint(ERROR, "dbus: unsupported cursor mode 
> requested, cancelling");
>                               goto error;
>                       }
> -                     logprint(INFO, "dbus: option cursor_mode:%x", 
> cursor_mode);
> +                     logprint(INFO, "dbus: option cursor_mode:%x", 
> sess->screencast_data.cursor_mode);
> +             } else if (strcmp(key, "restore_data") == 0) {
> +                     logprint(INFO, "dbus: restore data available");
> +                     char *portal_vendor;
> +                     innerRet = sd_bus_message_enter_container(msg, 'v', 
> "(suv)");
> +                     if (innerRet < 0) {
> +                             logprint(ERROR, "dbus: error entering variant");
> +                             return innerRet;
> +                     }
> +                     innerRet = sd_bus_message_enter_container(msg, 'r', 
> "suv");
> +                     if (innerRet < 0) {
> +                             logprint(ERROR, "dbus: error entering struct");
> +                             return innerRet;
> +                     }
> +                     sd_bus_message_read(msg, "s", &portal_vendor);
> +                     if (strcmp(portal_vendor, "wlroots") != 0) {
> +                             logprint(INFO, "dbus: skipping restore_data 
> from another vendor (%s)", portal_vendor);
> +                             sd_bus_message_skip(msg, "uv");
> +                             continue;
> +                     }
> +                     sd_bus_message_read(msg, "u", &restore_data.version);
> +                     if (restore_data.version == 1) {
> +                             innerRet = sd_bus_message_enter_container(msg, 
> 'v', "a{sv}");
> +                             if (innerRet < 0) {
> +                                     return innerRet;
> +                             }
> +                             innerRet = sd_bus_message_enter_container(msg, 
> 'a', "{sv}");
> +                             if (innerRet < 0) {
> +                                     return innerRet;
> +                             }
> +                             logprint(INFO, "dbus: restoring session from 
> data");
> +                             int rdRet;
> +                             char *rdKey;
> +                             while ((innerRet = 
> sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
> +                                     rdRet = sd_bus_message_read(msg, "s", 
> &rdKey);
> +                                     if (rdRet < 0) {
> +                                             return rdRet;
> +                                     }
> +                                     if (strcmp(rdKey, "output_name") == 0) {
> +                                             sd_bus_message_read(msg, "v", 
> "s", &restore_data.output_name);
> +                                             logprint(INFO, "dbus: option 
> restore_data.output_name: %s", restore_data.output_name);
> +                                     } else {
> +                                             logprint(WARN, "dbus: unknown 
> option %s", rdKey);
> +                                             sd_bus_message_skip(msg, "v");
> +                                     }
> +                                     innerRet = 
> sd_bus_message_exit_container(msg); // dictionary
> +                                     if (innerRet < 0) {
> +                                             return innerRet;
> +                                     }
> +                             }
> +                             if (innerRet < 0) {
> +                                     return innerRet;
> +                             }
> +                             innerRet = sd_bus_message_exit_container(msg); 
> //array
> +                             if (innerRet < 0) {
> +                                     return innerRet;
> +                             }
> +                             innerRet = sd_bus_message_exit_container(msg); 
> //variant
> +                             if (innerRet < 0) {
> +                                     return innerRet;
> +                             }
> +                     } else {
> +                             sd_bus_message_skip(msg, "v");
> +                             logprint(ERROR, "Unknown restore_data version: 
> %u", restore_data.version);
> +                     }
> +                     innerRet = sd_bus_message_exit_container(msg); // struct
> +                     if (innerRet < 0) {
> +                             return innerRet;
> +                     }
> +                     innerRet = sd_bus_message_exit_container(msg); // 
> variant
> +                     if (innerRet < 0) {
> +                             return innerRet;
> +                     }
> +             } else if (strcmp(key, "persist_mode") == 0) {
> +                     sd_bus_message_read(msg, "v", "u", 
> &sess->screencast_data.persist_mode);
> +                     logprint(INFO, "dbus: option persist_mode:%u", 
> sess->screencast_data.persist_mode);
>               } else {
>                       logprint(WARN, "dbus: unknown option %s", key);
>                       sd_bus_message_skip(msg, "v");
> @@ -342,13 +456,7 @@
>               return ret;
>       }
>  
> -     bool output_selection_canceled = 1;
> -     wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) 
> {
> -             if (strcmp(sess->session_handle, session_handle) == 0) {
> -                             logprint(DEBUG, "dbus: select sources: found 
> matching session %s", sess->session_handle);
> -                             output_selection_canceled = !setup_outputs(ctx, 
> sess, cursor_embedded);
> -             }
> -     }
> +     bool output_selection_canceled = !setup_target(ctx, sess, 
> restore_data.version > 0 ? &restore_data : NULL);
>  
>       ret = sd_bus_message_new_method_return(msg, &reply);
>       if (ret < 0) {
> @@ -370,11 +478,8 @@
>       return 0;
>  
>  error:
> -     wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) 
> {
> -             if (strcmp(sess->session_handle, session_handle) == 0) {
> -                             logprint(DEBUG, "dbus: select sources error: 
> destroying matching session %s", sess->session_handle);
> -                             xdpw_session_destroy(sess);
> -             }
> +     if (sess) {
> +             xdpw_session_destroy(sess);
>       }
>  
>       ret = sd_bus_message_new_method_return(msg, &reply);
> @@ -443,7 +548,7 @@
>       wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) 
> {
>               if (strcmp(sess->session_handle, session_handle) == 0) {
>                               logprint(DEBUG, "dbus: start: found matching 
> session %s", sess->session_handle);
> -                             cast = sess->screencast_instance;
> +                             cast = 
> sess->screencast_data.screencast_instance;
>               }
>       }
>       if (!cast) {
> @@ -472,12 +577,41 @@
>       }
>  
>       logprint(DEBUG, "dbus: start: returning node %d", (int)cast->node_id);
> -     ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 1,
> +     ret = sd_bus_message_append(reply, "u", PORTAL_RESPONSE_SUCCESS);
> +     if (ret < 0) {
> +             return ret;
> +     }
> +     ret = sd_bus_message_open_container(reply, 'a', "{sv}");
> +     if (ret < 0) {
> +             return ret;
> +     }
> +     ret = sd_bus_message_append(reply, "{sv}",
>               "streams", "a(ua{sv})", 1,
> -             cast->node_id, 2,
> +             cast->node_id, 3,
>               "position", "(ii)", 0, 0,
> -             "size", "(ii)", cast->screencopy_frame_info[WL_SHM].width, 
> cast->screencopy_frame_info[WL_SHM].height);
> +             "size", "(ii)", cast->screencopy_frame_info[WL_SHM].width, 
> cast->screencopy_frame_info[WL_SHM].height,
> +             "source_type", "u", 1 << MONITOR);
> +     if (ret < 0) {
> +             return ret;
> +     }
> +     ret = sd_bus_message_append(reply, "{sv}",
> +             "persist_mode", "u", sess->screencast_data.persist_mode);
> +     if (ret < 0) {
> +             return ret;
> +     }
> +     if (sess->screencast_data.persist_mode != PERSIST_NONE) {
> +             struct xdpw_screencast_restore_data restore_data;
> +             restore_data.output_name = cast->target->output->name;
> +             ret = sd_bus_message_append(reply, "{sv}",
> +                     "restore_data", "(suv)",
> +                     "wlroots", XDP_CAST_DATA_VER,
> +                     "a{sv}", 1, "output_name", "s", 
> restore_data.output_name);
> +             if (ret < 0) {
> +                     return ret;
> +             }
> +     }
>  
> +     ret = sd_bus_message_close_container(reply);
>       if (ret < 0) {
>               return ret;
>       }
> diff -Nru xdg-desktop-portal-wlr-0.6.0/src/screencast/screencast_common.c 
> xdg-desktop-portal-wlr-0.7.0/src/screencast/screencast_common.c
> --- xdg-desktop-portal-wlr-0.6.0/src/screencast/screencast_common.c   
> 2022-06-09 11:25:25.000000000 +0200
> +++ xdg-desktop-portal-wlr-0.7.0/src/screencast/screencast_common.c   
> 2023-04-15 10:32:26.000000000 +0200
> @@ -153,6 +153,12 @@
>                               frame_info->format, flags);
>               }
>  
> +             // Fallback for linear buffers via the implicit api
> +             if (buffer->bo == NULL && cast->pwr_format.modifier == 
> DRM_FORMAT_MOD_LINEAR) {
> +                     buffer->bo = gbm_bo_create(cast->ctx->gbm, 
> frame_info->width, frame_info->height,
> +                                     frame_info->format, flags | 
> GBM_BO_USE_LINEAR);
> +             }
> +
>               if (buffer->bo == NULL) {
>                       logprint(ERROR, "xdpw: failed to create gbm_bo");
>                       free(buffer);
> @@ -404,3 +410,17 @@
>       fprintf(stderr, "Could not find chooser type %d\n", chooser_type);
>       abort();
>  }
> +
> +struct xdpw_frame_damage merge_damage(struct xdpw_frame_damage *damage1, 
> struct xdpw_frame_damage *damage2) {
> +     struct xdpw_frame_damage damage;
> +     uint32_t x0, y0;
> +     damage.x = damage1->x < damage2->y ? damage1->x : damage2->x;
> +     damage.y = damage1->y < damage2->y ? damage1->y : damage2->y;
> +
> +     x0 = damage1->x + damage1->width < damage2->x + damage2->width ? 
> damage2->x + damage2->width : damage1->x + damage1->width;
> +     y0 = damage1->y + damage1->height < damage2->y + damage2->height ? 
> damage2->y + damage2->height : damage1->y + damage1->height;
> +     damage.width = x0 - damage.x;
> +     damage.height = y0 - damage.y;
> +
> +     return damage;
> +}
> diff -Nru xdg-desktop-portal-wlr-0.6.0/src/screencast/wlr_screencast.c 
> xdg-desktop-portal-wlr-0.7.0/src/screencast/wlr_screencast.c
> --- xdg-desktop-portal-wlr-0.6.0/src/screencast/wlr_screencast.c      
> 2022-06-09 11:25:25.000000000 +0200
> +++ xdg-desktop-portal-wlr-0.7.0/src/screencast/wlr_screencast.c      
> 2023-04-15 10:32:26.000000000 +0200
> @@ -2,7 +2,6 @@
>  
>  #include "linux-dmabuf-unstable-v1-client-protocol.h"
>  #include "wlr-screencopy-unstable-v1-client-protocol.h"
> -#include "xdg-output-unstable-v1-client-protocol.h"
>  #include <fcntl.h>
>  #include <limits.h>
>  #include <stdbool.h>
> @@ -174,6 +173,7 @@
>               return;
>       }
>  
> +     cast->current_frame.damage_count = 0;
>       zwlr_screencopy_frame_v1_copy_with_damage(frame, 
> cast->current_frame.xdpw_buffer->buffer);
>       logprint(TRACE, "wlroots: frame copied");
>  
> @@ -200,10 +200,13 @@
>  
>       logprint(TRACE, "wlroots: damage event handler");
>  
> -     cast->current_frame.damage.x = x;
> -     cast->current_frame.damage.y = y;
> -     cast->current_frame.damage.width = width;
> -     cast->current_frame.damage.height = height;
> +     logprint(TRACE, "wlroots: damage %"PRIu32": 
> %"PRIu32",%"PRIu32"x%"PRIu32",%"PRIu32, cast->current_frame.damage_count, x, 
> y, width, height);
> +     struct xdpw_frame_damage damage = {x, y, width, height};
> +     if (cast->current_frame.damage_count < 4) {
> +             cast->current_frame.damage[cast->current_frame.damage_count++] 
> = damage;
> +     } else {
> +             cast->current_frame.damage[3] = 
> merge_damage(&cast->current_frame.damage[3], &damage);
> +     }
>  }
>  
>  static void wlr_frame_ready(void *data, struct zwlr_screencopy_frame_v1 
> *frame,
> @@ -250,7 +253,7 @@
>  
>  void xdpw_wlr_register_cb(struct xdpw_screencast_instance *cast) {
>       cast->frame_callback = zwlr_screencopy_manager_v1_capture_output(
> -             cast->ctx->screencopy_manager, cast->with_cursor, 
> cast->target_output->output);
> +             cast->ctx->screencopy_manager, cast->target->with_cursor, 
> cast->target->output->output);
>  
>       zwlr_screencopy_frame_v1_add_listener(cast->frame_callback,
>               &wlr_frame_listener, cast);
> @@ -263,6 +266,7 @@
>       struct xdpw_wlr_output *output = data;
>       output->make = strdup(make);
>       output->model = strdup(model);
> +     output->transformation = transform;
>  }
>  
>  static void wlr_output_handle_mode(void *data, struct wl_output *wl_output,
> @@ -282,55 +286,54 @@
>       /* Nothing to do */
>  }
>  
> +static void wlr_output_handle_name(void *data, struct wl_output *wl_output,
> +             const char *name) {
> +     struct xdpw_wlr_output *output = data;
> +     output->name = strdup(name);
> +}
> +
> +static void wlr_output_handle_description(void *data, struct wl_output 
> *wl_output,
> +             const char *description) {
> +     /* Nothing to do */
> +}
> +
>  static const struct wl_output_listener wlr_output_listener = {
>       .geometry = wlr_output_handle_geometry,
>       .mode = wlr_output_handle_mode,
>       .done = wlr_output_handle_done,
>       .scale = wlr_output_handle_scale,
> +     .name = wlr_output_handle_name,
> +     .description = wlr_output_handle_description,
>  };
>  
> -static void wlr_xdg_output_name(void *data, struct zxdg_output_v1 
> *xdg_output,
> -             const char *name) {
> -     struct xdpw_wlr_output *output = data;
> -
> -     output->name = strdup(name);
> -};
> -
> -static void noop() {
> -     // This space intentionally left blank
> +static struct xdpw_wlr_output *xdpw_wlr_output_first(struct wl_list 
> *output_list) {
> +     struct xdpw_wlr_output *output, *tmp;
> +     wl_list_for_each_safe(output, tmp, output_list, link) {
> +             return output;
> +     }
> +     return NULL;
>  }
>  
> -static const struct zxdg_output_v1_listener wlr_xdg_output_listener = {
> -     .logical_position = noop,
> -     .logical_size = noop,
> -     .done = NULL, /* Deprecated */
> -     .description = noop,
> -     .name = wlr_xdg_output_name,
> -};
> -
> -static void wlr_add_xdg_output_listener(struct xdpw_wlr_output *output,
> -             struct zxdg_output_v1 *xdg_output) {
> -     output->xdg_output = xdg_output;
> -     zxdg_output_v1_add_listener(output->xdg_output, 
> &wlr_xdg_output_listener,
> -             output);
> -}
> -
> -static void wlr_init_xdg_output(struct xdpw_screencast_context *ctx,
> -             struct xdpw_wlr_output *output) {
> -     struct zxdg_output_v1 *xdg_output =
> -             zxdg_output_manager_v1_get_xdg_output(ctx->xdg_output_manager,
> -                     output->output);
> -     wlr_add_xdg_output_listener(output, xdg_output);
> +static struct xdpw_wlr_output *xdpw_wlr_output_find_by_name(struct wl_list 
> *output_list,
> +             const char *name) {
> +     struct xdpw_wlr_output *output, *tmp;
> +     wl_list_for_each_safe(output, tmp, output_list, link) {
> +             if (strcmp(output->name, name) == 0) {
> +                     return output;
> +             }
> +     }
> +     return NULL;
>  }
>  
> -static void wlr_init_xdg_outputs(struct xdpw_screencast_context *ctx) {
> +static struct xdpw_wlr_output *xdpw_wlr_output_find(struct 
> xdpw_screencast_context *ctx,
> +             struct wl_output *out, uint32_t id) {
>       struct xdpw_wlr_output *output, *tmp;
>       wl_list_for_each_safe(output, tmp, &ctx->output_list, link) {
> -             if (output->xdg_output) {
> -                     continue;
> +             if ((output->output == out) || (output->id == id)) {
> +                     return output;
>               }
> -             wlr_init_xdg_output(ctx, output);
>       }
> +     return NULL;
>  }
>  
>  static pid_t spawn_chooser(char *cmd, int chooser_in[2], int chooser_out[2]) 
> {
> @@ -493,7 +496,7 @@
>       return xdpw_wlr_output_first(output_list);
>  }
>  
> -struct xdpw_wlr_output *xdpw_wlr_output_chooser(struct 
> xdpw_screencast_context *ctx) {
> +static struct xdpw_wlr_output *xdpw_wlr_output_chooser(struct 
> xdpw_screencast_context *ctx) {
>       switch (ctx->state->config->screencast_conf.chooser_type) {
>       case XDPW_CHOOSER_DEFAULT:
>               return wlr_output_chooser_default(&ctx->output_list);
> @@ -531,41 +534,27 @@
>       return NULL;
>  }
>  
> -struct xdpw_wlr_output *xdpw_wlr_output_first(struct wl_list *output_list) {
> -     struct xdpw_wlr_output *output, *tmp;
> -     wl_list_for_each_safe(output, tmp, output_list, link) {
> -             return output;
> -     }
> -     return NULL;
> +bool xdpw_wlr_target_chooser(struct xdpw_screencast_context *ctx, struct 
> xdpw_screencast_target *target) {
> +     target->output = xdpw_wlr_output_chooser(ctx);
> +     return target->output != NULL;
>  }
>  
> -struct xdpw_wlr_output *xdpw_wlr_output_find_by_name(struct wl_list 
> *output_list,
> -             const char *name) {
> -     struct xdpw_wlr_output *output, *tmp;
> -     wl_list_for_each_safe(output, tmp, output_list, link) {
> -             if (strcmp(output->name, name) == 0) {
> -                     return output;
> -             }
> -     }
> -     return NULL;
> -}
> +bool xdpw_wlr_target_from_data(struct xdpw_screencast_context *ctx, struct 
> xdpw_screencast_target *target,
> +             struct xdpw_screencast_restore_data *data) {
> +     struct xdpw_wlr_output *out = NULL;
> +     out = xdpw_wlr_output_find_by_name(&ctx->output_list, 
> data->output_name);
>  
> -struct xdpw_wlr_output *xdpw_wlr_output_find(struct xdpw_screencast_context 
> *ctx,
> -             struct wl_output *out, uint32_t id) {
> -     struct xdpw_wlr_output *output, *tmp;
> -     wl_list_for_each_safe(output, tmp, &ctx->output_list, link) {
> -             if ((output->output == out) || (output->id == id)) {
> -                     return output;
> -             }
> +     if (!out) {
> +             return false;
>       }
> -     return NULL;
> +     target->output = out;
> +     return true;
>  }
>  
>  static void wlr_remove_output(struct xdpw_wlr_output *out) {
>       free(out->name);
>       free(out->make);
>       free(out->model);
> -     zxdg_output_v1_destroy(out->xdg_output);
>       wl_output_destroy(out->output);
>       wl_list_remove(&out->link);
>       free(out);
> @@ -598,6 +587,10 @@
>       wlr_format_modifier_pair_add(ctx, format, modifier);
>  }
>  
> +static void noop() {
> +       // This space intentionally left blank
> +}
> +
>  static const struct zwp_linux_dmabuf_v1_listener linux_dmabuf_listener = {
>       .format = noop,
>       .modifier = linux_dmabuf_handle_modifier,
> @@ -746,9 +739,6 @@
>  
>               wl_output_add_listener(output->output, &wlr_output_listener, 
> output);
>               wl_list_insert(&ctx->output_list, &output->link);
> -             if (ctx->xdg_output_manager) {
> -                     wlr_init_xdg_output(ctx, output);
> -             }
>       }
>  
>       if (!strcmp(interface, zwlr_screencopy_manager_v1_interface.name)) {
> @@ -768,11 +758,6 @@
>               ctx->shm = wl_registry_bind(reg, id, &wl_shm_interface, 
> WL_SHM_VERSION);
>       }
>  
> -     if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) {
> -             logprint(DEBUG, "wlroots: |-- registered to interface %s 
> (Version %u)", interface, XDG_OUTPUT_MANAGER_VERSION);
> -             ctx->xdg_output_manager =
> -                     wl_registry_bind(reg, id, 
> &zxdg_output_manager_v1_interface, XDG_OUTPUT_MANAGER_VERSION);
> -     }
>       if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0) {
>               uint32_t version = ver;
>               if (LINUX_DMABUF_VERSION < ver) {
> @@ -801,7 +786,7 @@
>               logprint(DEBUG, "wlroots: output removed (%s)", output->name);
>               struct xdpw_screencast_instance *cast, *tmp;
>               wl_list_for_each_safe(cast, tmp, &ctx->screencast_instances, 
> link) {
> -                     if (cast->target_output == output) {
> +                     if (cast->target->output == output) {
>                               // screencopy might be in process for this 
> instance
>                               wlr_frame_free(cast);
>                               // instance might be waiting for wakeup by the 
> frame limiter
> @@ -844,18 +829,11 @@
>  
>       logprint(DEBUG, "wayland: registry listeners run");
>  
> -     // make sure our wlroots supports xdg_output_manager
> -     if (!ctx->xdg_output_manager) {
> -             logprint(ERROR, "Compositor doesn't support %s!",
> -                     zxdg_output_manager_v1_interface.name);
> -             return -1;
> -     }
> -
> -     wlr_init_xdg_outputs(ctx);
> +     if (ctx->linux_dmabuf_feedback) {
> +             wl_display_roundtrip(state->wl_display);
>  
> -     wl_display_roundtrip(state->wl_display);
> -
> -     logprint(DEBUG, "wayland: xdg output listeners run");
> +             logprint(DEBUG, "wayland: dmabuf_feedback listeners run");
> +     }
>  
>       // make sure our wlroots supports shm protocol
>       if (!ctx->shm) {
> @@ -887,7 +865,6 @@
>       struct xdpw_wlr_output *output, *tmp_o;
>       wl_list_for_each_safe(output, tmp_o, &ctx->output_list, link) {
>               wl_list_remove(&output->link);
> -             zxdg_output_v1_destroy(output->xdg_output);
>               wl_output_destroy(output->output);
>       }
>  
> @@ -902,9 +879,6 @@
>       if (ctx->shm) {
>               wl_shm_destroy(ctx->shm);
>       }
> -     if (ctx->xdg_output_manager) {
> -             zxdg_output_manager_v1_destroy(ctx->xdg_output_manager);
> -     }
>       if (ctx->gbm) {
>               int fd = gbm_device_get_fd(ctx->gbm);
>               gbm_device_destroy(ctx->gbm);
> diff -Nru xdg-desktop-portal-wlr-0.6.0/src/screenshot/screenshot.c 
> xdg-desktop-portal-wlr-0.7.0/src/screenshot/screenshot.c
> --- xdg-desktop-portal-wlr-0.6.0/src/screenshot/screenshot.c  2022-06-09 
> 11:25:25.000000000 +0200
> +++ xdg-desktop-portal-wlr-0.7.0/src/screenshot/screenshot.c  2023-04-15 
> 10:32:26.000000000 +0200
> @@ -286,6 +286,9 @@
>       SD_BUS_VTABLE_START(0),
>       SD_BUS_METHOD("Screenshot", "ossa{sv}", "ua{sv}", method_screenshot, 
> SD_BUS_VTABLE_UNPRIVILEGED),
>       SD_BUS_METHOD("PickColor", "ossa{sv}", "ua{sv}", method_pick_color, 
> SD_BUS_VTABLE_UNPRIVILEGED),
> +     SD_BUS_PROPERTY("version", "u", NULL,
> +             offsetof(struct xdpw_state, screenshot_version),
> +             SD_BUS_VTABLE_PROPERTY_CONST),
>       SD_BUS_VTABLE_END
>  };
>  
> @@ -293,5 +296,5 @@
>       // TODO: cleanup
>       sd_bus_slot *slot = NULL;
>       return sd_bus_add_object_vtable(state->bus, &slot, object_path, 
> interface_name,
> -             screenshot_vtable, NULL);
> +             screenshot_vtable, state);
>  }
> diff -Nru xdg-desktop-portal-wlr-0.6.0/wlr.portal 
> xdg-desktop-portal-wlr-0.7.0/wlr.portal
> --- xdg-desktop-portal-wlr-0.6.0/wlr.portal   2022-06-09 11:25:25.000000000 
> +0200
> +++ xdg-desktop-portal-wlr-0.7.0/wlr.portal   2023-04-15 10:32:26.000000000 
> +0200
> @@ -1,4 +1,4 @@
>  [portal]
>  DBusName=org.freedesktop.impl.portal.desktop.wlr
>  
> Interfaces=org.freedesktop.impl.portal.Screenshot;org.freedesktop.impl.portal.ScreenCast;
> -UseIn=wlroots;sway;Wayfire;river;phosh;
> +UseIn=wlroots;sway;Wayfire;river;phosh;Hyprland;


-- 
Sebastian Ramacher

Reply via email to