glock

glock -- show an analog clock using GTK+ with cairo
Log | Files | Refs | LICENSE

glock.c (4109B)


      1 /**
      2  * glock -- show an analog clock using GTK+ with cairo
      3  * Copyright (C) 2020 Matthias Balk
      4  *
      5  * This program is free software: you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation, either version 3 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
     17  */
     18 
     19 #include <cairo.h>
     20 #include <gtk/gtk.h>
     21 #include <math.h>
     22 
     23 
     24 static gboolean setup_transparency(GtkWidget *window)
     25 {
     26   GdkScreen *screen;
     27   GdkVisual *visual;
     28 
     29   gtk_widget_set_app_paintable(window, TRUE);
     30   screen = gdk_screen_get_default();
     31   visual = gdk_screen_get_rgba_visual(screen);
     32 
     33   if (visual != NULL && gdk_screen_is_composited(screen)) {
     34     gtk_widget_set_visual(window, visual);
     35     return TRUE;
     36   }
     37   return FALSE;
     38 }
     39 
     40 
     41 static gboolean on_draw_event(GtkWidget *widget,
     42                               cairo_t *cr,
     43                               gpointer user_data)
     44 {
     45   static gboolean currently_drawing;
     46 
     47   if (currently_drawing) {
     48     return FALSE;
     49   }
     50 
     51   currently_drawing = TRUE;
     52 
     53   GDateTime *t = g_date_time_new_now_local();
     54   double angle_hours = ((g_date_time_get_hour(t) +
     55                          g_date_time_get_minute(t) / 60.0) / 6.0 - 0.5) * M_PI;
     56   double angle_minutes = (g_date_time_get_minute(t) / 30.0 - 0.5) * M_PI;
     57   g_date_time_unref(t);
     58 
     59   cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
     60   cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
     61   cairo_paint(cr);
     62 
     63   int width, height, half;
     64   gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
     65   half = (width < height ? width / 2 : height / 2);
     66   cairo_translate(cr, width / 2, height / 2);
     67 
     68   cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.3);
     69   cairo_arc(cr, 0, 0, half - half / 30.0, 0, 2 * M_PI);
     70   cairo_fill(cr);
     71 
     72   cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
     73   cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
     74 
     75   int radius = half - half / 15.0;
     76   double line_width = (width < height ? width / 75.0 : height / 75.0);
     77 
     78   cairo_set_line_width(cr, line_width);
     79   cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
     80   cairo_move_to(cr, 0.0, 0.0);
     81   cairo_rel_line_to(cr,
     82                     (radius - (radius * 0.3)) * cos(angle_hours),
     83                     (radius - (radius * 0.3)) * sin(angle_hours));
     84   cairo_move_to(cr, 0.0, 0.0);
     85   cairo_rel_line_to(cr,
     86                     (radius - (radius * 0.1)) * cos(angle_minutes),
     87                     (radius - (radius * 0.1)) * sin(angle_minutes));
     88   cairo_stroke(cr);
     89 
     90   cairo_arc(cr, 0, 0, radius, 0, 2 * M_PI);
     91   cairo_stroke(cr);
     92 
     93   currently_drawing = FALSE;
     94   return FALSE;
     95 }
     96 
     97 
     98 int main(int argc, char **argv)
     99 {
    100   GtkWidget *window;
    101   GtkWidget *darea;
    102 
    103   gtk_init(&argc, &argv);
    104 
    105   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    106   gtk_window_set_gravity(GTK_WINDOW(window), GDK_GRAVITY_NORTH_WEST);
    107   gtk_window_move(GTK_WINDOW(window), 15, 15);
    108   gtk_window_set_default_size(GTK_WINDOW(window), 300, 300);
    109   gtk_window_set_title(GTK_WINDOW(window), "glock");
    110   gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
    111   gtk_window_set_keep_above(GTK_WINDOW(window), TRUE);
    112   gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
    113   gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
    114 
    115   if (!setup_transparency(window)) {
    116     g_critical(
    117         "Failed to setup transparency. Screen must be composited. Exiting.");
    118     return EXIT_FAILURE;
    119   }
    120 
    121   darea = gtk_drawing_area_new();
    122   gtk_container_add(GTK_CONTAINER(window), darea);
    123 
    124   g_signal_connect(window, "draw", G_CALLBACK(on_draw_event), NULL);
    125   g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
    126   gdk_threads_add_timeout(7000, (GSourceFunc) gtk_main_quit, NULL);
    127 
    128   gtk_widget_show_all(window);
    129 
    130   gtk_main();
    131 
    132   return EXIT_SUCCESS;
    133 }