1 | /* Benchmark/Fishbowl |
2 | * |
3 | * This demo models the fishbowl demos seen on the web in a GTK way. |
4 | * It's also a neat little tool to see how fast your computer (or |
5 | * your GTK version) is. |
6 | */ |
7 | |
8 | #include <gtk/gtk.h> |
9 | |
10 | #include "gtkfishbowl.h" |
11 | #include "gtkgears.h" |
12 | #include "gskshaderpaintable.h" |
13 | |
14 | const char *const css = |
15 | ".blurred-button {" |
16 | " box-shadow: 0px 0px 5px 10px rgba(0, 0, 0, 0.5);" |
17 | "}" |
18 | "" ; |
19 | |
20 | char **icon_names = NULL; |
21 | gsize n_icon_names = 0; |
22 | |
23 | static void |
24 | init_icon_names (GtkIconTheme *theme) |
25 | { |
26 | if (icon_names) |
27 | return; |
28 | |
29 | icon_names = gtk_icon_theme_get_icon_names (self: theme); |
30 | n_icon_names = g_strv_length (str_array: icon_names); |
31 | } |
32 | |
33 | static const char * |
34 | get_random_icon_name (GtkIconTheme *theme) |
35 | { |
36 | init_icon_names (theme); |
37 | |
38 | return icon_names[g_random_int_range(begin: 0, end: n_icon_names)]; |
39 | } |
40 | |
41 | /* Can't be static because it's also used in iconscroll.c */ |
42 | GtkWidget * |
43 | create_icon (void) |
44 | { |
45 | GtkWidget *image; |
46 | |
47 | image = gtk_image_new (); |
48 | gtk_image_set_icon_size (GTK_IMAGE (image), icon_size: GTK_ICON_SIZE_LARGE); |
49 | gtk_image_set_from_icon_name (GTK_IMAGE (image), |
50 | icon_name: get_random_icon_name (theme: gtk_icon_theme_get_for_display (display: gtk_widget_get_display (widget: image)))); |
51 | |
52 | return image; |
53 | } |
54 | |
55 | static GtkWidget * |
56 | create_button (void) |
57 | { |
58 | return gtk_button_new_with_label (label: "Button" ); |
59 | } |
60 | |
61 | static GtkWidget * |
62 | create_blurred_button (void) |
63 | { |
64 | GtkWidget *w = gtk_button_new (); |
65 | |
66 | gtk_widget_add_css_class (widget: w, css_class: "blurred-button" ); |
67 | |
68 | return w; |
69 | } |
70 | |
71 | static GtkWidget * |
72 | create_font_button (void) |
73 | { |
74 | return gtk_font_button_new (); |
75 | } |
76 | |
77 | static GtkWidget * |
78 | create_level_bar (void) |
79 | { |
80 | GtkWidget *w = gtk_level_bar_new_for_interval (min_value: 0, max_value: 100); |
81 | |
82 | gtk_level_bar_set_value (GTK_LEVEL_BAR (w), value: 50); |
83 | |
84 | /* Force them to be a bit larger */ |
85 | gtk_widget_set_size_request (widget: w, width: 200, height: -1); |
86 | |
87 | return w; |
88 | } |
89 | |
90 | static GtkWidget * |
91 | create_spinner (void) |
92 | { |
93 | GtkWidget *w = gtk_spinner_new (); |
94 | |
95 | gtk_spinner_start (GTK_SPINNER (w)); |
96 | |
97 | return w; |
98 | } |
99 | |
100 | static GtkWidget * |
101 | create_spinbutton (void) |
102 | { |
103 | GtkWidget *w = gtk_spin_button_new_with_range (min: 0, max: 10, step: 1); |
104 | |
105 | return w; |
106 | } |
107 | |
108 | static GtkWidget * |
109 | create_label (void) |
110 | { |
111 | GtkWidget *w = gtk_label_new (str: "pLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua." ); |
112 | |
113 | gtk_label_set_wrap (GTK_LABEL (w), TRUE); |
114 | gtk_label_set_max_width_chars (GTK_LABEL (w), n_chars: 100); |
115 | |
116 | return w; |
117 | } |
118 | |
119 | static GtkWidget * |
120 | create_video (void) |
121 | { |
122 | GtkWidget *w = gtk_video_new (); |
123 | |
124 | gtk_widget_set_size_request (widget: w, width: 64, height: 64); |
125 | gtk_video_set_loop (self: GTK_VIDEO (ptr: w), TRUE); |
126 | gtk_video_set_autoplay (self: GTK_VIDEO (ptr: w), TRUE); |
127 | gtk_video_set_resource (self: GTK_VIDEO (ptr: w), resource_path: "/images/gtk-logo.webm" ); |
128 | |
129 | return w; |
130 | } |
131 | |
132 | static GtkWidget * |
133 | create_gears (void) |
134 | { |
135 | GtkWidget *w = gtk_gears_new (); |
136 | |
137 | gtk_widget_set_size_request (widget: w, width: 100, height: 100); |
138 | |
139 | return w; |
140 | } |
141 | |
142 | static GtkWidget * |
143 | create_switch (void) |
144 | { |
145 | GtkWidget *w = gtk_switch_new (); |
146 | |
147 | gtk_switch_set_state (GTK_SWITCH (w), TRUE); |
148 | |
149 | return w; |
150 | } |
151 | |
152 | static gboolean |
153 | update_paintable (GtkWidget *widget, |
154 | GdkFrameClock *frame_clock, |
155 | gpointer user_data) |
156 | { |
157 | GskShaderPaintable *paintable; |
158 | gint64 frame_time; |
159 | |
160 | paintable = GSK_SHADER_PAINTABLE (ptr: gtk_picture_get_paintable (self: GTK_PICTURE (ptr: widget))); |
161 | frame_time = gdk_frame_clock_get_frame_time (frame_clock); |
162 | gsk_shader_paintable_update_time (self: paintable, time_idx: 0, frame_time); |
163 | |
164 | return G_SOURCE_CONTINUE; |
165 | } |
166 | |
167 | static GtkWidget * |
168 | create_cogs (void) |
169 | { |
170 | GtkWidget *picture; |
171 | static GskGLShader *cog_shader = NULL; |
172 | GdkPaintable *paintable; |
173 | |
174 | if (cog_shader == NULL) |
175 | cog_shader = gsk_gl_shader_new_from_resource (resource_path: "/gltransition/cogs2.glsl" ); |
176 | paintable = gsk_shader_paintable_new (g_object_ref (cog_shader), NULL); |
177 | picture = gtk_picture_new_for_paintable (paintable); |
178 | gtk_widget_set_size_request (widget: picture, width: 150, height: 75); |
179 | gtk_widget_add_tick_callback (widget: picture, callback: update_paintable, NULL, NULL); |
180 | |
181 | return picture; |
182 | } |
183 | |
184 | static void |
185 | mapped (GtkWidget *w) |
186 | { |
187 | gtk_menu_button_popup (GTK_MENU_BUTTON (w)); |
188 | } |
189 | |
190 | static GtkWidget * |
191 | (void) |
192 | { |
193 | GtkWidget *w = gtk_menu_button_new (); |
194 | GtkWidget *popover = gtk_popover_new (); |
195 | |
196 | gtk_popover_set_child (GTK_POPOVER (popover), child: gtk_button_new_with_label (label: "Hey!" )); |
197 | gtk_popover_set_autohide (GTK_POPOVER (popover), FALSE); |
198 | gtk_menu_button_set_popover (GTK_MENU_BUTTON (w), popover); |
199 | g_signal_connect (w, "map" , G_CALLBACK (mapped), NULL); |
200 | |
201 | return w; |
202 | } |
203 | |
204 | static const struct { |
205 | const char *name; |
206 | GtkWidget * (*create_func) (void); |
207 | } widget_types[] = { |
208 | { "Icon" , create_icon }, |
209 | { "Button" , create_button }, |
210 | { "Blurbutton" , create_blurred_button }, |
211 | { "Fontbutton" , create_font_button }, |
212 | { "Levelbar" , create_level_bar }, |
213 | { "Label" , create_label }, |
214 | { "Spinner" , create_spinner }, |
215 | { "Spinbutton" , create_spinbutton }, |
216 | { "Video" , create_video }, |
217 | { "Gears" , create_gears }, |
218 | { "Switch" , create_switch }, |
219 | { "Menubutton" , create_menu_button }, |
220 | { "Shader" , create_cogs }, |
221 | }; |
222 | |
223 | static int selected_widget_type = -1; |
224 | static const int N_WIDGET_TYPES = G_N_ELEMENTS (widget_types); |
225 | |
226 | static void |
227 | set_widget_type (GtkFishbowl *fishbowl, |
228 | int widget_type_index) |
229 | { |
230 | GtkWidget *window; |
231 | |
232 | if (widget_type_index == selected_widget_type) |
233 | return; |
234 | |
235 | selected_widget_type = widget_type_index; |
236 | |
237 | gtk_fishbowl_set_creation_func (fishbowl, |
238 | creation_func: widget_types[selected_widget_type].create_func); |
239 | |
240 | window = GTK_WIDGET (gtk_widget_get_root (GTK_WIDGET (fishbowl))); |
241 | gtk_window_set_title (GTK_WINDOW (window), |
242 | title: widget_types[selected_widget_type].name); |
243 | } |
244 | |
245 | G_MODULE_EXPORT void |
246 | fishbowl_next_button_clicked_cb (GtkButton *source, |
247 | gpointer user_data) |
248 | { |
249 | GtkFishbowl *fishbowl = user_data; |
250 | int new_index; |
251 | |
252 | if (selected_widget_type + 1 >= N_WIDGET_TYPES) |
253 | new_index = 0; |
254 | else |
255 | new_index = selected_widget_type + 1; |
256 | |
257 | set_widget_type (fishbowl, widget_type_index: new_index); |
258 | } |
259 | |
260 | G_MODULE_EXPORT void |
261 | fishbowl_prev_button_clicked_cb (GtkButton *source, |
262 | gpointer user_data) |
263 | { |
264 | GtkFishbowl *fishbowl = user_data; |
265 | int new_index; |
266 | |
267 | if (selected_widget_type - 1 < 0) |
268 | new_index = N_WIDGET_TYPES - 1; |
269 | else |
270 | new_index = selected_widget_type - 1; |
271 | |
272 | set_widget_type (fishbowl, widget_type_index: new_index); |
273 | } |
274 | |
275 | G_MODULE_EXPORT void |
276 | fishbowl_changes_toggled_cb (GtkToggleButton *button, |
277 | gpointer user_data) |
278 | { |
279 | if (gtk_toggle_button_get_active (toggle_button: button)) |
280 | gtk_button_set_icon_name (GTK_BUTTON (button), icon_name: "changes-prevent" ); |
281 | else |
282 | gtk_button_set_icon_name (GTK_BUTTON (button), icon_name: "changes-allow" ); |
283 | } |
284 | |
285 | G_MODULE_EXPORT char * |
286 | (GObject *object, |
287 | guint count, |
288 | double fps) |
289 | { |
290 | return g_strdup_printf (format: "%u Icons, %.2f fps" , count, fps); |
291 | } |
292 | |
293 | GtkWidget * |
294 | do_fishbowl (GtkWidget *do_widget) |
295 | { |
296 | static GtkWidget *window = NULL; |
297 | static GtkCssProvider *provider = NULL; |
298 | |
299 | if (provider == NULL) |
300 | { |
301 | provider = gtk_css_provider_new (); |
302 | gtk_css_provider_load_from_data (css_provider: provider, data: css, length: -1); |
303 | gtk_style_context_add_provider_for_display (display: gdk_display_get_default (), |
304 | GTK_STYLE_PROVIDER (provider), |
305 | GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); |
306 | } |
307 | |
308 | if (!window) |
309 | { |
310 | GtkBuilder *builder; |
311 | GtkWidget *bowl; |
312 | |
313 | g_type_ensure (GTK_TYPE_FISHBOWL); |
314 | |
315 | builder = gtk_builder_new_from_resource (resource_path: "/fishbowl/fishbowl.ui" ); |
316 | window = GTK_WIDGET (gtk_builder_get_object (builder, "window" )); |
317 | g_object_add_weak_pointer (G_OBJECT (window), weak_pointer_location: (gpointer *)&window); |
318 | |
319 | bowl = GTK_WIDGET (gtk_builder_get_object (builder, "bowl" )); |
320 | selected_widget_type = -1; |
321 | set_widget_type (GTK_FISHBOWL (bowl), widget_type_index: 0); |
322 | gtk_window_set_display (GTK_WINDOW (window), |
323 | display: gtk_widget_get_display (widget: do_widget)); |
324 | |
325 | gtk_widget_realize (widget: window); |
326 | g_object_unref (object: builder); |
327 | } |
328 | |
329 | if (!gtk_widget_get_visible (widget: window)) |
330 | gtk_widget_show (widget: window); |
331 | else |
332 | gtk_window_destroy (GTK_WINDOW (window)); |
333 | |
334 | return window; |
335 | } |
336 | |