diff --git a/include/config.h b/include/config.h index e8785d9..7961bf6 100644 --- a/include/config.h +++ b/include/config.h @@ -6,6 +6,8 @@ struct config_screencast { char *output_name; double max_fps; + char *exec_before; + char *exec_after; }; struct xdpw_config { diff --git a/src/core/config.c b/src/core/config.c index c19da34..3510af2 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -20,6 +20,8 @@ void finish_config(struct xdpw_config *config) { // screencast free(&config->screencast_conf.output_name); + free(&config->screencast_conf.exec_before); + free(&config->screencast_conf.exec_after); } static void getstring_from_conffile(dictionary *d, @@ -79,6 +81,8 @@ static void config_parse_file(const char *configfile, struct xdpw_config *config // screencast getstring_from_conffile(d, "screencast:output_name", &config->screencast_conf.output_name, NULL); 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); iniparser_freedict(d); logprint(DEBUG, "config: config file parsed"); diff --git a/src/screencast/screencast.c b/src/screencast/screencast.c index a1acedf..24fdbcc 100644 --- a/src/screencast/screencast.c +++ b/src/screencast/screencast.c @@ -18,8 +18,36 @@ static const char object_path[] = "/org/freedesktop/portal/desktop"; static const char interface_name[] = "org.freedesktop.impl.portal.ScreenCast"; +void exec_with_shell(char *command) { + pid_t pid = fork(); + if (pid < 0) { + perror("fork"); + } else if (pid == 0) { + char *const argv[] = { + "sh", + "-c", + command, + NULL, + }; + execvp("sh", argv); + + perror("execvp"); + exit(127); + } +} + void xdpw_screencast_instance_init(struct xdpw_screencast_context *ctx, struct xdpw_screencast_instance *cast, struct xdpw_wlr_output *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); + } + } + cast->ctx = ctx; cast->target_output = out; cast->framerate = out->framerate; @@ -34,6 +62,16 @@ void xdpw_screencast_instance_init(struct xdpw_screencast_context *ctx, void xdpw_screencast_instance_destroy(struct xdpw_screencast_instance *cast) { assert(cast->refcount == 0); // Fails assert if called by screencast_finish logprint(DEBUG, "xdpw: destroying cast instance"); + + // make sure this is the last running instance that is being destroyed + if (wl_list_length(&cast->link) == 1) { + char *exec_after = cast->ctx->state->config->screencast_conf.exec_after; + if (exec_after) { + logprint(INFO, "xdpw: executing %s after screencast", exec_after); + exec_with_shell(exec_after); + } + } + wl_list_remove(&cast->link); xdpw_pwr_stream_destroy(cast); free(cast); diff --git a/xdg-desktop-portal-wlr.5.scd b/xdg-desktop-portal-wlr.5.scd index 717d0ce..c3c0805 100644 --- a/xdg-desktop-portal-wlr.5.scd +++ b/xdg-desktop-portal-wlr.5.scd @@ -25,6 +25,8 @@ The configuration files use the INI file format. Example: [screencast] output_name=HDMI-A-1 max_fps=30 +exec_before=disable_notifications.sh +exec_after=enable_notifications.sh ``` # SCREENCAST OPTIONS @@ -44,6 +46,12 @@ These options need to be placed under the **[screencast]** section. This is useful to reduce CPU usage when capturing frames at the output's refresh rate is unnecessary. +**exec_before** = _command_ + Execute _command_ before starting a screencast. The command will be executed within sh. + +**exec_after** = _command_ + Execute _command_ after ending all screencasts. The command will be executed within sh. + # SEE ALSO **pipewire**(1)