1 | /* Benchmark/Frames |
2 | * |
3 | * This demo is intentionally as simple as possible, to see what |
4 | * framerate the windowing system can deliver on its own. |
5 | * |
6 | * It does nothing but change the drawn color, for every frame. |
7 | */ |
8 | |
9 | #include <gtk/gtk.h> |
10 | |
11 | typedef struct |
12 | { |
13 | GtkWidget parent_instance; |
14 | |
15 | GdkRGBA color1; |
16 | GdkRGBA color2; |
17 | guint64 time2; |
18 | float t; |
19 | |
20 | guint tick_cb; |
21 | } ColorWidget; |
22 | |
23 | typedef struct |
24 | { |
25 | GtkWidgetClass parent_class; |
26 | } ColorWidgetClass; |
27 | |
28 | G_DEFINE_TYPE (ColorWidget, color_widget, GTK_TYPE_WIDGET) |
29 | |
30 | #define TIME_SPAN (3.0 * G_TIME_SPAN_SECOND) |
31 | |
32 | static gboolean |
33 | change_color (GtkWidget *widget, |
34 | GdkFrameClock *frame_clock, |
35 | gpointer data) |
36 | { |
37 | ColorWidget *color = (ColorWidget *)widget; |
38 | gint64 time; |
39 | |
40 | time = gdk_frame_clock_get_frame_time (frame_clock); |
41 | |
42 | if (time >= color->time2) |
43 | { |
44 | color->time2 = time + TIME_SPAN; |
45 | |
46 | color->color1 = color->color2; |
47 | color->color2.red = g_random_double_range (begin: 0, end: 1); |
48 | color->color2.green = g_random_double_range (begin: 0, end: 1); |
49 | color->color2.blue = g_random_double_range (begin: 0, end: 1); |
50 | color->color2.alpha = 1; |
51 | } |
52 | |
53 | color->t = 1 - (color->time2 - time) / TIME_SPAN; |
54 | |
55 | gtk_widget_queue_draw (widget); |
56 | |
57 | return G_SOURCE_CONTINUE; |
58 | } |
59 | |
60 | static void |
61 | color_widget_snapshot (GtkWidget *widget, |
62 | GtkSnapshot *snapshot) |
63 | { |
64 | ColorWidget *color = (ColorWidget *)widget; |
65 | float w, h; |
66 | GdkRGBA c; |
67 | |
68 | w = gtk_widget_get_width (widget); |
69 | h = gtk_widget_get_height (widget); |
70 | |
71 | c.red = (1 - color->t) * color->color1.red + color->t * color->color2.red; |
72 | c.green = (1 - color->t) * color->color1.green + color->t * color->color2.green; |
73 | c.blue = (1 - color->t) * color->color1.blue + color->t * color->color2.blue; |
74 | c.alpha = 1; |
75 | |
76 | gtk_snapshot_append_color (snapshot, color: &c, bounds: &GRAPHENE_RECT_INIT (0, 0, w, h)); |
77 | } |
78 | |
79 | static void |
80 | color_widget_init (ColorWidget *color) |
81 | { |
82 | gtk_widget_add_tick_callback (GTK_WIDGET (color), callback: change_color, NULL, NULL); |
83 | gtk_widget_set_hexpand (GTK_WIDGET (color), TRUE); |
84 | gtk_widget_set_vexpand (GTK_WIDGET (color), TRUE); |
85 | } |
86 | |
87 | static void |
88 | color_widget_class_init (ColorWidgetClass *class) |
89 | { |
90 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); |
91 | |
92 | widget_class->snapshot = color_widget_snapshot; |
93 | } |
94 | |
95 | GtkWidget * |
96 | color_widget_new (void) |
97 | { |
98 | return g_object_new (object_type: color_widget_get_type (), NULL); |
99 | } |
100 | |
101 | static gboolean |
102 | update_fps_label (gpointer data) |
103 | { |
104 | GtkWidget *label = GTK_WIDGET (data); |
105 | GdkFrameClock *frame_clock; |
106 | |
107 | frame_clock = gtk_widget_get_frame_clock (widget: label); |
108 | |
109 | if (frame_clock) |
110 | { |
111 | char *fps; |
112 | |
113 | fps = g_strdup_printf (format: "%.2f fps" , gdk_frame_clock_get_fps (frame_clock)); |
114 | gtk_label_set_label (GTK_LABEL (label), str: fps); |
115 | g_free (mem: fps); |
116 | } |
117 | else |
118 | gtk_label_set_label (GTK_LABEL (label), str: "" ); |
119 | |
120 | return G_SOURCE_CONTINUE; |
121 | } |
122 | |
123 | static void |
124 | remove_id (gpointer data) |
125 | { |
126 | guint id = GPOINTER_TO_UINT (data); |
127 | |
128 | g_source_remove (tag: id); |
129 | } |
130 | |
131 | GtkWidget * |
132 | do_frames (GtkWidget *do_widget) |
133 | { |
134 | static GtkWidget *window = NULL; |
135 | |
136 | if (!window) |
137 | { |
138 | GtkBuilder *builder; |
139 | GtkWidget *box; |
140 | GtkWidget *label; |
141 | guint id; |
142 | |
143 | builder = gtk_builder_new_from_resource (resource_path: "/frames/frames.ui" ); |
144 | window = GTK_WIDGET (gtk_builder_get_object (builder, "window" )); |
145 | g_object_add_weak_pointer (G_OBJECT (window), weak_pointer_location: (gpointer *)&window); |
146 | gtk_window_set_display (GTK_WINDOW (window), |
147 | display: gtk_widget_get_display (widget: do_widget)); |
148 | |
149 | label = GTK_WIDGET (gtk_builder_get_object (builder, "fps" )); |
150 | box = GTK_WIDGET (gtk_builder_get_object (builder, "box" )); |
151 | |
152 | gtk_box_append (GTK_BOX (box), child: color_widget_new ()); |
153 | |
154 | id = g_timeout_add (interval: 500, function: update_fps_label, data: label); |
155 | g_object_set_data_full (G_OBJECT (label), key: "tick_cb" , |
156 | GUINT_TO_POINTER (id), destroy: remove_id); |
157 | } |
158 | |
159 | if (!gtk_widget_get_visible (widget: window)) |
160 | gtk_widget_show (widget: window); |
161 | else |
162 | gtk_window_destroy (GTK_WINDOW (window)); |
163 | |
164 | return window; |
165 | } |
166 | |