2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 * See the COPYING file for license information.
18 * Guillaume Chazarain <booh@altern.org>
21 /************************************
22 * Loading and unloading of images. *
23 ************************************/
40 extern gliv_image
*current_image
;
42 static gliv_image
*previous_image
= NULL
;
43 static gliv_image
*next_image
= NULL
;
45 static GPtrArray
*filenames_array
;
47 static gchar
*loading_filename
;
49 /*** Image destroying. ***/
51 void free_imlib_image(Imlib_Image im
)
54 imlib_context_set_image(im
);
59 static void destroy_image(gliv_image
* im
)
62 glDeleteTextures(im
->nb_width
* im
->nb_height
, im
->textures
);
63 glDeleteLists(im
->list
, 1);
71 #define FILE_ID(x) g_ptr_array_index(filenames_array, x)
73 static void segv_handler(gint sig
)
75 if (loading_filename
== NULL
)
76 g_printerr("Segmentation fault, not while loading an image\n");
78 g_printerr("Segmentation fault while loading %s\n", loading_filename
);
84 void fill_ident(gliv_image
* im
)
87 im
->ident
= g_strdup_printf("%s (%u/%u)", (gchar
*) FILE_ID(im
->number
),
88 im
->number
+ 1, filenames_array
->len
);
92 static gint
compar(gconstpointer a
, gconstpointer b
)
94 return strcmp(*((gchar
**) a
), *((gchar
**) b
));
97 static void reorder_array(gpointer
* ptr
, guint num
, gboolean shuffle
)
102 if (shuffle
== TRUE
) {
104 srandom((guint
) (time(NULL
) + getpid()));
106 for (i
= 0; i
< num
; i
++) {
113 qsort(ptr
, num
, sizeof(gpointer
), compar
);
116 /*** Operations on the filenames array. ***/
118 static void add_file_to_list(gchar
* filename
)
120 g_ptr_array_add(filenames_array
, filename
);
123 /* Called only by ftw(). */
124 static gint
ftw_add_to_list(const gchar
* file
, const struct stat
*s
, gint flag
)
126 if (flag
== FTW_F
&& S_ISDIR(s
->st_mode
) == FALSE
)
127 add_file_to_list(g_strdup(file
));
131 static void add_to_list(gchar
* name
, gboolean recursive
)
134 struct dirent
*dir_ent
;
139 if (stat(name
, &st
) == -1)
142 if (S_ISDIR(st
.st_mode
) == TRUE
) {
143 if (recursive
== TRUE
)
144 /* Traverse recursively the directory. */
145 ftw(name
, ftw_add_to_list
, 32);
147 /* Add all files in the directory. */
152 dir_ent
= readdir(dir
);
153 while (dir_ent
!= NULL
) {
154 full_path
= g_strconcat(name
, "/", dir_ent
->d_name
, NULL
);
156 #ifdef _DIRENT_HAVE_D_TYPE
157 is_dir
= (dir_ent
->d_type
== DT_DIR
);
159 stat(full_path
, &st
);
160 is_dir
= (S_ISDIR(st
.st_mode
) == TRUE
);
164 add_file_to_list(full_path
);
167 dir_ent
= readdir(dir
);
173 add_file_to_list(name
);
176 void init_list(gchar
** files
, guint num
, gboolean recursive
, gboolean shuffle
)
180 filenames_array
= g_ptr_array_new();
182 for (i
= 0; i
< num
; i
++)
183 add_to_list(files
[i
], recursive
);
185 reorder_array(filenames_array
->pdata
, filenames_array
->len
, shuffle
);
189 * This function is used when we want an image in a bunch
190 * starting at 'position' to be the first of the bunch.
191 * That's why the searching loop starts at 'i = position'.
193 void place_at_position(gchar
* filename
, gint position
)
197 for (i
= position
; i
< filenames_array
->len
; i
++) {
198 if (g_str_equal(FILE_ID(i
), filename
) == TRUE
) {
200 FILE_ID(i
) = FILE_ID(position
);
201 FILE_ID(position
) = filename
;
208 * This function is used to place what was added at the end
209 * of the array at its correct position. It exchanges :
210 * FILE_ID(index1) with FILE_ID(index2),
211 * FILE_ID(index1 + 1) with FILE_ID(index2 + 1),
213 * FILE_ID(index1 + nb) with FILE_ID(index2 + nb).
215 static void array_switch(guint index1
, guint index2
, guint nb
)
219 for (; nb
> 0; index1
++, index2
++, nb
--) {
220 tmp
= FILE_ID(index2
);
221 FILE_ID(index2
) = FILE_ID(index1
);
222 FILE_ID(index1
) = tmp
;
226 void insert_at_current_position(gchar
** filename
, gint nb
, gboolean shuffle
)
231 offset
= filenames_array
->len
;
233 for (i
= 0; i
< nb
; i
++)
234 add_to_list(filename
[i
], FALSE
);
236 reorder_array(filenames_array
->pdata
+ offset
,
237 filenames_array
->len
- offset
, shuffle
);
239 /* Put the extension at its place in the array. */
240 array_switch(offset
, current_image
->number
+ 1,
241 filenames_array
->len
- offset
);
244 /*** Image loading. ***/
246 static gliv_image
*load_file(const gchar
* filename
)
250 im
= g_new0(gliv_image
, 1);
252 /* Used if there is a segfault. */
253 loading_filename
= (gchar
*) filename
;
255 im
->im
= imlib_load_image(filename
);
256 if (im
->im
== NULL
) {
261 imlib_context_set_image(im
->im
);
262 im
->width
= imlib_image_get_width();
263 im
->height
= imlib_image_get_height();
265 create_display_list(im
);
267 /* If there is a segfault it won't be because of the loading. */
268 loading_filename
= NULL
;
273 static gliv_image
*load_in_direction(gshort dir
)
275 gliv_image
*im
= NULL
;
278 if (current_image
== NULL
)
282 id
= current_image
->number
+ dir
;
284 while (id
< filenames_array
->len
) {
285 im
= load_file(FILE_ID(id
));
287 /* Delete bad images from the list. */
288 g_ptr_array_remove_index(filenames_array
, id
);
299 void load_direction(gchar dir
)
304 static gchar next_direction
;
307 * Before loading the next image in a prebuffer we let GTK process
308 * remaining events and if there is a request for the next
309 * image in the events pending then -> crash.
310 * With this boolean we process loading request only if we know
311 * all loadings are finished.
313 static gboolean load_finished
= TRUE
;
315 if (load_finished
== FALSE
) {
317 * We come from a gtk_main_iteration() called here, so
318 * we stop processing events and we load the next image.
320 next_direction
= dir
;
324 load_finished
= FALSE
;
326 while (ABS(dir
) == 1 && gtk_events_pending() == 0) {
328 if ((dir
== 1 && next_image
== NULL
)
329 || (dir
== -1 && previous_image
== NULL
)) {
331 load_finished
= TRUE
;
336 backup
= &next_image
;
337 next
= &previous_image
;
340 backup
= &previous_image
;
345 *backup
= current_image
;
346 current_image
= *next
;
348 destroy_image(trash
);
351 while (gtk_events_pending() != 0 && next_direction
== 0)
352 gtk_main_iteration();
354 *next
= load_in_direction(dir
);
356 /* Usually next_direction == 0, and the while loop ends. */
357 dir
= next_direction
;
359 load_finished
= TRUE
;
362 void load_first_images(void)
364 signal(SIGSEGV
, segv_handler
);
366 current_image
= load_in_direction(1);
367 if (current_image
== NULL
) {
368 g_printerr("No images found.\n");
373 next_image
= load_in_direction(1);
376 void open_file(gchar
* filename
, gboolean add_dir
, gboolean shuffle_flag
)
383 /* Try to load the requested image. */
384 im
= load_file(filename
);
388 if (add_dir
== TRUE
) {
389 /* Add all files in the directory to the end of the array. */
390 dir
= g_dirname(filename
);
391 insert_at_current_position(&dir
, 1, shuffle_flag
);
393 /* Put the requested image at current position in the file list. */
394 place_at_position(filename
, current_image
->number
+ 1);
396 tmp
= g_strdup(filename
);
397 insert_at_current_position(&tmp
, 1, shuffle_flag
);
400 im
->number
= current_image
->number
+ 1;
402 trash
= previous_image
;
403 previous_image
= current_image
;
407 destroy_image(trash
);
408 destroy_image(next_image
);
410 next_image
= load_in_direction(1);