st-background-image-signal-reload-0.8.5.diff (3333B)
1 From b56c9081dc4c62b7de5357cc73bc10a310f011b8 Mon Sep 17 00:00:00 2001 2 From: Matthias Schoth <mschoth@gmail.com> 3 Date: Sun, 17 Apr 2022 04:01:59 +0200 4 Subject: [PATCH] Reload background image on USR1 signal. 5 6 Queue reload requests from the signal handler and service them from the 7 main loop. Xlib is not async-signal-safe, so calling it directly from the 8 handler can crash st or leak X resources when signals arrive while st is 9 drawing. 10 --- 11 x.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 12 1 file changed, 55 insertions(+), 1 deletion(-) 13 14 diff --git a/x.c b/x.c 15 index cab0058..7c9076c 100644 16 --- a/x.c 17 +++ b/x.c 18 @@ -1,5 +1,6 @@ 19 /* See LICENSE for license details. */ 20 #include <errno.h> 21 +#include <fcntl.h> 22 #include <math.h> 23 #include <limits.h> 24 #include <locale.h> 25 @@ -157,6 +158,8 @@ static int xicdestroy(XIC, XPointer, XPointer); 26 static void xinit(int, int); 27 static void updatexy(void); 28 static XImage *loadff(const char *); 29 +static void bgreload(int); 30 +static void bgreloadinit(void); 31 static void bginit(); 32 static void cresize(int, int); 33 static void xresize(int, int); 34 @@ -1319,6 +1322,46 @@ loadff(const char *filename) 35 return xi; 36 } 37 38 +static int bgreloadpipe[2] = {-1, -1}; 39 + 40 +/* 41 + * Xlib is not async-signal-safe, so just wake up the main loop and let it 42 + * reload the image there. 43 + */ 44 +static void 45 +bgreload(int sig) 46 +{ 47 + char c = 0; 48 + 49 + (void)sig; 50 + if (bgreloadpipe[1] != -1) 51 + (void)write(bgreloadpipe[1], &c, 1); 52 +} 53 + 54 +static void 55 +bgreloadinit(void) 56 +{ 57 + struct sigaction sa; 58 + int flags; 59 + 60 + if (pipe(bgreloadpipe) < 0) 61 + die("pipe: %s\n", strerror(errno)); 62 + 63 + flags = fcntl(bgreloadpipe[0], F_GETFL); 64 + fcntl(bgreloadpipe[0], F_SETFL, flags | O_NONBLOCK); 65 + flags = fcntl(bgreloadpipe[1], F_GETFL); 66 + fcntl(bgreloadpipe[1], F_SETFL, flags | O_NONBLOCK); 67 + fcntl(bgreloadpipe[0], F_SETFD, FD_CLOEXEC); 68 + fcntl(bgreloadpipe[1], F_SETFD, FD_CLOEXEC); 69 + 70 + memset(&sa, 0, sizeof(sa)); 71 + sa.sa_handler = bgreload; 72 + sigemptyset(&sa.sa_mask); 73 + sa.sa_flags = SA_RESTART; 74 + if (sigaction(SIGUSR1, &sa, NULL) < 0) 75 + die("sigaction: %s\n", strerror(errno)); 76 +} 77 + 78 /* 79 * initialize background image 80 */ 81 @@ -2046,6 +2089,8 @@ run(void) 82 int w = win.w, h = win.h; 83 fd_set rfd; 84 int xfd = XConnectionNumber(xw.dpy), ttyfd, xev, drawing; 85 + int bgrfd = bgreloadpipe[0]; 86 + char c; 87 struct timespec seltv, *tv, now, lastblink, trigger; 88 double timeout; 89 90 @@ -2072,6 +2117,7 @@ run(void) 91 FD_ZERO(&rfd); 92 FD_SET(ttyfd, &rfd); 93 FD_SET(xfd, &rfd); 94 + FD_SET(bgrfd, &rfd); 95 96 if (XPending(xw.dpy)) 97 timeout = 0; /* existing events might not set xfd */ 98 @@ -2080,13 +2126,20 @@ run(void) 99 seltv.tv_nsec = 1E6 * (timeout - 1E3 * seltv.tv_sec); 100 tv = timeout >= 0 ? &seltv : NULL; 101 102 - if (pselect(MAX(xfd, ttyfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) { 103 + if (pselect(MAX(xfd, MAX(ttyfd, bgrfd))+1, &rfd, NULL, NULL, tv, NULL) < 0) { 104 if (errno == EINTR) 105 continue; 106 die("select failed: %s\n", strerror(errno)); 107 } 108 clock_gettime(CLOCK_MONOTONIC, &now); 109 110 + if (FD_ISSET(bgrfd, &rfd)) { 111 + while (read(bgrfd, &c, 1) > 0) 112 + ; 113 + bginit(); 114 + redraw(); 115 + } 116 + 117 if (FD_ISSET(ttyfd, &rfd)) 118 ttyread(); 119 120 @@ -2219,6 +2272,7 @@ run: 121 rows = MAX(rows, 1); 122 tnew(cols, rows); 123 xinit(cols, rows); 124 + bgreloadinit(); 125 bginit(); 126 xsetenv(); 127 selinit(); 128 -- 129 2.55.0 130