/* * File: main.c, author: John Sauter, date: April 7, 2024. * Display a digital clock. */ /* * Copyright © 2024 by John Sauter * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . * The author's contact information is as follows: * John Sauter * System Eyes Computer Store * 20A Northwest Blvd. Ste 345 * Nashua, NH 03063-4066 * telephone: (603) 424-1188 * e-mail: John_Sauter@systemeyescomputerstore.com */ /* * This program is based on the GTK Display Time in Glade Application * at https://prognotes.net/2017/05/gtk-display-time-glade-application/. */ /* GTK definitions */ #include /* libtime definitions */ #include /* Structure passed to the timer handler. It holds a pointer * to the label which is modified to contain the current time, * and a flag to tell the timer handler that we are quitting. */ typedef struct { GtkWidget *w_lbl_time; gint quitting; } app_widgets; /* Forward reference */ gboolean timer_handler(app_widgets *widgets); /* Make sure the operating system isn't concealing leap seconds. */ static int test_for_disabled_adjtimex () { int adjtimex_is_disabled; adjtimex_is_disabled = time_test_for_disabled_adjtimex(); if (adjtimex_is_disabled != 0) { /* Some high security environments disable the adjtimex function, * even when, as here, it is just fetching information. * The adjtimex function is the only way to determine that * there is a leap second in progress, so complain if it * doesn't work. */ printf ("The current time will not be correct during a leap second\n" "because the Linux adjtimex function is not working.\n"); exit (EXIT_FAILURE); } return (0); } /* Main program */ int main(int argc, char *argv[]) { GtkBuilder *builder; GtkWidget *window; app_widgets *widgets = g_slice_new (app_widgets); gtk_init (&argc, &argv); widgets->quitting = 0; test_for_disabled_adjtimex(); /* Load the Glade window description. */ builder = gtk_builder_new(); gtk_builder_add_from_file (builder, "glade/window_main.glade", NULL); window = GTK_WIDGET(gtk_builder_get_object(builder, "window_main")); widgets->w_lbl_time = GTK_WIDGET(gtk_builder_get_object(builder, "lbl_time")); gtk_builder_connect_signals(builder, widgets); g_object_unref(builder); /* start the 0.1-second timer */ g_timeout_add (100, (GSourceFunc)timer_handler, widgets); /* Show the window. */ gtk_widget_show(window); /* Run the event loop. */ gtk_main(); /* We have quit. Free storage and exit. * To avoid a race condition with the timer handler, tell it to * cancel its timer if it gets called while we are quitting. */ widgets->quitting = 1; g_slice_free(app_widgets, widgets); return 0; } /* handler for the 0.1 second timer tick */ gboolean timer_handler(app_widgets *widgets) { /* We use libtime instead of GDateTime because GDdateTime is * oblivious to leap seconds. */ struct tm time1_tm; struct tm time2_tm; int nanoseconds; gchar *fraction_display; gchar *final_display; gchar buffer1 [128]; /* If we are quitting, stop the timer. */ if (widgets->quitting != 0) return FALSE; /* Get the current time. */ time_current_tm_nano (&time1_tm, &nanoseconds); /* Convert to local time and use strftime to make a readable display. * The Kameron font is a readable font with tabular digits. * It can be installed from the Google family of free fonts. * Note the '.%.1s' in the output from strftime. */ time_UTC_to_local (&time1_tm, &time2_tm, INT_MIN); strftime (&buffer1 [0], sizeof (buffer1), "" "%A, %B %d, %Y, %I:%M:%S.%%.1s %p %Z" "", &time2_tm); /* Strftime has no provision for outputting fractions of a second, * so we put a literal '.%.1s' after the seconds. We will now use * the output of strftime as a format string to insert the * fraction of a second. */ fraction_display = g_strdup_printf ((gchar*) "%09d", nanoseconds); final_display = g_strdup_printf ((gchar *) &buffer1 [0], fraction_display); /* Update the display with the current time. */ gtk_label_set_markup (GTK_LABEL(widgets->w_lbl_time), final_display); /* Free allocated strings. */ g_free (fraction_display); fraction_display = NULL; g_free (final_display); final_display = NULL; /* Return TRUE so the timer will fire after another tenth of a second. */ return TRUE; } /* When the window is closed, the application exits. */ void on_window_main_destroy() { gtk_main_quit(); } /* End of file main.c */