Display Clock

Suppose you want a big clock on your screen, so you can learn the date and time at a glance. If you search the internet for "GTK display time" you will find an excellent tutorial at https://prognotes.net/2017/05/gtk-display-time-glade-application/. The only problems with using this code unchanged are (1) the display isn't very big, and (2) it doesn't display leap seconds.

Here is my modification to that tutorial to correct those problems. Start by creating a project directory. Within it create two subdirectories named glade and src. Add a file named makefile to the project directory with the following content:

# change application name here (executable output name)
TARGET=display_time

# compiler
CC=gcc
# debug
DEBUG=-g
# optimisation
OPT=-O0
# warnings
WARN=-Wall

PTHREAD=-pthread

CCFLAGS=$(DEBUG) $(OPT) $(WARN) $(PTHREAD) -pipe

GTKLIB=`pkg-config --cflags --libs gtk+-3.0`

TIMELIB=-L/usr/local/lib -Wl,-rpath=/usr/local/lib -ltime

# linker
LD=gcc
LDFLAGS=$(PTHREAD) $(GTKLIB) ${TIMELIB} -export-dynamic

OBJS=    main.o

all: $(OBJS)
	$(LD) -o $(TARGET) $(OBJS) $(LDFLAGS)

main.o: src/main.c
	$(CC) -c $(CCFLAGS) src/main.c $(GTKLIB) -o main.o

clean:
	rm -f *.o $(TARGET)

If you copy and paste the above text, replace the indenting with tab characters so Make will work correctly. As an alternative to copy and paste, you can download the file here: makefile.

The program has two major dependencies: on GTK and libtime. To write programs that use GTK, you will need to install gtk3-devel on Fedora or gtk+-3.0 on Ubuntu. For libtime, you can get an installation kit from github at https://github.com/ShowControl/libtime. or by extracting it from its documentation at https://commons.wikimedia.org/wiki/File:Avoid_Using_POSIX_time_t_for_Telling_Time.pdf.

Use GLADE to create a file in the glade subdirectory named windows_main.glade containing just a GTK box with a label named lbl_time. Make the title be Current Time and the destroy signal handler be on_window_main_destroy. It will look more or less like this:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
  <requires lib="gtk+" version="3.12"/>
  <object class="GtkWindow" id="window_main">
    <property name="can_focus">False</property>
    <property name="title" translatable="yes">Current Time</property>
    <signal name="destroy" handler="on_window_main_destroy" swapped="no"/>
    <child>
      <placeholder/>
    </child>
    <child>
      <object class="GtkBox" id="box1">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="margin_left">10</property>
        <property name="margin_right">10</property>
        <property name="margin_top">10</property>
        <property name="margin_bottom">10</property>
        <property name="spacing">7</property>
        <property name="homogeneous">True</property>
        <child>
          <object class="GtkLabel" id="lbl_time">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">Time</property>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

As an alternative to copy and paste, you can download the file here: glade/window_main.glade.

The application is written in C. The source code is in the src subdirectory in file main.c. It looks like this:

/*
 * File: main.c, author: John Sauter, date: January 21, 2019.
 * Display a digital clock. 
*/

/*
 * Copyright © 2019 by John Sauter <John_Sauter@systemeyescomputerstore.com>

 * 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 <https://www.gnu.org/licenses/>.

 *  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 <gtk/gtk.h>

/* libtime definitions */
#include <time_subroutines.h>

/* 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);

/* 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;
  
  /* 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 Changa One font is a readable sans-serif font with tabular digits.
   * Note the '.%.1s' in the output from strftime.  */
  time_UTC_to_local (&time1_tm, &time2_tm, INT_MIN);
  strftime (&buffer1 [0], sizeof (buffer1),
	    "<span font='Changa One' size='xx-large'>"
	    "%A, %B %d, %Y, %I:%M:%S.%%.1s %p %Z"
	    "</span>", &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  */

As an alternative to copying and pasting the above text, you can download the file from src/main.c.

I modified the original tutorial to show time in tenths of a second. That means updating the label every tenth of a second and a more complex procedure for turning binary time into text. The <span font='Changa One' size='xx-large'> causes the display to be large, and the use of time_current_tm_nano and time_UTC_to_local causes leap seconds to be handled correctly.

This program is distributed under a license that allows you to run it for any purpose, study how it works, adapt it to your needs, redistribute it, improve it, and distribute the improved version. You can learn more about the license from https://www.gnu.org/licenses/. If you distribute the software you can include a plain-text copy of the license from https://www.gnu.org/licenses/gpl.txt.