Change configuration system from Autotools to Meson
[geeqie.git] / src / ui_spinner.c
1 /*
2  * Copyright (C) 2004 John Ellis
3  * Copyright (C) 2008 - 2016 The Geeqie Team
4  *
5  * Author: John Ellis
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include <config.h>
23 #include "intl.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <gtk/gtk.h>
30
31 #include "main.h"
32 #include "ui_spinner.h"
33
34 #include "ui_icons.h"
35 #include "ui_fileops.h"
36
37
38 #define SPINNER_FRAMES 19
39
40
41 /*
42  *-----------------------------------------------------------------------------
43  * spinner utility
44  *-----------------------------------------------------------------------------
45  */
46
47 typedef struct _SpinnerData SpinnerData;
48 struct _SpinnerData {
49         GtkWidget *image;
50         GList *list;            /* list of pixbufs */
51         guint frame;
52         guint timer_id; /* event source id */
53 };
54
55 static void spinner_set_frame(SpinnerData *sp, guint frame)
56 {
57         GdkPixbuf *pb;
58
59         pb = g_list_nth_data(sp->list, frame);
60         if (pb) gtk_image_set_from_pixbuf(GTK_IMAGE(sp->image), pb);
61
62         sp->frame = frame;
63 }
64
65 static void spinner_increment_frame(SpinnerData *sp)
66 {
67         sp->frame++;
68         if (sp->frame >= g_list_length(sp->list)) sp->frame = 1;
69         spinner_set_frame(sp, sp->frame);
70 }
71
72 static gboolean spinner_loop_cb(gpointer data)
73 {
74         SpinnerData *sp = data;
75
76         if (sp->list) spinner_increment_frame(sp);
77
78         return TRUE;
79 }
80
81 static void spinner_set_timeout(SpinnerData *sp, gint interval)
82 {
83         if (!sp) return;
84
85         if (sp->timer_id)
86                 {
87                 g_source_remove(sp->timer_id);
88                 sp->timer_id = 0;
89                 }
90
91         if (interval > 0)
92                 {
93                 sp->timer_id = g_timeout_add(interval, spinner_loop_cb, sp);
94                 }
95         else if (interval < 0)
96                 {
97                 spinner_set_frame(sp, 0);
98                 }
99
100         gtk_widget_set_sensitive(sp->image, (interval >= 0));
101 }
102
103 static void spinner_destroy_cb(GtkWidget *widget, gpointer data)
104 {
105         SpinnerData *sp = data;
106         GList *work;
107
108         spinner_set_timeout(sp, 0);
109
110         work = sp->list;
111         while (work)
112                 {
113                 GdkPixbuf *pb = work->data;
114                 work = work->next;
115
116                 g_object_unref(pb);
117                 }
118         g_list_free(sp->list);
119         g_free(sp);
120 }
121
122 GtkWidget *spinner_new(const gchar *path, gint interval)
123 {
124         SpinnerData *sp;
125
126         sp = g_new0(SpinnerData, 1);
127
128         if (path)
129                 {
130                 gchar *pathl;
131                 GdkPixbuf *pb;
132                 gint n;
133                 gchar *buf;
134
135                 pathl = path_from_utf8(path);
136
137                 n = 0;
138                 buf = g_strdup_printf("%s%02d.png", pathl, n);
139                 while ((pb = gdk_pixbuf_new_from_file(buf, NULL)))
140                         {
141                         sp->list = g_list_append(sp->list, pb);
142
143                         n++;
144                         g_free(buf);
145                         buf = g_strdup_printf("%s%02d.png", pathl, n);
146                         }
147                 g_free(buf);
148
149                 g_free(pathl);
150                 }
151
152         if (!sp->list)
153                 {
154                 GdkPixbuf *pb;
155                 gint n;
156                 gint w, h;
157
158                 pb = gdk_pixbuf_new_from_inline(-1, icon_spinner, FALSE, NULL);
159                 w = gdk_pixbuf_get_width(pb);
160                 h = gdk_pixbuf_get_height(pb) / SPINNER_FRAMES;
161                 for (n = 0; n < SPINNER_FRAMES; n++)
162                         {
163                         sp->list = g_list_append(sp->list,
164                                                  gdk_pixbuf_new_subpixbuf(pb, 0, n * h, w, h));
165                         }
166                 /* pb pixels is inline static, so the subpixbufs in sp->list will be ok */
167                 g_object_unref(pb);
168                 }
169
170         if (sp->list)
171                 {
172                 GdkPixbuf *pb;
173
174                 pb = sp->list->data;
175                 sp->image = gtk_image_new_from_pixbuf(pb);
176                 }
177         else
178                 {
179                 sp->image = gtk_image_new_from_stock(GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_DIALOG);
180                 }
181
182         g_object_set_data(G_OBJECT(sp->image), "spinner", sp);
183
184         g_signal_connect(G_OBJECT(sp->image), "destroy",
185                          G_CALLBACK(spinner_destroy_cb), sp);
186
187         spinner_set_timeout(sp, interval);
188
189         return sp->image;
190 }
191
192 void spinner_set_interval(GtkWidget *spinner, gint interval)
193 {
194         SpinnerData *sp;
195
196         sp = g_object_get_data(G_OBJECT(spinner), "spinner");
197
198         spinner_set_timeout(sp, interval);
199 }
200
201 void spinner_step(GtkWidget *spinner, gboolean reset)
202 {
203         SpinnerData *sp;
204
205         sp = g_object_get_data(G_OBJECT(spinner), "spinner");
206         if (sp->timer_id)
207                 {
208                 log_printf("spinner warning: attempt to step with timer set\n");
209                 return;
210                 }
211
212         if (reset)
213                 {
214                 spinner_set_frame(sp, 0);
215                 }
216         else
217                 {
218                 spinner_increment_frame(sp);
219                 }
220 }
221 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */