commit f03dc8913a82e6eea3ea2c6b7e7ea99a7ad0f7e7
parent 5b1489ed90d1aec929657788eef32737bbbf4a89
Author: Michail Konstantinos Dimopoulos <mk@mcdim.xyz>
Date: Sat, 19 Sep 2026 19:07:44 +0300
Read from stdin with -s, argument lines appended
Diffstat:
| M | README.txt | | | 15 | ++++++++++++--- |
| M | sxalert.1 | | | 2 | ++ |
| M | sxalert.c | | | 85 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ |
3 files changed, 73 insertions(+), 29 deletions(-)
diff --git a/README.txt b/README.txt
@@ -52,7 +52,7 @@ And to install on /bin:
Usage
-----
-You can simply run the tool with each argument being a line of text
+You can simply run the tool with each argument being a line of text"
$ sxalert "First line" "Second line"
@@ -62,6 +62,14 @@ You can also set color, border width & duration:
These will overwrite the defaults defined in `config.h`
+sxalert can read from standard input:
+
+ $ sxalert < banner.txt
+
+ $ { printf '%s\n' '===== BUILD FAILED ====='; \
+ tail -n 20 build.log; } \
+ | ./sxalert -s
+
Return values
-------------
sxalert returns:
@@ -74,11 +82,11 @@ Yes, this does mean that sxalert returns non-zero values even with normal
execution, but for a good reason. This makes sxalert excellent for shell
scripts. For example:
-You can set your mail to read with an acknowledgment
+You can set your mail to read with an acknowledgment:
$ sxalert "New Mail" && mail-set-to-read
-Or you can create a more elaborate interaction
+Or you can create a more elaborate interaction:
sxalert "New Mail: X" "Left click to set to read" \
"Middle click to delete" \
@@ -95,6 +103,7 @@ Or you can create a more elaborate interaction
2)
echo "Unread mail"
;;
+ esac
Optional D-Bus daemon hack
--------------------------
diff --git a/sxalert.1 b/sxalert.1
@@ -21,6 +21,8 @@ sxalert will draw text as a notification for X
-d duration in milliseconds
for values below or equal to 0 the notification will run indefinitely
+-s read from stdin (command line arguments will be appended)
+
-h print help panel & exit
-v print version & exit
diff --git a/sxalert.c b/sxalert.c
@@ -18,7 +18,7 @@
#include "config.h"
-#define VERSION "v0.1"
+#define VERSION "v0.2"
static inline void
die(const char *msg, int code)
@@ -35,7 +35,8 @@ help(char *bin)
" -g background hex color\n"
" -r border hex color\n"
" -b border width in pixels\n"
- " -d duration in milliseconds\n\n"
+ " -d duration in milliseconds\n"
+ " -s read from stdin\n\n"
" -v print version & exit\n"
" -h print help panel & exit\n\n"
"Usage: %s [arguments] \"text\" \"text\" \"text\"\n",
@@ -204,15 +205,6 @@ init_window(Display *dpy, struct xrender *r, struct xwin *w,
}
static void
-cleanup(Display *dpy, struct xrender *r, struct xwin *w, struct alert *a)
-{
- XftColorFree(dpy, r->visual, r->cmap, &r->color);
- XftDrawDestroy(w->draw);
- XDestroyWindow(dpy, w->win);
- XCloseDisplay(dpy);
-}
-
-static void
draw(struct alert a)
{
Display *dpy = XOpenDisplay(NULL);
@@ -227,15 +219,6 @@ draw(struct alert a)
m.monitors = XRRGetMonitors(dpy, RootWindow(dpy, r.scr),
True, &m.monitor_count);
- /* for debugging
- printf("Found %d monitors\n", m.monitor_count);
- for (int i = 0; i < m.monitor_count; i++) {
- printf("Monitor %d: x=%d y=%d width=%d height=%d "
- "primary=%d\n", i, m.monitors[i].x, m.monitors[i].y,
- m.monitors[i].width, m.monitors[i].height,
- m.monitors[i].primary);
- } */
-
struct xwin *w = calloc(m.monitor_count, sizeof(struct xwin));
if (!w)
die("Cannot allocate window array\n", -1);
@@ -246,10 +229,34 @@ draw(struct alert a)
}
write_text(dpy, w, m.monitor_count, r.color, r.font, &a);
+}
- //cleanup(dpy, &r, &w, &a); /* TODO */
+void
+read_stdin(struct alert *a, FILE *f)
+{
+ int buffer = 264;
+ char *p = malloc(buffer);
+
+ int i = 0;
+ while (fgets(p, buffer, f) != NULL) {
+ for (int j=0; j<264; j++) {
+ if (p[j] == '\n')
+ p[j] = '\0';
+ }
+
+ a->lines = realloc(a->lines, (i + 1)*sizeof(*a->lines));
+ if (a->lines == NULL) {
+ die("Cannot allocate memory\n", -1);
+ }
+ a->lines[i] = calloc(buffer, 1);
+ strncpy(a->lines[i], p, buffer);
+ i++;
+ }
+ a->lines_len = i;
+ free(p);
}
+
int
main(int argc, char **argv)
{
@@ -258,7 +265,8 @@ main(int argc, char **argv)
struct alert a = default_alert;
- while ((c = getopt(argc, argv, "d:b:t:g:r:vh")) != -1 ) {
+ int s = 0;
+ while ((c = getopt(argc, argv, "d:b:t:g:r:svh")) != -1 ) {
switch (c) {
case 'v':
die(VERSION, EXIT_SUCCESS);
@@ -266,9 +274,8 @@ main(int argc, char **argv)
help(argv[0]);
case 'd':
a.duration=atoi(optarg);
- if (a.duration == 0) {
+ if (a.duration == 0)
a.duration = -1;
- }
break;
case 'b':
a.border_width=atoi(optarg);
@@ -282,11 +289,37 @@ main(int argc, char **argv)
case 'r':
strncpy(a.border_color, optarg, 7);
break;
+ case 's':
+ s = 1;
+ break;
}
}
- a.lines_len = argc - optind;
- a.lines = argv + optind; /* get lines to print */
+ int cmd_lines_len = argc - optind;
+ char **lines = argv + optind;
+
+ if (!s) {
+ a.lines = lines;
+ a.lines_len = cmd_lines_len;
+ draw(a);
+ return 4;
+ }
+
+ FILE *f = tmpfile();
+ int cc;
+
+ while ((cc = getchar()) != EOF)
+ fputc(cc, f);
+
+ for (int i=0; i<cmd_lines_len; i++)
+ fprintf(f, "%s\n", lines[i]);
+ //fputs(lines[i], f);
+
+ a.lines = NULL;
+ a.lines_len = 0;
+ rewind(f);
+ read_stdin(&a, f);
+
draw(a);
return 4;