Article 5P7ET C Practice, Linux analogue clock

C Practice, Linux analogue clock

by
teckk
from LinuxQuestions.org on (#5P7ET)
You'll need gtk3 and cairo for this.
https://www.cairographics.org/manual/cairo-cairo-t.html
https://docs.gtk.org/gtk3/
https://docs.huihoo.com/api/gtk/2.6/gobject/

clock.c
Code://Gtk3 Analogue-Digital Linux clock

#include <math.h>
#include <cairo.h>
#include <gtk/gtk.h>
#include <time.h>

//Clock size
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 800

//Colors
#define WHITE 255, 255, 255
#define RED 255, 0, 0
#define CYAN 0, 255, 255
#define BLUE 0, 0, 135
#define WIDTH 3

static char buffer[256];
static time_t curtime; //Epoch
static struct tm *loctime;
static int seconds;
static int minutes;
static int hours;
static int radius;
static int width;

//Distributions for clock face
static char dist[] = "Powered by Arch Linux";
//static char dist[] = "Powered by Slackware Linux";
//static char dist[] = "Powered by Debian Linux";
//static char dist[] = "Powered by Ubuntu Linux";

//Quit
static void quit_application(gpointer app)
{
g_application_quit (G_APPLICATION (app));
}

//Window Frame
static void show_hide_frame(GtkWindow *window)
{
gtk_window_set_decorated(window, !gtk_window_get_decorated(window));
}

//Right click menu
int show_popup(GtkWidget *widget, GdkEvent *event)
{
const int RIGHT_CLICK = 3;
if (event->type == GDK_BUTTON_PRESS)
{
GdkEventButton *bevent = (GdkEventButton *) event;

if (bevent->button == RIGHT_CLICK)
{
gtk_menu_popup_at_pointer(GTK_MENU(widget), NULL);
}
return TRUE;
}
return FALSE;
}

//Hour ticks
void HourTick (GtkWidget *widget, cairo_t *cr, int hourSeg, int cx, int cy)
{
double htRadians = hourSeg * 3.14 / 6.0;
//Draw line from .9 * rad to 1.0 * rad for hours
int x1 = cx+(int) ((0.9 * radius * sin (htRadians)));
int y1 = cy-(int) ((0.9 * radius * cos (htRadians)));
int x2 = cx+(int) ((1.0 * radius * sin (htRadians)));
int y2 = cy-(int) ((1.0 * radius * cos (htRadians)));
cairo_set_source_rgb(cr, CYAN); //Color
cairo_set_line_width(cr, WIDTH); //Width
cairo_move_to(cr, x1, y1); //Place and length
cairo_line_to(cr, x2, y2); //Add line
cairo_stroke(cr);
}

//Minute ticks
void MinTick (GtkWidget *widget, cairo_t *cr, int hourSeg, int cx, int cy)
{
double mtRadians = hourSeg * 3.14 / 30.0;
//Draw line from .96 * rad to 1.0 * rad for mins
int a1 = cx+(int) ((0.96 * radius * sin (mtRadians)));
int b1 = cy-(int) ((0.96 * radius * cos (mtRadians)));
int a2 = cx+(int) ((1.0 * radius * sin (mtRadians)));
int b2 = cy-(int) ((1.0 * radius * cos (mtRadians)));
cairo_set_source_rgb(cr, CYAN);
cairo_set_line_width(cr, WIDTH);
cairo_move_to(cr, a1, b1);
cairo_line_to(cr, a2, b2);
cairo_stroke(cr);
}

//Second hand
void DrawSeconds (GtkWidget *widget, cairo_t *cr, int cx, int cy)
{
//Get radians from seconds
float sRadians = seconds * 3.14 / 30.0;
//Draw second hand
cairo_set_source_rgb(cr, RED); //Color
cairo_set_line_width(cr, WIDTH); //Width
cairo_move_to(cr, cx, cy); //Place and length
cairo_line_to(cr, cx + (0.9 * radius * sin (sRadians)),
cy - (0.9 * radius * cos (sRadians)));
cairo_stroke(cr);
}

//Minute hand
void DrawMinutes (GtkWidget *widget, cairo_t *cr, int cx, int cy)
{
//Get radians
float mRadians = (minutes * 3.14 / 30.0) + (seconds * 3.14 / 1800.0);
//Draw minute hand
cairo_set_source_rgb(cr, CYAN);
cairo_set_line_width(cr, WIDTH * 2);
cairo_move_to(cr, cx, cy);
cairo_line_to(cr, cx + (0.8 * radius * sin (mRadians)),
cy - (0.8 * radius * cos (mRadians)));
cairo_stroke(cr);
}

//Hour hand
void DrawHours (GtkWidget *widget, cairo_t *cr, int cx, int cy)
{
//Get radians
float hRadians = ((hours % 12) * 3.14 / 6.0) + (minutes * 3.14 / 360.0);
//Draw hour hand
cairo_set_source_rgb(cr, CYAN);
cairo_set_line_width(cr, WIDTH * 3);
cairo_move_to(cr, cx, cy);
cairo_line_to(cr, cx + (0.6 * radius * sin (hRadians)),
cy - (0.6 * radius * cos (hRadians)));
cairo_stroke(cr);
}

//Draw
static gboolean draw_cb(GtkWidget *widget, cairo_t *cr, gpointer data)
{
int midx = gtk_widget_get_allocated_width(widget)/2; //Center
int midy = gtk_widget_get_allocated_height(widget)/2;
int hourSeg;

//Draw Tickmarks at each hour/minute
for (hourSeg = 1; hourSeg <= 60; hourSeg++)
{
MinTick(widget, cr, hourSeg, midx, midy);
if(hourSeg <= 12)
{
HourTick(widget, cr, hourSeg, midx, midy);
}
}

//Digital Clock
cairo_set_source_rgb(cr, WHITE); //Font Color
cairo_set_font_size (cr, 50); //Font size
cairo_move_to(cr, midx/1.4, midy/2); //Position
cairo_show_text(cr, buffer);

//Powered by distribution
cairo_set_source_rgb(cr, BLUE); //Distro color
cairo_set_font_size (cr, 50); //Distro Size
width = strlen(dist) * 28 / 2; //Approx center
cairo_move_to(cr, midx - width, midy/1.1);
cairo_show_text(cr, dist);

radius = MIN (midx, midy) -2 ; //Clock radius in window
cairo_move_to(cr, midx , 0);
//Clock Hands
DrawHours (widget, cr, midx, midy);
DrawMinutes (widget, cr, midx, midy);
DrawSeconds (widget, cr, midx, midy);
return FALSE;
}

//Get Time
static gint time_handler (GtkWidget *widget)
{
curtime = time(NULL);
loctime = localtime(&curtime);
seconds = loctime->tm_sec;
minutes = loctime->tm_min;
hours = loctime->tm_hour;
strftime(buffer, 256, "%H:%M:%S", loctime);
gtk_widget_queue_draw(widget);
return TRUE;
}

static void activate (GtkApplication* app, gpointer user_data)
{
GtkWidget *window;
GtkWidget *drawing_area;
GtkWidget *ebox;
GtkWidget *pmenu;
GtkWidget *frameMenuItem;
GtkWidget *hideMenuItem;
GtkWidget *quitMenuItem;

window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Gtk3 Clock"); //Title
gtk_window_set_default_size (GTK_WINDOW (window), //App size
WINDOW_WIDTH, WINDOW_HEIGHT);
gtk_window_set_decorated (GTK_WINDOW (window), FALSE); //Window decorations
gtk_container_set_border_width (GTK_CONTAINER (window), 0);
gtk_widget_set_app_paintable(window, TRUE); //Window color

GdkScreen *screen = gtk_widget_get_screen(window);
GdkVisual *visual = gdk_screen_get_rgba_visual(screen);
gtk_widget_set_visual(window, visual);

ebox = gtk_event_box_new();
gtk_container_add(GTK_CONTAINER(window), ebox);

drawing_area = gtk_drawing_area_new();
gtk_widget_set_size_request (drawing_area, WINDOW_WIDTH - 2 ,
WINDOW_HEIGHT - 2);

gtk_container_add(GTK_CONTAINER (ebox), drawing_area);

g_signal_connect(drawing_area, "draw",
G_CALLBACK (draw_cb), NULL);
g_signal_connect(drawing_area, "delete-event",
G_CALLBACK (gtk_main_quit), NULL);

pmenu = gtk_menu_new();
//Right click menu items
frameMenuItem = gtk_menu_item_new_with_label("Show-Hide Frame");
gtk_widget_show(frameMenuItem);
gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), frameMenuItem);

hideMenuItem = gtk_menu_item_new_with_label("Minimize");
gtk_widget_show(hideMenuItem);
gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), hideMenuItem);

quitMenuItem = gtk_menu_item_new_with_label("Quit");
gtk_widget_show(quitMenuItem);
gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), quitMenuItem);
//Connect to signals
g_signal_connect_swapped(G_OBJECT(frameMenuItem), "activate",
G_CALLBACK(show_hide_frame), GTK_WINDOW(window));

g_signal_connect_swapped(G_OBJECT(hideMenuItem), "activate",
G_CALLBACK(gtk_window_iconify), GTK_WINDOW(window));

g_signal_connect_swapped(G_OBJECT(quitMenuItem), "activate",
G_CALLBACK(quit_application), app);

g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(quit_application), app);

g_signal_connect_swapped(G_OBJECT(ebox), "button-press-event",
G_CALLBACK(show_popup), pmenu);

g_timeout_add (1000, (GSourceFunc) time_handler, drawing_area);

gtk_widget_show_all(window);
}

int main (int argc, char **argv)
{
GtkApplication *app;
int status;

app = gtk_application_new("my.clock", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);

status = g_application_run(G_APPLICATION (app), argc, argv);
g_object_unref (app); //Mem Freed

return status;
}You can compile that with:
Code:gcc -lm clock.c -o clock $(pkg-config --cflags --libs gtk+-3.0)Or with:
Code:gcc -I/usr/include/gtk-3.0 -I/usr/include/pango-1.0 \
-I/usr/include/harfbuzz -I/usr/include/glib-2.0 \
-I/usr/lib/glib-2.0/include -I/usr/include/cairo \
-I/usr/include/gdk-pixbuf-2.0 -I/usr/include/atk-1.0 \
-pthread -lgtk-3 -lgdk-3 -lz -lpangocairo-1.0 -lpango-1.0 \
-lharfbuzz -latk-1.0 -lcairo-gobject -lcairo -lm \
-lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 \
clock.c -o clockOr create a Makefile and run make.

Makefile
Code:CFLAGS += -Wall -Wextra -Wno-unused-parameter -O3
__NAME__ = clock
__NAME_UPPERCASE__ = CLOCK

INSTALL = install
INSTALL_PROGRAM = $(INSTALL)
INSTALL_DATA = $(INSTALL) -m 644

prefix = /usr/local
exec_prefix = $(prefix)
bindir = $(exec_prefix)/bin
libdir = $(exec_prefix)/lib
datarootdir = $(prefix)/share
mandir = $(datarootdir)/man
man1dir = $(mandir)/man1
datadir = $(prefix)/share

.PHONY: all clean install installdirs

all: $(__NAME__)

$(__NAME__): clock.c
$(CC) $(CFLAGS) $(LDFLAGS) \
-D__NAME__=\"$(__NAME__)\" \
-D__NAME_UPPERCASE__=\"$(__NAME_UPPERCASE__)\" \
-o $@ $< \
-lm `pkg-config --cflags --libs gtk+-3.0`

install: all installdirs
$(INSTALL_PROGRAM) $(__NAME__) $(DESTDIR)$(bindir)/$(__NAME__)
$(INSTALL_DATA) man1/$(__NAME__).1 $(DESTDIR)$(man1dir)/$(__NAME__).1
$(INSTALL_DATA) man1/$(__NAME__).usage.1 \
$(DESTDIR)$(man1dir)/$(__NAME__).usage.1

installdirs:
mkdir -p $(DESTDIR)$(bindir) $(DESTDIR)$(man1dir) \
$(DESTDIR)$(libdir)/$(__NAME__)/web_extensions \
$(DESTDIR)$(datadir)/$(__NAME__)/user-scripts

clean:
#Nothing to cleanlatest?d=yIl2AUoC8zA latest?i=H8GUG9v6sE8:BCYHJVuOtvc:F7zBnMy latest?i=H8GUG9v6sE8:BCYHJVuOtvc:V_sGLiP latest?d=qj6IDK7rITs latest?i=H8GUG9v6sE8:BCYHJVuOtvc:gIN9vFwH8GUG9v6sE8
External Content
Source RSS or Atom Feed
Feed Location https://feeds.feedburner.com/linuxquestions/latest
Feed Title LinuxQuestions.org
Feed Link https://www.linuxquestions.org/questions/
Reply 0 comments