foswret.com

Pomodoro Timer

<– Back

Recently, I finally got around to completing a project. I had started work on a simple pomodoro timer in the terminal, but I only got as far as the backend timer portion of it. However, I finally got a basic version of it working and I thought for posterity’s sake I would go through my code.

The code is located on my git repository at https://git.foswret.com/beefsteak/. I called it beefsteak because beefsteak is a variety of tomato, and the name sounds very un-like the functionality of the program and the pomodoro method in general. The program is coded in C and platform compatible to the best of my ability.

The Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#define WORK_TIME_MIN 50
#define BREAK_TIME_MIN 10
#define SESSION_COUNT 3

/* System requirements:
 * notify-send
 * */

/* 60 SECONDS = 1 MINUTE */
/* 60 MINUTES = 1 HOUR, 3600 SECONDS */


int clear_stream(void) {
	fflush(stdout);
	printf("\r");
	return(0);
}

^^^ This first chunk is defining time variables and the clear_stream() function. clear_stream() allows the timer to continuously be on the same line after every second change. For the variables, the default work session timing is 50 minutes with each break being 10 minutes. These constants are turned into seconds, which is usable with the next function.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
void seconds_to_string(int seconds) {
	int hour = 0;
	int minute = 0;

	if ((seconds/60) >= 60) { // If seconds > one hour
		hour = (seconds - (seconds % 3600)) / 3600;
		seconds = seconds % 600;
	}
	if ((seconds/60) >= 1) { // If seconds > one minute
		minute = (seconds - (seconds % 60)) / 60;
		seconds = seconds % 60;
	}
	printf("%.2d:%.2d:%.2d", hour, minute, seconds);
	clear_stream();
}

^^^ This is probably the most important part of the whole program. The actual timer value is just an integer value for seconds and the time remaining is printed using this function. For every second that goes by, this function is called again, but with the seconds variable being decreased by one.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
int send_notification(int type) {
	char command[100], message[100];
	strcpy(command, "notify-send "); /* Notifcation Backend */
	switch(type) {
		case 0: /* Work Started */
			sprintf(message, "\"🍅 Work Session Started\" \"Time Remaining: %d minutes.\"", WORK_TIME_MIN);
			strcat(command, message);
			system(command);
			break;
		case 1: /* Break Started */
			sprintf(message, "\"🏖️ Break Session Started\" \"Time Remaining: %d minutes.\"", BREAK_TIME_MIN);
			strcat(command, message);
			system(command);
			break;
		case 2: /* Session Ended*/
			sprintf(message, "\"🕰️ Pomodoro Session Complete\" \"All Done.\"");
			strcat(command, message);
			system(command);
			break;
	}
	return 0;
}

^^^ The send_notification function does what it says: send a notification. It uses the libnotify library, which is defined in the org.freedesktop.Notifications Desktop Specification. I have only tested this program out with dunst, but if it works with that I’m pretty sure it will function with desktop environment notifiers.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
int main(int argc, char **argv) {
	for (int i = 0; i < SESSION_COUNT; i++) {
		int work_time_seconds = WORK_TIME_MIN * 60;
		int break_time_seconds = BREAK_TIME_MIN * 60;
		send_notification(0);
		while (work_time_seconds > 0) {
			printf("Work Time Left: ");
			seconds_to_string(work_time_seconds);
			sleep(1);
			work_time_seconds--;
		}
		send_notification(1);
		while (break_time_seconds > 0) {
			printf("Break Time Left: ");
			seconds_to_string(break_time_seconds);
			sleep(1);
			break_time_seconds--;
		}
	}
	send_notification(2);
	return 0;
}

^^^ Putting the program together. Basically:

The Future

In the future, I want to add an audible alarm that says work has finished. I also want a key to be pressed in order for the timers to switch. This timer isn’t perfect, but it works well enough and is pretty similar to a physical timer.