mirror of
https://github.com/hyprwm/xdg-desktop-portal-hyprland.git
synced 2024-11-22 06:35:57 +01:00
Bind toplevel protos once before first screencast
Also style.
This commit is contained in:
parent
b03b1c2f27
commit
ee73fca9cc
3 changed files with 1232 additions and 1235 deletions
|
@ -6,134 +6,134 @@
|
||||||
#include <spa/param/video/format-utils.h>
|
#include <spa/param/video/format-utils.h>
|
||||||
#include <wayland-client-protocol.h>
|
#include <wayland-client-protocol.h>
|
||||||
#include <xf86drm.h>
|
#include <xf86drm.h>
|
||||||
#include "hyprland-toplevel-export-v1-client-protocol.h"
|
|
||||||
|
|
||||||
#include "fps_limit.h"
|
#include "fps_limit.h"
|
||||||
|
#include "hyprland-toplevel-export-v1-client-protocol.h"
|
||||||
|
|
||||||
// this seems to be right based on
|
// this seems to be right based on
|
||||||
// https://github.com/flatpak/xdg-desktop-portal/blob/309a1fc0cf2fb32cceb91dbc666d20cf0a3202c2/src/screen-cast.c#L955
|
// 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 2
|
||||||
|
|
||||||
enum cursor_modes {
|
enum cursor_modes {
|
||||||
HIDDEN = 1,
|
HIDDEN = 1,
|
||||||
EMBEDDED = 2,
|
EMBEDDED = 2,
|
||||||
METADATA = 4,
|
METADATA = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum source_types {
|
enum source_types {
|
||||||
MONITOR = 1,
|
MONITOR = 1,
|
||||||
WINDOW = 2,
|
WINDOW = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum buffer_type {
|
enum buffer_type {
|
||||||
WL_SHM = 0,
|
WL_SHM = 0,
|
||||||
DMABUF = 1,
|
DMABUF = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum xdpw_chooser_types {
|
enum xdpw_chooser_types {
|
||||||
XDPW_CHOOSER_DEFAULT,
|
XDPW_CHOOSER_DEFAULT,
|
||||||
XDPW_CHOOSER_NONE,
|
XDPW_CHOOSER_NONE,
|
||||||
XDPW_CHOOSER_SIMPLE,
|
XDPW_CHOOSER_SIMPLE,
|
||||||
XDPW_CHOOSER_DMENU,
|
XDPW_CHOOSER_DMENU,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum xdpw_frame_state {
|
enum xdpw_frame_state {
|
||||||
XDPW_FRAME_STATE_NONE,
|
XDPW_FRAME_STATE_NONE,
|
||||||
XDPW_FRAME_STATE_STARTED,
|
XDPW_FRAME_STATE_STARTED,
|
||||||
XDPW_FRAME_STATE_RENEG,
|
XDPW_FRAME_STATE_RENEG,
|
||||||
XDPW_FRAME_STATE_FAILED,
|
XDPW_FRAME_STATE_FAILED,
|
||||||
XDPW_FRAME_STATE_SUCCESS,
|
XDPW_FRAME_STATE_SUCCESS,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xdpw_output_chooser {
|
struct xdpw_output_chooser {
|
||||||
enum xdpw_chooser_types type;
|
enum xdpw_chooser_types type;
|
||||||
char *cmd;
|
char *cmd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xdpw_frame_damage {
|
struct xdpw_frame_damage {
|
||||||
uint32_t x;
|
uint32_t x;
|
||||||
uint32_t y;
|
uint32_t y;
|
||||||
uint32_t width;
|
uint32_t width;
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xdpw_frame {
|
struct xdpw_frame {
|
||||||
bool y_invert;
|
bool y_invert;
|
||||||
uint64_t tv_sec;
|
uint64_t tv_sec;
|
||||||
uint32_t tv_nsec;
|
uint32_t tv_nsec;
|
||||||
struct xdpw_frame_damage damage;
|
struct xdpw_frame_damage damage;
|
||||||
struct xdpw_buffer *xdpw_buffer;
|
struct xdpw_buffer *xdpw_buffer;
|
||||||
struct pw_buffer *pw_buffer;
|
struct pw_buffer *pw_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xdpw_screencopy_frame_info {
|
struct xdpw_screencopy_frame_info {
|
||||||
uint32_t width;
|
uint32_t width;
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
uint32_t stride;
|
uint32_t stride;
|
||||||
uint32_t format;
|
uint32_t format;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xdpw_buffer {
|
struct xdpw_buffer {
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
enum buffer_type buffer_type;
|
enum buffer_type buffer_type;
|
||||||
|
|
||||||
uint32_t width;
|
uint32_t width;
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
uint32_t format;
|
uint32_t format;
|
||||||
int plane_count;
|
int plane_count;
|
||||||
|
|
||||||
int fd[4];
|
int fd[4];
|
||||||
uint32_t size[4];
|
uint32_t size[4];
|
||||||
uint32_t stride[4];
|
uint32_t stride[4];
|
||||||
uint32_t offset[4];
|
uint32_t offset[4];
|
||||||
|
|
||||||
struct gbm_bo *bo;
|
struct gbm_bo *bo;
|
||||||
|
|
||||||
struct wl_buffer *buffer;
|
struct wl_buffer *buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xdpw_format_modifier_pair {
|
struct xdpw_format_modifier_pair {
|
||||||
uint32_t fourcc;
|
uint32_t fourcc;
|
||||||
uint64_t modifier;
|
uint64_t modifier;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xdpw_dmabuf_feedback_data {
|
struct xdpw_dmabuf_feedback_data {
|
||||||
void *format_table_data;
|
void *format_table_data;
|
||||||
uint32_t format_table_size;
|
uint32_t format_table_size;
|
||||||
bool device_used;
|
bool device_used;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xdpw_screencast_context {
|
struct xdpw_screencast_context {
|
||||||
|
// xdpw
|
||||||
|
struct xdpw_state *state;
|
||||||
|
|
||||||
// xdpw
|
// pipewire
|
||||||
struct xdpw_state *state;
|
struct pw_context *pwr_context;
|
||||||
|
struct pw_core *core;
|
||||||
|
|
||||||
// pipewire
|
// wlroots
|
||||||
struct pw_context *pwr_context;
|
struct wl_list output_list;
|
||||||
struct pw_core *core;
|
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;
|
||||||
|
struct xdpw_dmabuf_feedback_data feedback_data;
|
||||||
|
struct wl_array format_modifier_pairs;
|
||||||
|
|
||||||
// wlroots
|
// hyprland
|
||||||
struct wl_list output_list;
|
struct hyprland_toplevel_export_manager_v1 *hyprland_toplevel_manager;
|
||||||
struct wl_registry *registry;
|
struct zwlr_foreign_toplevel_manager_v1 *wlroots_toplevel_manager;
|
||||||
struct zwlr_screencopy_manager_v1 *screencopy_manager;
|
struct wl_list toplevel_resource_list;
|
||||||
struct zxdg_output_manager_v1 *xdg_output_manager;
|
int toplevel_mgr_bind;
|
||||||
struct wl_shm *shm;
|
|
||||||
struct zwp_linux_dmabuf_v1 *linux_dmabuf;
|
|
||||||
struct zwp_linux_dmabuf_feedback_v1 *linux_dmabuf_feedback;
|
|
||||||
struct xdpw_dmabuf_feedback_data feedback_data;
|
|
||||||
struct wl_array format_modifier_pairs;
|
|
||||||
|
|
||||||
// hyprland
|
// gbm
|
||||||
struct hyprland_toplevel_export_manager_v1 *hyprland_toplevel_manager;
|
struct gbm_device *gbm;
|
||||||
struct zwlr_foreign_toplevel_manager_v1 *wlroots_toplevel_manager;
|
|
||||||
struct wl_list toplevel_resource_list;
|
|
||||||
|
|
||||||
// gbm
|
// sessions
|
||||||
struct gbm_device *gbm;
|
struct wl_list screencast_instances;
|
||||||
|
|
||||||
// sessions
|
|
||||||
struct wl_list screencast_instances;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xdpw_wlr_output {
|
struct xdpw_wlr_output {
|
||||||
|
@ -155,58 +155,58 @@ struct xdpw_share {
|
||||||
int y;
|
int y;
|
||||||
int w;
|
int w;
|
||||||
int h;
|
int h;
|
||||||
int window_handle;
|
int window_handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xdpw_screencast_instance {
|
struct xdpw_screencast_instance {
|
||||||
// list
|
// list
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
|
||||||
// xdpw
|
// xdpw
|
||||||
uint32_t refcount;
|
uint32_t refcount;
|
||||||
struct xdpw_screencast_context *ctx;
|
struct xdpw_screencast_context *ctx;
|
||||||
bool initialized;
|
bool initialized;
|
||||||
struct xdpw_frame current_frame;
|
struct xdpw_frame current_frame;
|
||||||
enum xdpw_frame_state frame_state;
|
enum xdpw_frame_state frame_state;
|
||||||
struct wl_list buffer_list;
|
struct wl_list buffer_list;
|
||||||
bool avoid_dmabufs;
|
bool avoid_dmabufs;
|
||||||
|
|
||||||
// pipewire
|
// pipewire
|
||||||
struct pw_stream *stream;
|
struct pw_stream *stream;
|
||||||
struct spa_hook stream_listener;
|
struct spa_hook stream_listener;
|
||||||
struct spa_video_info_raw pwr_format;
|
struct spa_video_info_raw pwr_format;
|
||||||
uint32_t seq;
|
uint32_t seq;
|
||||||
uint32_t node_id;
|
uint32_t node_id;
|
||||||
bool pwr_stream_state;
|
bool pwr_stream_state;
|
||||||
uint32_t framerate;
|
uint32_t framerate;
|
||||||
|
|
||||||
// wlroots
|
// wlroots
|
||||||
struct zwlr_screencopy_frame_v1 *frame_callback;
|
struct zwlr_screencopy_frame_v1 *frame_callback;
|
||||||
struct xdpw_share target;
|
struct xdpw_share target;
|
||||||
uint32_t max_framerate;
|
uint32_t max_framerate;
|
||||||
struct zwlr_screencopy_frame_v1 *wlr_frame;
|
struct zwlr_screencopy_frame_v1 *wlr_frame;
|
||||||
struct xdpw_screencopy_frame_info screencopy_frame_info[2];
|
struct xdpw_screencopy_frame_info screencopy_frame_info[2];
|
||||||
bool with_cursor;
|
bool with_cursor;
|
||||||
int err;
|
int err;
|
||||||
bool quit;
|
bool quit;
|
||||||
bool teardown;
|
bool teardown;
|
||||||
enum buffer_type buffer_type;
|
enum buffer_type buffer_type;
|
||||||
|
|
||||||
// hyprland
|
// hyprland
|
||||||
struct hyprland_toplevel_export_frame_v1 *frame_callback_hyprland;
|
struct hyprland_toplevel_export_frame_v1 *frame_callback_hyprland;
|
||||||
struct hyprland_toplevel_export_frame_v1 *hyprland_frame;
|
struct hyprland_toplevel_export_frame_v1 *hyprland_frame;
|
||||||
|
|
||||||
// fps limit
|
// fps limit
|
||||||
struct fps_limit_state fps_limit;
|
struct fps_limit_state fps_limit;
|
||||||
};
|
};
|
||||||
|
|
||||||
void randname(char *buf);
|
void randname(char *buf);
|
||||||
struct gbm_device *xdpw_gbm_device_create(drmDevice *device);
|
struct gbm_device *xdpw_gbm_device_create(drmDevice *device);
|
||||||
struct xdpw_buffer *xdpw_buffer_create(struct xdpw_screencast_instance *cast,
|
struct xdpw_buffer *xdpw_buffer_create(struct xdpw_screencast_instance *cast,
|
||||||
enum buffer_type buffer_type, struct xdpw_screencopy_frame_info *frame_info);
|
enum buffer_type buffer_type, struct xdpw_screencopy_frame_info *frame_info);
|
||||||
void xdpw_buffer_destroy(struct xdpw_buffer *buffer);
|
void xdpw_buffer_destroy(struct xdpw_buffer *buffer);
|
||||||
bool wlr_query_dmabuf_modifiers(struct xdpw_screencast_context *ctx, uint32_t drm_format,
|
bool wlr_query_dmabuf_modifiers(struct xdpw_screencast_context *ctx, uint32_t drm_format,
|
||||||
uint32_t num_modifiers, uint64_t *modifiers, uint32_t *max_modifiers);
|
uint32_t num_modifiers, uint64_t *modifiers, uint32_t *max_modifiers);
|
||||||
enum wl_shm_format xdpw_format_wl_shm_from_drm_fourcc(uint32_t format);
|
enum wl_shm_format xdpw_format_wl_shm_from_drm_fourcc(uint32_t format);
|
||||||
uint32_t xdpw_format_drm_fourcc_from_wl_shm(enum wl_shm_format format);
|
uint32_t xdpw_format_drm_fourcc_from_wl_shm(enum wl_shm_format format);
|
||||||
enum spa_video_format xdpw_format_pw_from_drm_fourcc(uint32_t format);
|
enum spa_video_format xdpw_format_pw_from_drm_fourcc(uint32_t format);
|
||||||
|
|
|
@ -1,135 +1,132 @@
|
||||||
#include "screencast.h"
|
#include "screencast.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <drm_fourcc.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <spa/utils/result.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <drm_fourcc.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <spa/utils/result.h>
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "logger.h"
|
||||||
#include "pipewire_screencast.h"
|
#include "pipewire_screencast.h"
|
||||||
#include "wlr_screencast.h"
|
#include "wlr_screencast.h"
|
||||||
#include "xdpw.h"
|
#include "xdpw.h"
|
||||||
#include "logger.h"
|
|
||||||
|
|
||||||
static const char object_path[] = "/org/freedesktop/portal/desktop";
|
static const char object_path[] = "/org/freedesktop/portal/desktop";
|
||||||
static const char interface_name[] = "org.freedesktop.impl.portal.ScreenCast";
|
static const char interface_name[] = "org.freedesktop.impl.portal.ScreenCast";
|
||||||
|
|
||||||
void exec_with_shell(char *command) {
|
void exec_with_shell(char *command) {
|
||||||
pid_t pid1 = fork();
|
pid_t pid1 = fork();
|
||||||
if (pid1 < 0) {
|
if (pid1 < 0) {
|
||||||
perror("fork");
|
perror("fork");
|
||||||
return;
|
return;
|
||||||
} else if (pid1 == 0) {
|
} else if (pid1 == 0) {
|
||||||
pid_t pid2 = fork();
|
pid_t pid2 = fork();
|
||||||
if (pid2 < 0) {
|
if (pid2 < 0) {
|
||||||
perror("fork");
|
perror("fork");
|
||||||
} else if (pid2 == 0) {
|
} else if (pid2 == 0) {
|
||||||
char *const argv[] = {
|
char *const argv[] = {
|
||||||
"sh",
|
"sh",
|
||||||
"-c",
|
"-c",
|
||||||
command,
|
command,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
execvp("sh", argv);
|
execvp("sh", argv);
|
||||||
perror("execvp");
|
perror("execvp");
|
||||||
_exit(127);
|
_exit(127);
|
||||||
}
|
}
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
int stat;
|
int stat;
|
||||||
if (waitpid(pid1, &stat, 0) < 0) {
|
if (waitpid(pid1, &stat, 0) < 0) {
|
||||||
perror("waitpid");
|
perror("waitpid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void xdpw_screencast_instance_init(struct xdpw_screencast_context *ctx,
|
void xdpw_screencast_instance_init(struct xdpw_screencast_context *ctx,
|
||||||
struct xdpw_screencast_instance *cast, struct xdpw_share out, bool with_cursor) {
|
struct xdpw_screencast_instance *cast, struct xdpw_share out, bool with_cursor) {
|
||||||
|
// only run exec_before if there's no other instance running that already ran it
|
||||||
|
if (wl_list_empty(&ctx->screencast_instances)) {
|
||||||
|
char *exec_before = ctx->state->config->screencast_conf.exec_before;
|
||||||
|
if (exec_before) {
|
||||||
|
logprint(INFO, "xdpw: executing %s before screencast", exec_before);
|
||||||
|
exec_with_shell(exec_before);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// only run exec_before if there's no other instance running that already ran it
|
cast->ctx = ctx;
|
||||||
if (wl_list_empty(&ctx->screencast_instances)) {
|
cast->target = out;
|
||||||
char *exec_before = ctx->state->config->screencast_conf.exec_before;
|
if (out.output == NULL) {
|
||||||
if (exec_before) {
|
|
||||||
logprint(INFO, "xdpw: executing %s before screencast", exec_before);
|
|
||||||
exec_with_shell(exec_before);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cast->ctx = ctx;
|
|
||||||
cast->target = out;
|
|
||||||
if (out.output == NULL) {
|
|
||||||
cast->max_framerate = 60; // dirty
|
cast->max_framerate = 60; // dirty
|
||||||
} else {
|
} else {
|
||||||
if (ctx->state->config->screencast_conf.max_fps > 0) {
|
if (ctx->state->config->screencast_conf.max_fps > 0) {
|
||||||
cast->max_framerate = ctx->state->config->screencast_conf.max_fps < (uint32_t)out.output->framerate ?
|
cast->max_framerate = ctx->state->config->screencast_conf.max_fps < (uint32_t)out.output->framerate ? ctx->state->config->screencast_conf.max_fps : (uint32_t)out.output->framerate;
|
||||||
ctx->state->config->screencast_conf.max_fps : (uint32_t)out.output->framerate;
|
} else {
|
||||||
} else {
|
cast->max_framerate = (uint32_t)out.output->framerate;
|
||||||
cast->max_framerate = (uint32_t)out.output->framerate;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
cast->framerate = cast->max_framerate;
|
||||||
cast->framerate = cast->max_framerate;
|
cast->with_cursor = with_cursor;
|
||||||
cast->with_cursor = with_cursor;
|
cast->refcount = 1;
|
||||||
cast->refcount = 1;
|
cast->node_id = SPA_ID_INVALID;
|
||||||
cast->node_id = SPA_ID_INVALID;
|
cast->avoid_dmabufs = false;
|
||||||
cast->avoid_dmabufs = false;
|
cast->teardown = false;
|
||||||
cast->teardown = false;
|
wl_list_init(&cast->buffer_list);
|
||||||
wl_list_init(&cast->buffer_list);
|
logprint(INFO, "xdpw: screencast instance %p has %d references", cast, cast->refcount);
|
||||||
logprint(INFO, "xdpw: screencast instance %p has %d references", cast, cast->refcount);
|
wl_list_insert(&ctx->screencast_instances, &cast->link);
|
||||||
wl_list_insert(&ctx->screencast_instances, &cast->link);
|
logprint(INFO, "xdpw: %d active screencast instances",
|
||||||
logprint(INFO, "xdpw: %d active screencast instances",
|
wl_list_length(&ctx->screencast_instances));
|
||||||
wl_list_length(&ctx->screencast_instances));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void xdpw_screencast_instance_destroy(struct xdpw_screencast_instance *cast) {
|
void xdpw_screencast_instance_destroy(struct xdpw_screencast_instance *cast) {
|
||||||
assert(cast->refcount == 0); // Fails assert if called by screencast_finish
|
assert(cast->refcount == 0); // Fails assert if called by screencast_finish
|
||||||
logprint(DEBUG, "xdpw: destroying cast instance");
|
logprint(DEBUG, "xdpw: destroying cast instance");
|
||||||
|
|
||||||
// make sure this is the last running instance that is being destroyed
|
// make sure this is the last running instance that is being destroyed
|
||||||
if (wl_list_length(&cast->link) == 1) {
|
if (wl_list_length(&cast->link) == 1) {
|
||||||
char *exec_after = cast->ctx->state->config->screencast_conf.exec_after;
|
char *exec_after = cast->ctx->state->config->screencast_conf.exec_after;
|
||||||
if (exec_after) {
|
if (exec_after) {
|
||||||
logprint(INFO, "xdpw: executing %s after screencast", exec_after);
|
logprint(INFO, "xdpw: executing %s after screencast", exec_after);
|
||||||
exec_with_shell(exec_after);
|
exec_with_shell(exec_after);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_list_remove(&cast->link);
|
wl_list_remove(&cast->link);
|
||||||
xdpw_pwr_stream_destroy(cast);
|
xdpw_pwr_stream_destroy(cast);
|
||||||
assert(wl_list_length(&cast->buffer_list) == 0);
|
assert(wl_list_length(&cast->buffer_list) == 0);
|
||||||
free(cast);
|
free(cast);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xdpw_screencast_instance_teardown(struct xdpw_screencast_instance *cast) {
|
void xdpw_screencast_instance_teardown(struct xdpw_screencast_instance *cast) {
|
||||||
struct xdpw_session *sess, *tmp;
|
struct xdpw_session *sess, *tmp;
|
||||||
wl_list_for_each_safe(sess, tmp, &cast->ctx->state->xdpw_sessions, link) {
|
wl_list_for_each_safe(sess, tmp, &cast->ctx->state->xdpw_sessions, link) {
|
||||||
if (sess->screencast_instance == cast) {
|
if (sess->screencast_instance == cast) {
|
||||||
xdpw_session_destroy(sess);
|
xdpw_session_destroy(sess);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setup_outputs(struct xdpw_screencast_context *ctx, struct xdpw_session *sess, bool with_cursor) {
|
bool setup_outputs(struct xdpw_screencast_context *ctx, struct xdpw_session *sess, bool with_cursor) {
|
||||||
|
struct xdpw_wlr_output *output, *tmp_o;
|
||||||
struct xdpw_wlr_output *output, *tmp_o;
|
wl_list_for_each_reverse_safe(output, tmp_o, &ctx->output_list, link) {
|
||||||
wl_list_for_each_reverse_safe(output, tmp_o, &ctx->output_list, link) {
|
logprint(INFO, "wlroots: capturable output: %s model: %s: id: %i name: %s",
|
||||||
logprint(INFO, "wlroots: capturable output: %s model: %s: id: %i name: %s",
|
output->make, output->model, output->id, output->name);
|
||||||
output->make, output->model, output->id, output->name);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
struct xdpw_share out;
|
struct xdpw_share out;
|
||||||
out = xdpw_wlr_chooser(ctx);
|
out = xdpw_wlr_chooser(ctx);
|
||||||
if (!out.output && out.window_handle == -1) {
|
if (!out.output && out.window_handle == -1) {
|
||||||
logprint(ERROR, "wlroots: no output / window found");
|
logprint(ERROR, "wlroots: no output / window found");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable screencast sharing to avoid sharing between dmabuf and shm capable clients
|
// Disable screencast sharing to avoid sharing between dmabuf and shm capable clients
|
||||||
/*
|
/*
|
||||||
struct xdpw_screencast_instance *cast, *tmp_c;
|
struct xdpw_screencast_instance *cast, *tmp_c;
|
||||||
wl_list_for_each_reverse_safe(cast, tmp_c, &ctx->screencast_instances, link) {
|
wl_list_for_each_reverse_safe(cast, tmp_c, &ctx->screencast_instances, link) {
|
||||||
logprint(INFO, "xdpw: existing screencast instance: %d %s cursor",
|
logprint(INFO, "xdpw: existing screencast instance: %d %s cursor",
|
||||||
|
@ -152,401 +149,400 @@ bool setup_outputs(struct xdpw_screencast_context *ctx, struct xdpw_session *ses
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!sess->screencast_instance) {
|
if (!sess->screencast_instance) {
|
||||||
sess->screencast_instance = calloc(1, sizeof(struct xdpw_screencast_instance));
|
sess->screencast_instance = calloc(1, sizeof(struct xdpw_screencast_instance));
|
||||||
xdpw_screencast_instance_init(ctx, sess->screencast_instance,
|
xdpw_screencast_instance_init(ctx, sess->screencast_instance,
|
||||||
out, with_cursor);
|
out, with_cursor);
|
||||||
}
|
}
|
||||||
if (out.output) {
|
if (out.output) {
|
||||||
logprint(INFO, "wlroots: output: %s",
|
logprint(INFO, "wlroots: output: %s",
|
||||||
sess->screencast_instance->target.output->name);
|
sess->screencast_instance->target.output->name);
|
||||||
} else {
|
} else {
|
||||||
logprint(INFO, "hyprland: window handle %d", sess->screencast_instance->target.window_handle);
|
logprint(INFO, "hyprland: window handle %d", sess->screencast_instance->target.window_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int start_screencast(struct xdpw_screencast_instance *cast) {
|
static int start_screencast(struct xdpw_screencast_instance *cast) {
|
||||||
xdpw_wlr_register_cb(cast);
|
xdpw_wlr_register_cb(cast);
|
||||||
|
|
||||||
// process at least one frame so that we know
|
// process at least one frame so that we know
|
||||||
// some of the metadata required for the pipewire
|
// some of the metadata required for the pipewire
|
||||||
// remote state connected event
|
// remote state connected event
|
||||||
wl_display_dispatch(cast->ctx->state->wl_display);
|
cast->ctx->toplevel_mgr_bind = 1;
|
||||||
wl_display_roundtrip(cast->ctx->state->wl_display);
|
wl_display_dispatch(cast->ctx->state->wl_display);
|
||||||
|
wl_display_roundtrip(cast->ctx->state->wl_display);
|
||||||
|
|
||||||
if (cast->screencopy_frame_info[WL_SHM].format == DRM_FORMAT_INVALID ||
|
if (cast->screencopy_frame_info[WL_SHM].format == DRM_FORMAT_INVALID ||
|
||||||
(cast->ctx->state->screencast_version >= 3 &&
|
(cast->ctx->state->screencast_version >= 3 &&
|
||||||
cast->screencopy_frame_info[DMABUF].format == DRM_FORMAT_INVALID)) {
|
cast->screencopy_frame_info[DMABUF].format == DRM_FORMAT_INVALID)) {
|
||||||
logprint(INFO, "wlroots: unable to receive a valid format from wlr_screencopy");
|
logprint(INFO, "wlroots: unable to receive a valid format from wlr_screencopy");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
xdpw_pwr_stream_create(cast);
|
xdpw_pwr_stream_create(cast);
|
||||||
|
|
||||||
cast->initialized = true;
|
cast->initialized = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int method_screencast_create_session(sd_bus_message *msg, void *data,
|
static int method_screencast_create_session(sd_bus_message *msg, void *data,
|
||||||
sd_bus_error *ret_error) {
|
sd_bus_error *ret_error) {
|
||||||
struct xdpw_state *state = data;
|
struct xdpw_state *state = data;
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
logprint(INFO, "dbus: create session method invoked");
|
logprint(INFO, "dbus: create session method invoked");
|
||||||
|
|
||||||
char *request_handle, *session_handle, *app_id;
|
char *request_handle, *session_handle, *app_id;
|
||||||
ret = sd_bus_message_read(msg, "oos", &request_handle, &session_handle, &app_id);
|
ret = sd_bus_message_read(msg, "oos", &request_handle, &session_handle, &app_id);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sd_bus_message_enter_container(msg, 'a', "{sv}");
|
ret = sd_bus_message_enter_container(msg, 'a', "{sv}");
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
logprint(INFO, "dbus: request_handle: %s", request_handle);
|
logprint(INFO, "dbus: request_handle: %s", request_handle);
|
||||||
logprint(INFO, "dbus: session_handle: %s", session_handle);
|
logprint(INFO, "dbus: session_handle: %s", session_handle);
|
||||||
logprint(INFO, "dbus: app_id: %s", app_id);
|
logprint(INFO, "dbus: app_id: %s", app_id);
|
||||||
|
|
||||||
char *key;
|
char *key;
|
||||||
int innerRet = 0;
|
int innerRet = 0;
|
||||||
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
||||||
innerRet = sd_bus_message_read(msg, "s", &key);
|
innerRet = sd_bus_message_read(msg, "s", &key);
|
||||||
if (innerRet < 0) {
|
if (innerRet < 0) {
|
||||||
return innerRet;
|
return innerRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(key, "session_handle_token") == 0) {
|
if (strcmp(key, "session_handle_token") == 0) {
|
||||||
char *token;
|
char *token;
|
||||||
sd_bus_message_read(msg, "v", "s", &token);
|
sd_bus_message_read(msg, "v", "s", &token);
|
||||||
logprint(INFO, "dbus: option token: %s", token);
|
logprint(INFO, "dbus: option token: %s", token);
|
||||||
} else {
|
} else {
|
||||||
logprint(WARN, "dbus: unknown option: %s", key);
|
logprint(WARN, "dbus: unknown option: %s", key);
|
||||||
sd_bus_message_skip(msg, "v");
|
sd_bus_message_skip(msg, "v");
|
||||||
}
|
}
|
||||||
|
|
||||||
innerRet = sd_bus_message_exit_container(msg);
|
innerRet = sd_bus_message_exit_container(msg);
|
||||||
if (innerRet < 0) {
|
if (innerRet < 0) {
|
||||||
return innerRet;
|
return innerRet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sd_bus_message_exit_container(msg);
|
ret = sd_bus_message_exit_container(msg);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct xdpw_request *req =
|
struct xdpw_request *req =
|
||||||
xdpw_request_create(sd_bus_message_get_bus(msg), request_handle);
|
xdpw_request_create(sd_bus_message_get_bus(msg), request_handle);
|
||||||
if (req == NULL) {
|
if (req == NULL) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct xdpw_session *sess =
|
struct xdpw_session *sess =
|
||||||
xdpw_session_create(state, sd_bus_message_get_bus(msg), strdup(session_handle));
|
xdpw_session_create(state, sd_bus_message_get_bus(msg), strdup(session_handle));
|
||||||
if (sess == NULL) {
|
if (sess == NULL) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
sd_bus_message *reply = NULL;
|
sd_bus_message *reply = NULL;
|
||||||
ret = sd_bus_message_new_method_return(msg, &reply);
|
ret = sd_bus_message_new_method_return(msg, &reply);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 0);
|
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
ret = sd_bus_send(NULL, reply, NULL);
|
ret = sd_bus_send(NULL, reply, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
sd_bus_message_unref(reply);
|
sd_bus_message_unref(reply);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int method_screencast_select_sources(sd_bus_message *msg, void *data,
|
static int method_screencast_select_sources(sd_bus_message *msg, void *data,
|
||||||
sd_bus_error *ret_error) {
|
sd_bus_error *ret_error) {
|
||||||
struct xdpw_state *state = data;
|
struct xdpw_state *state = data;
|
||||||
struct xdpw_screencast_context *ctx = &state->screencast;
|
struct xdpw_screencast_context *ctx = &state->screencast;
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct xdpw_session *sess, *tmp_s;
|
struct xdpw_session *sess, *tmp_s;
|
||||||
sd_bus_message *reply = NULL;
|
sd_bus_message *reply = NULL;
|
||||||
|
|
||||||
logprint(INFO, "dbus: select sources method invoked");
|
logprint(INFO, "dbus: select sources method invoked");
|
||||||
|
|
||||||
// default to embedded cursor mode if not specified
|
// default to embedded cursor mode if not specified
|
||||||
bool cursor_embedded = true;
|
bool cursor_embedded = true;
|
||||||
|
|
||||||
char *request_handle, *session_handle, *app_id;
|
char *request_handle, *session_handle, *app_id;
|
||||||
ret = sd_bus_message_read(msg, "oos", &request_handle, &session_handle, &app_id);
|
ret = sd_bus_message_read(msg, "oos", &request_handle, &session_handle, &app_id);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
ret = sd_bus_message_enter_container(msg, 'a', "{sv}");
|
ret = sd_bus_message_enter_container(msg, 'a', "{sv}");
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
logprint(INFO, "dbus: request_handle: %s", request_handle);
|
logprint(INFO, "dbus: request_handle: %s", request_handle);
|
||||||
logprint(INFO, "dbus: session_handle: %s", session_handle);
|
logprint(INFO, "dbus: session_handle: %s", session_handle);
|
||||||
logprint(INFO, "dbus: app_id: %s", app_id);
|
logprint(INFO, "dbus: app_id: %s", app_id);
|
||||||
|
|
||||||
char *key;
|
char *key;
|
||||||
int innerRet = 0;
|
int innerRet = 0;
|
||||||
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
||||||
innerRet = sd_bus_message_read(msg, "s", &key);
|
innerRet = sd_bus_message_read(msg, "s", &key);
|
||||||
if (innerRet < 0) {
|
if (innerRet < 0) {
|
||||||
return innerRet;
|
return innerRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(key, "multiple") == 0) {
|
if (strcmp(key, "multiple") == 0) {
|
||||||
int multiple;
|
int multiple;
|
||||||
sd_bus_message_read(msg, "v", "b", &multiple);
|
sd_bus_message_read(msg, "v", "b", &multiple);
|
||||||
logprint(INFO, "dbus: option multiple: %d", multiple);
|
logprint(INFO, "dbus: option multiple: %d", multiple);
|
||||||
} else if (strcmp(key, "types") == 0) {
|
} else if (strcmp(key, "types") == 0) {
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
sd_bus_message_read(msg, "v", "u", &mask);
|
sd_bus_message_read(msg, "v", "u", &mask);
|
||||||
if (mask & (1<<WINDOW)) {
|
if (mask & (1 << WINDOW)) {
|
||||||
logprint(INFO, "dbus: non-monitor cast requested, not replying");
|
logprint(INFO, "dbus: non-monitor cast requested, not replying");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
logprint(INFO, "dbus: option types:%x", mask);
|
logprint(INFO, "dbus: option types:%x", mask);
|
||||||
} else if (strcmp(key, "cursor_mode") == 0) {
|
} else if (strcmp(key, "cursor_mode") == 0) {
|
||||||
uint32_t cursor_mode;
|
uint32_t cursor_mode;
|
||||||
sd_bus_message_read(msg, "v", "u", &cursor_mode);
|
sd_bus_message_read(msg, "v", "u", &cursor_mode);
|
||||||
if (cursor_mode & HIDDEN) {
|
if (cursor_mode & HIDDEN) {
|
||||||
cursor_embedded = false;
|
cursor_embedded = false;
|
||||||
}
|
}
|
||||||
if (cursor_mode & METADATA) {
|
if (cursor_mode & METADATA) {
|
||||||
logprint(ERROR, "dbus: unsupported cursor mode requested, cancelling");
|
logprint(ERROR, "dbus: unsupported cursor mode requested, cancelling");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
logprint(INFO, "dbus: option cursor_mode:%x", cursor_mode);
|
logprint(INFO, "dbus: option cursor_mode:%x", cursor_mode);
|
||||||
} else {
|
} else {
|
||||||
logprint(WARN, "dbus: unknown option %s", key);
|
logprint(WARN, "dbus: unknown option %s", key);
|
||||||
sd_bus_message_skip(msg, "v");
|
sd_bus_message_skip(msg, "v");
|
||||||
}
|
}
|
||||||
|
|
||||||
innerRet = sd_bus_message_exit_container(msg);
|
innerRet = sd_bus_message_exit_container(msg);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
ret = sd_bus_message_exit_container(msg);
|
ret = sd_bus_message_exit_container(msg);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool output_selection_canceled = 1;
|
bool output_selection_canceled = 1;
|
||||||
wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) {
|
wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) {
|
||||||
if (strcmp(sess->session_handle, session_handle) == 0) {
|
if (strcmp(sess->session_handle, session_handle) == 0) {
|
||||||
logprint(DEBUG, "dbus: select sources: found matching session %s", sess->session_handle);
|
logprint(DEBUG, "dbus: select sources: found matching session %s", sess->session_handle);
|
||||||
output_selection_canceled = !setup_outputs(ctx, sess, cursor_embedded);
|
output_selection_canceled = !setup_outputs(ctx, sess, cursor_embedded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sd_bus_message_new_method_return(msg, &reply);
|
ret = sd_bus_message_new_method_return(msg, &reply);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
if (output_selection_canceled) {
|
if (output_selection_canceled) {
|
||||||
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_CANCELLED, 0);
|
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_CANCELLED, 0);
|
||||||
} else {
|
} else {
|
||||||
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 0);
|
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 0);
|
||||||
}
|
}
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
ret = sd_bus_send(NULL, reply, NULL);
|
ret = sd_bus_send(NULL, reply, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
sd_bus_message_unref(reply);
|
sd_bus_message_unref(reply);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) {
|
wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) {
|
||||||
if (strcmp(sess->session_handle, session_handle) == 0) {
|
if (strcmp(sess->session_handle, session_handle) == 0) {
|
||||||
logprint(DEBUG, "dbus: select sources error: destroying matching session %s", sess->session_handle);
|
logprint(DEBUG, "dbus: select sources error: destroying matching session %s", sess->session_handle);
|
||||||
xdpw_session_destroy(sess);
|
xdpw_session_destroy(sess);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sd_bus_message_new_method_return(msg, &reply);
|
ret = sd_bus_message_new_method_return(msg, &reply);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_CANCELLED, 0);
|
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_CANCELLED, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
ret = sd_bus_send(NULL, reply, NULL);
|
ret = sd_bus_send(NULL, reply, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
sd_bus_message_unref(reply);
|
sd_bus_message_unref(reply);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int method_screencast_start(sd_bus_message *msg, void *data,
|
static int method_screencast_start(sd_bus_message *msg, void *data,
|
||||||
sd_bus_error *ret_error) {
|
sd_bus_error *ret_error) {
|
||||||
struct xdpw_state *state = data;
|
struct xdpw_state *state = data;
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
logprint(INFO, "dbus: start method invoked");
|
logprint(INFO, "dbus: start method invoked");
|
||||||
|
|
||||||
char *request_handle, *session_handle, *app_id, *parent_window;
|
char *request_handle, *session_handle, *app_id, *parent_window;
|
||||||
ret = sd_bus_message_read(msg, "ooss", &request_handle, &session_handle, &app_id, &parent_window);
|
ret = sd_bus_message_read(msg, "ooss", &request_handle, &session_handle, &app_id, &parent_window);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
ret = sd_bus_message_enter_container(msg, 'a', "{sv}");
|
ret = sd_bus_message_enter_container(msg, 'a', "{sv}");
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
logprint(INFO, "dbus: request_handle: %s", request_handle);
|
logprint(INFO, "dbus: request_handle: %s", request_handle);
|
||||||
logprint(INFO, "dbus: session_handle: %s", session_handle);
|
logprint(INFO, "dbus: session_handle: %s", session_handle);
|
||||||
logprint(INFO, "dbus: app_id: %s", app_id);
|
logprint(INFO, "dbus: app_id: %s", app_id);
|
||||||
logprint(INFO, "dbus: parent_window: %s", parent_window);
|
logprint(INFO, "dbus: parent_window: %s", parent_window);
|
||||||
|
|
||||||
char *key;
|
char *key;
|
||||||
int innerRet = 0;
|
int innerRet = 0;
|
||||||
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
||||||
innerRet = sd_bus_message_read(msg, "s", &key);
|
innerRet = sd_bus_message_read(msg, "s", &key);
|
||||||
if (innerRet < 0) {
|
if (innerRet < 0) {
|
||||||
return innerRet;
|
return innerRet;
|
||||||
}
|
}
|
||||||
logprint(WARN, "dbus: unknown option: %s", key);
|
logprint(WARN, "dbus: unknown option: %s", key);
|
||||||
sd_bus_message_skip(msg, "v");
|
sd_bus_message_skip(msg, "v");
|
||||||
innerRet = sd_bus_message_exit_container(msg);
|
innerRet = sd_bus_message_exit_container(msg);
|
||||||
if (innerRet < 0) {
|
if (innerRet < 0) {
|
||||||
return innerRet;
|
return innerRet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
ret = sd_bus_message_exit_container(msg);
|
ret = sd_bus_message_exit_container(msg);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct xdpw_screencast_instance *cast = NULL;
|
struct xdpw_screencast_instance *cast = NULL;
|
||||||
struct xdpw_session *sess, *tmp_s;
|
struct xdpw_session *sess, *tmp_s;
|
||||||
wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) {
|
wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) {
|
||||||
if (strcmp(sess->session_handle, session_handle) == 0) {
|
if (strcmp(sess->session_handle, session_handle) == 0) {
|
||||||
logprint(DEBUG, "dbus: start: found matching session %s", sess->session_handle);
|
logprint(DEBUG, "dbus: start: found matching session %s", sess->session_handle);
|
||||||
cast = sess->screencast_instance;
|
cast = sess->screencast_instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!cast) {
|
if (!cast) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cast->initialized) {
|
if (!cast->initialized) {
|
||||||
ret = start_screencast(cast);
|
ret = start_screencast(cast);
|
||||||
}
|
}
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (cast->node_id == SPA_ID_INVALID) {
|
while (cast->node_id == SPA_ID_INVALID) {
|
||||||
int ret = pw_loop_iterate(state->pw_loop, 0);
|
int ret = pw_loop_iterate(state->pw_loop, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
logprint(ERROR, "pipewire_loop_iterate failed: %s", spa_strerror(ret));
|
logprint(ERROR, "pipewire_loop_iterate failed: %s", spa_strerror(ret));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sd_bus_message *reply = NULL;
|
sd_bus_message *reply = NULL;
|
||||||
ret = sd_bus_message_new_method_return(msg, &reply);
|
ret = sd_bus_message_new_method_return(msg, &reply);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
logprint(DEBUG, "dbus: start: returning node %d", (int)cast->node_id);
|
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, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 1,
|
||||||
"streams", "a(ua{sv})", 1,
|
"streams", "a(ua{sv})", 1,
|
||||||
cast->node_id, 2,
|
cast->node_id, 2,
|
||||||
"position", "(ii)", 0, 0,
|
"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);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sd_bus_send(NULL, reply, NULL);
|
ret = sd_bus_send(NULL, reply, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
sd_bus_message_unref(reply);
|
sd_bus_message_unref(reply);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const sd_bus_vtable screencast_vtable[] = {
|
static const sd_bus_vtable screencast_vtable[] = {
|
||||||
SD_BUS_VTABLE_START(0),
|
SD_BUS_VTABLE_START(0),
|
||||||
SD_BUS_METHOD("CreateSession", "oosa{sv}", "ua{sv}",
|
SD_BUS_METHOD("CreateSession", "oosa{sv}", "ua{sv}",
|
||||||
method_screencast_create_session, SD_BUS_VTABLE_UNPRIVILEGED),
|
method_screencast_create_session, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_METHOD("SelectSources", "oosa{sv}", "ua{sv}",
|
SD_BUS_METHOD("SelectSources", "oosa{sv}", "ua{sv}",
|
||||||
method_screencast_select_sources, SD_BUS_VTABLE_UNPRIVILEGED),
|
method_screencast_select_sources, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_METHOD("Start", "oossa{sv}", "ua{sv}",
|
SD_BUS_METHOD("Start", "oossa{sv}", "ua{sv}",
|
||||||
method_screencast_start, SD_BUS_VTABLE_UNPRIVILEGED),
|
method_screencast_start, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_PROPERTY("AvailableSourceTypes", "u", NULL,
|
SD_BUS_PROPERTY("AvailableSourceTypes", "u", NULL,
|
||||||
offsetof(struct xdpw_state, screencast_source_types),
|
offsetof(struct xdpw_state, screencast_source_types),
|
||||||
SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("AvailableCursorModes", "u", NULL,
|
SD_BUS_PROPERTY("AvailableCursorModes", "u", NULL,
|
||||||
offsetof(struct xdpw_state, screencast_cursor_modes),
|
offsetof(struct xdpw_state, screencast_cursor_modes),
|
||||||
SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("version", "u", NULL,
|
SD_BUS_PROPERTY("version", "u", NULL,
|
||||||
offsetof(struct xdpw_state, screencast_version),
|
offsetof(struct xdpw_state, screencast_version),
|
||||||
SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_VTABLE_END
|
SD_BUS_VTABLE_END};
|
||||||
};
|
|
||||||
|
|
||||||
int xdpw_screencast_init(struct xdpw_state *state) {
|
int xdpw_screencast_init(struct xdpw_state *state) {
|
||||||
sd_bus_slot *slot = NULL;
|
sd_bus_slot *slot = NULL;
|
||||||
|
|
||||||
state->screencast = (struct xdpw_screencast_context) { 0 };
|
state->screencast = (struct xdpw_screencast_context){0};
|
||||||
state->screencast.state = state;
|
state->screencast.state = state;
|
||||||
state->screencast.hyprland_toplevel_manager = NULL;
|
state->screencast.hyprland_toplevel_manager = NULL;
|
||||||
|
state->screencast.toplevel_mgr_bind = 0;
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
err = xdpw_pwr_context_create(state);
|
err = xdpw_pwr_context_create(state);
|
||||||
if (err) {
|
if (err) {
|
||||||
goto fail_pipewire;
|
goto fail_pipewire;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = xdpw_wlr_screencopy_init(state);
|
err = xdpw_wlr_screencopy_init(state);
|
||||||
if (err) {
|
if (err) {
|
||||||
goto fail_screencopy;
|
goto fail_screencopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sd_bus_add_object_vtable(state->bus, &slot, object_path, interface_name,
|
return sd_bus_add_object_vtable(state->bus, &slot, object_path, interface_name,
|
||||||
screencast_vtable, state);
|
screencast_vtable, state);
|
||||||
|
|
||||||
fail_screencopy:
|
fail_screencopy:
|
||||||
xdpw_wlr_screencopy_finish(&state->screencast);
|
xdpw_wlr_screencopy_finish(&state->screencast);
|
||||||
|
|
||||||
fail_pipewire:
|
fail_pipewire:
|
||||||
xdpw_pwr_context_destroy(state);
|
xdpw_pwr_context_destroy(state);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue