1 #include <stdlib.h>
2 #include <math.h>
3 #include <cairo.h>
4 #include <clutter/clutter.h>
5 
6 static gboolean
draw_clock(ClutterCanvas * canvas,cairo_t * cr,int width,int height)7 draw_clock (ClutterCanvas *canvas,
8             cairo_t       *cr,
9             int            width,
10             int            height)
11 {
12   GDateTime *now;
13   float hours, minutes, seconds;
14 
15   /* get the current time and compute the angles */
16   now = g_date_time_new_now_local ();
17   seconds = g_date_time_get_second (now) * G_PI / 30;
18   minutes = g_date_time_get_minute (now) * G_PI / 30;
19   hours = g_date_time_get_hour (now) * G_PI / 6;
20 
21   /* clear the contents of the canvas, to avoid painting
22    * over the previous frame
23    */
24   cairo_save (cr);
25   cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
26   cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
27   cairo_paint (cr);
28   cairo_restore (cr);
29 
30   /* scale the modelview to the size of the surface */
31   cairo_scale (cr, width, height);
32 
33   cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
34   cairo_set_line_width (cr, 0.1);
35 
36   /* the black rail that holds the seconds indicator */
37   clutter_cairo_set_source_color (cr, CLUTTER_COLOR_Black);
38   cairo_translate (cr, 0.5, 0.5);
39   cairo_arc (cr, 0, 0, 0.4, 0, G_PI * 2);
40   cairo_stroke (cr);
41 
42   /* the seconds indicator */
43   clutter_cairo_set_source_color (cr, CLUTTER_COLOR_White);
44   cairo_move_to (cr, 0, 0);
45   cairo_arc (cr, sinf (seconds) * 0.4, - cosf (seconds) * 0.4, 0.05, 0, G_PI * 2);
46   cairo_fill (cr);
47 
48   /* the minutes hand */
49   clutter_cairo_set_source_color (cr, CLUTTER_COLOR_DarkChameleon);
50   cairo_move_to (cr, 0, 0);
51   cairo_line_to (cr, sinf (minutes) * 0.4, -cosf (minutes) * 0.4);
52   cairo_stroke (cr);
53 
54   /* the hours hand */
55   cairo_move_to (cr, 0, 0);
56   cairo_line_to (cr, sinf (hours) * 0.2, -cosf (hours) * 0.2);
57   cairo_stroke (cr);
58 
59   g_date_time_unref (now);
60 
61   /* we're done drawing */
62   return TRUE;
63 }
64 
65 static gboolean
invalidate_clock(gpointer data_)66 invalidate_clock (gpointer data_)
67 {
68   /* invalidate the contents of the canvas */
69   clutter_content_invalidate (data_);
70 
71   /* keep the timeout source */
72   return TRUE;
73 }
74 
75 G_MODULE_EXPORT int
test_cairo_clock_main(int argc,char * argv[])76 test_cairo_clock_main (int argc, char *argv[])
77 {
78   ClutterActor *stage;
79   ClutterContent *canvas;
80 
81   /* initialize Clutter */
82   if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
83     return EXIT_FAILURE;
84 
85   /* create a resizable stage */
86   stage = clutter_stage_new ();
87   clutter_stage_set_title (CLUTTER_STAGE (stage), "2D Clock");
88   clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
89   clutter_actor_set_background_color (stage, CLUTTER_COLOR_LightSkyBlue);
90   clutter_actor_set_size (stage, 300, 300);
91   clutter_actor_show (stage);
92 
93   /* our 2D canvas, courtesy of Cairo */
94   canvas = clutter_canvas_new ();
95   clutter_canvas_set_size (CLUTTER_CANVAS (canvas), 300, 300);
96   clutter_actor_set_content (stage, canvas);
97 
98   /* quit on destroy */
99   g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
100 
101   /* connect our drawing code */
102   g_signal_connect (canvas, "draw", G_CALLBACK (draw_clock), NULL);
103 
104   /* invalidate the canvas, so that we can draw before the main loop starts */
105   clutter_content_invalidate (canvas);
106 
107   /* set up a timer that invalidates the canvas every second */
108   clutter_threads_add_timeout (1000, invalidate_clock, canvas);
109 
110   clutter_main ();
111 
112   return EXIT_SUCCESS;
113 }
114 
115 G_MODULE_EXPORT const char *
test_cairo_clock_describe(void)116 test_cairo_clock_describe (void)
117 {
118   return "Simple 2D canvas using a Cairo texture actor";
119 }
120