1/* -*- mode: C; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
2
3#include <gtk/gtk.h>
4#include <math.h>
5#include <string.h>
6
7#include "frame-stats.h"
8
9#define RADIUS 64
10#define DIAMETER (2*RADIUS)
11#define WIDTH 600
12#define HEIGHT 600
13#define WINDOW_SIZE_JITTER 200
14#define CYCLE_TIME 5.
15
16static GtkWidget *window;
17static int window_width = WIDTH, window_height = HEIGHT;
18
19gint64 start_frame_time;
20static double angle;
21
22static double load_factor = 1.0;
23static double cb_no_resize = FALSE;
24
25static cairo_surface_t *source_surface;
26
27static void
28ensure_resources(cairo_surface_t *target)
29{
30 cairo_t *cr;
31 int i, j;
32
33 if (source_surface != NULL)
34 return;
35
36 source_surface = cairo_surface_create_similar (other: target, content: CAIRO_CONTENT_COLOR_ALPHA,
37 width: 16 * DIAMETER, height: 16 * DIAMETER);
38 cr = cairo_create(target: source_surface);
39
40 cairo_save(cr);
41 cairo_set_source_rgba(cr, red: 0, green: 0, blue: 0, alpha: 0);
42 cairo_set_operator(cr, op: CAIRO_OPERATOR_SOURCE);
43 cairo_paint(cr);
44 cairo_restore(cr);
45
46 cairo_set_line_width(cr, width: 1.0);
47
48 for (j = 0; j < 16; j++)
49 for (i = 0; i < 16; i++)
50 {
51 cairo_set_source_rgba(cr,
52 red: ((i * 41) % 16) / 15.,
53 green: ((i * 31) % 16) / 15.,
54 blue: ((i * 23) % 16) / 15.,
55 alpha: 0.25);
56 cairo_arc(cr,
57 xc: i * DIAMETER + RADIUS, yc: j * DIAMETER + RADIUS,
58 RADIUS - 0.5, angle1: 0, angle2: 2 * M_PI);
59 cairo_fill_preserve(cr);
60 cairo_set_source_rgba(cr,
61 red: ((i * 41) % 16) / 15.,
62 green: ((i * 31) % 16) / 15.,
63 blue: ((i * 23) % 16) / 15.,
64 alpha: 1.0);
65 cairo_stroke(cr);
66 }
67}
68
69static void
70on_draw (GtkDrawingArea *da,
71 cairo_t *cr,
72 int width,
73 int height,
74 gpointer data)
75
76{
77 GRand *rand = g_rand_new_with_seed(seed: 0);
78 int i;
79
80 ensure_resources (target: cairo_get_target (cr));
81
82 cairo_set_source_rgb(cr, red: 1, green: 1, blue: 1);
83 cairo_paint(cr);
84
85 cairo_set_source_rgb(cr, red: 0, green: 0, blue: 0);
86 cairo_set_line_width(cr, width: 1.0);
87 cairo_rectangle (cr, x: 0.5, y: 0.5, width: width - 1, height: height - 1);
88 cairo_stroke (cr);
89
90 for(i = 0; i < load_factor * 150; i++)
91 {
92 int source = g_rand_int_range(rand_: rand, begin: 0, end: 255);
93 double phi = g_rand_double_range(rand_: rand, begin: 0, end: 2 * M_PI) + angle;
94 double r = g_rand_double_range(rand_: rand, begin: 0, end: width / 2 - RADIUS);
95 int x, y;
96
97 int source_x = (source % 16) * DIAMETER;
98 int source_y = (source / 16) * DIAMETER;
99
100 x = round(x: width / 2 + r * cos(x: phi) - RADIUS);
101 y = round(x: height / 2 - r * sin(x: phi) - RADIUS);
102
103 cairo_set_source_surface(cr, surface: source_surface,
104 x: x - source_x, y: y - source_y);
105 cairo_rectangle(cr, x, y, DIAMETER, DIAMETER);
106 cairo_fill(cr);
107 }
108
109 g_rand_free(rand_: rand);
110}
111
112static void
113on_frame (double progress)
114{
115 int jitter;
116
117 angle = 2 * M_PI * progress;
118 jitter = WINDOW_SIZE_JITTER * sin(x: angle);
119
120 if (!cb_no_resize)
121 {
122 window_width = WIDTH + jitter;
123 window_height = HEIGHT + jitter;
124 }
125
126 gtk_window_set_default_size (GTK_WINDOW (window),
127 width: window_width, height: window_height);
128
129 gtk_widget_queue_draw (widget: window);
130}
131
132static gboolean
133resize_idle (gpointer user_data)
134{
135 GdkFrameClock *frame_clock = user_data;
136 gint64 frame_time = gdk_frame_clock_get_frame_time (frame_clock);
137 double scaled_time;
138
139 if (start_frame_time == 0)
140 start_frame_time = frame_time;
141
142 scaled_time = (frame_time - start_frame_time) / (CYCLE_TIME * 1000000);
143 on_frame (progress: scaled_time - floor (x: scaled_time));
144
145 return G_SOURCE_REMOVE;
146}
147
148static gboolean
149tick_callback (GtkWidget *widget,
150 GdkFrameClock *frame_clock,
151 gpointer user_data)
152{
153 g_idle_add (function: resize_idle, data: frame_clock);
154
155 return G_SOURCE_CONTINUE;
156}
157
158static gboolean
159on_map (GtkWidget *widget)
160{
161 gtk_widget_add_tick_callback (widget: window, callback: tick_callback, NULL, NULL);
162
163 return FALSE;
164}
165
166static GOptionEntry options[] = {
167 { "factor", 'f', 0, G_OPTION_ARG_DOUBLE, &load_factor, "Load factor", "FACTOR" },
168 { "no-resize", 'n', 0, G_OPTION_ARG_NONE, &cb_no_resize, "No Resize", NULL },
169 { NULL }
170};
171
172static void
173quit_cb (GtkWidget *widget,
174 gpointer data)
175{
176 gboolean *done = data;
177
178 *done = TRUE;
179
180 g_main_context_wakeup (NULL);
181}
182
183int
184main(int argc, char **argv)
185{
186 GError *error = NULL;
187 GtkWidget *da;
188 gboolean done = FALSE;
189
190 GOptionContext *context = g_option_context_new (NULL);
191 g_option_context_add_main_entries (context, entries: options, NULL);
192 frame_stats_add_options (group: g_option_context_get_main_group (context));
193
194 if (!g_option_context_parse (context, argc: &argc, argv: &argv, error: &error))
195 {
196 g_printerr (format: "Option parsing failed: %s\n", error->message);
197 return 1;
198 }
199
200 gtk_init ();
201
202 g_print (format: "# Load factor: %g\n",
203 load_factor);
204 g_print (format: "# Resizing?: %s\n",
205 cb_no_resize ? "no" : "yes");
206
207 window = gtk_window_new ();
208 frame_stats_ensure (GTK_WINDOW (window));
209
210 da = gtk_drawing_area_new ();
211 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_func: on_draw, NULL, NULL);
212 gtk_window_set_child (GTK_WINDOW (window), child: da);
213
214 g_signal_connect (window, "destroy",
215 G_CALLBACK (quit_cb), NULL);
216
217 g_signal_connect (window, "map",
218 G_CALLBACK (on_map), NULL);
219 on_frame (progress: 0.);
220
221 gtk_widget_show (widget: window);
222
223 while (!done)
224 g_main_context_iteration (NULL, TRUE);
225
226 return 0;
227}
228

source code of gtk/tests/animated-resizing.c