From a57459cc69e1d051f91696213d22780147480b8a Mon Sep 17 00:00:00 2001 From: NRK Date: Sat, 27 May 2023 11:34:40 +0600 Subject: [PATCH] rework scrotWaitUntil() => scrotSleepFor() absolute time is really awkward to use. scrotSleepFor() instead takes a starting timestamp and a relative millisecond offset from that start and returns back the ending timestamp. this, combined with clockNow(), makes the API easy to use and easy to replace the existing nanosleep calls with. --- src/scrot.c | 39 +++++++++++++++++++++++---------------- src/scrot.h | 1 + src/scrot_selection.c | 4 ++-- src/selection_edge.c | 3 +-- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/scrot.c b/src/scrot.c index 4e70431..a063bb9 100644 --- a/src/scrot.c +++ b/src/scrot.c @@ -75,7 +75,6 @@ static Imlib_Image scrotGrabFocused(void); static void applyFilterIfRequired(void); static Imlib_Image scrotGrabAutoselect(void); static long miliToNanoSec(int); -static void scrotWaitUntil(const struct timespec *); static Imlib_Image scrotGrabShotMulti(void); static Imlib_Image scrotGrabShotMonitor(void); static Imlib_Image scrotGrabStackWindows(void); @@ -336,13 +335,11 @@ void scrotDoDelay(void) dprintf(STDERR_FILENO, "Taking shot in "); for (int i = opt.delay; i > 0; i--) { dprintf(STDERR_FILENO, "%d.. ", i); - opt.delayStart.tv_sec++; - scrotWaitUntil(&opt.delayStart); + opt.delayStart = scrotSleepFor(opt.delayStart, 1000); } dprintf(STDERR_FILENO, "0.\n"); } else { - opt.delayStart.tv_sec += opt.delay; - scrotWaitUntil(&opt.delayStart); + scrotSleepFor(opt.delayStart, opt.delay * 1000); } } @@ -366,13 +363,22 @@ struct timespec clockNow(void) return ret; } -/* scrotWaitUntil: clock_nanosleep with a simpler interface and no EINTR nagging +/* OpenBSD and OS X lack clock_nanosleep(), so we call nanosleep() and use a + * trivial algorithm to correct for drift. The end timespec is returned for + * callers that want it. EINTR is also dealt with. */ -static void scrotWaitUntil(const struct timespec *time) +struct timespec scrotSleepFor(struct timespec start, int ms) { - /* OpenBSD and OS X lack clock_nanosleep(), so we use a trivial algorithm to - * correct for drift and call nanosleep() everywhere. - */ + scrotAssert(ms >= 0); + struct timespec end = { + .tv_sec = start.tv_sec + (ms / 1000), + .tv_nsec = start.tv_nsec + miliToNanoSec(ms % 1000), + }; + if (end.tv_nsec >= miliToNanoSec(1000)) { + ++end.tv_sec; + end.tv_nsec -= miliToNanoSec(1000); + } + struct timespec tmp; do { tmp = clockNow(); @@ -381,13 +387,15 @@ static void scrotWaitUntil(const struct timespec *time) * doesn't support OS X save for an unmaintained fork. libobsd supports * OS X but doesn't have the macro yet. */ - tmp.tv_sec = time->tv_sec - tmp.tv_sec; - tmp.tv_nsec = time->tv_nsec - tmp.tv_nsec; + tmp.tv_sec = end.tv_sec - tmp.tv_sec; + tmp.tv_nsec = end.tv_nsec - tmp.tv_nsec; if (tmp.tv_nsec < 0) { - tmp.tv_sec--; + --tmp.tv_sec; tmp.tv_nsec += miliToNanoSec(1000); } - } while (nanosleep(&tmp, NULL) == -1 && errno == EINTR); + } while (nanosleep(&tmp, NULL) < 0 && errno == EINTR); + + return end; } /* Clip rectangle nicely */ @@ -450,8 +458,7 @@ int scrotGetGeometry(Window target, int *rx, int *ry, int *rw, int *rh) /* HACK: there doesn't seem to be any way to figure out whether the * raise request was accepted or rejected. so just sleep a bit to * give the WM some time to update. */ - struct timespec t = { .tv_nsec = 160 * 1000L * 1000L }; - while (nanosleep(&t, &t) < 0 && errno == EINTR); + scrotSleepFor(clockNow(), 160); } } stat = XGetWindowAttributes(disp, target, &attr); diff --git a/src/scrot.h b/src/scrot.h index b32a9c6..5f87794 100644 --- a/src/scrot.h +++ b/src/scrot.h @@ -42,5 +42,6 @@ Window scrotGetWindow(Display *, Window, int, int); int scrotGetGeometry(Window, int *, int *, int *, int *); void scrotNiceClip(int *, int *, int *, int *); struct timespec clockNow(void); +struct timespec scrotSleepFor(struct timespec, int); void scrotDoDelay(void); void scrotGrabMousePointer(const Imlib_Image, const int, const int); diff --git a/src/scrot_selection.c b/src/scrot_selection.c index 298e10e..29514c8 100644 --- a/src/scrot_selection.c +++ b/src/scrot_selection.c @@ -233,9 +233,9 @@ bool scrotSelectionGetUserSel(struct SelectionRect *selectionRect) ret = XGrabKeyboard(disp, root, False, GrabModeAsync, GrabModeAsync, CurrentTime); if (ret == AlreadyGrabbed) { int attempts = 20; - struct timespec delay = { 0, 50 * 1000L * 1000L }; + struct timespec t = clockNow(); do { - nanosleep(&delay, NULL); + t = scrotSleepFor(t, 50); ret = XGrabKeyboard(disp, root, False, GrabModeAsync, GrabModeAsync, CurrentTime); } while (--attempts > 0 && ret == AlreadyGrabbed); } diff --git a/src/selection_edge.c b/src/selection_edge.c index 2a9cae4..e73efc3 100644 --- a/src/selection_edge.c +++ b/src/selection_edge.c @@ -143,8 +143,7 @@ void selectionEdgeDestroy(void) * might not have been updated. a compositor might also buffer frames * adding latency. so wait a bit for the screen to update and the * selection borders to go away. */ - struct timespec t = { .tv_nsec = 80 * 1000L * 1000L }; - while (nanosleep(&t, &t) < 0 && errno == EINTR); + scrotSleepFor(clockNow(), 80); XFree(pe->classHint); }