Compare commits

..

No commits in common. "168b4f092caff12d2dddcf24fd85718d48e44a9a" and "bf82caf6e00f92dce995f9838337ce249948c871" have entirely different histories.

13 changed files with 432 additions and 82 deletions

30
.gitignore vendored Normal file
View File

@ -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

View File

@ -1,5 +1,4 @@
Copyright (c) 2015-2020, Ivan Tham <pickfire@riseup.net>
2023- , Nuño Sempere <nuno.semperelh@protonmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above

59
Makefile Normal file
View File

@ -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

View File

@ -1,26 +1,36 @@
# pomo - a simple pomodoro timer
spt - simple pomodoro timer
===========================
spt is a simple timer that uses the pomodoro technique that doubles your
efficiency.
## about
Features
--------
- Get the jobs done quicker than ever
- Keeps you free like a dog
- Able to show remaining time
pomo is a simple timer that uses the pomodoro technique. It is based on [spt](https://github.com/pickfire/spt), which is a bit less simple.
Installation
------------
Edit config.mk to match your local setup (spt is installed into the /usr/local
namespace by default).
## dependencies
Afterwards enter the following command to build and install spt (if necessary
as root):
Instead of inotify, this pomodoro timer uses [sent](https://tools.suckless.org/sent/), displaying messages to the user by spawning a process that calls `echo 'msg' | sent`.
make clean install
## installation
See the man pages for additional details.
Read pomo.c, then:
Configuration
-------------
The configuration of spt is done by creating a custom config.h and
(re)compiling the source code. By default, the timer runs by 4
pomodoro timer (25 mins) with subsequent rests in between (15 mins)
followed by a long rest (5 mins) in an infinite loop.
```
make
sudo make install
```
Links
-----
http://pomodorotechnique.com/
## usage
In a terminal, call the "pomo" command. Then, an initial message will appear in its own window. Close it and start working. By default, the timer runs by 4 pomodoro timer (25 mins) with subsequent rests in between (5 mins) followed by a long rest (15 mins) in an infinite loop.
## configuration
read through the <60 lines of C, and change as appropriate. If this functionality is too simple, consider looking at [spt](https://github.com/pickfire/spt) instead.
The project is licensed under the MIT license.

1
TODO Normal file
View File

@ -0,0 +1 @@
Good luck! Nothing TODO for now.

40
arg.h Normal file
View File

@ -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

22
config.def.h Normal file
View File

@ -0,0 +1,22 @@
/* See LICENSE file for copyright and license details. */
/* Notification, remove DNOTIFY in config.mk if you don't want it */
static char *notifycmd = ""; /* Uses given command if not compiled by DNOTIFY */
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 Timers timers[] = {
/* timer(s) 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!"},
};

24
config.mk Normal file
View File

@ -0,0 +1,24 @@
# spt version
VERSION = 0.5
# Customize below to fit your system
# paths
PREFIX = /usr/local
MANPREFIX = ${PREFIX}/share/man
INCS = -I. -I/usr/include
LIBS = -L/usr/lib
# libnotify, comment if you don't want it
DEFS = -DNOTIFY
INCS+= `pkg-config --cflags libnotify`
LIBS+= `pkg-config --libs libnotify`
# flags
CPPFLAGS += -DVERSION=\"${VERSION}\" -D_POSIX_C_SOURCE=199309
CFLAGS += -g -std=c99 -pedantic -Wall -Os ${INCS} ${DEFS} ${CPPFLAGS}
LDFLAGS += -g ${LIBS}
# compiler and linker
CC ?= cc

6
contrib/notify-macos Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
# A notification wrapper for MacOS. It will appear in Notification
# Center as owned by Script Editor.
#
# usage: spt -n ./notify-macos
osascript -e "display notification \"$2\" with title \"$1\""

View File

@ -1,8 +0,0 @@
build:
gcc pomo.c -o pomo
install:
mv ./pomo /bin/pomo
lint:
clang-tidy pomo.c --

56
pomo.c
View File

@ -1,56 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX_MSG_LEN 100
#define LEN(a) (sizeof(a) / sizeof(a[0]))
typedef struct {
unsigned int t;
char *msg;
} Timers;
static Timers timers[] = {
/* timer(s) 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!"},
{ 900, "Time to take a longer rest!" },
};
void spawn(char *argv[]){
if (fork() == 0) {
// we need to fork the process so that
// when we exit the sent screen
// this program continues.
setsid();
execvp(argv[0], argv);
perror(" failed");
exit(0);
}
}
void display_message(char *msg){
char sh_command[MAX_MSG_LEN];
snprintf(sh_command, MAX_MSG_LEN, "echo '%s' | sent", msg); // NOLINT: We are being carefull here by considering MAX_MSG_LEN explicitly.
printf("%s", sh_command);
char *spawn_args[] = {
"/bin/sh",
"-c",
sh_command,
NULL
};
spawn(spawn_args);
// fprintf(stderr, "%s\n", msg);
}
int main(int argc, char *argv[]){
for(int i=0; ; i = (i+1) % LEN(timers)){
display_message(timers[i].msg);
sleep(timers[i].t);
}
}

51
spt.1 Normal file
View File

@ -0,0 +1,51 @@
.TH SPT 1 spt\-VERSION
.SH NAME
spt \- simple pomodoro timer
.SH SYNOPSIS
.B spt
.RB [ \-e
.IR notifyext ]
.RB [ \-n
.IR notifycmd ]
.RB [ \-v ]
.SH DESCRIPTION
.B spt
is a simple timer that uses pomodoro technique with desktop notification to
double your efficiency.
.B spt
receives 2 signals:
.P
.RS
.B SIGUSR1
\- show remaining time, state
.br
.B SIGUSR2
\- play/pause the timer
.RE
.SH OPTIONS
.TP
.BI \-e " notifyext"
Execute
.I notifycmd
when timer starts ticking.
.TP
.BI \-n " notifycmd"
Execute
.I notifycmd
if not compiled with
.IR "-DNOTIFY".
.TP
.BI \-v
Prints version information to stderr, then exits.
.SH TIMER
4 pomodoro timer (
.B 25 min.
) with subsequent rests in between (
.B 5 min.
) and followed by a long rest (
.B 15 min.
) in an infinite loop.
.SH EXAMPLES
Use system notify_send and play a music without libnotify:
.IP
spt -e 'aplay alarm.wav' -n 'notify-send'

172
spt.c Normal file
View File

@ -0,0 +1,172 @@
/* See LICENSE file for copyright and license details. */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#ifdef NOTIFY
#include <libnotify/notify.h>
#endif /* NOTIFY */
#include "arg.h"
char *argv0;
/* macros */
#define LEN(a) (sizeof(a) / sizeof(a[0]))
typedef struct {
unsigned int tmr;
char *cmt;
} Timers;
#include "config.h"
volatile static sig_atomic_t display, suspend;
/* function declarations */
static void die(const char *errstr, ...);
static void spawn(char *argv[]);
static void notify_send(char *cmt);
static void display_state(int remaining, int suspend);
static void toggle_display(int sigint);
static void toggle_suspend(int sigint);
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(1);
}
void
spawn(char *argv[])
{
if (fork() == 0) {
setsid();
execvp(argv[0], argv);
die("spt: execvp %s\n", argv[0]);
perror(" failed");
exit(0);
}
}
void
notify_send(char *cmt)
{
if (strcmp(notifycmd, ""))
spawn((char *[]) { notifycmd, "spt", cmt, NULL });
#ifdef NOTIFY
else {
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();
}
#endif /* NOTIFY */
if (strcmp(notifyext, "")) /* extra commands to use */
spawn((char *[]) { "/bin/sh", "-c", notifyext, NULL });
}
void
display_state(int remaining, int suspend)
{
char buf[29];
snprintf(buf, 29, "Remaining: %02d:%02d %s",
remaining / 60,
remaining % 60,
(suspend) ? "" : "");
notify_send(buf);
display = 0;
}
void
toggle_display(int sigint)
{
display = 1;
}
void
toggle_suspend(int sigint)
{
suspend ^= 1;
}
void
usage(void)
{
die("usage: %s [-e notifyext] [-n notifycmd] [-v]\n", argv0);
}
int
main(int argc, char *argv[])
{
struct timespec remaining;
struct sigaction sa;
sigset_t emptymask;
int i;
ARGBEGIN {
case 'e':
notifyext = EARGF(usage());
break;
case 'n':
notifycmd = EARGF(usage());
break;
case 'v':
die("spt " VERSION " © 2015-2020 spt engineers, "
"see LICENSE for details\n");
default:
usage();
} ARGEND;
/* add SIGUSR1 handler: remaining_time */
sa.sa_handler = toggle_display;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGUSR1, &sa, NULL) == -1)
die("cannot associate SIGUSR1 to handler\n");
/* add SIGUSR2 handler: toggle */
sa.sa_handler = toggle_suspend;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGUSR2, &sa, NULL) == -1)
die("cannot associate SIGUSR2 to handler\n");
sigemptyset(&emptymask);
for (i = 0; ; i = (i + 1) % LEN(timers)) {
notify_send(timers[i].cmt);
remaining.tv_sec = timers[i].tmr;
remaining.tv_nsec = 0;
while (remaining.tv_sec) {
if (display)
display_state(remaining.tv_sec, suspend);
if (suspend)
sigsuspend(&emptymask);
else
if (nanosleep(&remaining, &remaining) == 0)
remaining.tv_sec = remaining.tv_nsec = 0;
}
}
return 0;
}