commit e87c72750e2e4955e2dfaccb89dcf6966c8e969e
parent 6d94996de9f50d43c78b6bef4bc8364f28b0a94b
Author: Christos Margiolis <christos@margiolis.net>
Date: Fri, 1 Apr 2022 22:42:21 +0300
added linebreak, fixed calcs, now reads from stdin only
Diffstat:
M | config.h | | | 9 | +++++---- |
M | config.mk | | | 4 | +++- |
M | nfy.1 | | | 42 | ++++++++++++++++++------------------------ |
M | nfy.c | | | 116 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------- |
4 files changed, 106 insertions(+), 65 deletions(-)
diff --git a/config.h b/config.h
@@ -2,19 +2,20 @@
#ifndef _NFY_CONFIG_H_
#define _NFY_CONFIG_H_
+#define MAXLEN 82 /* Max length per line (characters) */
+
enum { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT }; /* Window positions */
static const char *bgcolor = "#201f1c"; /* Background color */
static const char *bordercolor = "#f18f19"; /* Border color */
static const char *fontcolor = "#e6e5e3"; /* Font color */
/* TODO: add fallbacks */
static const char *fonts = "monospace:size=12"; /* Fonts */
-static const unsigned int padding = 15; /* Padding (pixels) */
-static const unsigned int borderw = 2; /* Border width (pixels) */
+static const unsigned int padding = 10; /* Padding (pixels) */
+static const unsigned int borderw = 3; /* Border width (pixels) */
static const unsigned int duration = 3; /* Notification duration (seconds) */
static const unsigned int pos = TOP_RIGHT; /* Window position */
static const unsigned int mx = 10; /* Margin X (pixels) */
-static const unsigned int my = 25; /* Margin Y (pixels) */
-static const unsigned int maxlen = 250; /* Max window length (pixels) */
+static const unsigned int my = 10; /* Margin Y (pixels) */
static const unsigned int linespace = 10; /* Line spacing (pixels) */
static const char *lockfile = "/tmp/nfy.lock";
diff --git a/config.mk b/config.mk
@@ -1,10 +1,12 @@
# See LICENSE file for copyright and license details.
# nfy version
-VERSION = 0.1
+VERSION = 0.2
# paths
PREFIX = /usr/local
MANPREFIX = ${PREFIX}/share/man
+# OpenBSD
+#MANPREFIX = ${PREFIX}/man
# includes and libs
# FreeBSD
diff --git a/nfy.1 b/nfy.1
@@ -7,44 +7,38 @@
.Sh SYNOPSIS
.Nm
.Op Fl v
-.Ar str...
.Sh DESCRIPTION
-.Pp
.Nm
-creates a temporary notification popup window and displays all the arguments
-that were passed to it. Configuration is done by editing the 'config.h' file
-in the source code.
-.Sh OPTIONS
-.Bl -tag -width Ds
-.It Fl v
-prints version to stdout and exits.
-.Sh USAGE
+reads input from stdin (only), creates a temporary popup window and \
+displays it. Configuration is done by editing the 'config.h' file in the \
+source code.
.Pp
-If the string is not surrounded in quotes,
.Nm
-will print one line for each word.
-.Pp
-.Nm
-has a non-blocking behaviour, meaning that commands
-coming after it can execute normally without them having
-to wait for
+has non-blocking behaviour, meaning that commands coming after it can execute \
+normally without them having to wait for
.Nm
-to finish first. This is especially helpful inside scripts.
+to finish first.
+This is especially useful inside scripts.
.Pp
.Nm
handles multiple notifications by queuing them using a lock file.
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl v
+prints version to stdout and exits.
+.El
.Sh SIGNALS
.Nm
-handles only SIGALRM, SIGTERM and SIGINT. It receives a
-SIGALRM signal by default after the specified duration
+handles only SIGALRM, SIGTERM and SIGINT.
+It receives a SIGALRM signal by default after the specified duration \
of the notification.
.Sh SEE ALSO
-.Xr signal 3 ,
+.Xr fcntl 2 ,
.Xr alarm 3 ,
-.Xr fcntl 3 ,
+.Xr signal 3 ,
.Xr Xft 3 ,
.Xr Xrandr 3
-.Sh BUGS
-Perhaps.
.Sh AUTHORS
.An Christos Margiolis Aq Mt christos@margiolis.net
+.Sh BUGS
+Perhaps.
diff --git a/nfy.c b/nfy.c
@@ -14,12 +14,39 @@
#include "config.h"
+struct line {
+ char data[MAXLEN+1];
+ size_t len;
+};
+
+#undef strlcpy /* compat with openbsd */
+size_t strlcpy(char *, const char *, size_t);
static void sighandler(int);
static char *argv0;
static Display *dpy;
static Window win;
+size_t
+strlcpy(char *dst, const char *src, size_t dsize)
+{
+ const char *osrc = src;
+ size_t nleft = dsize;
+
+ if (nleft != 0) {
+ while (--nleft != 0)
+ if ((*dst++ = *src++) == '\0')
+ break;
+ }
+ if (nleft == 0) {
+ if (dsize != 0)
+ *dst = '\0';
+ while (*src++)
+ ;
+ }
+ return (src - osrc - 1);
+}
+
static void
sighandler(int sig)
{
@@ -49,18 +76,18 @@ main(int argc, char *argv[])
XftColor color;
XftDraw *drw;
XftFont *font;
+ XGlyphInfo gi;
struct flock fl;
- struct sigaction sig;
+ struct sigaction sa;
+ struct line *lines, *lp;
pid_t pid;
int lockfd;
int scr, scrw, scrh;
- int x, y, w, h, th;
- int i, j, len, argi;
- char ch;
+ int x, y, w = 0, h, th;
+ int i, len = 0, nlines = 0;
+ char buf[MAXLEN+1], ch;
argv0 = *argv;
- if (argc < 2)
- usage();
while ((ch = getopt(argc, argv, "v")) != -1) {
switch (ch) {
case 'v':
@@ -71,10 +98,10 @@ main(int argc, char *argv[])
usage();
}
}
- /*argc -= optind;*/
- /*argv += optind;*/
- argi = optind;
+ argc -= optind;
+ argv += optind;
+ /* detach from tty */
if ((pid = fork()) < 0)
err(1, "fork");
if (pid > 0)
@@ -85,6 +112,8 @@ main(int argc, char *argv[])
if ((lockfd = open(lockfile, O_CREAT | O_RDWR, 0600)) < 0)
err(1, "open");
+
+ /* init x11 */
if (!(dpy = XOpenDisplay(NULL)))
errx(1, "XOpenDisplay");
@@ -106,38 +135,50 @@ main(int argc, char *argv[])
th = font->ascent - font->descent;
XftColorAllocName(dpy, vis, colormap, fontcolor, &color);
- w = 0;
- for (i = argi; i < argc; i++) {
- len = strlen(argv[i]);
- j = len;
- while (j--)
- if (**argv == '\n')
- **argv++ = ' ';
- /* TODO: handle maxlen */
- if (len > w)
- w = len;
- }
- w *= th + borderw;
- h = th * (argc - 1) + (linespace * (argc - 2)) + (padding << 1);
+ /* read stdin into buffer */
+ if ((lines = malloc(sizeof(struct line))) == NULL)
+ err(1, "malloc");
+ while (read(STDIN_FILENO, &ch, 1) > 0) {
+ if (ch == '\n' || len == MAXLEN) {
+ buf[len] = '\0';
+ if ((lines = realloc(lines,
+ (nlines + 1) * sizeof(struct line))) == NULL)
+ err(1, "realloc");
+ lp = &lines[nlines];
+ lp->len = len;
+ strlcpy(lp->data, buf, sizeof(lp->data));
+ /* determine window width based on largest line */
+ XftTextExtentsUtf8(dpy, font, (XftChar8 *)lp->data,
+ lp->len, &gi);
+ if (gi.width > w)
+ w = gi.width;
+ nlines++;
+ len = 0;
+ } else
+ buf[len++] = ch;
+ }
+ w += padding * 2;
+ h = (nlines - 1) * linespace + nlines * th + 2 * padding;
+ /* calculate position coordinates */
switch (pos) {
case TOP_LEFT:
x = mx;
y = my;
break;
- case TOP_RIGHT:
+ case TOP_RIGHT: /* FALLTHROUGH */
default:
- x = scrw - w - my;
+ x = scrw - w - mx - borderw * 2;
y = my;
break;
case BOTTOM_LEFT:
x = mx;
- y = scrh - h - my;
+ y = scrh - h - my - borderw * 2;
break;
case BOTTOM_RIGHT:
- x = scrw - w - mx;
- y = scrh - h - my;
+ x = scrw - w - mx - borderw * 2;
+ y = scrh - h - my - borderw * 2;
break;
}
@@ -148,16 +189,17 @@ main(int argc, char *argv[])
XSelectInput(dpy, win, ExposureMask | ButtonPress);
XMapWindow(dpy, win);
- sig.sa_handler = sighandler;
- sig.sa_flags = SA_RESTART;
- (void)sigfillset(&sig.sa_mask);
- if (sigaction(SIGALRM, &sig, NULL) < 0)
+ sa.sa_handler = sighandler;
+ sa.sa_flags = SA_RESTART;
+ (void)sigfillset(&sa.sa_mask);
+ if (sigaction(SIGALRM, &sa, NULL) < 0)
err(1, "sigaction(SIGALRM)");
- if (sigaction(SIGTERM, &sig, NULL) < 0)
+ if (sigaction(SIGTERM, &sa, NULL) < 0)
err(1, "sigaction(SIGTERM)");
- if (sigaction(SIGINT, &sig, NULL) < 0)
+ if (sigaction(SIGINT, &sa, NULL) < 0)
err(1, "sigaction(SIGINT)");
+ /* setup lock file */
fl.l_len = 0;
fl.l_start = 0;
fl.l_type = F_WRLCK;
@@ -172,14 +214,16 @@ main(int argc, char *argv[])
XNextEvent(dpy, &ev);
if (ev.type == Expose) {
XClearWindow(dpy, win);
- for (i = argi; i < argc; i++)
+ for (i = 0; i < nlines; i++)
XftDrawStringUtf8(drw, &color, font,
- w >> 3, linespace * (i - 1) + th * i + padding,
- (FcChar8 *)argv[i], strlen(argv[i]));
+ padding,
+ linespace * i + th * (i + 1) + padding,
+ (XftChar8 *)lines[i].data, lines[i].len);
} else if (ev.type == ButtonPress)
break;
}
+ free(lines);
XftDrawDestroy(drw);
XftColorFree(dpy, vis, colormap, &color);
XftFontClose(dpy, font);