[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1035047: marked as done (unblock: [pre-approval] xdg-desktop-portal-wlr/0.7.0-1)



Your message dated Sun, 30 Apr 2023 12:51:44 +0200
with message-id <CAM8zJQtM595O-=mv=1w9OSSUkxUQ8gbTic1wg=9yq_MXMMyFbA@mail.gmail.com>
and subject line Re: Bug#1035047: unblock: [pre-approval] xdg-desktop-portal-wlr/0.7.0-1
has caused the Debian Bug report #1035047,
regarding unblock: [pre-approval] xdg-desktop-portal-wlr/0.7.0-1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
1035047: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1035047
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
X-Debbugs-Cc: xdg-desktop-portal-wlr@packages.debian.org, Birger Schacht <birger@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 <jspricke@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;

--- End Message ---
--- Begin Message ---
On Sat, 29 Apr 2023 at 13:06, Jochen Sprickerhof <jspricke@debian.org> wrote:
> Thanks, it was just accepted into unstable.

Unblocked, thanks.

--- End Message ---

Reply to: