Skip to content

Commit

Permalink
screencast: add outputchooser with config option
Browse files Browse the repository at this point in the history
Supports "dmenu" chooser type, which is called with a dmenu type list
piped to stdin, "simple" type, which recieves nothing on stdin and
default, which tries the hardcoded choosers.
Choosers are required to return the name of the choosen output as given
by the xdg-output protocol.

Thanks to piater for closing overlooked pipes.
Thanks to ericonr for suggestions regarding fork and pipes.
  • Loading branch information
columbarius committed Apr 2, 2021
1 parent 4c2d8fc commit 90bd353
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 36 deletions.
2 changes: 2 additions & 0 deletions contrib/config.sample
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[screencast]
output_name=
max_fps=30
chooser_cmd="slurp -f %o -o"
chooser_type=simple
3 changes: 3 additions & 0 deletions include/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
#define CONFIG_H

#include "logger.h"
#include "screencast_common.h"

struct config_screencast {
char *output_name;
double max_fps;
char *exec_before;
char *exec_after;
char *chooser_cmd;
enum xdpw_chooser_types chooser_type;
};

struct xdpw_config {
Expand Down
14 changes: 14 additions & 0 deletions include/screencast_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ enum source_types {
WINDOW = 2,
};

enum xdpw_chooser_types {
XDPW_CHOOSER_DEFAULT,
XDPW_CHOOSER_NONE,
XDPW_CHOOSER_SIMPLE,
XDPW_CHOOSER_DMENU,
};

struct xdpw_output_chooser {
enum xdpw_chooser_types type;
char *cmd;
};

struct xdpw_frame_damage {
uint32_t x;
uint32_t y;
Expand Down Expand Up @@ -113,4 +125,6 @@ enum spa_video_format xdpw_format_pw_from_wl_shm(
struct xdpw_screencast_instance *cast);
enum spa_video_format xdpw_format_pw_strip_alpha(enum spa_video_format format);

enum xdpw_chooser_types get_chooser_type(const char *chooser_type);
const char *chooser_type_str(enum xdpw_chooser_types chooser_type);
#endif /* SCREENCAST_COMMON_H */
1 change: 1 addition & 0 deletions include/wlr_screencast.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct xdpw_wlr_output *xdpw_wlr_output_find_by_name(struct wl_list *output_list
struct xdpw_wlr_output *xdpw_wlr_output_first(struct wl_list *output_list);
struct xdpw_wlr_output *xdpw_wlr_output_find(struct xdpw_screencast_context *ctx,
struct wl_output *out, uint32_t id);
struct xdpw_wlr_output *xdpw_wlr_output_chooser(struct xdpw_screencast_context *ctx);

void xdpw_wlr_frame_free(struct xdpw_screencast_instance *cast);
void xdpw_wlr_register_cb(struct xdpw_screencast_instance *cast);
Expand Down
37 changes: 24 additions & 13 deletions src/core/config.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "config.h"
#include "xdpw.h"
#include "logger.h"
#include "screencast_common.h"

#include <dictionary.h>
#include <stdio.h>
Expand All @@ -11,6 +12,8 @@

void print_config(enum LOGLEVEL loglevel, struct xdpw_config *config) {
logprint(loglevel, "config: outputname %s", config->screencast_conf.output_name);
logprint(loglevel, "config: chooser_cmd: %s\n", config->screencast_conf.chooser_cmd);
logprint(loglevel, "config: chooser_type: %s\n", chooser_type_str(config->screencast_conf.chooser_type));
}

// NOTE: calling finish_config won't prepare the config to be read again from config file
Expand All @@ -22,6 +25,7 @@ void finish_config(struct xdpw_config *config) {
free(&config->screencast_conf.output_name);
free(&config->screencast_conf.exec_before);
free(&config->screencast_conf.exec_after);
free(&config->screencast_conf.chooser_cmd);
}

static void getstring_from_conffile(dictionary *d,
Expand Down Expand Up @@ -53,19 +57,6 @@ static bool file_exists(const char *path) {
return path && access(path, R_OK) != -1;
}

static char *config_path(const char *prefix, const char *filename) {
if (!prefix || !prefix[0] || !filename || !filename[0]) {
return NULL;
}

char *config_folder = "xdg-desktop-portal-wlr";

size_t size = 3 + strlen(prefix) + strlen(config_folder) + strlen(filename);
char *path = calloc(size, sizeof(char));
snprintf(path, size, "%s/%s/%s", prefix, config_folder, filename);
return path;
}

static void config_parse_file(const char *configfile, struct xdpw_config *config) {
dictionary *d = NULL;
if (configfile) {
Expand All @@ -83,12 +74,32 @@ static void config_parse_file(const char *configfile, struct xdpw_config *config
getdouble_from_conffile(d, "screencast:max_fps", &config->screencast_conf.max_fps, 0);
getstring_from_conffile(d, "screencast:exec_before", &config->screencast_conf.exec_before, NULL);
getstring_from_conffile(d, "screencast:exec_after", &config->screencast_conf.exec_after, NULL);
getstring_from_conffile(d, "screencast:chooser_cmd", &config->screencast_conf.chooser_cmd, NULL);
if (!config->screencast_conf.chooser_type) {
char *chooser_type = NULL;
getstring_from_conffile(d, "screencast:chooser_type", &chooser_type, "default");
config->screencast_conf.chooser_type = get_chooser_type(chooser_type);
free(chooser_type);
}

iniparser_freedict(d);
logprint(DEBUG, "config: config file parsed");
print_config(DEBUG, config);
}

static char *config_path(const char *prefix, const char *filename) {
if (!prefix || !prefix[0] || !filename || !filename[0]) {
return NULL;
}

char *config_folder = "xdg-desktop-portal-wlr";

size_t size = 3 + strlen(prefix) + strlen(config_folder) + strlen(filename);
char *path = calloc(size, sizeof(char));
snprintf(path, size, "%s/%s/%s", prefix, config_folder, filename);
return path;
}

static char *get_config_path(void) {
const char *home = getenv("HOME");
size_t size_fallback = 1 + strlen(home) + strlen("/.config");
Expand Down
2 changes: 1 addition & 1 deletion src/core/logger.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ enum LOGLEVEL get_loglevel(const char *level) {
}

fprintf(stderr, "Could not understand log level %s\n", level);
abort();
exit(1);
}

static const char *print_loglevel(enum LOGLEVEL loglevel) {
Expand Down
1 change: 1 addition & 0 deletions src/core/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ int main(int argc, char *argv[]) {
break;
case 'o':
config.screencast_conf.output_name = strdup(optarg);
config.screencast_conf.chooser_type = XDPW_CHOOSER_NONE;
break;
case 'c':
configfile = strdup(optarg);
Expand Down
34 changes: 13 additions & 21 deletions src/screencast/screencast.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ void xdpw_screencast_instance_destroy(struct xdpw_screencast_instance *cast) {
free(cast);
}

int 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;
wl_list_for_each_reverse_safe(output, tmp_o, &ctx->output_list, link) {
Expand All @@ -86,19 +86,10 @@ int setup_outputs(struct xdpw_screencast_context *ctx, struct xdpw_session *sess
}

struct xdpw_wlr_output *out;
if (ctx->state->config->screencast_conf.output_name) {
out = xdpw_wlr_output_find_by_name(&ctx->output_list,
ctx->state->config->screencast_conf.output_name);
if (!out) {
logprint(ERROR, "wlroots: no such output");
abort();
}
} else {
out = xdpw_wlr_output_first(&ctx->output_list);
if (!out) {
logprint(ERROR, "wlroots: no output found");
abort();
}
out = xdpw_wlr_output_chooser(ctx);
if (!out) {
logprint(ERROR, "wlroots: no output found");
return false;
}

struct xdpw_screencast_instance *cast, *tmp_c;
Expand Down Expand Up @@ -130,7 +121,7 @@ int setup_outputs(struct xdpw_screencast_context *ctx, struct xdpw_session *sess
logprint(INFO, "wlroots: output: %s",
sess->screencast_instance->target_output->name);

return 0;
return true;

}

Expand Down Expand Up @@ -310,22 +301,23 @@ static int method_screencast_select_sources(sd_bus_message *msg, void *data,
return ret;
}

ret = -1;
bool output_selection_canceled = 1;
wl_list_for_each_reverse_safe(sess, tmp_s, &state->xdpw_sessions, link) {
if (strcmp(sess->session_handle, session_handle) == 0) {
logprint(DEBUG, "dbus: select sources: found matching session %s", sess->session_handle);
ret = setup_outputs(ctx, sess, cursor_embedded);
output_selection_canceled = !setup_outputs(ctx, sess, cursor_embedded);
}
}
if (ret < 0) {
return ret;
}

ret = sd_bus_message_new_method_return(msg, &reply);
if (ret < 0) {
return ret;
}
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 0);
if (output_selection_canceled) {
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_CANCELLED, 0);
} else {
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 0);
}
if (ret < 0) {
return ret;
}
Expand Down
29 changes: 29 additions & 0 deletions src/screencast/screencast_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,32 @@ enum spa_video_format xdpw_format_pw_strip_alpha(enum spa_video_format format) {
return SPA_VIDEO_FORMAT_UNKNOWN;
}
}

enum xdpw_chooser_types get_chooser_type(const char *chooser_type) {
if (!chooser_type || strcmp(chooser_type, "default") == 0) {
return XDPW_CHOOSER_DEFAULT;
} else if (strcmp(chooser_type, "none") == 0) {
return XDPW_CHOOSER_NONE;
} else if (strcmp(chooser_type, "simple") == 0) {
return XDPW_CHOOSER_SIMPLE;
} else if (strcmp(chooser_type, "dmenu") == 0) {
return XDPW_CHOOSER_DMENU;
}
fprintf(stderr, "Could not understand chooser type %s\n", chooser_type);
exit(1);
}

const char *chooser_type_str(enum xdpw_chooser_types chooser_type) {
switch (chooser_type) {
case XDPW_CHOOSER_DEFAULT:
return "default";
case XDPW_CHOOSER_NONE:
return "none";
case XDPW_CHOOSER_SIMPLE:
return "simple";
case XDPW_CHOOSER_DMENU:
return "dmenu";
}
fprintf(stderr, "Could not find chooser type %d\n", chooser_type);
abort();
}
Loading

0 comments on commit 90bd353

Please sign in to comment.