GTK+ New Years Eve Countdown App
I’ve been educating myself about GTK+ programming lately. So I wrote this semi-short GTK app to countdown the time to New Years Day to learn more about GTK+, Cairo drawing, and Pango font library.
#include <gtk/gtk.h>
#include <time.h>
#include <glib/gprintf.h>
static char *
nye_countdown_str()
{
struct tm nyd = {0}; /* inits struct members to 0 */
nyd.tm_year = 2025 - 1900;
nyd.tm_mday = 1;
time_t nyd_time = mktime(&nyd);
time_t diff = difftime(nyd_time, time(NULL));
GString *buff = g_string_new("");
if ((int)(diff / 86400))
g_string_append_printf(buff, " %d %s\n", (int)(diff / 86400), "days");
if ((int)((diff % 86400) / 3600))
g_string_append_printf(buff, "%d %s\n", (int)(diff % 86400) / 3600, "hours");
if ((int)(diff % 3600) / 60)
g_string_append_printf(buff, "%d %s\n", (int)(diff % 3600) / 60, "minutes");
if ((int)(diff % 60))
g_string_append_printf(buff, "%d %s\n", (int)(diff % 60), "seconds");
return buff->str;
}
static void
draw_countdown(GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer user_data)
{
// make the ball drop one pixel every second through the top of minute
time_t now = time(NULL);
struct tm *currentTime = localtime(&now);
cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
cairo_paint(cr);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_rectangle(cr, width / 2 - 20, (width - 500) / 2 + 20, 40, height);
cairo_fill(cr);
float colorShift = currentTime->tm_sec / 60 + 0.5;
if (colorShift > 1)
colorShift = 0.85;
cairo_set_source_rgb(cr, 1, 1, colorShift);
cairo_arc(cr, width / 2, 80 + currentTime->tm_sec, 200 / 2, 0,
2 * 3.14159);
cairo_fill(cr);
cairo_set_source_rgb(cr, 1, 1, 1);
PangoLayout *pangLayout;
PangoFontDescription *pangDesc;
pangLayout = pango_cairo_create_layout(cr);
pango_layout_set_text(pangLayout, nye_countdown_str(), -1);
pangDesc = pango_font_description_from_string("American Typewriter 40");
pango_layout_set_font_description(pangLayout, pangDesc);
pango_font_description_free(pangDesc);
pango_layout_set_alignment(pangLayout, PANGO_ALIGN_CENTER);
PangoRectangle pLExtents = {0};
pango_layout_get_extents(pangLayout, NULL, &pLExtents);
pango_extents_to_pixels(NULL, &pLExtents);
cairo_move_to(cr, (width / 2) - (pLExtents.width / 2), 300);
pango_cairo_update_layout(cr, pangLayout);
pango_cairo_show_layout(cr, pangLayout);
pangLayout = pango_cairo_create_layout(cr);
pango_layout_set_text(pangLayout, "2025", -1);
pangDesc = pango_font_description_from_string("American Typewriter Bold 50");
pango_layout_set_font_description(pangLayout, pangDesc);
pango_font_description_free(pangDesc);
pango_layout_set_alignment(pangLayout, PANGO_ALIGN_CENTER);
pango_layout_get_extents(pangLayout, NULL, &pLExtents);
pango_extents_to_pixels(NULL, &pLExtents);
cairo_move_to(cr, 0, 120);
cairo_rotate(cr, -45 * (M_PI / 180));
pango_cairo_update_layout(cr, pangLayout);
pango_cairo_show_layout(cr, pangLayout);
}
static gboolean
time_handler(GtkWidget *widget)
{
gtk_widget_queue_draw(widget);
return TRUE;
}
static void
app_activate(GApplication *app, gpointer user_data)
{
GtkWidget *win, *countdown, *box, *creator_labl;
int curWindowHeight;
win = gtk_application_window_new(GTK_APPLICATION(app));
gtk_window_set_title(GTK_WINDOW(win), "Countdown to 2025");
gtk_window_set_default_size(GTK_WINDOW(win), 600, 600);
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
gtk_window_set_child(GTK_WINDOW(win), box);
countdown = gtk_drawing_area_new();
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(countdown), draw_countdown, NULL, NULL);
gtk_window_get_default_size(GTK_WINDOW(win), NULL, &curWindowHeight);
gtk_drawing_area_set_content_height(GTK_DRAWING_AREA(countdown), hgcurWindowHeight);
gtk_box_append(GTK_BOX(box), countdown);
creator_labl = gtk_label_new("Created by Andy Arthur, December 29, 2024");
gtk_box_append(GTK_BOX(box), creator_labl);
g_timeout_add(1000, (GSourceFunc)time_handler, (gpointer)countdown);
gtk_window_present(GTK_WINDOW(win));
}
static void
app_open(GApplication *app, GFile **files, gint n_files, gchar *hint, gpointer user_data)
{
app_activate(app, user_data);
}
int main(int argc, char **argv)
{
GtkApplication *app;
int stat;
app = gtk_application_new("org.andyarthur.nye", G_APPLICATION_HANDLES_OPEN);
g_signal_connect(app, "activate", G_CALLBACK(app_activate), NULL);
g_signal_connect(app, "open", G_CALLBACK(app_open), NULL);
stat = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return stat;
}



















