Package: release.debian.org
Severity: normal
User: release.debian....@packages.debian.org
Usertags: unblock
X-Debbugs-Cc: xdg-desktop-portal-...@packages.debian.org, Birger Schacht 
<bir...@debian.org>
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.

[ 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 <jspri...@debian.org>  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;

Reply via email to