commit db2c03b9dda742d584185290a66913910b223bd2
parent 3dd4fe5416c2f9050723fc1c0ebf50f9e0a77094
Author: Christos Margiolis <christos@margiolis.net>
Date: Mon, 24 May 2021 20:45:29 +0300
Fixed lockfile bug, made Makefile portable
Diffstat:
M | Makefile | | | 28 | ++++++++++++++-------------- |
M | README | | | 2 | +- |
M | config.h | | | 25 | +++++++++++++++---------- |
M | config.mk | | | 18 | ++++-------------- |
M | nfy.1 | | | 31 | ++++++++++++++++++------------- |
M | nfy.c | | | 108 | +++++++++++++++++++++++++++++++++++++++---------------------------------------- |
6 files changed, 105 insertions(+), 107 deletions(-)
diff --git a/Makefile b/Makefile
@@ -26,28 +26,28 @@ ${BIN}: ${OBJ}
${CC} -c ${CFLAGS} $<
dist: clean
- ${MKDIR} ${DIST}
- ${CP} -R nfy.c config.h Makefile config.mk ${DIST}
- ${TAR} ${DIST}.tar ${DIST}
- ${GZIP} ${DIST}.tar
- ${RM_DIR} ${DIST}
+ mkdir -p ${DIST}
+ cp -R config.h config.mk LICENSE Makefile nfy.1 nfy.c README ${DIST}
+ tar -cf ${DIST}.tar ${DIST}
+ gzip ${DIST}.tar
+ rm -rf ${DIST}
run:
./${BIN}
install: all
- ${MKDIR} ${DESTDIR}${BIN_DIR} ${DESTDIR}${MAN_DIR}
- ${CP} ${BIN} ${BIN_DIR}
- ${CP} ${MAN1} ${DESTDIR}${MAN_DIR}
- sed "s/VERSION/${VERSION}/g" < ${MAN1} > ${DESTDIR}${MAN_DIR}/${MAN1}
- chmod 755 ${DESTDIR}${BIN_DIR}/${BIN}
- chmod 644 ${DESTDIR}${MAN_DIR}/${MAN1}
+ mkdir -p ${DESTDIR}${PREFIX}/bin ${DESTDIR}${MANPREFIX}/man1
+ cp -f ${BIN} ${DESTDIR}${PREFIX}/bin
+ cp -f ${MAN1} ${DESTDIR}${MANPREFIX}/man1
+ sed "s/VERSION/${VERSION}/g" < ${MAN1} > ${DESTDIR}${MANPREFIX}/man1/${MAN1}
+ chmod 755 ${DESTDIR}${PREFIX}/bin/${BIN}
+ chmod 644 ${DESTDIR}${MANPREFIX}/man1/${MAN1}
uninstall:
- ${RM} ${DESTDIR}${BIN_DIR}/${BIN}
- ${RM} ${DESTDIR}${MAN_DIR}/${MAN1}
+ rm -f ${DESTDIR}${PREFIX}/bin/${BIN} \
+ ${DESTDIR}${MANPREFIX}/man1/${MAN1}
clean:
- ${RM} ${BIN} ${OBJ} ${DIST}.tar.gz
+ rm -f ${BIN} ${OBJ} ${DIST}.tar.gz *.core
.PHONY: all options clean dist install uninstall run
diff --git a/README b/README
@@ -10,7 +10,7 @@ Dependencies:
- libXrandr
Usage:
------
+------
Edit config.mk and config.h to match your particular
setup and preferences.
diff --git a/config.h b/config.h
@@ -1,16 +1,21 @@
/* See LICENSE file for copyright and license details. */
+#ifndef _NFY_CONFIG_H_
+#define _NFY_CONFIG_H_
+
enum { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT }; /* Window positions */
static const char *bgcolor = "#201f1c"; /* Background color */
-static const char *bordercolor = "#f28f19"; /* Border color */
+static const char *bordercolor = "#f18f19"; /* Border color */
static const char *fontcolor = "#e6e5e3"; /* Font color */
/* TODO: add fallbacks */
-static const char *fonts = "monospace:size=15"; /* Font */
-static const int padding = 15; /* Padding (pixels) */
-static const int borderw = 2; /* Border width (pixels) */
-static const int duration = 3; /* Notification duration (seconds) */
-static const int pos = TOP_RIGHT; /* Window position */
-static const int mx = 10; /* Margin X (pixels) */
-static const int my = 25; /* Margin Y (pixels) */
-static const int maxlen = 250; /* Max window length (pixels) */
-static const int linespace = 10; /* Line spacing (pixels) */
+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 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 linespace = 10; /* Line spacing (pixels) */
static const char *lockfile = "/tmp/nfy.lock";
+
+#endif /* _NFY_CONFIG_H_ */
diff --git a/config.mk b/config.mk
@@ -1,17 +1,17 @@
# See LICENSE file for copyright and license details.
# nfy version
-VERSION = 0
+VERSION = 0.1
# paths
PREFIX = /usr/local
-MAN_DIR = ${PREFIX}/share/man/man1
-BIN_DIR = ${PREFIX}/bin
+MANPREFIX = ${PREFIX}/share/man
# includes and libs
+# FreeBSD
X11INC = /usr/local/include
X11LIB = /usr/local/lib
-# Linux
+# Linux/OpenBSD
#X11INC = /usr/X11R6/include
#X11LIB = /usr/X11R6/lib
@@ -26,15 +26,5 @@ CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L \
CFLAGS = -std=c99 -pedantic -Wall -Os -I${X11INC} -I${FREETYPEINC} ${CPPFLAGS}
LDFLAGS = -L${X11LIB} ${FREETYPELIBS} -lX11 -lXrandr
-# utils
-CP = cp -f
-RM = rm -f
-RM_DIR = rm -rf
-MV = mv
-MKDIR = mkdir -p
-RM_DIR = rm -rf
-TAR = tar -cf
-GZIP = gzip
-
# compiler
CC = cc
diff --git a/nfy.1 b/nfy.1
@@ -6,19 +6,18 @@
.Nd a minimal and daemonless notification program for X
.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. It uses the
-.Xr Xft 3
-library to render fonts and colors, and
-.Xr Xrandr 3
-to handle screen sizes.
-.Pp
-All configuration is done by
-editing the 'config.h' file in the source code.
+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
.Pp
If the string is not surrounded in quotes,
@@ -30,9 +29,10 @@ has a non-blocking behaviour, meaning that commands
coming after it can execute normally without them having
to wait for
.Nm
-to finish first. This is helpful since it's a notification
-program and there's no reason to wait for the notification
-to die off before other commands can execute.
+to finish first. This is especially helpful inside scripts.
+.Pp
+.Nm
+handles multiple notifications by queuing them using a lock file.
.Sh SIGNALS
.Nm
handles only SIGALRM, SIGTERM and SIGINT. It receives a
@@ -40,6 +40,11 @@ SIGALRM signal by default after the specified duration
of the notification.
.Sh SEE ALSO
.Xr signal 3 ,
-.Xr alarm 3
+.Xr alarm 3 ,
+.Xr fcntl 3 ,
+.Xr Xft 3 ,
+.Xr Xrandr 3
+.Sh BUGS
+Perhaps.
.Sh AUTHORS
.An Christos Margiolis Aq Mt christos@christosmarg.xyz
diff --git a/nfy.c b/nfy.c
@@ -1,5 +1,5 @@
/* See LICENSE file for copyright and license details. */
-#include <errno.h>
+#include <err.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
@@ -14,35 +14,14 @@
#include "config.h"
-static void die(const char *, ...);
-static void recvalrm(int);
+static void sighandler(int);
static char *argv0;
static Display *dpy;
static Window win;
static void
-die(const char *fmt, ...)
-{
- va_list args;
-
- fprintf(stderr, "%s: ", argv0);
-
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- va_end(args);
-
- if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
- fputc(' ', stderr);
- perror(NULL);
- } else
- fputc('\n', stderr);
-
- exit(EXIT_FAILURE);
-}
-
-static void
-recvalrm(int sig)
+sighandler(int sig)
{
XEvent ev;
@@ -51,6 +30,13 @@ recvalrm(int sig)
XFlush(dpy);
}
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-v] str...\n", argv0);
+ exit(1);
+}
+
int
main(int argc, char *argv[])
{
@@ -63,34 +49,44 @@ main(int argc, char *argv[])
XftColor color;
XftDraw *drw;
XftFont *font;
+ struct flock fl;
struct sigaction sig;
pid_t pid;
int lockfd;
int scr, scrw, scrh;
int x, y, w, h, th;
- int i, j, len;
+ int i, j, len, argi;
+ char ch;
argv0 = *argv;
- if (argc < 2) {
- fprintf(stderr, "usage: %s str...\n", argv0);
- return 1;
+ if (argc < 2)
+ usage();
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ puts("nfy-"VERSION);
+ exit(0);
+ case '?':
+ default:
+ usage();
+ }
}
-
- if ((lockfd = open(lockfile, O_CREAT | O_RDWR, 0600)) == -1)
- die("open:");
- if (!(dpy = XOpenDisplay(NULL)))
- die("XOpenDisplay:");
+ /*argc -= optind;*/
+ /*argv += optind;*/
+ argi = optind;
if ((pid = fork()) < 0)
- die("fork:");
+ err(1, "fork");
if (pid > 0)
- exit(EXIT_SUCCESS);
+ _exit(0);
umask(0);
if (setsid() < 0)
- die("setsid:");
- close(STDIN_FILENO);
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
+ err(1, "setsid");
+
+ if ((lockfd = open(lockfile, O_CREAT | O_RDWR, 0600)) < 0)
+ err(1, "open");
+ if (!(dpy = XOpenDisplay(NULL)))
+ errx(1, "XOpenDisplay");
scr = DefaultScreen(dpy);
screens = XRRGetScreenResources(dpy, RootWindow(dpy, scr));
@@ -110,7 +106,7 @@ main(int argc, char *argv[])
th = font->ascent - font->descent;
w = 0;
- for (i = 1; i < argc; i++) {
+ for (i = argi; i < argc; i++) {
len = strlen(argv[i]);
j = len;
while (j--)
@@ -154,26 +150,31 @@ main(int argc, char *argv[])
XSelectInput(dpy, win, ExposureMask | ButtonPress);
XMapWindow(dpy, win);
- sig.sa_handler = recvalrm;
+ sig.sa_handler = sighandler;
sig.sa_flags = SA_RESTART;
- sigemptyset(&sig.sa_mask);
- sigaction(SIGALRM, &sig, 0);
- sigaction(SIGTERM, &sig, 0);
- sigaction(SIGINT, &sig, 0);
- /* XXX: replace with just singal? */
-
- /* XXX: when being called from another process this one succeeds */
- while (lockf(lockfd, F_LOCK, 0L) == -1)
- ;
+ (void)sigemptyset(&sig.sa_mask);
+ if (sigaction(SIGALRM, &sig, NULL) < 0)
+ err(1, "sigaction(SIGALRM)");
+ if (sigaction(SIGTERM, &sig, NULL) < 0)
+ err(1, "sigaction(SIGTERM)");
+ if (sigaction(SIGINT, &sig, NULL) < 0)
+ err(1, "sigaction(SIGINT)");
+
+ fl.l_len = 0;
+ fl.l_start = 0;
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ if (fcntl(lockfd, F_SETLKW, &fl) < 0)
+ err(1, "fcntl(F_SETLKW)");
+
if (duration > 0)
(void)alarm(duration);
for (;;) {
XNextEvent(dpy, &ev);
-
if (ev.type == Expose) {
XClearWindow(dpy, win);
- for (i = 1; i < argc; i++)
+ for (i = argi; i < argc; i++)
XftDrawStringUtf8(drw, &color, font,
w >> 3, linespace * (i - 1) + th * i + padding,
(FcChar8 *)argv[i], strlen(argv[i]));
@@ -187,10 +188,7 @@ main(int argc, char *argv[])
XRRFreeCrtcInfo(info);
XRRFreeScreenResources(screens);
XCloseDisplay(dpy);
-
- (void)lockf(lockfd, F_ULOCK, 0);
(void)close(lockfd);
- (void)unlink(lockfile);
return 0;
}