aboutsummaryrefslogtreecommitdiff
path: root/dbus
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2025-06-28 04:25:20 +0200
committerdec05eba <dec05eba@protonmail.com>2025-06-28 04:25:26 +0200
commitb9537941c9eba041b7afc8b0f4256c73e35c2387 (patch)
tree84b650502b0a54ae173acfa9b3cf45d5089beb0e /dbus
parent2290f0641c91317c4fd05f35d2c0cfc25fba2181 (diff)
Restart portal capture if it's paused for 3 seconds or more (can happen if returning from lock screen)
Remove dbus server, no longer needed. Just run dbus code directly.
Diffstat (limited to 'dbus')
-rw-r--r--dbus/client/dbus_client.c269
-rw-r--r--dbus/client/dbus_client.h36
-rw-r--r--dbus/dbus_impl.c913
-rw-r--r--dbus/dbus_impl.h37
-rw-r--r--dbus/portal.h17
-rw-r--r--dbus/protocol.h86
-rw-r--r--dbus/server/dbus_server.c175
7 files changed, 0 insertions, 1533 deletions
diff --git a/dbus/client/dbus_client.c b/dbus/client/dbus_client.c
deleted file mode 100644
index de2df62..0000000
--- a/dbus/client/dbus_client.c
+++ /dev/null
@@ -1,269 +0,0 @@
-#include "dbus_client.h"
-#include "../protocol.h"
-
-#include <sys/socket.h>
-#include <sys/wait.h>
-#include <sys/prctl.h>
-#include <unistd.h>
-#include <poll.h>
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-
-// TODO: Error checking for write/read
-
-static bool gsr_dbus_client_wait_for_startup(gsr_dbus_client *self) {
- struct pollfd poll_fd = {
- .fd = self->socket_pair[0],
- .events = POLLIN,
- .revents = 0
- };
- for(;;) {
- int poll_res = poll(&poll_fd, 1, 100);
- if(poll_res > 0 && (poll_fd.revents & POLLIN)) {
- char msg;
- read(self->socket_pair[0], &msg, 1);
- return true;
- } else {
- int status = 0;
- int wait_result = waitpid(self->pid, &status, WNOHANG);
- if(wait_result != 0) {
- int exit_code = -1;
- if(WIFEXITED(status))
- exit_code = WEXITSTATUS(status);
- fprintf(stderr, "gsr error: gsr_dbus_client_init: server died or never started, exit code: %d\n", exit_code);
- self->pid = 0;
- return false;
- }
- }
- }
-}
-
-bool gsr_dbus_client_init(gsr_dbus_client *self, const char *screencast_restore_token) {
- memset(self, 0, sizeof(*self));
-
- if(socketpair(AF_UNIX, SOCK_STREAM, 0, self->socket_pair) == -1) {
- fprintf(stderr, "gsr error: gsr_dbus_client_init: socketpair failed, error: %s\n", strerror(errno));
- return false;
- }
-
- if(screencast_restore_token) {
- self->screencast_restore_token = strdup(screencast_restore_token);
- if(!self->screencast_restore_token) {
- fprintf(stderr, "gsr error: gsr_dbus_client_init: failed to clone restore token\n");
- gsr_dbus_client_deinit(self);
- return false;
- }
- }
-
- self->pid = fork();
- if(self->pid == -1) {
- fprintf(stderr, "gsr error: gsr_dbus_client_init: failed to fork process\n");
- gsr_dbus_client_deinit(self);
- return false;
- } else if(self->pid == 0) { /* child */
- char socket_pair_server_str[32];
- snprintf(socket_pair_server_str, sizeof(socket_pair_server_str), "%d", self->socket_pair[1]);
-
- /* Needed for NixOS for example, to make sure gsr-dbus-server doesn't inherit cap_sys_nice */
- prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
-
- const char *args[] = { "gsr-dbus-server", socket_pair_server_str, self->screencast_restore_token ? self->screencast_restore_token : "", NULL };
- execvp(args[0], (char *const*)args);
-
- fprintf(stderr, "gsr error: gsr_dbus_client_init: failed to launch \"gsr-dbus-server\", error: %s\n", strerror(errno));
- _exit(127);
- } else { /* parent */
- if(!gsr_dbus_client_wait_for_startup(self)) {
- gsr_dbus_client_deinit(self);
- return false;
- }
- }
-
- return true;
-}
-
-void gsr_dbus_client_deinit(gsr_dbus_client *self) {
- for(int i = 0; i < 2; ++i) {
- if(self->socket_pair[i] > 0) {
- close(self->socket_pair[i]);
- self->socket_pair[i] = -1;
- }
- }
-
- if(self->screencast_restore_token) {
- free(self->screencast_restore_token);
- self->screencast_restore_token = NULL;
- }
-
- if(self->pid > 0) {
- kill(self->pid, SIGKILL);
- int status = 0;
- waitpid(self->pid, &status, 0);
- self->pid = 0;
- }
-}
-
-int gsr_dbus_client_screencast_create_session(gsr_dbus_client *self, char *session_handle, size_t session_handle_size) {
- const gsr_dbus_request_message request = {
- .protocol_version = GSR_DBUS_PROTOCOL_VERSION,
- .type = GSR_DBUS_MESSAGE_REQ_CREATE_SESSION,
- .create_session = (gsr_dbus_message_req_create_session) {}
- };
- write(self->socket_pair[0], &request, sizeof(request));
-
- gsr_dbus_response_message response = {0};
- read(self->socket_pair[0], &response, sizeof(response));
-
- if(response.protocol_version != GSR_DBUS_PROTOCOL_VERSION) {
- fprintf(stderr, "gsr error: gsr_dbus_client_screencast_create_session: server uses protocol version %d while the client is using protocol version %d", response.protocol_version, GSR_DBUS_PROTOCOL_VERSION);
- return -1;
- }
-
- if(response.type == GSR_DBUS_MESSAGE_RESP_ERROR) {
- fprintf(stderr, "gsr error: gsr_dbus_client_screencast_create_session: server return error: %s (%d)\n", response.error.message, (int)response.error.error_code);
- return response.error.error_code;
- }
-
- if(response.type != GSR_DBUS_MESSAGE_RESP_CREATE_SESSION) {
- fprintf(stderr, "gsr error: gsr_dbus_client_screencast_create_session: received incorrect response type. Expected %d got %d\n", GSR_DBUS_MESSAGE_RESP_CREATE_SESSION, response.type);
- return -1;
- }
-
- snprintf(session_handle, session_handle_size, "%s", response.create_session.session_handle);
- return 0;
-}
-
-int gsr_dbus_client_screencast_select_sources(gsr_dbus_client *self, const char *session_handle, uint32_t capture_type, uint32_t cursor_mode) {
- gsr_dbus_request_message request = {
- .protocol_version = GSR_DBUS_PROTOCOL_VERSION,
- .type = GSR_DBUS_MESSAGE_REQ_SELECT_SOURCES,
- .select_sources = (gsr_dbus_message_req_select_sources) {
- .capture_type = capture_type,
- .cursor_mode = cursor_mode
- }
- };
- snprintf(request.select_sources.session_handle, sizeof(request.select_sources.session_handle), "%s", session_handle);
- write(self->socket_pair[0], &request, sizeof(request));
-
- gsr_dbus_response_message response = {0};
- read(self->socket_pair[0], &response, sizeof(response));
-
- if(response.protocol_version != GSR_DBUS_PROTOCOL_VERSION) {
- fprintf(stderr, "gsr error: gsr_dbus_client_screencast_select_sources: server uses protocol version %d while the client is using protocol version %d", response.protocol_version, GSR_DBUS_PROTOCOL_VERSION);
- return -1;
- }
-
- if(response.type == GSR_DBUS_MESSAGE_RESP_ERROR) {
- fprintf(stderr, "gsr error: gsr_dbus_client_screencast_select_sources: server return error: %s (%d)\n", response.error.message, (int)response.error.error_code);
- return response.error.error_code;
- }
-
- if(response.type != GSR_DBUS_MESSAGE_RESP_SELECT_SOURCES) {
- fprintf(stderr, "gsr error: gsr_dbus_client_screencast_select_sources: received incorrect response type. Expected %d got %d\n", GSR_DBUS_MESSAGE_RESP_SELECT_SOURCES, response.type);
- return -1;
- }
-
- return 0;
-}
-
-int gsr_dbus_client_screencast_start(gsr_dbus_client *self, const char *session_handle, uint32_t *pipewire_node) {
- *pipewire_node = 0;
-
- gsr_dbus_request_message request = {
- .protocol_version = GSR_DBUS_PROTOCOL_VERSION,
- .type = GSR_DBUS_MESSAGE_REQ_START,
- .start = (gsr_dbus_message_req_start) {}
- };
- snprintf(request.start.session_handle, sizeof(request.start.session_handle), "%s", session_handle);
- write(self->socket_pair[0], &request, sizeof(request));
-
- gsr_dbus_response_message response = {0};
- read(self->socket_pair[0], &response, sizeof(response));
-
- if(response.protocol_version != GSR_DBUS_PROTOCOL_VERSION) {
- fprintf(stderr, "gsr error: gsr_dbus_client_screencast_start: server uses protocol version %d while the client is using protocol version %d", response.protocol_version, GSR_DBUS_PROTOCOL_VERSION);
- return -1;
- }
-
- if(response.type == GSR_DBUS_MESSAGE_RESP_ERROR) {
- fprintf(stderr, "gsr error: gsr_dbus_client_screencast_start: server return error: %s (%d)\n", response.error.message, (int)response.error.error_code);
- return response.error.error_code;
- }
-
- if(response.type != GSR_DBUS_MESSAGE_RESP_START) {
- fprintf(stderr, "gsr error: gsr_dbus_client_screencast_start: received incorrect response type. Expected %d got %d\n", GSR_DBUS_MESSAGE_RESP_START, response.type);
- return -1;
- }
-
- if(self->screencast_restore_token) {
- free(self->screencast_restore_token);
- if(response.start.restore_token[0] == '\0')
- self->screencast_restore_token = NULL;
- else
- self->screencast_restore_token = strdup(response.start.restore_token);
- }
-
- *pipewire_node = response.start.pipewire_node;
- return 0;
-}
-
-bool gsr_dbus_client_screencast_open_pipewire_remote(gsr_dbus_client *self, const char *session_handle, int *pipewire_fd) {
- *pipewire_fd = 0;
-
- gsr_dbus_request_message request = {
- .protocol_version = GSR_DBUS_PROTOCOL_VERSION,
- .type = GSR_DBUS_MESSAGE_REQ_OPEN_PIPEWIRE_REMOTE,
- .open_pipewire_remote = (gsr_dbus_message_req_open_pipewire_remote) {}
- };
- snprintf(request.open_pipewire_remote.session_handle, sizeof(request.open_pipewire_remote.session_handle), "%s", session_handle);
- write(self->socket_pair[0], &request, sizeof(request));
-
- gsr_dbus_response_message response = {0};
- struct iovec iov = {
- .iov_base = &response,
- .iov_len = sizeof(response)
- };
-
- char msg_control[CMSG_SPACE(sizeof(int))];
-
- struct msghdr message = {
- .msg_iov = &iov,
- .msg_iovlen = 1,
- .msg_control = msg_control,
- .msg_controllen = sizeof(msg_control)
- };
-
- const int bla = recvmsg(self->socket_pair[0], &message, MSG_WAITALL);
- (void)bla;
-
- if(response.protocol_version != GSR_DBUS_PROTOCOL_VERSION) {
- fprintf(stderr, "gsr error: gsr_dbus_client_screencast_open_pipewire_remote: server uses protocol version %d while the client is using protocol version %d", response.protocol_version, GSR_DBUS_PROTOCOL_VERSION);
- return false;
- }
-
- if(response.type == GSR_DBUS_MESSAGE_RESP_ERROR) {
- fprintf(stderr, "gsr error: gsr_dbus_client_screencast_open_pipewire_remote: server return error: %s (%d)\n", response.error.message, (int)response.error.error_code);
- return false;
- }
-
- if(response.type != GSR_DBUS_MESSAGE_RESP_OPEN_PIPEWIRE_REMOTE) {
- fprintf(stderr, "gsr error: gsr_dbus_client_screencast_open_pipewire_remote: received incorrect response type. Expected %d got %d\n", GSR_DBUS_MESSAGE_RESP_OPEN_PIPEWIRE_REMOTE, response.type);
- return false;
- }
-
- struct cmsghdr *cmsg = CMSG_FIRSTHDR(&message);
- if(!cmsg || cmsg->cmsg_type != SCM_RIGHTS) {
- fprintf(stderr, "gsr error: gsr_dbus_client_screencast_open_pipewire_remote: returned message data is missing file descriptor\n");
- return false;
- }
-
- memcpy(pipewire_fd, CMSG_DATA(cmsg), sizeof(*pipewire_fd));
- return true;
-}
-
-const char* gsr_dbus_client_screencast_get_restore_token(gsr_dbus_client *self) {
- return self->screencast_restore_token;
-}
diff --git a/dbus/client/dbus_client.h b/dbus/client/dbus_client.h
deleted file mode 100644
index 98a1ecf..0000000
--- a/dbus/client/dbus_client.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef GSR_DBUS_CLIENT_H
-#define GSR_DBUS_CLIENT_H
-
-/*
- Using a client-server architecture is needed for dbus because cap_sys_nice breaks desktop portal.
- The main binary has cap_sys_nice and we launch a new child-process without it which uses uses desktop portal.
-*/
-
-#include "../portal.h"
-#include <stdbool.h>
-#include <stdint.h>
-#include <signal.h>
-
-typedef struct {
- int socket_pair[2];
- char *screencast_restore_token;
- pid_t pid;
-} gsr_dbus_client;
-
-/* Blocking. TODO: Make non-blocking */
-bool gsr_dbus_client_init(gsr_dbus_client *self, const char *screencast_restore_token);
-void gsr_dbus_client_deinit(gsr_dbus_client *self);
-
-/* The follow functions should be called in order to setup ScreenCast properly */
-/* These functions that return an int return the response status code */
-int gsr_dbus_client_screencast_create_session(gsr_dbus_client *self, char *session_handle, size_t session_handle_size);
-/*
- |capture_type| is a bitmask of gsr_portal_capture_type values. gsr_portal_capture_type values that are not supported by the desktop portal will be ignored.
- |gsr_portal_cursor_mode| is a bitmask of gsr_portal_cursor_mode values. gsr_portal_cursor_mode values that are not supported will be ignored.
-*/
-int gsr_dbus_client_screencast_select_sources(gsr_dbus_client *self, const char *session_handle, uint32_t capture_type, uint32_t cursor_mode);
-int gsr_dbus_client_screencast_start(gsr_dbus_client *self, const char *session_handle, uint32_t *pipewire_node);
-bool gsr_dbus_client_screencast_open_pipewire_remote(gsr_dbus_client *self, const char *session_handle, int *pipewire_fd);
-const char* gsr_dbus_client_screencast_get_restore_token(gsr_dbus_client *self);
-
-#endif /* GSR_DBUS_CLIENT_H */
diff --git a/dbus/dbus_impl.c b/dbus/dbus_impl.c
deleted file mode 100644
index 600fcc5..0000000
--- a/dbus/dbus_impl.c
+++ /dev/null
@@ -1,913 +0,0 @@
-#include "dbus_impl.h"
-
-#include <sys/random.h>
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <assert.h>
-
-/* TODO: Make non-blocking when GPU Screen Recorder is turned into a library */
-/* TODO: Make sure responses matches the requests */
-
-#define DESKTOP_PORTAL_SIGNAL_RULE "type='signal',interface='org.freedesktop.Portal.Request'"
-
-typedef enum {
- DICT_TYPE_STRING,
- DICT_TYPE_UINT32,
- DICT_TYPE_BOOL,
-} dict_value_type;
-
-typedef struct {
- const char *key;
- dict_value_type value_type;
- union {
- char *str;
- dbus_uint32_t u32;
- dbus_bool_t boolean;
- };
-} dict_entry;
-
-static bool generate_random_characters(char *buffer, int buffer_size, const char *alphabet, size_t alphabet_size) {
- /* TODO: Use other functions on other platforms than linux */
- if(getrandom(buffer, buffer_size, 0) < buffer_size) {
- fprintf(stderr, "Failed to get random bytes, error: %s\n", strerror(errno));
- return false;
- }
-
- for(int i = 0; i < buffer_size; ++i) {
- unsigned char c = *(unsigned char*)&buffer[i];
- buffer[i] = alphabet[c % alphabet_size];
- }
-
- return true;
-}
-
-static bool generate_random_characters_standard_alphabet(char *buffer, int buffer_size) {
- return generate_random_characters(buffer, buffer_size, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 62);
-}
-
-static const char* dict_value_type_to_string(dict_value_type type) {
- switch(type) {
- case DICT_TYPE_STRING: return "string";
- case DICT_TYPE_UINT32: return "uint32";
- case DICT_TYPE_BOOL: return "boolean";
- }
- return "(unknown)";
-}
-
-bool gsr_dbus_init(gsr_dbus *self, const char *screencast_restore_token) {
- memset(self, 0, sizeof(*self));
- dbus_error_init(&self->err);
-
- self->random_str[DBUS_RANDOM_STR_SIZE] = '\0';
- if(!generate_random_characters_standard_alphabet(self->random_str, DBUS_RANDOM_STR_SIZE)) {
- fprintf(stderr, "gsr error: gsr_dbus_init: failed to generate random string\n");
- return false;
- }
-
- self->con = dbus_bus_get(DBUS_BUS_SESSION, &self->err);
- if(dbus_error_is_set(&self->err)) {
- fprintf(stderr, "gsr error: gsr_dbus_init: dbus_bus_get failed with error: %s\n", self->err.message);
- return false;
- }
-
- if(!self->con) {
- fprintf(stderr, "gsr error: gsr_dbus_init: failed to get dbus session\n");
- return false;
- }
-
- /* TODO: Check the name */
- const int ret = dbus_bus_request_name(self->con, "com.dec05eba.gpu_screen_recorder", DBUS_NAME_FLAG_REPLACE_EXISTING, &self->err);
- if(dbus_error_is_set(&self->err)) {
- fprintf(stderr, "gsr error: gsr_dbus_init: dbus_bus_request_name failed with error: %s\n", self->err.message);
- gsr_dbus_deinit(self);
- return false;
- }
-
- if(screencast_restore_token) {
- self->screencast_restore_token = strdup(screencast_restore_token);
- if(!self->screencast_restore_token) {
- fprintf(stderr, "gsr error: gsr_dbus_init: failed to clone restore token\n");
- gsr_dbus_deinit(self);
- return false;
- }
- }
-
- (void)ret;
- // if(ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- // fprintf(stderr, "gsr error: gsr_capture_portal_setup_dbus: dbus_bus_request_name failed to get primary owner\n");
- // return false;
- // }
-
- return true;
-}
-
-void gsr_dbus_deinit(gsr_dbus *self) {
- if(self->screencast_restore_token) {
- free(self->screencast_restore_token);
- self->screencast_restore_token = NULL;
- }
-
- if(self->desktop_portal_rule_added) {
- dbus_bus_remove_match(self->con, DESKTOP_PORTAL_SIGNAL_RULE, NULL);
- // dbus_connection_flush(self->con);
- self->desktop_portal_rule_added = false;
- }
-
- if(self->con) {
- dbus_error_free(&self->err);
-
- dbus_bus_release_name(self->con, "com.dec05eba.gpu_screen_recorder", NULL);
-
- // Apparently shouldn't be used when a connection is setup by using dbus_bus_get
- //dbus_connection_close(self->con);
- dbus_connection_unref(self->con);
- self->con = NULL;
- }
-}
-
-static bool gsr_dbus_desktop_portal_get_property(gsr_dbus *self, const char *interface, const char *property_name, uint32_t *result) {
- *result = 0;
-
- DBusMessage *msg = dbus_message_new_method_call(
- "org.freedesktop.portal.Desktop", // target for the method call
- "/org/freedesktop/portal/desktop", // object to call on
- "org.freedesktop.DBus.Properties", // interface to call on
- "Get"); // method name
- if(!msg) {
- fprintf(stderr, "gsr error: gsr_dbus_desktop_portal_get_property: dbus_message_new_method_call failed\n");
- return false;
- }
-
- DBusMessageIter it;
- dbus_message_iter_init_append(msg, &it);
-
- if(!dbus_message_iter_append_basic(&it, DBUS_TYPE_STRING, &interface)) {
- fprintf(stderr, "gsr error: gsr_dbus_desktop_portal_get_property: failed to add interface\n");
- dbus_message_unref(msg);
- return false;
- }
-
- if(!dbus_message_iter_append_basic(&it, DBUS_TYPE_STRING, &property_name)) {
- fprintf(stderr, "gsr error: gsr_dbus_desktop_portal_get_property: failed to add property_name\n");
- dbus_message_unref(msg);
- return false;
- }
-
- DBusPendingCall *pending = NULL;
- if(!dbus_connection_send_with_reply(self->con, msg, &pending, -1) || !pending) { // -1 is default timeout
- fprintf(stderr, "gsr error: gsr_dbus_desktop_portal_get_property: dbus_connection_send_with_reply failed\n");
- dbus_message_unref(msg);
- return false;
- }
- dbus_connection_flush(self->con);
-
- //fprintf(stderr, "Request Sent\n");
-
- dbus_message_unref(msg);
- msg = NULL;
-
- dbus_pending_call_block(pending);
-
- msg = dbus_pending_call_steal_reply(pending);
- if(!msg) {
- fprintf(stderr, "gsr error: gsr_dbus_desktop_portal_get_property: dbus_pending_call_steal_reply failed\n");
- dbus_pending_call_unref(pending);
- dbus_message_unref(msg);
- return false;
- }
-
- dbus_pending_call_unref(pending);
- pending = NULL;
-
- DBusMessageIter resp_args;
- if(!dbus_message_iter_init(msg, &resp_args)) {
- fprintf(stderr, "gsr error: gsr_dbus_desktop_portal_get_property: response message is missing arguments\n");
- dbus_message_unref(msg);
- return false;
- } else if(DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type(&resp_args)) {
- dbus_message_iter_get_basic(&resp_args, result);
- } else if(DBUS_TYPE_VARIANT == dbus_message_iter_get_arg_type(&resp_args)) {
- DBusMessageIter variant_iter;
- dbus_message_iter_recurse(&resp_args, &variant_iter);
-
- if(dbus_message_iter_get_arg_type(&variant_iter) == DBUS_TYPE_UINT32) {
- dbus_message_iter_get_basic(&variant_iter, result);
- } else {
- fprintf(stderr, "gsr error: gsr_dbus_desktop_portal_get_property: response message is not a variant with an uint32, %c\n", dbus_message_iter_get_arg_type(&variant_iter));
- dbus_message_unref(msg);
- return false;
- }
- } else {
- fprintf(stderr, "gsr error: gsr_dbus_desktop_portal_get_property: response message is not an uint32, %c\n", dbus_message_iter_get_arg_type(&resp_args));
- dbus_message_unref(msg);
- return false;
- // TODO: Check dbus_error_is_set?
- }
-
- dbus_message_unref(msg);
- return true;
-}
-
-static uint32_t gsr_dbus_get_screencast_version_cached(gsr_dbus *self) {
- if(self->screencast_version == 0)
- gsr_dbus_desktop_portal_get_property(self, "org.freedesktop.portal.ScreenCast", "version", &self->screencast_version);
- return self->screencast_version;
-}
-
-static bool gsr_dbus_ensure_desktop_portal_rule_added(gsr_dbus *self) {
- if(self->desktop_portal_rule_added)
- return true;
-
- dbus_bus_add_match(self->con, DESKTOP_PORTAL_SIGNAL_RULE, &self->err);
- dbus_connection_flush(self->con);
- if(dbus_error_is_set(&self->err)) {
- fprintf(stderr, "gsr error: gsr_dbus_ensure_desktop_portal_rule_added: failed to add dbus rule %s, error: %s\n", DESKTOP_PORTAL_SIGNAL_RULE, self->err.message);
- return false;
- }
- self->desktop_portal_rule_added = true;
- return true;
-}
-
-static void gsr_dbus_portal_get_unique_handle_token(gsr_dbus *self, char *buffer, int size) {
- snprintf(buffer, size, "gpu_screen_recorder_handle_%s_%u", self->random_str, self->handle_counter++);
-}
-
-static void gsr_dbus_portal_get_unique_session_token(gsr_dbus *self, char *buffer, int size) {
- snprintf(buffer, size, "gpu_screen_recorder_session_%s", self->random_str);
-}
-
-static bool dbus_add_dict(DBusMessageIter *it, const dict_entry *entries, int num_entries) {
- DBusMessageIter array_it;
- if(!dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, "{sv}", &array_it))
- return false;
-
- for (int i = 0; i < num_entries; ++i) {
- DBusMessageIter entry_it = DBUS_MESSAGE_ITER_INIT_CLOSED;
- DBusMessageIter variant_it = DBUS_MESSAGE_ITER_INIT_CLOSED;
-
- if(!dbus_message_iter_open_container(&array_it, DBUS_TYPE_DICT_ENTRY, NULL, &entry_it))
- goto entry_err;
-
- if(!dbus_message_iter_append_basic(&entry_it, DBUS_TYPE_STRING, &entries[i].key))
- goto entry_err;
-
- switch (entries[i].value_type) {
- case DICT_TYPE_STRING: {
- if(!dbus_message_iter_open_container(&entry_it, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &variant_it))
- goto entry_err;
- if(!dbus_message_iter_append_basic(&variant_it, DBUS_TYPE_STRING, &entries[i].str))
- goto entry_err;
- break;
- }
- case DICT_TYPE_UINT32: {
- if(!dbus_message_iter_open_container(&entry_it, DBUS_TYPE_VARIANT, DBUS_TYPE_UINT32_AS_STRING, &variant_it))
- goto entry_err;
- if(!dbus_message_iter_append_basic(&variant_it, DBUS_TYPE_UINT32, &entries[i].u32))
- goto entry_err;
- break;
- }
- case DICT_TYPE_BOOL: {
- if(!dbus_message_iter_open_container(&entry_it, DBUS_TYPE_VARIANT, DBUS_TYPE_BOOLEAN_AS_STRING, &variant_it))
- goto entry_err;
- if(!dbus_message_iter_append_basic(&variant_it, DBUS_TYPE_BOOLEAN, &entries[i].boolean))
- goto entry_err;
- break;
- }
- }
-
- dbus_message_iter_close_container(&entry_it, &variant_it);
- dbus_message_iter_close_container(&array_it, &entry_it);
- continue;
-
- entry_err:
- dbus_message_iter_abandon_container_if_open(&array_it, &variant_it);
- dbus_message_iter_abandon_container_if_open(&array_it, &entry_it);
- dbus_message_iter_abandon_container_if_open(it, &array_it);
- return false;
- }
-
- return dbus_message_iter_close_container(it, &array_it);
-}
-
-/* If |response_msg| is NULL then we dont wait for a response signal */
-static bool gsr_dbus_call_screencast_method(gsr_dbus *self, const char *method_name, const char *session_handle, const char *parent_window, const dict_entry *entries, int num_entries, int *resp_fd, DBusMessage **response_msg) {
- if(resp_fd)
- *resp_fd = -1;
-
- if(response_msg)
- *response_msg = NULL;
-
- if(!gsr_dbus_ensure_desktop_portal_rule_added(self))
- return false;
-
- DBusMessage *msg = dbus_message_new_method_call(
- "org.freedesktop.portal.Desktop", // target for the method call
- "/org/freedesktop/portal/desktop", // object to call on
- "org.freedesktop.portal.ScreenCast", // interface to call on
- method_name); // method name
- if(!msg) {
- fprintf(stderr, "gsr error: gsr_dbus_call_screencast_method: dbus_message_new_method_call failed\n");
- return false;
- }
-
- DBusMessageIter it;
- dbus_message_iter_init_append(msg, &it);
-
- if(session_handle) {
- if(!dbus_message_iter_append_basic(&it, DBUS_TYPE_OBJECT_PATH, &session_handle)) {
- fprintf(stderr, "gsr error: gsr_dbus_call_screencast_method: failed to add session_handle\n");
- dbus_message_unref(msg);
- return false;
- }
- }
-
- if(parent_window) {
- if(!dbus_message_iter_append_basic(&it, DBUS_TYPE_STRING, &parent_window)) {
- fprintf(stderr, "gsr error: gsr_dbus_call_screencast_method: failed to add parent_window\n");
- dbus_message_unref(msg);
- return false;
- }
- }
-
- if(!dbus_add_dict(&it, entries, num_entries)) {
- fprintf(stderr, "gsr error: gsr_dbus_call_screencast_method: failed to add dict\n");
- dbus_message_unref(msg);
- return false;
- }
-
- DBusPendingCall *pending = NULL;
- if(!dbus_connection_send_with_reply(self->con, msg, &pending, -1) || !pending) { // -1 is default timeout
- fprintf(stderr, "gsr error: gsr_dbus_call_screencast_method: dbus_connection_send_with_reply failed\n");
- dbus_message_unref(msg);
- return false;
- }
- dbus_connection_flush(self->con);
-
- //fprintf(stderr, "Request Sent\n");
-
- dbus_message_unref(msg);
- msg = NULL;
-
- dbus_pending_call_block(pending);
-
- msg = dbus_pending_call_steal_reply(pending);
- if(!msg) {
- fprintf(stderr, "gsr error: gsr_dbus_call_screencast_method: dbus_pending_call_steal_reply failed\n");
- dbus_pending_call_unref(pending);
- dbus_message_unref(msg);
- return false;
- }
-
- dbus_pending_call_unref(pending);
- pending = NULL;
-
- DBusMessageIter resp_args;
- if(!dbus_message_iter_init(msg, &resp_args)) {
- fprintf(stderr, "gsr error: gsr_dbus_call_screencast_method: response message is missing arguments\n");
- dbus_message_unref(msg);
- return false;
- } else if (DBUS_TYPE_OBJECT_PATH == dbus_message_iter_get_arg_type(&resp_args)) {
- const char *res = NULL;
- dbus_message_iter_get_basic(&resp_args, &res);
- } else if(DBUS_TYPE_UNIX_FD == dbus_message_iter_get_arg_type(&resp_args)) {
- int fd = -1;
- dbus_message_iter_get_basic(&resp_args, &fd);
-
- if(resp_fd)
- *resp_fd = fd;
- } else if(DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&resp_args)) {
- char *err = NULL;
- dbus_message_iter_get_basic(&resp_args, &err);
- fprintf(stderr, "gsr error: gsr_dbus_call_screencast_method: failed with error: %s\n", err);
-
- dbus_message_unref(msg);
- return false;
- // TODO: Check dbus_error_is_set?
- } else {
- fprintf(stderr, "gsr error: gsr_dbus_call_screencast_method: response message is not an object path or unix fd\n");
- dbus_message_unref(msg);
- return false;
- // TODO: Check dbus_error_is_set?
- }
-
- dbus_message_unref(msg);
- if(!response_msg)
- return true;
-
- /* TODO: Add timeout, but take into consideration user interactive signals (such as selecting a monitor to capture for ScreenCast) */
- for (;;) {
- const int timeout_milliseconds = 10;
- dbus_connection_read_write(self->con, timeout_milliseconds);
- *response_msg = dbus_connection_pop_message(self->con);
-
- if(!*response_msg)
- continue;
-
- if(!dbus_message_is_signal(*response_msg, "org.freedesktop.portal.Request", "Response")) {
- dbus_message_unref(*response_msg);
- *response_msg = NULL;
- continue;
- }
-
- break;
- }
-
- return true;
-}
-
-static int gsr_dbus_get_response_status(DBusMessageIter *resp_args) {
- if(dbus_message_iter_get_arg_type(resp_args) != DBUS_TYPE_UINT32) {
- fprintf(stderr, "gsr error: gsr_dbus_get_response_status: missing uint32 in response\n");
- return -1;
- }
-
- dbus_uint32_t response_status = 0;
- dbus_message_iter_get_basic(resp_args, &response_status);
-
- dbus_message_iter_next(resp_args);
- return (int)response_status;
-}
-
-static dict_entry* find_dict_entry_by_key(dict_entry *entries, int num_entries, const char *key) {
- for(int i = 0; i < num_entries; ++i) {
- if(strcmp(entries[i].key, key) == 0)
- return &entries[i];
- }
- return NULL;
-}
-
-static bool gsr_dbus_get_variant_value(DBusMessageIter *iter, dict_entry *entry) {
- if(dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT) {
- fprintf(stderr, "gsr error: gsr_dbus_get_variant_value: value is not a variant\n");
- return false;
- }
-
- DBusMessageIter variant_iter;
- dbus_message_iter_recurse(iter, &variant_iter);
-
- switch(dbus_message_iter_get_arg_type(&variant_iter)) {
- case DBUS_TYPE_STRING: {
- if(entry->value_type != DICT_TYPE_STRING) {
- fprintf(stderr, "gsr error: gsr_dbus_get_variant_value: expected entry value to be a(n) %s was a string\n", dict_value_type_to_string(entry->value_type));
- return false;
- }
-
- const char *value = NULL;
- dbus_message_iter_get_basic(&variant_iter, &value);
-
- if(!value) {
- fprintf(stderr, "gsr error: gsr_dbus_get_variant_value: failed to get entry value as value\n");
- return false;
- }
-
- if(entry->str) {
- free(entry->str);
- entry->str = NULL;
- }
-
- entry->str = strdup(value);
- if(!entry->str) {
- fprintf(stderr, "gsr error: gsr_dbus_get_variant_value: failed to copy value\n");
- return false;
- }
- return true;
- }
- case DBUS_TYPE_UINT32: {
- if(entry->value_type != DICT_TYPE_UINT32) {
- fprintf(stderr, "gsr error: gsr_dbus_get_variant_value: expected entry value to be a(n) %s was an uint32\n", dict_value_type_to_string(entry->value_type));
- return false;
- }
-
- dbus_message_iter_get_basic(&variant_iter, &entry->u32);
- return true;
- }
- case DBUS_TYPE_BOOLEAN: {
- if(entry->value_type != DICT_TYPE_BOOL) {
- fprintf(stderr, "gsr error: gsr_dbus_get_variant_value: expected entry value to be a(n) %s was a boolean\n", dict_value_type_to_string(entry->value_type));
- return false;
- }
-
- dbus_message_iter_get_basic(&variant_iter, &entry->boolean);
- return true;
- }
- }
-
- fprintf(stderr, "gsr error: gsr_dbus_get_variant_value: got unexpected type, expected string, uint32 or boolean\n");
- return false;
-}
-
-/*
- Parses a{sv} into matching key entries in |entries|.
- If the entry value is a string then it's allocated with malloc and is null-terminated
- and has to be free by the caller.
- The entry values should be 0 before this method is called.
- The entries are free'd if this function fails.
-*/
-static bool gsr_dbus_get_map(DBusMessageIter *resp_args, dict_entry *entries, int num_entries) {
- if(dbus_message_iter_get_arg_type(resp_args) != DBUS_TYPE_ARRAY) {
- fprintf(stderr, "gsr error: gsr_dbus_get_map: missing array in response\n");
- return false;
- }
-
- DBusMessageIter subiter;
- dbus_message_iter_recurse(resp_args, &subiter);
-
- while(dbus_message_iter_get_arg_type(&subiter) != DBUS_TYPE_INVALID) {
- DBusMessageIter dictiter = DBUS_MESSAGE_ITER_INIT_CLOSED;
- const char *key = NULL;
- dict_entry *entry = NULL;
-
- // fprintf(stderr, " array element type: %c, %s\n",
- // dbus_message_iter_get_arg_type(&subiter),
- // dbus_message_iter_get_signature(&subiter));
- if(dbus_message_iter_get_arg_type(&subiter) != DBUS_TYPE_DICT_ENTRY) {
- fprintf(stderr, "gsr error: gsr_dbus_get_map: array value is not an entry\n");
- return false;
- }
-
- dbus_message_iter_recurse(&subiter, &dictiter);
-
- if(dbus_message_iter_get_arg_type(&dictiter) != DBUS_TYPE_STRING) {
- fprintf(stderr, "gsr error: gsr_dbus_get_map: entry key is not a string\n");
- goto error;
- }
-
- dbus_message_iter_get_basic(&dictiter, &key);
- if(!key) {
- fprintf(stderr, "gsr error: gsr_dbus_get_map: failed to get entry key as value\n");
- goto error;
- }
-
- entry = find_dict_entry_by_key(entries, num_entries, key);
- if(!entry) {
- dbus_message_iter_next(&subiter);
- continue;
- }
-
- if(!dbus_message_iter_next(&dictiter)) {
- fprintf(stderr, "gsr error: gsr_dbus_get_map: missing entry value\n");
- goto error;
- }
-
- if(!gsr_dbus_get_variant_value(&dictiter, entry))
- goto error;
-
- dbus_message_iter_next(&subiter);
- }
-
- return true;
-
- error:
- for(int i = 0; i < num_entries; ++i) {
- if(entries[i].value_type == DICT_TYPE_STRING) {
- free(entries[i].str);
- entries[i].str = NULL;
- }
- }
- return false;
-}
-
-int gsr_dbus_screencast_create_session(gsr_dbus *self, char **session_handle) {
- assert(session_handle);
- *session_handle = NULL;
-
- char handle_token[64];
- gsr_dbus_portal_get_unique_handle_token(self, handle_token, sizeof(handle_token));
-
- char session_handle_token[64];
- gsr_dbus_portal_get_unique_session_token(self, session_handle_token, sizeof(session_handle_token));
-
- dict_entry args[2];
- args[0].key = "handle_token";
- args[0].value_type = DICT_TYPE_STRING;
- args[0].str = handle_token;
-
- args[1].key = "session_handle_token";
- args[1].value_type = DICT_TYPE_STRING;
- args[1].str = session_handle_token;
-
- DBusMessage *response_msg = NULL;
- if(!gsr_dbus_call_screencast_method(self, "CreateSession", NULL, NULL, args, 2, NULL, &response_msg)) {
- fprintf(stderr, "gsr error: gsr_dbus_screencast_create_session: failed to setup ScreenCast session. Make sure you have a desktop portal running with support for the ScreenCast interface and that the desktop portal matches the Wayland compositor you are running.\n");
- return -1;
- }
-
- // TODO: Verify signal path matches |res|, maybe check the below
- // DBUS_TYPE_ARRAY value?
- //fprintf(stderr, "signature: %s, sender: %s\n", dbus_message_get_signature(msg), dbus_message_get_sender(msg));
- DBusMessageIter resp_args;
- if(!dbus_message_iter_init(response_msg, &resp_args)) {
- fprintf(stderr, "gsr error: gsr_dbus_screencast_create_session: missing response\n");
- dbus_message_unref(response_msg);
- return -1;
- }
-
- const int response_status = gsr_dbus_get_response_status(&resp_args);
- if(response_status != 0) {
- dbus_message_unref(response_msg);
- return response_status;
- }
-
- dict_entry entries[1];
- entries[0].key = "session_handle";
- entries[0].str = NULL;
- entries[0].value_type = DICT_TYPE_STRING;
- if(!gsr_dbus_get_map(&resp_args, entries, 1)) {
- dbus_message_unref(response_msg);
- return -1;
- }
-
- if(!entries[0].str) {
- fprintf(stderr, "gsr error: gsr_dbus_screencast_create_session: missing \"session_handle\" in response\n");
- dbus_message_unref(response_msg);
- return -1;
- }
-
- *session_handle = entries[0].str;
- //fprintf(stderr, "session handle: |%s|\n", entries[0].str);
- //free(entries[0].str);
-
- dbus_message_unref(response_msg);
- return 0;
-}
-
-static uint32_t unset_unsupported_capture_types(uint32_t requested_capture_types, uint32_t available_capture_types) {
- if(!(available_capture_types & GSR_PORTAL_CAPTURE_TYPE_MONITOR))
- requested_capture_types &= ~GSR_PORTAL_CAPTURE_TYPE_MONITOR;
- if(!(available_capture_types & GSR_PORTAL_CAPTURE_TYPE_WINDOW))
- requested_capture_types &= ~GSR_PORTAL_CAPTURE_TYPE_WINDOW;
- if(!(available_capture_types & GSR_PORTAL_CAPTURE_TYPE_VIRTUAL))
- requested_capture_types &= ~GSR_PORTAL_CAPTURE_TYPE_VIRTUAL;
- return requested_capture_types;
-}
-
-static uint32_t unset_unsupported_cursor_modes(uint32_t requested_cursor_modes, uint32_t available_cursor_modes) {
- if(!(available_cursor_modes & GSR_PORTAL_CURSOR_MODE_HIDDEN))
- requested_cursor_modes &= ~GSR_PORTAL_CURSOR_MODE_HIDDEN;
- if(!(available_cursor_modes & GSR_PORTAL_CURSOR_MODE_EMBEDDED))
- requested_cursor_modes &= ~GSR_PORTAL_CURSOR_MODE_EMBEDDED;
- if(!(available_cursor_modes & GSR_PORTAL_CURSOR_MODE_METADATA))
- requested_cursor_modes &= ~GSR_PORTAL_CURSOR_MODE_METADATA;
- return requested_cursor_modes;
-}
-
-int gsr_dbus_screencast_select_sources(gsr_dbus *self, const char *session_handle, uint32_t capture_type, uint32_t cursor_mode) {
- assert(session_handle);
-
- uint32_t available_source_types = 0;
- gsr_dbus_desktop_portal_get_property(self, "org.freedesktop.portal.ScreenCast", "AvailableSourceTypes", &available_source_types);
- if(available_source_types == 0)
- fprintf(stderr, "gsr error: gsr_dbus_screencast_select_sources: no source types are available\n");
- capture_type = unset_unsupported_capture_types(capture_type, available_source_types);
-
- uint32_t available_cursor_modes = 0;
- gsr_dbus_desktop_portal_get_property(self, "org.freedesktop.portal.ScreenCast", "AvailableCursorModes", &available_cursor_modes);
- if(available_cursor_modes == 0)
- fprintf(stderr, "gsr error: gsr_dbus_screencast_select_sources: no cursors modes are available\n");
- cursor_mode = unset_unsupported_cursor_modes(cursor_mode, available_cursor_modes);
-
- char handle_token[64];
- gsr_dbus_portal_get_unique_handle_token(self, handle_token, sizeof(handle_token));
-
- int num_arg_dict = 4;
- dict_entry args[6];
- args[0].key = "types";
- args[0].value_type = DICT_TYPE_UINT32;
- args[0].u32 = capture_type;
-
- args[1].key = "multiple";
- args[1].value_type = DICT_TYPE_BOOL;
- args[1].boolean = false; /* TODO: Wayland ignores this and still gives the option to select multiple sources. Support that case.. */
-
- args[2].key = "handle_token";
- args[2].value_type = DICT_TYPE_STRING;
- args[2].str = handle_token;
-
- args[3].key = "cursor_mode";
- args[3].value_type = DICT_TYPE_UINT32;
- args[3].u32 = cursor_mode;
-
- const int screencast_server_version = gsr_dbus_get_screencast_version_cached(self);
- if(screencast_server_version >= 4) {
- num_arg_dict = 5;
- args[4].key = "persist_mode";
- args[4].value_type = DICT_TYPE_UINT32;
- args[4].u32 = 2; /* persist until explicitly revoked */
-
- if(self->screencast_restore_token && self->screencast_restore_token[0]) {
- num_arg_dict = 6;
-
- args[5].key = "restore_token";
- args[5].value_type = DICT_TYPE_STRING;
- args[5].str = self->screencast_restore_token;
- }
- } else if(self->screencast_restore_token && self->screencast_restore_token[0]) {
- fprintf(stderr, "gsr warning: gsr_dbus_screencast_select_sources: tried to use restore token but this option is only available in screencast version >= 4, your wayland compositors screencast version is %d\n", screencast_server_version);
- }
-
- DBusMessage *response_msg = NULL;
- if(!gsr_dbus_call_screencast_method(self, "SelectSources", session_handle, NULL, args, num_arg_dict, NULL, &response_msg)) {
- if(num_arg_dict == 6) {
- /* We dont know what the error exactly is but assume it may be because of invalid restore token. In that case try without restore token */
- fprintf(stderr, "gsr warning: gsr_dbus_screencast_select_sources: SelectSources failed, retrying without restore_token\n");
- num_arg_dict = 5;
- if(!gsr_dbus_call_screencast_method(self, "SelectSources", session_handle, NULL, args, num_arg_dict, NULL, &response_msg))
- return -1;
- } else {
- return -1;
- }
- }
-
- // TODO: Verify signal path matches |res|, maybe check the below
- //fprintf(stderr, "signature: %s, sender: %s\n", dbus_message_get_signature(msg), dbus_message_get_sender(msg));
- DBusMessageIter resp_args;
- if(!dbus_message_iter_init(response_msg, &resp_args)) {
- fprintf(stderr, "gsr error: gsr_dbus_screencast_create_session: missing response\n");
- dbus_message_unref(response_msg);
- return -1;
- }
-
-
- const int response_status = gsr_dbus_get_response_status(&resp_args);
- if(response_status != 0) {
- dbus_message_unref(response_msg);
- return response_status;
- }
-
- dbus_message_unref(response_msg);
- return 0;
-}
-
-static dbus_uint32_t screencast_stream_get_pipewire_node(DBusMessageIter *iter) {
- DBusMessageIter subiter;
- dbus_message_iter_recurse(iter, &subiter);
-
- if(dbus_message_iter_get_arg_type(&subiter) == DBUS_TYPE_STRUCT) {
- DBusMessageIter structiter;
- dbus_message_iter_recurse(&subiter, &structiter);
-
- if(dbus_message_iter_get_arg_type(&structiter) == DBUS_TYPE_UINT32) {
- dbus_uint32_t data = 0;
- dbus_message_iter_get_basic(&structiter, &data);
- return data;
- }
- }
-
- return 0;
-}
-
-int gsr_dbus_screencast_start(gsr_dbus *self, const char *session_handle, uint32_t *pipewire_node) {
- assert(session_handle);
- *pipewire_node = 0;
-
- char handle_token[64];
- gsr_dbus_portal_get_unique_handle_token(self, handle_token, sizeof(handle_token));
-
- dict_entry args[1];
- args[0].key = "handle_token";
- args[0].value_type = DICT_TYPE_STRING;
- args[0].str = handle_token;
-
- DBusMessage *response_msg = NULL;
- if(!gsr_dbus_call_screencast_method(self, "Start", session_handle, "", args, 1, NULL, &response_msg))
- return -1;
-
- // TODO: Verify signal path matches |res|, maybe check the below
- //fprintf(stderr, "signature: %s, sender: %s\n", dbus_message_get_signature(msg), dbus_message_get_sender(msg));
- DBusMessageIter resp_args;
- if(!dbus_message_iter_init(response_msg, &resp_args)) {
- fprintf(stderr, "gsr error: gsr_dbus_screencast_start: missing response\n");
- dbus_message_unref(response_msg);
- return -1;
- }
-
- const int response_status = gsr_dbus_get_response_status(&resp_args);
- if(response_status != 0) {
- dbus_message_unref(response_msg);
- return response_status;
- }
-
- if(dbus_message_iter_get_arg_type(&resp_args) != DBUS_TYPE_ARRAY) {
- fprintf(stderr, "gsr error: gsr_dbus_screencast_start: missing array in response\n");
- dbus_message_unref(response_msg);
- return -1;
- }
-
- DBusMessageIter subiter;
- dbus_message_iter_recurse(&resp_args, &subiter);
-
- while(dbus_message_iter_get_arg_type(&subiter) != DBUS_TYPE_INVALID) {
- DBusMessageIter dictiter = DBUS_MESSAGE_ITER_INIT_CLOSED;
- const char *key = NULL;
-
- // fprintf(stderr, " array element type: %c, %s\n",
- // dbus_message_iter_get_arg_type(&subiter),
- // dbus_message_iter_get_signature(&subiter));
- if(dbus_message_iter_get_arg_type(&subiter) != DBUS_TYPE_DICT_ENTRY) {
- fprintf(stderr, "gsr error: gsr_dbus_screencast_start: array value is not an entry\n");
- goto error;
- }
-
- dbus_message_iter_recurse(&subiter, &dictiter);
-
- if(dbus_message_iter_get_arg_type(&dictiter) != DBUS_TYPE_STRING) {
- fprintf(stderr, "gsr error: gsr_dbus_screencast_start: entry key is not a string\n");
- goto error;
- }
-
- dbus_message_iter_get_basic(&dictiter, &key);
- if(!key) {
- fprintf(stderr, "gsr error: gsr_dbus_screencast_start: failed to get entry key as value\n");
- goto error;
- }
-
- if(strcmp(key, "restore_token") == 0) {
- if(!dbus_message_iter_next(&dictiter)) {
- fprintf(stderr, "gsr error: gsr_dbus_screencast_start: missing restore_token value\n");
- goto error;
- }
-
- if(dbus_message_iter_get_arg_type(&dictiter) != DBUS_TYPE_VARIANT) {
- fprintf(stderr, "gsr error: gsr_dbus_screencast_start: restore_token is not a variant\n");
- goto error;
- }
-
- DBusMessageIter variant_iter;
- dbus_message_iter_recurse(&dictiter, &variant_iter);
-
- if(dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_STRING) {
- fprintf(stderr, "gsr error: gsr_dbus_screencast_start: restore_token is not a string\n");
- goto error;
- }
-
- char *restore_token_str = NULL;
- dbus_message_iter_get_basic(&variant_iter, &restore_token_str);
-
- if(restore_token_str) {
- if(self->screencast_restore_token) {
- free(self->screencast_restore_token);
- self->screencast_restore_token = NULL;
- }
- self->screencast_restore_token = strdup(restore_token_str);
- //fprintf(stderr, "got restore token: %s\n", self->screencast_restore_token);
- }
- } else if(strcmp(key, "streams") == 0) {
- if(!dbus_message_iter_next(&dictiter)) {
- fprintf(stderr, "gsr error: gsr_dbus_screencast_start: missing streams value\n");
- goto error;
- }
-
- if(dbus_message_iter_get_arg_type(&dictiter) != DBUS_TYPE_VARIANT) {
- fprintf(stderr, "gsr error: gsr_dbus_screencast_start: streams value is not a variant\n");
- goto error;
- }
-
- DBusMessageIter variant_iter;
- dbus_message_iter_recurse(&dictiter, &variant_iter);
-
- if(dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY) {
- fprintf(stderr, "gsr error: gsr_dbus_screencast_start: streams value is not an array\n");
- goto error;
- }
-
- int num_streams = dbus_message_iter_get_element_count(&variant_iter);
- //fprintf(stderr, "num streams: %d\n", num_streams);
- /* Skip over all streams except the last one, since kde can return multiple streams even if only 1 is requested. The last one is the valid one */
- for(int i = 0; i < num_streams - 1; ++i) {
- screencast_stream_get_pipewire_node(&variant_iter);
- }
-
- if(num_streams > 0) {
- *pipewire_node = screencast_stream_get_pipewire_node(&variant_iter);
- //fprintf(stderr, "pipewire node: %u\n", *pipewire_node);
- }
- }
-
- dbus_message_iter_next(&subiter);
- }
-
- if(*pipewire_node == 0) {
- fprintf(stderr, "gsr error: gsr_dbus_screencast_start: no pipewire node returned\n");
- goto error;
- }
-
- dbus_message_unref(response_msg);
- return 0;
-
- error:
- dbus_message_unref(response_msg);
- return -1;
-}
-
-bool gsr_dbus_screencast_open_pipewire_remote(gsr_dbus *self, const char *session_handle, int *pipewire_fd) {
- assert(session_handle);
- *pipewire_fd = -1;
- return gsr_dbus_call_screencast_method(self, "OpenPipeWireRemote", session_handle, NULL, NULL, 0, pipewire_fd, NULL);
-}
-
-const char* gsr_dbus_screencast_get_restore_token(gsr_dbus *self) {
- return self->screencast_restore_token;
-}
diff --git a/dbus/dbus_impl.h b/dbus/dbus_impl.h
deleted file mode 100644
index c3f0751..0000000
--- a/dbus/dbus_impl.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef GSR_DBUS_H
-#define GSR_DBUS_H
-
-#include "portal.h"
-#include <stdbool.h>
-#include <stdint.h>
-#include <dbus/dbus.h>
-
-#define DBUS_RANDOM_STR_SIZE 16
-
-typedef struct {
- DBusConnection *con;
- DBusError err;
- char random_str[DBUS_RANDOM_STR_SIZE + 1];
- unsigned int handle_counter;
- bool desktop_portal_rule_added;
- uint32_t screencast_version;
- char *screencast_restore_token;
-} gsr_dbus;
-
-/* Blocking. TODO: Make non-blocking */
-bool gsr_dbus_init(gsr_dbus *self, const char *screencast_restore_token);
-void gsr_dbus_deinit(gsr_dbus *self);
-
-/* The follow functions should be called in order to setup ScreenCast properly */
-/* These functions that return an int return the response status code */
-int gsr_dbus_screencast_create_session(gsr_dbus *self, char **session_handle);
-/*
- |capture_type| is a bitmask of gsr_portal_capture_type values. gsr_portal_capture_type values that are not supported by the desktop portal will be ignored.
- |gsr_portal_cursor_mode| is a bitmask of gsr_portal_cursor_mode values. gsr_portal_cursor_mode values that are not supported will be ignored.
-*/
-int gsr_dbus_screencast_select_sources(gsr_dbus *self, const char *session_handle, uint32_t capture_type, uint32_t cursor_mode);
-int gsr_dbus_screencast_start(gsr_dbus *self, const char *session_handle, uint32_t *pipewire_node);
-bool gsr_dbus_screencast_open_pipewire_remote(gsr_dbus *self, const char *session_handle, int *pipewire_fd);
-const char* gsr_dbus_screencast_get_restore_token(gsr_dbus *self);
-
-#endif /* GSR_DBUS_H */
diff --git a/dbus/portal.h b/dbus/portal.h
deleted file mode 100644
index 6b93aa6..0000000
--- a/dbus/portal.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef GSR_PORTAL_H
-#define GSR_PORTAL_H
-
-typedef enum {
- GSR_PORTAL_CAPTURE_TYPE_MONITOR = 1 << 0,
- GSR_PORTAL_CAPTURE_TYPE_WINDOW = 1 << 1,
- GSR_PORTAL_CAPTURE_TYPE_VIRTUAL = 1 << 2,
- GSR_PORTAL_CAPTURE_TYPE_ALL = GSR_PORTAL_CAPTURE_TYPE_MONITOR | GSR_PORTAL_CAPTURE_TYPE_WINDOW | GSR_PORTAL_CAPTURE_TYPE_VIRTUAL
-} gsr_portal_capture_type;
-
-typedef enum {
- GSR_PORTAL_CURSOR_MODE_HIDDEN = 1 << 0,
- GSR_PORTAL_CURSOR_MODE_EMBEDDED = 1 << 1,
- GSR_PORTAL_CURSOR_MODE_METADATA = 1 << 2
-} gsr_portal_cursor_mode;
-
-#endif /* GSR_PORTAL_H */
diff --git a/dbus/protocol.h b/dbus/protocol.h
deleted file mode 100644
index 212358d..0000000
--- a/dbus/protocol.h
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef GSR_DBUS_PROTOCOL_H
-#define GSR_DBUS_PROTOCOL_H
-
-#include <stdint.h>
-
-#define GSR_DBUS_PROTOCOL_VERSION 1
-
-typedef enum {
- GSR_DBUS_MESSAGE_REQ_CREATE_SESSION,
- GSR_DBUS_MESSAGE_REQ_SELECT_SOURCES,
- GSR_DBUS_MESSAGE_REQ_START,
- GSR_DBUS_MESSAGE_REQ_OPEN_PIPEWIRE_REMOTE
-} gsr_dbus_message_req_type;
-
-typedef struct {
-
-} gsr_dbus_message_req_create_session;
-
-typedef struct {
- char session_handle[128];
- uint32_t capture_type;
- uint32_t cursor_mode;
-} gsr_dbus_message_req_select_sources;
-
-typedef struct {
- char session_handle[128];
-} gsr_dbus_message_req_start;
-
-typedef struct {
- char session_handle[128];
-} gsr_dbus_message_req_open_pipewire_remote;
-
-typedef struct {
- uint8_t protocol_version;
- gsr_dbus_message_req_type type;
- union {
- gsr_dbus_message_req_create_session create_session;
- gsr_dbus_message_req_select_sources select_sources;
- gsr_dbus_message_req_start start;
- gsr_dbus_message_req_open_pipewire_remote open_pipewire_remote;
- };
-} gsr_dbus_request_message;
-
-typedef enum {
- GSR_DBUS_MESSAGE_RESP_ERROR,
- GSR_DBUS_MESSAGE_RESP_CREATE_SESSION,
- GSR_DBUS_MESSAGE_RESP_SELECT_SOURCES,
- GSR_DBUS_MESSAGE_RESP_START,
- GSR_DBUS_MESSAGE_RESP_OPEN_PIPEWIRE_REMOTE
-} gsr_dbus_message_resp_type;
-
-typedef struct {
- uint32_t error_code;
- char message[128];
-} gsr_dbus_message_resp_error;
-
-typedef struct {
- char session_handle[128];
-} gsr_dbus_message_resp_create_session;
-
-typedef struct {
-
-} gsr_dbus_message_resp_select_sources;
-
-typedef struct {
- char restore_token[128];
- uint32_t pipewire_node;
-} gsr_dbus_message_resp_start;
-
-typedef struct {
-
-} gsr_dbus_message_resp_open_pipewire_remote;
-
-typedef struct {
- uint8_t protocol_version;
- gsr_dbus_message_resp_type type;
- union {
- gsr_dbus_message_resp_error error;
- gsr_dbus_message_resp_create_session create_session;
- gsr_dbus_message_resp_select_sources select_sources;
- gsr_dbus_message_resp_start start;
- gsr_dbus_message_resp_open_pipewire_remote open_pipewire_remote;
- };
-} gsr_dbus_response_message;
-
-#endif /* GSR_DBUS_PROTOCOL_H */
diff --git a/dbus/server/dbus_server.c b/dbus/server/dbus_server.c
deleted file mode 100644
index bde6acb..0000000
--- a/dbus/server/dbus_server.c
+++ /dev/null
@@ -1,175 +0,0 @@
-#include "../dbus_impl.h"
-#include "../protocol.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <unistd.h>
-#include <sys/socket.h>
-
-/* TODO: Error check write/read */
-
-static int handle_create_session(gsr_dbus *dbus, int rpc_fd, const gsr_dbus_message_req_create_session *create_session) {
- (void)create_session;
- char *session_handle = NULL;
- const int status = gsr_dbus_screencast_create_session(dbus, &session_handle);
- if(status == 0) {
- gsr_dbus_response_message response = {
- .protocol_version = GSR_DBUS_PROTOCOL_VERSION,
- .type = GSR_DBUS_MESSAGE_RESP_CREATE_SESSION,
- .create_session = (gsr_dbus_message_resp_create_session) {}
- };
- snprintf(response.create_session.session_handle, sizeof(response.create_session.session_handle), "%s", session_handle);
- free(session_handle);
- write(rpc_fd, &response, sizeof(response));
- }
- return status;
-}
-
-static int handle_select_sources(gsr_dbus *dbus, int rpc_fd, const gsr_dbus_message_req_select_sources *select_sources) {
- const int status = gsr_dbus_screencast_select_sources(dbus, select_sources->session_handle, select_sources->capture_type, select_sources->cursor_mode);
- if(status == 0) {
- gsr_dbus_response_message response = {
- .protocol_version = GSR_DBUS_PROTOCOL_VERSION,
- .type = GSR_DBUS_MESSAGE_RESP_SELECT_SOURCES,
- .select_sources = (gsr_dbus_message_resp_select_sources) {}
- };
- write(rpc_fd, &response, sizeof(response));
- }
- return status;
-}
-
-static int handle_start(gsr_dbus *dbus, int rpc_fd, const gsr_dbus_message_req_start *start) {
- uint32_t pipewire_node = 0;
- const int status = gsr_dbus_screencast_start(dbus, start->session_handle, &pipewire_node);
- if(status == 0) {
- const char *screencast_restore_token = gsr_dbus_screencast_get_restore_token(dbus);
- gsr_dbus_response_message response = {
- .protocol_version = GSR_DBUS_PROTOCOL_VERSION,
- .type = GSR_DBUS_MESSAGE_RESP_START,
- .start = (gsr_dbus_message_resp_start) {
- .pipewire_node = pipewire_node
- }
- };
- snprintf(response.start.restore_token, sizeof(response.start.restore_token), "%s", screencast_restore_token ? screencast_restore_token : "");
- write(rpc_fd, &response, sizeof(response));
- }
- return status;
-}
-
-static bool handle_open_pipewire_remote(gsr_dbus *dbus, int rpc_fd, const gsr_dbus_message_req_open_pipewire_remote *open_pipewire_remote) {
- int pipewire_fd = 0;
- const bool success = gsr_dbus_screencast_open_pipewire_remote(dbus, open_pipewire_remote->session_handle, &pipewire_fd);
- if(success) {
- gsr_dbus_response_message response = {
- .protocol_version = GSR_DBUS_PROTOCOL_VERSION,
- .type = GSR_DBUS_MESSAGE_RESP_OPEN_PIPEWIRE_REMOTE,
- .open_pipewire_remote = (gsr_dbus_message_resp_open_pipewire_remote) {}
- };
-
- struct iovec iov = {
- .iov_base = &response,
- .iov_len = sizeof(response)
- };
-
- char msg_control[CMSG_SPACE(sizeof(int))];
-
- struct msghdr message = {
- .msg_iov = &iov,
- .msg_iovlen = 1,
- .msg_control = msg_control,
- .msg_controllen = sizeof(msg_control)
- };
-
- struct cmsghdr *cmsg = CMSG_FIRSTHDR(&message);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- int *fds = (int*)CMSG_DATA(cmsg);
- fds[0] = pipewire_fd;
- message.msg_controllen = cmsg->cmsg_len;
- sendmsg(rpc_fd, &message, 0);
- }
- return success;
-}
-
-int main(int argc, char **argv) {
- if(argc != 3) {
- fprintf(stderr, "usage: gsr-dbus-server <rpc-fd> <screencast-restore-token>\n");
- return 1;
- }
-
- const char *rpc_fd_str = argv[1];
- const char *screencast_restore_token = argv[2];
-
- int rpc_fd = -1;
- if(sscanf(rpc_fd_str, "%d", &rpc_fd) != 1) {
- fprintf(stderr, "gsr-dbus-server error: rpc-fd is not a number: %s\n", rpc_fd_str);
- return 1;
- }
-
- if(screencast_restore_token[0] == '\0')
- screencast_restore_token = NULL;
-
- gsr_dbus dbus;
- if(!gsr_dbus_init(&dbus, screencast_restore_token))
- return 1;
-
- /* Tell client we have started up */
- write(rpc_fd, "S", 1);
-
- gsr_dbus_request_message request;
- for(;;) {
- read(rpc_fd, &request, sizeof(request));
-
- if(request.protocol_version != GSR_DBUS_PROTOCOL_VERSION) {
- gsr_dbus_response_message response = {
- .protocol_version = GSR_DBUS_PROTOCOL_VERSION,
- .type = GSR_DBUS_MESSAGE_RESP_ERROR,
- .error = (gsr_dbus_message_resp_error) {
- .error_code = 1
- }
- };
- snprintf(response.error.message, sizeof(response.error.message), "Client uses protocol version %d while the server is using protocol version %d", request.protocol_version, GSR_DBUS_PROTOCOL_VERSION);
- fprintf(stderr, "gsr-dbus-server error: %s\n", response.error.message);
- write(rpc_fd, &response, sizeof(response));
- continue;
- }
-
- int status = 0;
- switch(request.type) {
- case GSR_DBUS_MESSAGE_REQ_CREATE_SESSION: {
- status = handle_create_session(&dbus, rpc_fd, &request.create_session);
- break;
- }
- case GSR_DBUS_MESSAGE_REQ_SELECT_SOURCES: {
- status = handle_select_sources(&dbus, rpc_fd, &request.select_sources);
- break;
- }
- case GSR_DBUS_MESSAGE_REQ_START: {
- status = handle_start(&dbus, rpc_fd, &request.start);
- break;
- }
- case GSR_DBUS_MESSAGE_REQ_OPEN_PIPEWIRE_REMOTE: {
- if(!handle_open_pipewire_remote(&dbus, rpc_fd, &request.open_pipewire_remote))
- status = -1;
- break;
- }
- }
-
- if(status != 0) {
- gsr_dbus_response_message response = {
- .protocol_version = GSR_DBUS_PROTOCOL_VERSION,
- .type = GSR_DBUS_MESSAGE_RESP_ERROR,
- .error = (gsr_dbus_message_resp_error) {
- .error_code = status
- }
- };
- snprintf(response.error.message, sizeof(response.error.message), "%s", "Failed to handle request");
- write(rpc_fd, &response, sizeof(response));
- }
- }
-
- gsr_dbus_deinit(&dbus);
- return 0;
-} \ No newline at end of file