Bind toplevel protos once before first screencast

Also style.
This commit is contained in:
vaxerski 2023-02-01 17:49:29 +00:00
parent b03b1c2f27
commit ee73fca9cc
3 changed files with 1232 additions and 1235 deletions

View File

@ -6,9 +6,9 @@
#include <spa/param/video/format-utils.h>
#include <wayland-client-protocol.h>
#include <xf86drm.h>
#include "hyprland-toplevel-export-v1-client-protocol.h"
#include "fps_limit.h"
#include "hyprland-toplevel-export-v1-client-protocol.h"
// this seems to be right based on
// https://github.com/flatpak/xdg-desktop-portal/blob/309a1fc0cf2fb32cceb91dbc666d20cf0a3202c2/src/screen-cast.c#L955
@ -105,7 +105,6 @@ struct xdpw_dmabuf_feedback_data {
};
struct xdpw_screencast_context {
// xdpw
struct xdpw_state *state;
@ -128,6 +127,7 @@ struct xdpw_screencast_context {
struct hyprland_toplevel_export_manager_v1 *hyprland_toplevel_manager;
struct zwlr_foreign_toplevel_manager_v1 *wlroots_toplevel_manager;
struct wl_list toplevel_resource_list;
int toplevel_mgr_bind;
// gbm
struct gbm_device *gbm;

View File

@ -1,20 +1,20 @@
#include "screencast.h"
#include <assert.h>
#include <drm_fourcc.h>
#include <errno.h>
#include <spa/utils/result.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <drm_fourcc.h>
#include <sys/wait.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 "wlr_screencast.h"
#include "xdpw.h"
#include "logger.h"
static const char object_path[] = "/org/freedesktop/portal/desktop";
static const char interface_name[] = "org.freedesktop.impl.portal.ScreenCast";
@ -49,7 +49,6 @@ void exec_with_shell(char *command) {
void xdpw_screencast_instance_init(struct xdpw_screencast_context *ctx,
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;
@ -65,8 +64,7 @@ void xdpw_screencast_instance_init(struct xdpw_screencast_context *ctx,
cast->max_framerate = 60; // dirty
} else {
if (ctx->state->config->screencast_conf.max_fps > 0) {
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;
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;
} else {
cast->max_framerate = (uint32_t)out.output->framerate;
}
@ -114,7 +112,6 @@ void xdpw_screencast_instance_teardown(struct xdpw_screencast_instance *cast) {
}
bool setup_outputs(struct xdpw_screencast_context *ctx, struct xdpw_session *sess, bool with_cursor) {
struct xdpw_wlr_output *output, *tmp_o;
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",
@ -164,9 +161,7 @@ bool setup_outputs(struct xdpw_screencast_context *ctx, struct xdpw_session *ses
logprint(INFO, "hyprland: window handle %d", sess->screencast_instance->target.window_handle);
}
return true;
}
static int start_screencast(struct xdpw_screencast_instance *cast) {
@ -175,6 +170,7 @@ static int start_screencast(struct xdpw_screencast_instance *cast) {
// process at least one frame so that we know
// some of the metadata required for the pipewire
// remote state connected event
cast->ctx->toplevel_mgr_bind = 1;
wl_display_dispatch(cast->ctx->state->wl_display);
wl_display_roundtrip(cast->ctx->state->wl_display);
@ -318,7 +314,7 @@ static int method_screencast_select_sources(sd_bus_message *msg, void *data,
} else if (strcmp(key, "types") == 0) {
uint32_t 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");
return -1;
}
@ -518,15 +514,15 @@ static const sd_bus_vtable screencast_vtable[] = {
SD_BUS_PROPERTY("version", "u", NULL,
offsetof(struct xdpw_state, screencast_version),
SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_VTABLE_END
};
SD_BUS_VTABLE_END};
int xdpw_screencast_init(struct xdpw_state *state) {
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.hyprland_toplevel_manager = NULL;
state->screencast.toplevel_mgr_bind = 0;
int err;
err = xdpw_pwr_context_create(state);

View File

@ -1,10 +1,6 @@
#include "wlr_screencast.h"
#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 "wlr-foreign-toplevel-management-unstable-v1-client-protocol.h"
#include "hyprland-toplevel-export-v1-client-protocol.h"
#include <assert.h>
#include <fcntl.h>
#include <limits.h>
#include <stdbool.h>
@ -15,16 +11,19 @@
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <assert.h>
#include <wayland-client-protocol.h>
#include <xf86drm.h>
#include <string.h>
#include "screencast.h"
#include "pipewire_screencast.h"
#include "xdpw.h"
#include "logger.h"
#include "fps_limit.h"
#include "hyprland-toplevel-export-v1-client-protocol.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "logger.h"
#include "pipewire_screencast.h"
#include "screencast.h"
#include "wlr-foreign-toplevel-management-unstable-v1-client-protocol.h"
#include "wlr-screencopy-unstable-v1-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h"
#include "xdpw.h"
//
struct SToplevelEntry {
@ -58,6 +57,8 @@ void handleAppID(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, con
break;
}
}
logprint(DEBUG, "hyprland: toplevel app_id %s", app_id);
}
void handleOutputEnter(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct wl_output *output) {
@ -86,6 +87,8 @@ void handleClosed(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle) {
}
}
logprint(DEBUG, "hyprland: toplevel closed %s", current->clazz);
wl_list_remove(&current->link);
}
@ -107,17 +110,19 @@ struct zwlr_foreign_toplevel_handle_v1_listener toplevelHandleListener = {
void handleToplevel(void *data, struct zwlr_foreign_toplevel_manager_v1 *manager, struct zwlr_foreign_toplevel_handle_v1 *toplevel) {
struct xdpw_screencast_context *ctx = data;
struct SToplevelEntry* entry = malloc(sizeof(struct SToplevelEntry));
struct SToplevelEntry *entry = malloc(sizeof(struct SToplevelEntry));
entry->handle = toplevel;
wl_list_insert(&ctx->toplevel_resource_list, &entry->link);
zwlr_foreign_toplevel_handle_v1_add_listener(toplevel, &toplevelHandleListener, ctx);
logprint(DEBUG, "hyprland: toplevel handle created %lx", toplevel);
}
void handleFinished(void *data, struct zwlr_foreign_toplevel_manager_v1 *zwlr_foreign_toplevel_manager_v1) {
; // noop
logprint(ERROR, "hyprland: compositor called finished on zwlr_foreign_toplevel_manager_v1!");
}
struct zwlr_foreign_toplevel_manager_v1_listener toplevelListener = {
@ -125,7 +130,7 @@ struct zwlr_foreign_toplevel_manager_v1_listener toplevelListener = {
.finished = handleFinished,
};
struct SToplevelEntry* toplevelEntryFromID(struct xdpw_screencast_context *ctx, uint32_t id) {
struct SToplevelEntry *toplevelEntryFromID(struct xdpw_screencast_context *ctx, uint32_t id) {
struct SToplevelEntry *current;
wl_list_for_each(current, &ctx->toplevel_resource_list, link) {
if (((uint64_t)current->handle & 0xFFFFFFFF) == id) {
@ -177,7 +182,7 @@ void xdpw_wlr_frame_finish(struct xdpw_screencast_instance *cast) {
uint64_t delay_ns = fps_limit_measure_end(&cast->fps_limit, cast->framerate);
if (delay_ns > 0) {
xdpw_add_timer(cast->ctx->state, delay_ns,
(xdpw_event_loop_timer_func_t) xdpw_wlr_frame_start, cast);
(xdpw_event_loop_timer_func_t)xdpw_wlr_frame_start, cast);
return;
}
}
@ -277,7 +282,7 @@ static void wlr_frame_buffer_done(void *data,
assert(cast->current_frame.xdpw_buffer);
// Check if dequeued buffer is compatible with announced buffer
if (( cast->buffer_type == WL_SHM &&
if ((cast->buffer_type == WL_SHM &&
(cast->current_frame.xdpw_buffer->size[0] != cast->screencopy_frame_info[cast->buffer_type].size ||
cast->current_frame.xdpw_buffer->stride[0] != cast->screencopy_frame_info[cast->buffer_type].stride)) ||
cast->current_frame.xdpw_buffer->width != cast->screencopy_frame_info[cast->buffer_type].width ||
@ -331,7 +336,7 @@ static void wlr_frame_ready(void *data, struct zwlr_screencopy_frame_v1 *frame,
cast->current_frame.tv_sec = ((((uint64_t)tv_sec_hi) << 32) | tv_sec_lo);
cast->current_frame.tv_nsec = tv_nsec;
logprint(TRACE, "wlroots: timestamp %"PRIu64":%"PRIu32, cast->current_frame.tv_sec, cast->current_frame.tv_nsec);
logprint(TRACE, "wlroots: timestamp %" PRIu64 ":%" PRIu32, cast->current_frame.tv_sec, cast->current_frame.tv_nsec);
cast->frame_state = XDPW_FRAME_STATE_SUCCESS;
@ -438,7 +443,7 @@ static void hyprland_frame_buffer_done(void *data,
assert(cast->current_frame.xdpw_buffer);
// Check if dequeued buffer is compatible with announced buffer
if (( cast->buffer_type == WL_SHM &&
if ((cast->buffer_type == WL_SHM &&
(cast->current_frame.xdpw_buffer->size[0] != cast->screencopy_frame_info[cast->buffer_type].size ||
cast->current_frame.xdpw_buffer->stride[0] != cast->screencopy_frame_info[cast->buffer_type].stride)) ||
cast->current_frame.xdpw_buffer->width != cast->screencopy_frame_info[cast->buffer_type].width ||
@ -492,7 +497,7 @@ static void hyprland_frame_ready(void *data, struct hyprland_toplevel_export_fra
cast->current_frame.tv_sec = ((((uint64_t)tv_sec_hi) << 32) | tv_sec_lo);
cast->current_frame.tv_nsec = tv_nsec;
logprint(TRACE, "hyprland: timestamp %"PRIu64":%"PRIu32, cast->current_frame.tv_sec, cast->current_frame.tv_nsec);
logprint(TRACE, "hyprland: timestamp %" PRIu64 ":%" PRIu32, cast->current_frame.tv_sec, cast->current_frame.tv_nsec);
cast->frame_state = XDPW_FRAME_STATE_SUCCESS;
@ -520,11 +525,9 @@ static const struct hyprland_toplevel_export_frame_v1_listener hyprland_frame_li
.flags = hyprland_frame_flags,
.ready = hyprland_frame_ready,
.failed = hyprland_frame_failed,
.damage = hyprland_frame_damage
};
.damage = hyprland_frame_damage};
void xdpw_wlr_register_cb(struct xdpw_screencast_instance *cast) {
if (cast->target.x != -1 && cast->target.y != -1 && cast->target.w != -1 && cast->target.h != -1 && cast->target.window_handle == -1) {
// capture region
cast->frame_callback = zwlr_screencopy_manager_v1_capture_output_region(
@ -535,7 +538,7 @@ void xdpw_wlr_register_cb(struct xdpw_screencast_instance *cast) {
cast->ctx->screencopy_manager, cast->with_cursor, cast->target.output->output);
} else {
// share window
struct SToplevelEntry* entry = toplevelEntryFromID(cast->ctx, cast->target.window_handle);
struct SToplevelEntry *entry = toplevelEntryFromID(cast->ctx, cast->target.window_handle);
if (!entry) {
logprint(DEBUG, "hyprland: error in getting entry");
@ -569,7 +572,7 @@ static void wlr_output_handle_mode(void *data, struct wl_output *wl_output,
uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
if (flags & WL_OUTPUT_MODE_CURRENT) {
struct xdpw_wlr_output *output = data;
output->framerate = (float)refresh/1000;
output->framerate = (float)refresh / 1000;
}
}
@ -670,14 +673,12 @@ char *getFormat(const char *fmt, ...) {
return outputStr;
}
char* buildWindowList(struct xdpw_screencast_context *ctx) {
char *buildWindowList(struct xdpw_screencast_context *ctx) {
char *rolling = calloc(1, 1);
char* rolling = calloc(1, 1);
struct SToplevelEntry* current;
struct SToplevelEntry *current;
wl_list_for_each(current, &ctx->toplevel_resource_list, link) {
char* oldRolling = rolling;
char *oldRolling = rolling;
rolling = getFormat("%s%u[HC\011]%s[HT\011]%s[HE\011]", rolling, (uint32_t)(((uint64_t)current->handle) & 0xFFFFFFFF), current->clazz, current->name);
@ -701,7 +702,7 @@ struct xdpw_share xdpw_wlr_chooser(struct xdpw_screencast_context *ctx) {
const char *XCURSOR_SIZE = getenv("XCURSOR_SIZE");
const char *HYPRLAND_INSTANCE_SIGNATURE = getenv("HYPRLAND_INSTANCE_SIGNATURE");
char* windowList = buildWindowList(ctx);
char *windowList = buildWindowList(ctx);
char *cmd = getFormat("WAYLAND_DISPLAY=%s QT_QPA_PLATFORM=\"wayland\" XCURSOR_SIZE=%s HYPRLAND_INSTANCE_SIGNATURE=%s XDPH_WINDOW_SHARING_LIST=\"%s\" hyprland-share-picker", WAYLAND_DISPLAY, XCURSOR_SIZE ? XCURSOR_SIZE : "24", HYPRLAND_INSTANCE_SIGNATURE ? HYPRLAND_INSTANCE_SIGNATURE : "0", windowList);
@ -731,11 +732,11 @@ struct xdpw_share xdpw_wlr_chooser(struct xdpw_screencast_context *ctx) {
// find output
logprint(DEBUG, "Screencast: Attempting to find screen for %s", result);
char* display_name = malloc(strlen(result) - 7);
char *display_name = malloc(strlen(result) - 7);
strncpy(display_name, result + 7, strlen(result) - 8);
display_name[strlen(result) - 8] = 0;
struct xdpw_wlr_output* out;
struct xdpw_wlr_output *out;
bool found = false;
wl_list_for_each(out, &ctx->output_list, link) {
if (strcmp(out->name, display_name) == 0) {
@ -757,7 +758,7 @@ struct xdpw_share xdpw_wlr_chooser(struct xdpw_screencast_context *ctx) {
int atPos = 7;
for (int i = 7; i < (int)strlen(result); ++i) {
if (result[i] == '@'){
if (result[i] == '@') {
atPos = i;
break;
}
@ -780,7 +781,7 @@ struct xdpw_share xdpw_wlr_chooser(struct xdpw_screencast_context *ctx) {
int coordbegin = 7 + strlen(display_name) + 1;
for (int i = 7 + strlen(display_name) + 1; i < (int)strlen(result); ++i) {
if (result[i] == ',' || result[i] == '@' || i + 1 == (int)strlen(result)) {
char* entire = malloc(i - coordbegin + 1);
char *entire = malloc(i - coordbegin + 1);
strncpy(entire, result + coordbegin, i - coordbegin);
entire[i - coordbegin] = 0;
coords[coordno] = strtol(entire, NULL, 10);
@ -922,7 +923,7 @@ static void linux_dmabuf_feedback_format_table(void *data,
wl_array_release(&ctx->format_modifier_pairs);
wl_array_init(&ctx->format_modifier_pairs);
ctx->feedback_data.format_table_data = mmap(NULL , size, PROT_READ, MAP_PRIVATE, fd, 0);
ctx->feedback_data.format_table_data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
if (ctx->feedback_data.format_table_data == MAP_FAILED) {
ctx->feedback_data.format_table_data = NULL;
ctx->feedback_data.format_table_size = 0;
@ -991,7 +992,7 @@ static void linux_dmabuf_feedback_tranche_formats(void *data,
// An entry in the table has to be 16 bytes long
assert(sizeof(struct fm_entry) == 16);
uint32_t n_modifiers = ctx->feedback_data.format_table_size/sizeof(struct fm_entry);
uint32_t n_modifiers = ctx->feedback_data.format_table_size / sizeof(struct fm_entry);
struct fm_entry *fm_entry = ctx->feedback_data.format_table_data;
uint16_t *idx;
wl_array_for_each(idx, indices) {
@ -1025,7 +1026,7 @@ static void wlr_registry_handle_add(void *data, struct wl_registry *reg,
uint32_t id, const char *interface, uint32_t ver) {
struct xdpw_screencast_context *ctx = data;
logprint(DEBUG, "wlroots: interface to register %s (Version: %u)",interface, ver);
logprint(DEBUG, "wlroots: interface to register %s (Version: %u)", interface, ver);
if (!strcmp(interface, wl_output_interface.name)) {
struct xdpw_wlr_output *output = calloc(1, sizeof(*output));
@ -1052,7 +1053,7 @@ static void wlr_registry_handle_add(void *data, struct wl_registry *reg,
reg, id, &zwlr_screencopy_manager_v1_interface, version);
}
if (!strcmp(interface, hyprland_toplevel_export_manager_v1_interface.name)) {
if (!strcmp(interface, hyprland_toplevel_export_manager_v1_interface.name) && !ctx->hyprland_toplevel_manager) {
uint32_t version = ver;
logprint(DEBUG, "hyprland: |-- registered to interface %s (Version %u)", interface, version);
@ -1060,7 +1061,7 @@ static void wlr_registry_handle_add(void *data, struct wl_registry *reg,
ctx->hyprland_toplevel_manager = wl_registry_bind(reg, id, &hyprland_toplevel_export_manager_v1_interface, version);
}
if (!strcmp(interface, zwlr_foreign_toplevel_manager_v1_interface.name)) {
if (!strcmp(interface, zwlr_foreign_toplevel_manager_v1_interface.name) && ctx->toplevel_mgr_bind && !ctx->wlroots_toplevel_manager) {
uint32_t version = ver;
logprint(DEBUG, "hyprland: |-- registered to interface %s (Version %u)", interface, version);