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 }