commit 8f2d5e294fab3ed40694d231bf1b53c84081c212 Author: Ivan Tham Date: Sat Nov 28 21:08:54 2015 +0800 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..95c40ba --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Object files +*.o +*.ko +*.obj +*.elf + +# Libraries +*.lib +*.a + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex +/spt + +# vim +*.swp +*~ + +config.h diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5f2f214 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT/X Consortium License + +© 2015 Ivan Tham + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..05e4894 --- /dev/null +++ b/Makefile @@ -0,0 +1,59 @@ +# spt - simple pomodoro timer +# See LICENSE file for copyright and license details. + +include config.mk + +SRC = spt.c +OBJ = ${SRC:.c=.o} + +all: options spt + +options: + @echo spt build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +.c.o: + @echo CC $< + @${CC} -c ${CFLAGS} $< + +${OBJ}: config.h config.mk + +config.h: + @echo creating $@ from config.def.h + @cp config.def.h $@ + +spt: ${OBJ} + @echo CC -o $@ + @${CC} -o $@ ${OBJ} ${LDFLAGS} + +clean: + @echo cleaning + @rm -f ${SRC:.c=} ${OBJ} spt-${VERSION}.tar.xz + +dist: clean + @echo creating dist tarball + @mkdir -p spt-${VERSION} + @cp -R LICENSE Makefile README config.mk config.def.h spt.info spt.1 ${SRC} spt-${VERSION} + @tar -cf spt-${VERSION}.tar spt-${VERSION} + @xz spt-${VERSION}.tar + @rm -rf spt-${VERSION} + +install: all + @echo installing executable file to ${DESTDIR}${PREFIX}/bin + @mkdir -p ${DESTDIR}${PREFIX}/bin + @cp -f spt ${DESTDIR}${PREFIX}/bin + @chmod 755 ${DESTDIR}${PREFIX}/bin/spt + @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 + @mkdir -p ${DESTDIR}${MANPREFIX}/man1 + @sed "s/VERSION/${VERSION}/g" < spt.1 > ${DESTDIR}${MANPREFIX}/man1/spt.1 + @chmod 644 ${DESTDIR}${MANPREFIX}/man1/spt.1 + +uninstall: + @echo removing executable file from ${DESTDIR}${PREFIX}/bin + @rm -f ${DESTDIR}${PREFIX}/bin/spt + @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 + @rm -f ${DESTDIR}${MANPREFIX}/man1/spt.1 + +.PHONY: all options clean dist install uninstall diff --git a/README b/README new file mode 100644 index 0000000..c98eb33 --- /dev/null +++ b/README @@ -0,0 +1,37 @@ +spt - simple pomodoro timer +=========================== +spt is a simple timer that uses the pomodoro technique that doubles your +efficiency. + + +Features +-------- +- Get the jobs done quicker than ever +- Keeps you free like a dog + + +Installation +------------ +Edit config.mk to match your local setup (spt is installed into the /usr/local +namespace by default). + +Afterwards enter the following command to build and install spt (if necessary +as root): + + make clean install + +See the man pages for additional details. + + +Configuration +------------- +The configuration of dwm is done by creating a custom config.h +and (re)compiling the source code. + + +Links +----- +http://pomodorotechnique.com/ + + +The project is licensed under the MIT license. diff --git a/TODO b/TODO new file mode 100644 index 0000000..09a1462 --- /dev/null +++ b/TODO @@ -0,0 +1,9 @@ +major +----- + - Add options to start and stop spt with only one process + +misc +---- + $ grep -n 'TODO' spt.c + +# vim:ft=markdown: diff --git a/arg.h b/arg.h new file mode 100644 index 0000000..3b0d22f --- /dev/null +++ b/arg.h @@ -0,0 +1,40 @@ +/* + * Copy me if you can. + * by 20h + */ + +#ifndef __ARG_H__ +#define __ARG_H__ + +extern char *argv0; + +#define USED(x) ((void)(x)) + +#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ + argv[0] && argv[0][1]\ + && argv[0][0] == '-';\ + argc--, argv++) {\ + char _argc;\ + char **_argv;\ + if (argv[0][1] == '-' && argv[0][2] == '\0') {\ + argv++;\ + argc--;\ + break;\ + }\ + for (argv[0]++, _argv = argv; argv[0][0];\ + argv[0]++) {\ + if (_argv != argv)\ + break;\ + _argc = argv[0][0];\ + switch (_argc) + +#define ARGEND }\ + USED(_argc);\ + }\ + USED(argv);\ + USED(argc); + +#define EARGF(x) ((argv[1] == NULL)? ((x), abort(), (char *)0) :\ + (argc--, argv++, argv[0])) + +#endif diff --git a/config.def.h b/config.def.h new file mode 100644 index 0000000..32e3774 --- /dev/null +++ b/config.def.h @@ -0,0 +1,22 @@ +/* See LICENSE file for copyright and license details. */ + +/* Notification */ +static char *notifycmd = "libnotify"; /* Use built-in libnotify if empty */ +static char *notifyext = ""; /* Notify with extra command (eg. play an alarm) */ + +/* + * This is the array which defines all the timer that will be used. + * It will be repeated after all of it is executed. + */ +static Timer timer[] = { + /* timer comment */ + { 1500, "Time to start working!"}, + { 300, "Time to start resting!"}, + { 1500, "Time to start working!"}, + { 300, "Time to start resting!"}, + { 1500, "Time to start working!"}, + { 300, "Time to start resting!"}, + { 1500, "Time to start working!"}, + { 300, "Time to start resting!"}, + { 900, "Time to take some nap!"}, +}; diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..3fdff03 --- /dev/null +++ b/config.mk @@ -0,0 +1,22 @@ +# spt version +VERSION = 0.0 + +# Customize below to fit your system + +# paths +PREFIX = /usr/local +MANPREFIX = ${PREFIX}/share/man + +# includes and libs +INCS = -I. -I/usr/include \ + `pkg-config --cflags libnotify` +LIBS = -L/usr/lib \ + `pkg-config --libs libnotify` + +# flags +CPPFLAGS = -DVERSION=\"${VERSION}\" +CFLAGS += -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} +LDFLAGS += -g ${LIBS} + +# compiler and linker +# CC = cc diff --git a/spt.1 b/spt.1 new file mode 100644 index 0000000..e672ef0 --- /dev/null +++ b/spt.1 @@ -0,0 +1,52 @@ +.TH SPT 1 spt\-VERSION +.SH NAME +spt \- simple pomodoro timer +.SH SYNOPSIS +.B spt +.RB [ \-e +.IR notifycmd ] +.RB [ \-n +.IR notifyext ] +.RB [ \-v ] +.SH DESCRIPTION +.B spt +is a simple timer that uses pomodoro technique with desktop notification to +double your efficiency. +.SH OPTIONS +.TP +.BI \-e " notifyext" +Execute +.I notifycmd +when timer starts ticking. +.TP +.BI \-n " notifycmd" +If +.IR empty , +do nothing. If +.IR libnotify , +use the default notification. If neither, it will use the command specified. +.TP +.BI \-v +Prints version information to stderr, then exits. +.SH TIMER +4 pomodoro timer +.RB ( "25 min." ) +with subsequent rests in between +.RB ( "5 min." ) +and +followed by a long rest +.RB ( "15 min." ) +.SH EXAMPLES +Use system notify_send and play a music without libnotify: +.RS +.B spt -e 'aplay alarm.wav' -n 'notify-send' +.RE +.SH AUTHOR +The author is not that important. A message from the author: +.TP +.I "Good luck and have a nice day!" +.SH LICENSE +See the LICENSE file for the terms of redistribution. +.SH BUGS +Bugs? You must be kidding; there is no bugs in this software. But if we +happened to be wrong, please report the bugs! diff --git a/spt.c b/spt.c new file mode 100644 index 0000000..40beaf4 --- /dev/null +++ b/spt.c @@ -0,0 +1,111 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include + +#include + +#include "arg.h" + +char *argv0; + +/* macros */ +#define LEN(a) (sizeof(a) / sizeof(a)[0]) + +typedef struct { + unsigned int tmr; + char *cmt; +} Timer; + +#include "config.h" + +/* function declarations */ +static void die(const char *errstr, ...); +static void spawn(char *); +static void notify_send(char *); +static void usage(void); + +/* functions implementations */ +void +die(const char *errstr, ...) +{ + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +void +spawn(char *cmd) +{ + if (fork() == 0) { + setsid(); + execvp("sh", (char *const []){"/bin/sh", "-c", cmd, 0}); + fprintf(stderr, "spt: execvp %s", cmd); + perror(" failed"); + exit(0); + } +} + +void +notify_send(char *cmt) +{ + if (!strcmp(notifycmd, "libnotify")) { /* use libnotify */ + notify_init("spt"); + NotifyNotification *n = notify_notification_new("spt", cmt, "dialog-information"); + notify_notification_show(n, NULL); + g_object_unref(G_OBJECT(n)); + notify_uninit(); + } else if (strcmp(notifycmd, "")) { + /* TODO(pickfire): merge this into spawn() */ + if (fork() == 0) { + setsid(); + execlp(notifycmd, "spt", cmt, NULL); + fprintf(stderr, "spt: execlp %s", notifycmd); + perror(" failed"); + exit(0); + } + } + + if (strcmp(notifyext, "")) /* extra commands to use */ + spawn(notifyext); +} + +void +usage(void) +{ + die("usage: %s [-e notifyext] [-n notifycmd] [-v]\n", argv0); +} + +int +main(int argc, char *argv[]) +{ + int i = 0; + + ARGBEGIN { + case 'e': + notifyext = EARGF(usage()); + break; + case 'n': + notifycmd = EARGF(usage()); + break; + case 'v': + die("spt " VERSION " © 2015 spt engineers, " + "see LICENSE for details\n"); + default: + usage(); + break; + } ARGEND; + +run: + notify_send(timer[i].cmt); + sleep(timer[i].tmr); + i + 1 >= LEN(timer) ? i = 0 : i++; /* i infinal loop */ + goto run; + + return 0; +}