diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2023-10-18 17:10:22 -0700 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2023-10-18 17:18:29 -0700 |
commit | f5c9b65592327c2094d5981bb95d3e4afdf76344 (patch) | |
tree | ed1c1e7f3e8bc7dbcb762eca6de9409dace5e7a3 | |
parent | c2f9bcd457b57b6d96a5cbdd9c36272994bc19c3 (diff) |
parseargs,error: add --need-shortcuts
When you depend on the shortcuts as _the_ means of
stopping/pausing a recording, like in a WM integration scenario,
it's preferable to have rmd exit fatally when the grabs can't be
setup. (usually this occurs when you've accidentally tried
starting multiple recordings, and the shortcuts collide)
This way, the integration can detect the failure and throw up a
dialog or something informing the user that the recording wasn't
started. All that's needed is including --need-shortcuts.
Note this is a little janky in how it's implemented, because
XSetErrorHandler() is janky and doesn't even support a user
pointer payload.
Rather than introducing global variables to either communicate
the grab failures to other parts of rmd, or exposing the parsed
args struct to the error handler globally in the other direction,
I just made a grab-errors-are-fatal variant of the handler which
gets installed when --need-shortcuts is specified.
-rw-r--r-- | src/rmd.c | 2 | ||||
-rw-r--r-- | src/rmd_error.c | 15 | ||||
-rw-r--r-- | src/rmd_error.h | 3 | ||||
-rw-r--r-- | src/rmd_parseargs.c | 5 | ||||
-rw-r--r-- | src/rmd_types.h | 1 |
5 files changed, 23 insertions, 3 deletions
@@ -76,7 +76,7 @@ int main(int argc, char **argv) if (pdata.args.display != NULL) { pdata.dpy = XOpenDisplay(pdata.args.display); - XSetErrorHandler(rmdErrorHandler); + XSetErrorHandler(pdata.args.need_shortcuts ? rmdGrabErrorsFatalErrorHandler : rmdErrorHandler); } else { fprintf(stderr, "No display specified for connection!\n"); exit(8); diff --git a/src/rmd_error.c b/src/rmd_error.c index aaef20a..f8c137e 100644 --- a/src/rmd_error.c +++ b/src/rmd_error.c @@ -35,7 +35,7 @@ -int rmdErrorHandler(Display *dpy, XErrorEvent *e) +static int rmdSharedErrorHandler(Display *dpy, XErrorEvent *e, boolean grabsfatal) { char error_desc[1024]; @@ -49,8 +49,19 @@ int rmdErrorHandler(Display *dpy, XErrorEvent *e) if ((e->error_code == BadAccess) && (e->request_code == X_GrabKey)) { fprintf(stderr, "Bad Access on XGrabKey.\n" "Shortcut already assigned.\n"); - return 0; + if (!grabsfatal) + return 0; } exit(1); } + +int rmdErrorHandler(Display *dpy, XErrorEvent *e) +{ + return rmdSharedErrorHandler(dpy, e, FALSE /* grabsfatal */); +} + +int rmdGrabErrorsFatalErrorHandler(Display *dpy, XErrorEvent *e) +{ + return rmdSharedErrorHandler(dpy, e, TRUE /* grabsfatal */); +} diff --git a/src/rmd_error.h b/src/rmd_error.h index 4d27264..de5c7b0 100644 --- a/src/rmd_error.h +++ b/src/rmd_error.h @@ -45,5 +45,8 @@ */ int rmdErrorHandler(Display *dpy,XErrorEvent *e); +/* identical to rmdErrorHandler, but exits on grab errors (--needs-shortcuts) */ +int rmdGrabErrorsFatalErrorHandler(Display *dpy, XErrorEvent *e); + #endif diff --git a/src/rmd_parseargs.c b/src/rmd_parseargs.c index 272d43e..8ee4328 100644 --- a/src/rmd_parseargs.c +++ b/src/rmd_parseargs.c @@ -257,6 +257,11 @@ boolean rmdParseArgs(int argc, char **argv, ProgArgs *arg_return) "Shortcut that will be used to stop the recording (default Control+Mod1+s).", "MOD+KEY" }, + { "need-shortcuts", '\0', + POPT_ARG_NONE, &arg_return->need_shortcuts, 0, + "Treat shorcut installation failures as fatal.", + NULL }, + { "compress-cache", '\0', POPT_ARG_NONE, &compress_cache, 0, "Image data are cached with light compression.", diff --git a/src/rmd_types.h b/src/rmd_types.h index f70efac..b503da8 100644 --- a/src/rmd_types.h +++ b/src/rmd_types.h @@ -151,6 +151,7 @@ typedef struct _ProgArgs{ char *workdir; //directory to be used for cache files(default $HOME) char *pause_shortcut; //pause/unpause shortcut sequence(Control+Alt+p) char *stop_shortcut; //stop shortcut sequence(Control+Alt+s) + int need_shortcuts; //exit fatally when shortcuts can't be installed int noframe; //don't draw a frame around the recording area int zerocompression; //image data are always flushed uncompressed unsigned periodic_datasync_ms; //interval between background async fdatasync calls while writing cache files, when zero no periodic fdatasync is performed |