Fix a few warning in editors/ module.
[blender-staging.git] / source / blender / editors / space_file / filelist.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2007 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30
31 /* global includes */
32
33 #include <stdlib.h>
34 #include <math.h>
35 #include <string.h>
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifndef WIN32
42 #include <unistd.h>
43 #else
44 #include <io.h>
45 #include <direct.h>
46 #endif   
47 #include "MEM_guardedalloc.h"
48
49 #include "BLI_blenlib.h"
50 #include "BLI_linklist.h"
51 #include "BLI_storage_types.h"
52 #include "BLI_threads.h"
53
54 #ifdef WIN32
55 #include "BLI_winstuff.h"
56 #endif
57
58 #include "BKE_context.h"
59 #include "BKE_utildefines.h"
60 #include "BKE_global.h"
61 #include "BKE_library.h"
62 #include "BKE_global.h"
63 #include "BKE_main.h"
64 #include "BKE_report.h"
65 #include "BLO_readfile.h"
66
67 #include "DNA_space_types.h"
68 #include "DNA_ipo_types.h"
69 #include "DNA_ID.h"
70 #include "DNA_object_types.h"
71 #include "DNA_listBase.h"
72 #include "DNA_lamp_types.h"
73 #include "DNA_material_types.h"
74 #include "DNA_texture_types.h"
75 #include "DNA_world_types.h"
76 #include "DNA_scene_types.h"
77 #include "DNA_userdef_types.h"
78
79 #include "ED_datafiles.h"
80
81 #include "IMB_imbuf.h"
82 #include "IMB_imbuf_types.h"
83 #include "IMB_thumbs.h"
84
85 #include "PIL_time.h"
86
87
88 #include "WM_api.h"
89 #include "WM_types.h"
90
91 #include "filelist.h"
92
93 /* max length of library group name within filesel */
94 #define GROUP_MAX 32
95
96 struct FileList;
97
98 typedef struct FileImage {
99         struct FileImage *next, *prev;
100         char path[FILE_MAX];
101         unsigned int flags;
102         int index;
103         short done;
104         ImBuf *img;
105 } FileImage;
106
107 typedef struct ThumbnailJob {
108         ListBase loadimages;
109         short *stop;
110         short *do_update;
111         struct FileList* filelist;
112         ReportList reports;
113 } ThumbnailJob;
114
115 typedef struct FileList
116 {
117         struct direntry *filelist;
118         int *fidx;
119         int numfiles;
120         int numfiltered;
121         char dir[FILE_MAX];
122         short prv_w;
123         short prv_h;
124         short hide_dot;
125         unsigned int filter;
126         short changed;
127
128         struct BlendHandle *libfiledata;
129         short hide_parent;
130
131         void (*readf)(struct FileList *);
132         int  (*filterf)(struct direntry* file, const char* dir, unsigned int filter, short hide_dot);
133
134 } FileList;
135
136 typedef struct FolderList
137 {
138         struct FolderList *next, *prev;
139         char *foldername;
140 } FolderList;
141
142 #define SPECIAL_IMG_SIZE 48
143 #define SPECIAL_IMG_ROWS 4
144 #define SPECIAL_IMG_COLS 4
145
146 #define SPECIAL_IMG_FOLDER 0
147 #define SPECIAL_IMG_PARENT 1
148 #define SPECIAL_IMG_REFRESH 2
149 #define SPECIAL_IMG_BLENDFILE 3
150 #define SPECIAL_IMG_SOUNDFILE 4
151 #define SPECIAL_IMG_MOVIEFILE 5
152 #define SPECIAL_IMG_PYTHONFILE 6
153 #define SPECIAL_IMG_TEXTFILE 7
154 #define SPECIAL_IMG_FONTFILE 8
155 #define SPECIAL_IMG_UNKNOWNFILE 9
156 #define SPECIAL_IMG_LOADING 10
157 #define SPECIAL_IMG_MAX SPECIAL_IMG_LOADING + 1
158
159 static ImBuf* gSpecialFileImages[SPECIAL_IMG_MAX];
160
161
162 /* ******************* SORT ******************* */
163
164 static int compare_name(const void *a1, const void *a2)
165 {
166         const struct direntry *entry1=a1, *entry2=a2;
167
168         /* type is is equal to stat.st_mode */
169
170         if (S_ISDIR(entry1->type)){
171                 if (S_ISDIR(entry2->type)==0) return (-1);
172         } else{
173                 if (S_ISDIR(entry2->type)) return (1);
174         }
175         if (S_ISREG(entry1->type)){
176                 if (S_ISREG(entry2->type)==0) return (-1);
177         } else{
178                 if (S_ISREG(entry2->type)) return (1);
179         }
180         if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
181         if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
182         
183         /* make sure "." and ".." are always first */
184         if( strcmp(entry1->relname, ".")==0 ) return (-1);
185         if( strcmp(entry2->relname, ".")==0 ) return (1);
186         if( strcmp(entry1->relname, "..")==0 ) return (-1);
187         if( strcmp(entry2->relname, "..")==0 ) return (1);
188         
189         return (BLI_natstrcmp(entry1->relname,entry2->relname));
190 }
191
192 static int compare_date(const void *a1, const void *a2) 
193 {
194         const struct direntry *entry1=a1, *entry2=a2;
195         
196         /* type is equal to stat.st_mode */
197
198         if (S_ISDIR(entry1->type)){
199                 if (S_ISDIR(entry2->type)==0) return (-1);
200         } else{
201                 if (S_ISDIR(entry2->type)) return (1);
202         }
203         if (S_ISREG(entry1->type)){
204                 if (S_ISREG(entry2->type)==0) return (-1);
205         } else{
206                 if (S_ISREG(entry2->type)) return (1);
207         }
208         if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
209         if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
210
211         /* make sure "." and ".." are always first */
212         if( strcmp(entry1->relname, ".")==0 ) return (-1);
213         if( strcmp(entry2->relname, ".")==0 ) return (1);
214         if( strcmp(entry1->relname, "..")==0 ) return (-1);
215         if( strcmp(entry2->relname, "..")==0 ) return (1);
216         
217         if ( entry1->s.st_mtime < entry2->s.st_mtime) return 1;
218         if ( entry1->s.st_mtime > entry2->s.st_mtime) return -1;
219         
220         else return BLI_natstrcmp(entry1->relname,entry2->relname);
221 }
222
223 static int compare_size(const void *a1, const void *a2) 
224 {
225         const struct direntry *entry1=a1, *entry2=a2;
226
227         /* type is equal to stat.st_mode */
228
229         if (S_ISDIR(entry1->type)){
230                 if (S_ISDIR(entry2->type)==0) return (-1);
231         } else{
232                 if (S_ISDIR(entry2->type)) return (1);
233         }
234         if (S_ISREG(entry1->type)){
235                 if (S_ISREG(entry2->type)==0) return (-1);
236         } else{
237                 if (S_ISREG(entry2->type)) return (1);
238         }
239         if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
240         if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
241
242         /* make sure "." and ".." are always first */
243         if( strcmp(entry1->relname, ".")==0 ) return (-1);
244         if( strcmp(entry2->relname, ".")==0 ) return (1);
245         if( strcmp(entry1->relname, "..")==0 ) return (-1);
246         if( strcmp(entry2->relname, "..")==0 ) return (1);
247         
248         if ( entry1->s.st_size < entry2->s.st_size) return 1;
249         if ( entry1->s.st_size > entry2->s.st_size) return -1;
250         else return BLI_natstrcmp(entry1->relname,entry2->relname);
251 }
252
253 static int compare_extension(const void *a1, const void *a2) {
254         const struct direntry *entry1=a1, *entry2=a2;
255         char *sufix1, *sufix2;
256         char *nil="";
257
258         if (!(sufix1= strstr (entry1->relname, ".blend.gz"))) 
259                 sufix1= strrchr (entry1->relname, '.');
260         if (!(sufix2= strstr (entry2->relname, ".blend.gz")))
261                 sufix2= strrchr (entry2->relname, '.');
262         if (!sufix1) sufix1= nil;
263         if (!sufix2) sufix2= nil;
264
265         /* type is is equal to stat.st_mode */
266
267         if (S_ISDIR(entry1->type)){
268                 if (S_ISDIR(entry2->type)==0) return (-1);
269         } else{
270                 if (S_ISDIR(entry2->type)) return (1);
271         }
272         if (S_ISREG(entry1->type)){
273                 if (S_ISREG(entry2->type)==0) return (-1);
274         } else{
275                 if (S_ISREG(entry2->type)) return (1);
276         }
277         if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
278         if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
279         
280         /* make sure "." and ".." are always first */
281         if( strcmp(entry1->relname, ".")==0 ) return (-1);
282         if( strcmp(entry2->relname, ".")==0 ) return (1);
283         if( strcmp(entry1->relname, "..")==0 ) return (-1);
284         if( strcmp(entry2->relname, "..")==0 ) return (1);
285         
286         return (BLI_strcasecmp(sufix1, sufix2));
287 }
288
289 static int is_hidden_file(const char* filename, short hide_dot)
290 {
291         int is_hidden=0;
292
293         if (hide_dot) {
294                 if(filename[0]=='.' && filename[1]!='.' && filename[1]!=0) {
295                         is_hidden=1; /* ignore .file */
296                 } else if (((filename[0] == '.') && (filename[1] == 0) )) {
297                         is_hidden=1; /* ignore . */
298                 } else {
299                         int len=strlen(filename);
300                         if( (len>0) && (filename[len-1]=='~') ) {
301                                 is_hidden=1;  /* ignore file~ */
302                         }
303                 } 
304         } else {
305                 if (((filename[0] == '.') && (filename[1] == 0) )) {
306                         is_hidden=1; /* ignore . */
307                 }
308         }
309         return is_hidden;
310 }
311
312 static int is_filtered_file(struct direntry* file, const char* dir, unsigned int filter, short hide_dot)
313 {
314         int is_filtered=0;
315         if (filter) {
316                 if (file->flags & filter) {
317                         is_filtered=1;
318                 } else if (file->type & S_IFDIR) {
319                         if (filter & FOLDERFILE) {
320                                 is_filtered = 1;
321                         }
322                 }
323         } else {
324                 is_filtered = 1;
325         }
326         return is_filtered && !is_hidden_file(file->relname, hide_dot);
327 }
328
329 static int is_filtered_lib(struct direntry* file, const char* dir, unsigned int filter, short hide_dot)
330 {
331         int is_filtered=0;
332         char tdir[FILE_MAX], tgroup[GROUP_MAX];
333         if (BLO_is_a_library(dir, tdir, tgroup)) {
334                 is_filtered = !is_hidden_file(file->relname, hide_dot);
335         } else {
336                 is_filtered = is_filtered_file(file, dir, filter, hide_dot);
337         }
338         return is_filtered;
339 }
340
341 static int is_filtered_main(struct direntry* file, const char* dir, unsigned int filter, short hide_dot)
342 {
343         return !is_hidden_file(file->relname, hide_dot);
344 }
345
346 void filelist_filter(FileList* filelist)
347 {
348         int num_filtered = 0;
349         int i, j;
350         
351         if (!filelist->filelist)
352                 return;
353
354         // How many files are left after filter ?
355         for (i = 0; i < filelist->numfiles; ++i) {
356                 struct direntry *file = &filelist->filelist[i];
357                 if ( filelist->filterf(file, filelist->dir, filelist->filter, filelist->hide_dot) ) {
358                         num_filtered++;
359                 } 
360         }
361         
362         if (filelist->fidx) {
363                 MEM_freeN(filelist->fidx);
364                 filelist->fidx = NULL;
365         }
366         filelist->fidx = (int *)MEM_callocN(num_filtered*sizeof(int), "filteridx");
367         filelist->numfiltered = num_filtered;
368
369         for (i = 0, j=0; i < filelist->numfiles; ++i) {
370                 struct direntry *file = &filelist->filelist[i];
371                 if ( filelist->filterf(file, filelist->dir, filelist->filter, filelist->hide_dot) ) {
372                         filelist->fidx[j++] = i;
373                 }
374         }
375 }
376
377 void filelist_init_icons()
378 {
379         short x, y, k;
380         ImBuf *bbuf;
381         ImBuf *ibuf;
382         bbuf = IMB_ibImageFromMemory((int *)datatoc_prvicons, datatoc_prvicons_size, IB_rect);
383         if (bbuf) {
384                 for (y=0; y<SPECIAL_IMG_ROWS; y++) {
385                         for (x=0; x<SPECIAL_IMG_COLS; x++) {
386                                 int tile = SPECIAL_IMG_COLS*y + x; 
387                                 if (tile < SPECIAL_IMG_MAX) {
388                                         ibuf = IMB_allocImBuf(SPECIAL_IMG_SIZE, SPECIAL_IMG_SIZE, 32, IB_rect, 0);
389                                         for (k=0; k<SPECIAL_IMG_SIZE; k++) {
390                                                 memcpy(&ibuf->rect[k*SPECIAL_IMG_SIZE], &bbuf->rect[(k+y*SPECIAL_IMG_SIZE)*SPECIAL_IMG_SIZE*SPECIAL_IMG_COLS+x*SPECIAL_IMG_SIZE], SPECIAL_IMG_SIZE*sizeof(int));
391                                         }
392                                         gSpecialFileImages[tile] = ibuf;
393                                 }
394                         }
395                 }
396                 IMB_freeImBuf(bbuf);
397         }
398 }
399
400 void filelist_free_icons()
401 {
402         int i;
403         for (i=0; i < SPECIAL_IMG_MAX; ++i) {
404                 IMB_freeImBuf(gSpecialFileImages[i]);
405                 gSpecialFileImages[i] = NULL;
406         }
407 }
408
409 //-----------------FOLDERLIST (previous/next) --------------//
410 struct ListBase* folderlist_new()
411 {
412         ListBase* p = MEM_callocN( sizeof(ListBase), "folderlist" );
413         return p;
414 }
415
416 void folderlist_popdir(struct ListBase* folderlist, char *dir)
417 {
418         const char *prev_dir;
419         struct FolderList *folder;
420         folder = folderlist->last;
421
422         if(folder){
423                 // remove the current directory
424                 MEM_freeN(folder->foldername);
425                 BLI_freelinkN(folderlist, folder);
426
427                 folder = folderlist->last;
428                 if(folder){
429                         prev_dir = folder->foldername;
430                         BLI_strncpy(dir, prev_dir, FILE_MAXDIR);
431                 }
432         }
433         // delete the folder next or use setdir directly before PREVIOUS OP
434 }
435
436 void folderlist_pushdir(ListBase* folderlist, const char *dir)
437 {
438         struct FolderList *folder, *previous_folder;
439         previous_folder = folderlist->last;
440
441         // check if already exists
442         if(previous_folder && previous_folder->foldername){
443                 if(! strcmp(previous_folder->foldername, dir)){
444                         return;
445                 }
446         }
447
448         // create next folder element
449         folder = (FolderList*)MEM_mallocN(sizeof(FolderList),"FolderList");
450         folder->foldername = (char*)MEM_mallocN(sizeof(char)*(strlen(dir)+1), "foldername");
451         folder->foldername[0] = '\0';
452
453         BLI_strncpy(folder->foldername, dir, FILE_MAXDIR);
454
455         // add it to the end of the list
456         BLI_addtail(folderlist, folder);
457 }
458
459 int folderlist_clear_next(struct SpaceFile *sfile)
460 {
461         struct FolderList *folder;
462
463         // if there is no folder_next there is nothing we can clear
464         if (!sfile->folders_next)
465                 return 0;
466
467         // if previous_folder, next_folder or refresh_folder operators are executed it doesn't clear folder_next
468         folder = sfile->folders_prev->last;
469         if ((!folder) ||(!strcmp(folder->foldername, sfile->params->dir)))
470                 return 0;
471
472         // eventually clear flist->folders_next
473         return 1;
474 }
475
476 /* not listbase itself */
477 void folderlist_free(ListBase* folderlist)
478 {
479         FolderList *folder;
480         if (folderlist){
481                 for(folder= folderlist->first; folder; folder= folder->next)
482                         MEM_freeN(folder->foldername);
483                 BLI_freelistN(folderlist);
484         }
485         folderlist= NULL;
486 }
487
488 ListBase *folderlist_duplicate(ListBase* folderlist)
489 {
490         
491         if (folderlist) {
492                 ListBase *folderlistn= MEM_callocN(sizeof(ListBase), "copy folderlist");
493                 FolderList *folder;
494                 
495                 BLI_duplicatelist(folderlistn, folderlist);
496                 
497                 for(folder= folderlistn->first; folder; folder= folder->next) {
498                         folder->foldername= MEM_dupallocN(folder->foldername);
499                 }
500                 return folderlistn;
501         }
502         return NULL;
503 }
504
505
506 static void filelist_read_main(struct FileList* filelist);
507 static void filelist_read_library(struct FileList* filelist);
508 static void filelist_read_dir(struct FileList* filelist);
509
510 //------------------FILELIST------------------------//
511 struct FileList*        filelist_new(short type)
512 {
513         FileList* p = MEM_callocN( sizeof(FileList), "filelist" );
514         switch(type) {
515                 case FILE_MAIN:
516                         p->readf = filelist_read_main;
517                         p->filterf = is_filtered_main;
518                         break;
519                 case FILE_LOADLIB:
520                         p->readf = filelist_read_library;
521                         p->filterf = is_filtered_lib;
522                         break;
523                 default:
524                         p->readf = filelist_read_dir;
525                         p->filterf = is_filtered_file;
526
527         }
528         return p;
529 }
530
531
532 void filelist_free(struct FileList* filelist)
533 {
534         int i;
535
536         if (!filelist) {
537                 printf("Attempting to delete empty filelist.\n");
538                 return;
539         }
540         
541         if (filelist->fidx) {
542                 MEM_freeN(filelist->fidx);
543                 filelist->fidx = NULL;
544         }
545
546         for (i = 0; i < filelist->numfiles; ++i) {
547                 if (filelist->filelist[i].image) {                      
548                         IMB_freeImBuf(filelist->filelist[i].image);
549                 }
550                 filelist->filelist[i].image = 0;
551                 if (filelist->filelist[i].relname)
552                         MEM_freeN(filelist->filelist[i].relname);
553                 if (filelist->filelist[i].path)
554                         MEM_freeN(filelist->filelist[i].path);
555                 filelist->filelist[i].relname = 0;
556                 if (filelist->filelist[i].string)
557                         MEM_freeN(filelist->filelist[i].string);
558                 filelist->filelist[i].string = 0;
559         }
560         
561         filelist->numfiles = 0;
562         free(filelist->filelist);
563         filelist->filelist = 0; 
564         filelist->filter = 0;
565         filelist->numfiltered =0;
566         filelist->hide_dot =0;
567 }
568
569 void filelist_freelib(struct FileList* filelist)
570 {
571         if(filelist->libfiledata)       
572                 BLO_blendhandle_close(filelist->libfiledata);
573         filelist->libfiledata= 0;
574 }
575
576 struct BlendHandle *filelist_lib(struct FileList* filelist)
577 {
578         return filelist->libfiledata;
579 }
580
581 int     filelist_numfiles(struct FileList* filelist)
582 {
583         return filelist->numfiltered;
584 }
585
586 const char * filelist_dir(struct FileList* filelist)
587 {
588         return filelist->dir;
589 }
590
591 void filelist_setdir(struct FileList* filelist, const char *dir)
592 {
593         BLI_strncpy(filelist->dir, dir, FILE_MAX);
594 }
595
596 void filelist_imgsize(struct FileList* filelist, short w, short h)
597 {
598         filelist->prv_w = w;
599         filelist->prv_h = h;
600 }
601
602 short filelist_changed(struct FileList* filelist)
603 {
604         return filelist->changed;
605 }
606
607 struct ImBuf * filelist_loadimage(struct FileList* filelist, int index)
608 {
609         ImBuf *imb = NULL;
610         int fidx = 0;
611         
612         if ( (index < 0) || (index >= filelist->numfiltered) ) {
613                 return NULL;
614         }
615         fidx = filelist->fidx[index];
616         imb = filelist->filelist[fidx].image;
617         if (!imb)
618         {
619                 if ( (filelist->filelist[fidx].flags & IMAGEFILE) || (filelist->filelist[fidx].flags & MOVIEFILE) ) {
620                         char path[FILE_MAX];
621                         BLI_join_dirfile(path, filelist->dir, filelist->filelist[fidx].relname);
622                         imb = IMB_thumb_read(path, THB_NORMAL);
623                 } 
624                 if (imb) {
625                         filelist->filelist[fidx].image = imb;
626                 } 
627         }
628         return imb;
629 }
630
631 struct ImBuf * filelist_getimage(struct FileList* filelist, int index)
632 {
633         ImBuf* ibuf = NULL;
634         int fidx = 0;   
635         if ( (index < 0) || (index >= filelist->numfiltered) ) {
636                 return NULL;
637         }
638         fidx = filelist->fidx[index];
639         ibuf = filelist->filelist[fidx].image;
640
641         return ibuf;
642 }
643
644 struct ImBuf * filelist_geticon(struct FileList* filelist, int index)
645 {
646         ImBuf* ibuf= NULL;
647         struct direntry *file= NULL;
648         int fidx = 0;   
649         if ( (index < 0) || (index >= filelist->numfiltered) ) {
650                 return NULL;
651         }
652         fidx = filelist->fidx[index];
653         file = &filelist->filelist[fidx];
654         if (file->type & S_IFDIR) {
655                 if ( strcmp(filelist->filelist[fidx].relname, "..") == 0) {
656                         ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT];
657                 } else if  ( strcmp(filelist->filelist[fidx].relname, ".") == 0) {
658                         ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH];
659                 } else {
660                         ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER];
661                 }
662         } else {
663                 ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
664         }
665
666         if (file->flags & BLENDERFILE) {
667                 ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE];
668         } else if ( (file->flags & MOVIEFILE) || (file->flags & MOVIEFILE_ICON) ) {
669                 ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE];
670         } else if (file->flags & SOUNDFILE) {
671                 ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE];
672         } else if (file->flags & PYSCRIPTFILE) {
673                 ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE];
674         } else if (file->flags & FTFONTFILE) {
675                 ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE];
676         } else if (file->flags & TEXTFILE) {
677                 ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE];
678         } else if (file->flags & IMAGEFILE) {
679                 ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING];
680         }
681
682         return ibuf;
683 }
684
685 struct direntry * filelist_file(struct FileList* filelist, int index)
686 {
687         int fidx = 0;
688         
689         if ( (index < 0) || (index >= filelist->numfiltered) ) {
690                 return NULL;
691         }
692         fidx = filelist->fidx[index];
693
694         return &filelist->filelist[fidx];
695 }
696
697 int filelist_find(struct FileList* filelist, char *file)
698 {
699         int index = -1;
700         int i;
701         int fidx = -1;
702         
703         if (!filelist->fidx) 
704                 return fidx;
705
706         
707         for (i = 0; i < filelist->numfiles; ++i) {
708                 if ( strcmp(filelist->filelist[i].relname, file) == 0) {
709                         index = i;
710                         break;
711                 }
712         }
713
714         for (i = 0; i < filelist->numfiltered; ++i) {
715                 if (filelist->fidx[i] == index) {
716                         fidx = i;
717                         break;
718                 }
719         }
720         return fidx;
721 }
722
723 void filelist_hidedot(struct FileList* filelist, short hide)
724 {
725         filelist->hide_dot = hide;
726 }
727
728 void filelist_setfilter(struct FileList* filelist, unsigned int filter)
729 {
730         filelist->filter = filter;
731 }
732
733 static void filelist_read_dir(struct FileList* filelist)
734 {
735         char wdir[FILE_MAX];
736         if (!filelist) return;
737
738         filelist->fidx = 0;
739         filelist->filelist = 0;
740
741         BLI_getwdN(wdir);        
742
743         BLI_cleanup_dir(G.sce, filelist->dir);
744         filelist->numfiles = BLI_getdir(filelist->dir, &(filelist->filelist));
745
746         if(!chdir(wdir)) /* fix warning about not checking return value */;
747         filelist_setfiletypes(filelist, G.have_quicktime);
748         filelist_filter(filelist);
749 }
750
751 static void filelist_read_main(struct FileList* filelist)
752 {
753         if (!filelist) return;
754         filelist_from_main(filelist);
755 }
756
757 static void filelist_read_library(struct FileList* filelist)
758 {
759         if (!filelist) return;
760         BLI_cleanup_dir(G.sce, filelist->dir);
761         filelist_from_library(filelist);
762         if(!filelist->libfiledata) {
763                 int num;
764                 struct direntry *file;
765
766                 BLI_make_exist(filelist->dir);
767                 filelist_read_dir(filelist);
768                 file = filelist->filelist;
769                 for(num=0; num<filelist->numfiles; num++, file++) {
770                         if(BLO_has_bfile_extension(file->relname)) {
771                                 char name[FILE_MAXDIR+FILE_MAXFILE];
772                         
773                                 BLI_strncpy(name, filelist->dir, sizeof(name));
774                                 strcat(name, file->relname);
775                                 
776                                 /* prevent current file being used as acceptable dir */
777                                 if (BLI_streq(G.main->name, name)==0) {
778                                         file->type &= ~S_IFMT;
779                                         file->type |= S_IFDIR;
780                                 }
781                         }
782                 }
783         }
784 }
785
786 void filelist_readdir(struct FileList* filelist)
787 {
788         filelist->readf(filelist);
789 }
790
791 int filelist_empty(struct FileList* filelist)
792 {       
793         return filelist->filelist == 0;
794 }
795
796 void filelist_parent(struct FileList* filelist)
797 {
798         BLI_parent_dir(filelist->dir);
799         BLI_make_exist(filelist->dir);
800         filelist_readdir(filelist);
801 }
802
803 void filelist_setfiletypes(struct FileList* filelist, short has_quicktime)
804 {
805         struct direntry *file;
806         int num;
807
808         file= filelist->filelist;
809
810         for(num=0; num<filelist->numfiles; num++, file++) {
811                 file->flags= 0;
812                 file->type= file->s.st_mode;    /* restore the mess below */ 
813
814                         /* Don't check extensions for directories */ 
815                 if (file->type & S_IFDIR) {
816                         if(BLO_has_bfile_extension(file->relname)) {
817                                 file->flags |= BLENDERFILE;
818                         }
819                         continue;
820                 }
821
822                 if(BLO_has_bfile_extension(file->relname)) {
823                         file->flags |= BLENDERFILE;
824                 } else if(BLI_testextensie(file->relname, ".py")) {
825                                 file->flags |= PYSCRIPTFILE;
826                 } else if(BLI_testextensie(file->relname, ".txt")
827                                         || BLI_testextensie(file->relname, ".glsl")
828                                         || BLI_testextensie(file->relname, ".data")) {
829                                 file->flags |= TEXTFILE;
830                 } else if( BLI_testextensie(file->relname, ".ttf")
831                                         || BLI_testextensie(file->relname, ".ttc")
832                                         || BLI_testextensie(file->relname, ".pfb")
833                                         || BLI_testextensie(file->relname, ".otf")
834                                         || BLI_testextensie(file->relname, ".otc")) {
835                                 file->flags |= FTFONTFILE;                      
836                 } else if(BLI_testextensie(file->relname, ".btx")) {
837                                 file->flags |= BTXFILE;
838                 } else if(BLI_testextensie(file->relname, ".dae")) {
839                         file->flags |= COLLADAFILE;
840                 } else if (has_quicktime){
841                         if(             BLI_testextensie(file->relname, ".int")
842                                 ||  BLI_testextensie(file->relname, ".inta")
843                                 ||  BLI_testextensie(file->relname, ".jpg")
844 #ifdef WITH_OPENJPEG
845                                 ||  BLI_testextensie(file->relname, ".jp2")
846 #endif
847                                 ||      BLI_testextensie(file->relname, ".jpeg")
848                                 ||      BLI_testextensie(file->relname, ".tga")
849                                 ||      BLI_testextensie(file->relname, ".rgb")
850                                 ||      BLI_testextensie(file->relname, ".rgba")
851                                 ||      BLI_testextensie(file->relname, ".bmp")
852                                 ||      BLI_testextensie(file->relname, ".png")
853                                 ||      BLI_testextensie(file->relname, ".iff")
854                                 ||      BLI_testextensie(file->relname, ".lbm")
855                                 ||      BLI_testextensie(file->relname, ".gif")
856                                 ||      BLI_testextensie(file->relname, ".psd")
857                                 ||      BLI_testextensie(file->relname, ".tif")
858                                 ||      BLI_testextensie(file->relname, ".tiff")
859                                 ||      BLI_testextensie(file->relname, ".pct")
860                                 ||      BLI_testextensie(file->relname, ".pict")
861                                 ||      BLI_testextensie(file->relname, ".pntg") //macpaint
862                                 ||      BLI_testextensie(file->relname, ".qtif")
863                                 ||      BLI_testextensie(file->relname, ".sgi")
864                                 ||      BLI_testextensie(file->relname, ".hdr")
865 #ifdef WITH_DDS
866                                 ||      BLI_testextensie(file->relname, ".dds")
867 #endif
868 #ifdef WITH_OPENEXR
869                                 ||      BLI_testextensie(file->relname, ".exr")
870 #endif
871                                 ) {
872                                 file->flags |= IMAGEFILE;                       
873                         }
874                         else if(BLI_testextensie(file->relname, ".avi")
875                                 ||      BLI_testextensie(file->relname, ".flc")
876                                 ||      BLI_testextensie(file->relname, ".mov")
877                                 ||      BLI_testextensie(file->relname, ".movie")
878                                 ||      BLI_testextensie(file->relname, ".mp4")
879                                 ||      BLI_testextensie(file->relname, ".m4v")
880                                 ||      BLI_testextensie(file->relname, ".mv")
881                                 ||      BLI_testextensie(file->relname, ".wmv")
882                                 ||      BLI_testextensie(file->relname, ".ogv")
883                                 ||      BLI_testextensie(file->relname, ".mpeg")
884                                 ||      BLI_testextensie(file->relname, ".mpg")
885                                 ||      BLI_testextensie(file->relname, ".mpg2")
886                                 ||      BLI_testextensie(file->relname, ".vob")
887                                 ||      BLI_testextensie(file->relname, ".mkv")
888                                 ||      BLI_testextensie(file->relname, ".flv")
889                                 ||      BLI_testextensie(file->relname, ".divx")
890                                 ||      BLI_testextensie(file->relname, ".xvid")) {
891                                 file->flags |= MOVIEFILE;                       
892                         }
893                         else if(BLI_testextensie(file->relname, ".wav")
894                                 ||      BLI_testextensie(file->relname, ".ogg")
895                                 ||      BLI_testextensie(file->relname, ".oga")
896                                 ||      BLI_testextensie(file->relname, ".mp3")
897                                 ||      BLI_testextensie(file->relname, ".mp2")
898                                 ||      BLI_testextensie(file->relname, ".ac3")
899                                 ||      BLI_testextensie(file->relname, ".aac")
900                                 ||      BLI_testextensie(file->relname, ".flac")
901                                 ||      BLI_testextensie(file->relname, ".wma")
902                                 ||      BLI_testextensie(file->relname, ".eac3")) {
903                                 file->flags |= SOUNDFILE;
904                         }
905                 } else { // no quicktime
906                         if(BLI_testextensie(file->relname, ".int")
907                                 ||      BLI_testextensie(file->relname, ".inta")
908                                 ||      BLI_testextensie(file->relname, ".jpg")
909                                 ||  BLI_testextensie(file->relname, ".jpeg")
910 #ifdef WITH_OPENJPEG
911                                 ||  BLI_testextensie(file->relname, ".jp2")
912 #endif
913                                 ||      BLI_testextensie(file->relname, ".tga")
914                                 ||      BLI_testextensie(file->relname, ".rgb")
915                                 ||      BLI_testextensie(file->relname, ".rgba")
916                                 ||      BLI_testextensie(file->relname, ".bmp")
917                                 ||      BLI_testextensie(file->relname, ".png")
918                                 ||      BLI_testextensie(file->relname, ".iff")
919                                 ||      BLI_testextensie(file->relname, ".tif")
920                                 ||      BLI_testextensie(file->relname, ".tiff")
921                                 ||      BLI_testextensie(file->relname, ".hdr")
922 #ifdef WITH_DDS
923                                 ||      BLI_testextensie(file->relname, ".dds")
924 #endif
925 #ifdef WITH_OPENEXR
926                                 ||      BLI_testextensie(file->relname, ".exr")
927 #endif
928                                 ||      BLI_testextensie(file->relname, ".lbm")
929                                 ||      BLI_testextensie(file->relname, ".sgi")) {
930                                 file->flags |= IMAGEFILE;                       
931                         }
932                         else if(BLI_testextensie(file->relname, ".avi")
933                                 ||      BLI_testextensie(file->relname, ".flc")
934                                 ||      BLI_testextensie(file->relname, ".mov")
935                                 ||      BLI_testextensie(file->relname, ".movie")
936                                 ||      BLI_testextensie(file->relname, ".mp4")
937                                 ||      BLI_testextensie(file->relname, ".m4v")
938                                 ||      BLI_testextensie(file->relname, ".mv")
939                                 ||      BLI_testextensie(file->relname, ".wmv")
940                                 ||      BLI_testextensie(file->relname, ".ogv")
941                                 ||      BLI_testextensie(file->relname, ".mpeg")
942                                 ||      BLI_testextensie(file->relname, ".mpg")
943                                 ||      BLI_testextensie(file->relname, ".mpg2")
944                                 ||      BLI_testextensie(file->relname, ".vob")
945                                 ||      BLI_testextensie(file->relname, ".mkv")
946                                 ||      BLI_testextensie(file->relname, ".flv")
947                                 ||      BLI_testextensie(file->relname, ".divx")
948                                 ||      BLI_testextensie(file->relname, ".xvid")) {
949                                 file->flags |= MOVIEFILE;                       
950                         }
951                         else if(BLI_testextensie(file->relname, ".wav")
952                                 ||      BLI_testextensie(file->relname, ".ogg")
953                                 ||      BLI_testextensie(file->relname, ".oga")
954                                 ||      BLI_testextensie(file->relname, ".mp3")
955                                 ||      BLI_testextensie(file->relname, ".mp2")
956                                 ||      BLI_testextensie(file->relname, ".ac3")
957                                 ||      BLI_testextensie(file->relname, ".aac")
958                                 ||      BLI_testextensie(file->relname, ".flac")
959                                 ||      BLI_testextensie(file->relname, ".wma")
960                                 ||      BLI_testextensie(file->relname, ".eac3")) {
961                                 file->flags |= SOUNDFILE;
962                         }
963                 }
964         }
965 }
966
967 void filelist_swapselect(struct FileList* filelist)
968 {
969         struct direntry *file;
970         int num, act= 0;
971         
972         file= filelist->filelist;
973         for(num=0; num<filelist->numfiles; num++, file++) {
974                 if(file->flags & ACTIVEFILE) {
975                         act= 1;
976                         break;
977                 }
978         }
979         file= filelist->filelist+2;
980         for(num=2; num<filelist->numfiles; num++, file++) {
981                 if(act) file->flags &= ~ACTIVEFILE;
982                 else file->flags |= ACTIVEFILE;
983         }
984 }
985
986 void filelist_sort(struct FileList* filelist, short sort)
987 {
988         switch(sort) {
989         case FILE_SORT_ALPHA:
990                 qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_name);   
991                 break;
992         case FILE_SORT_TIME:
993                 qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_date);   
994                 break;
995         case FILE_SORT_SIZE:
996                 qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_size);   
997                 break;
998         case FILE_SORT_EXTENSION:
999                 qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_extension);      
1000         }
1001
1002         filelist_filter(filelist);
1003 }
1004
1005
1006 int filelist_islibrary(struct FileList* filelist, char* dir, char* group)
1007 {
1008         return BLO_is_a_library(filelist->dir, dir, group);
1009 }
1010
1011 static int groupname_to_code(char *group)
1012 {
1013         char buf[32];
1014         char *lslash;
1015         
1016         BLI_strncpy(buf, group, 31);
1017         lslash= BLI_last_slash(buf);
1018         if (lslash)
1019                 lslash[0]= '\0';
1020
1021         return BLO_idcode_from_name(buf);
1022 }
1023
1024 void filelist_from_library(struct FileList* filelist)
1025 {
1026         LinkNode *l, *names, *previews;
1027         struct ImBuf* ima;
1028         int ok, i, nnames, idcode;
1029         char filename[FILE_MAXDIR+FILE_MAXFILE];
1030         char dir[FILE_MAX], group[GROUP_MAX];   
1031         
1032         /* name test */
1033         ok= filelist_islibrary(filelist, dir, group);
1034         if (!ok) {
1035                 /* free */
1036                 if(filelist->libfiledata) BLO_blendhandle_close(filelist->libfiledata);
1037                 filelist->libfiledata= 0;
1038                 return;
1039         }
1040         
1041         BLI_strncpy(filename, G.sce, sizeof(filename)); // G.sce = last file loaded, for UI
1042
1043         /* there we go */
1044         /* for the time being only read filedata when libfiledata==0 */
1045         if (filelist->libfiledata==0) {
1046                 filelist->libfiledata= BLO_blendhandle_from_file(dir);
1047                 if(filelist->libfiledata==0) return;
1048         }
1049         
1050         idcode= groupname_to_code(group);
1051
1052                 // memory for strings is passed into filelist[i].relname
1053                 // and free'd in freefilelist
1054         previews = NULL;
1055         if (idcode) {
1056                 previews= BLO_blendhandle_get_previews(filelist->libfiledata, idcode);
1057                 names= BLO_blendhandle_get_datablock_names(filelist->libfiledata, idcode);
1058                 /* ugh, no rewind, need to reopen */
1059                 BLO_blendhandle_close(filelist->libfiledata);
1060                 filelist->libfiledata= BLO_blendhandle_from_file(dir);
1061                 
1062         } else {
1063                 names= BLO_blendhandle_get_linkable_groups(filelist->libfiledata);
1064         }
1065         
1066         nnames= BLI_linklist_length(names);
1067
1068         filelist->numfiles= nnames + 1;
1069         filelist->filelist= malloc(filelist->numfiles * sizeof(*filelist->filelist));
1070         memset(filelist->filelist, 0, filelist->numfiles * sizeof(*filelist->filelist));
1071
1072         filelist->filelist[0].relname= BLI_strdup("..");
1073         filelist->filelist[0].type |= S_IFDIR;
1074                 
1075         for (i=0, l= names; i<nnames; i++, l= l->next) {
1076                 char *blockname= l->link;
1077
1078                 filelist->filelist[i + 1].relname= BLI_strdup(blockname);
1079                 if (!idcode)
1080                         filelist->filelist[i + 1].type |= S_IFDIR;
1081         }
1082         
1083         if(previews) {
1084                 for (i=0, l= previews; i<nnames; i++, l= l->next) {
1085                         PreviewImage *img= l->link;
1086                         
1087                         if (img) {
1088                                 unsigned int w = img->w[PREVIEW_MIPMAP_LARGE];
1089                                 unsigned int h = img->h[PREVIEW_MIPMAP_LARGE];
1090                                 unsigned int *rect = img->rect[PREVIEW_MIPMAP_LARGE];
1091
1092                                 /* first allocate imbuf for copying preview into it */
1093                                 if (w > 0 && h > 0 && rect) {
1094                                         ima = IMB_allocImBuf(w, h, 32, IB_rect, 0);
1095                                         memcpy(ima->rect, rect, w*h*sizeof(unsigned int));
1096                                         filelist->filelist[i + 1].image = ima;
1097                                         filelist->filelist[i + 1].flags = IMAGEFILE;
1098                                 }
1099                         }
1100                 }
1101         }
1102
1103         BLI_linklist_free(names, free);
1104         if (previews) BLI_linklist_free(previews, (void(*)(void*)) MEM_freeN);
1105
1106         filelist_sort(filelist, FILE_SORT_ALPHA);
1107
1108         BLI_strncpy(G.sce, filename, sizeof(filename)); // prevent G.sce to change
1109
1110         filelist->filter = 0;
1111         filelist_filter(filelist);
1112 }
1113
1114 void filelist_hideparent(struct FileList* filelist, short hide)
1115 {
1116         filelist->hide_parent = hide;
1117 }
1118
1119 void filelist_from_main(struct FileList *filelist)
1120 {
1121         ID *id;
1122         struct direntry *files, *firstlib = NULL;
1123         ListBase *lb;
1124         int a, fake, idcode, ok, totlib, totbl;
1125         
1126         // filelist->type = FILE_MAIN; // XXXXX TODO: add modes to filebrowser
1127
1128         if(filelist->dir[0]=='/') filelist->dir[0]= 0;
1129         
1130         if(filelist->dir[0]) {
1131                 idcode= groupname_to_code(filelist->dir);
1132                 if(idcode==0) filelist->dir[0]= 0;
1133         }
1134         
1135         if( filelist->dir[0]==0) {
1136                 
1137                 /* make directories */
1138                 filelist->numfiles= 23;
1139                 filelist->filelist= (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry));
1140                 
1141                 for(a=0; a<filelist->numfiles; a++) {
1142                         memset( &(filelist->filelist[a]), 0 , sizeof(struct direntry));
1143                         filelist->filelist[a].type |= S_IFDIR;
1144                 }
1145                 
1146                 filelist->filelist[0].relname= BLI_strdup("..");
1147                 filelist->filelist[2].relname= BLI_strdup("Scene");
1148                 filelist->filelist[3].relname= BLI_strdup("Object");
1149                 filelist->filelist[4].relname= BLI_strdup("Mesh");
1150                 filelist->filelist[5].relname= BLI_strdup("Curve");
1151                 filelist->filelist[6].relname= BLI_strdup("Metaball");
1152                 filelist->filelist[7].relname= BLI_strdup("Material");
1153                 filelist->filelist[8].relname= BLI_strdup("Texture");
1154                 filelist->filelist[9].relname= BLI_strdup("Image");
1155                 filelist->filelist[10].relname= BLI_strdup("Ika");
1156                 filelist->filelist[11].relname= BLI_strdup("Wave");
1157                 filelist->filelist[12].relname= BLI_strdup("Lattice");
1158                 filelist->filelist[13].relname= BLI_strdup("Lamp");
1159                 filelist->filelist[14].relname= BLI_strdup("Camera");
1160                 filelist->filelist[15].relname= BLI_strdup("Ipo");
1161                 filelist->filelist[16].relname= BLI_strdup("World");
1162                 filelist->filelist[17].relname= BLI_strdup("Screen");
1163                 filelist->filelist[18].relname= BLI_strdup("VFont");
1164                 filelist->filelist[19].relname= BLI_strdup("Text");
1165                 filelist->filelist[20].relname= BLI_strdup("Armature");
1166                 filelist->filelist[21].relname= BLI_strdup("Action");
1167                 filelist->filelist[22].relname= BLI_strdup("NodeTree");
1168                 filelist_sort(filelist, FILE_SORT_ALPHA);
1169         }
1170         else {
1171
1172                 /* make files */
1173                 idcode= groupname_to_code(filelist->dir);
1174                 
1175                 lb= wich_libbase(G.main, idcode );
1176                 if(lb==0) return;
1177                 
1178                 id= lb->first;
1179                 filelist->numfiles= 0;
1180                 while(id) {
1181                         if (!filelist->hide_dot || id->name[2] != '.') {
1182                                 filelist->numfiles++;
1183                         }
1184                         
1185                         id= id->next;
1186                 }
1187                 
1188                 /* XXXXX TODO: if databrowse F4 or append/link filelist->hide_parent has to be set */
1189                 if (!filelist->hide_parent) filelist->numfiles+= 1;
1190                 filelist->filelist= (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry));
1191                 
1192                 files = filelist->filelist;
1193                 
1194                 if (!filelist->hide_parent) {
1195                         memset( &(filelist->filelist[0]), 0 , sizeof(struct direntry));
1196                         filelist->filelist[0].relname= BLI_strdup("..");
1197                         filelist->filelist[0].type |= S_IFDIR;
1198                 
1199                         files++;
1200                 }
1201                 
1202                 id= lb->first;
1203                 totlib= totbl= 0;
1204                 
1205                 while(id) {
1206                         ok = 1;
1207                         if(ok) {
1208                                 if (!filelist->hide_dot || id->name[2] != '.') {
1209                                         memset( files, 0 , sizeof(struct direntry));
1210                                         if(id->lib==NULL)
1211                                                 files->relname= BLI_strdup(id->name+2);
1212                                         else {
1213                                                 files->relname= MEM_mallocN(FILE_MAXDIR+FILE_MAXFILE+32, "filename for lib");
1214                                                 sprintf(files->relname, "%s | %s", id->lib->name, id->name+2);
1215                                         }
1216                                         /* files->type |= S_IFDIR; */
1217 #if 0                           // XXXXX TODO show the selection status of the objects
1218                                         if(!filelist->has_func) { /* F4 DATA BROWSE */
1219                                                 if(idcode==ID_OB) {
1220                                                         if( ((Object *)id)->flag & SELECT) files->flags |= ACTIVEFILE;
1221                                                 }
1222                                                 else if(idcode==ID_SCE) {
1223                                                         if( ((Scene *)id)->r.scemode & R_BG_RENDER) files->flags |= ACTIVEFILE;
1224                                                 }                                       
1225                                         }
1226 #endif
1227                                         files->nr= totbl+1;
1228                                         files->poin= id;
1229                                         fake= id->flag & LIB_FAKEUSER;
1230                                         if(idcode == ID_MA || idcode == ID_TE || idcode == ID_LA || idcode == ID_WO || idcode == ID_IM) {
1231                                                 files->flags |= IMAGEFILE;
1232                                         }
1233                                         if(id->lib && fake) sprintf(files->extra, "LF %d", id->us);
1234                                         else if(id->lib) sprintf(files->extra, "L    %d", id->us);
1235                                         else if(fake) sprintf(files->extra, "F    %d", id->us);
1236                                         else sprintf(files->extra, "      %d", id->us);
1237                                         
1238                                         if(id->lib) {
1239                                                 if(totlib==0) firstlib= files;
1240                                                 totlib++;
1241                                         }
1242                                         
1243                                         files++;
1244                                 }
1245                                 totbl++;
1246                         }
1247                         
1248                         id= id->next;
1249                 }
1250                 
1251                 /* only qsort of library blocks */
1252                 if(totlib>1) {
1253                         qsort(firstlib, totlib, sizeof(struct direntry), compare_name);
1254                 }
1255         }
1256         filelist->filter = 0;
1257         filelist_filter(filelist);
1258 }
1259
1260 static void thumbnail_joblist_free(ThumbnailJob *tj)
1261 {
1262         FileImage* limg = tj->loadimages.first;
1263         
1264         /* free the images not yet copied to the filelist -> these will get freed with the filelist */
1265         while (limg != tj->loadimages.last) {
1266                 if ((limg->img) && (!limg->done)) {
1267                         IMB_freeImBuf(limg->img);
1268                 }
1269                 limg = limg->next;
1270         }
1271         BLI_freelistN(&tj->loadimages);
1272 }
1273
1274 static void thumbnails_startjob(void *tjv, short *stop, short *do_update)
1275 {
1276         ThumbnailJob *tj= tjv;
1277         FileImage* limg = tj->loadimages.first;
1278
1279         tj->stop= stop;
1280         tj->do_update= do_update;
1281
1282         while ( (*stop==0) && (limg) ) {
1283                 if ( limg->flags & IMAGEFILE ) {
1284                         limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_IMAGE);
1285                 } else if ( limg->flags & MOVIEFILE ) {                 
1286                         limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_MOVIE);
1287                         if (!limg->img) {
1288                                         /* remember that file can't be loaded via IMB_open_anim */
1289                                         limg->flags &= ~MOVIEFILE;
1290                                         limg->flags |= MOVIEFILE_ICON;
1291                                 }
1292                 }
1293                 *do_update = 1;
1294                 PIL_sleep_ms(10);
1295                 limg = limg->next;
1296         }
1297 }
1298
1299 static void thumbnails_update(void *tjv)
1300 {
1301         ThumbnailJob *tj= tjv;
1302
1303         if (tj->filelist && tj->filelist->filelist) {
1304                 FileImage* limg = tj->loadimages.first;
1305                 while (limg) {
1306                         if (!limg->done && limg->img) {
1307                                 tj->filelist->filelist[limg->index].image = limg->img;
1308                                 /* update flag for movie files where thumbnail can't be created */
1309                                 if (limg->flags & MOVIEFILE_ICON) {
1310                                         tj->filelist->filelist[limg->index].flags &= ~MOVIEFILE;
1311                                         tj->filelist->filelist[limg->index].flags |= MOVIEFILE_ICON;
1312                                 }
1313                                 limg->done=1;
1314                         }
1315                         limg = limg->next;
1316                 }
1317         }
1318 }
1319
1320 static void thumbnails_free(void *tjv)
1321 {
1322         ThumbnailJob *tj= tjv;
1323         thumbnail_joblist_free(tj);
1324         MEM_freeN(tj);
1325 }
1326
1327
1328 void thumbnails_start(struct FileList* filelist, const struct bContext* C)
1329 {
1330         wmJob *steve;
1331         ThumbnailJob *tj;
1332         int idx;
1333         
1334         /* prepare job data */
1335         tj= MEM_callocN(sizeof(ThumbnailJob), "thumbnails\n");
1336         tj->filelist = filelist;
1337         for (idx = 0; idx < filelist->numfiles;idx++) {
1338                 if (!filelist->filelist[idx].image) {
1339                         if ( (filelist->filelist[idx].flags & IMAGEFILE) || (filelist->filelist[idx].flags & MOVIEFILE) ) {
1340                                 FileImage* limg = MEM_callocN(sizeof(struct FileImage), "loadimage");
1341                                 BLI_join_dirfile(limg->path, filelist->dir, filelist->filelist[idx].relname);
1342                                 limg->index= idx;
1343                                 limg->flags= filelist->filelist[idx].flags;
1344                                 BLI_addtail(&tj->loadimages, limg);
1345                         }
1346                 }
1347         }
1348
1349         BKE_reports_init(&tj->reports, RPT_PRINT);
1350
1351         /* setup job */
1352         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), filelist, 0);
1353         WM_jobs_customdata(steve, tj, thumbnails_free);
1354         WM_jobs_timer(steve, 0.5, NC_WINDOW, NC_WINDOW);
1355         WM_jobs_callbacks(steve, thumbnails_startjob, NULL, thumbnails_update);
1356
1357         /* start the job */
1358         WM_jobs_start(CTX_wm_manager(C), steve);
1359 }
1360
1361 void thumbnails_stop(struct FileList* filelist, const struct bContext* C)
1362 {
1363         WM_jobs_kill(CTX_wm_manager(C), filelist);
1364 }