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 -[](https://builds.sr.ht/~emersion/xdg-desktop-portal-wlr/commits?) +[](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, ¶ms[0]); + n_params = build_formats(builder, cast, ¶ms[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, ¶ms[1]); + n_params = build_formats(builder, cast, ¶ms[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;