1 /********************************************************************\
2 ** _________________________________ **
3 ** A n t h o n y |________ __ __ _________| **
4 ** | |o_| |o_| | **
5 ** T h y s s e n __| __ __ |__ **
6 ** __| __| | | |__ |__ **
7 ** `` Dragon Computing! '' __| __| | | |__ |__ **
8 ** |_____| |__| |_____| **
9 ** **
10 \********************************************************************/
11 /*
12 ** images.c
13 **
14 ** This module controls the data structure of `items' used to hold all the
15 ** directory elements. The icon images represented by these elements are read
16 ** in and assigned to widgets to be displayed.
17 **
18 ** The goal here is to create a data structure which can merge in new icons
19 ** or changes to the currently displayed icons with the minimum of reads and
20 ** delays. The rescan in particular could and should be improved.
21 **
22 ** Anthony Thyssen <anthony@dragon.cit.gu.edu.au>
23 */
24 #include "xbmbrowser.h"
25
26 static Item *file_list = NULL; /* current list of all files */
27 static Item *new_file_list = NULL; /* new file list just scanned (to merge) */
28 static Item *old_file_list = NULL; /* old file list already loaded (merge) */
29 static Item **last_link = NULL; /* point to the last next ptr in merge */
30
31 static Widget *widget_array = NULL; /* array of widgets available to use */
32 static int allocated = 0; /* number of widgets in above array */
33 static int managed = 0; /* number of widgets being managed */
34
35 static int items_allocated = 0; /* current number of allocated items */
36 static int num_files; /* number files in file_list */
37 static int num_visible; /* number items which are visible */
38 static int file_counts[(int)NumFileTypes]; /* count of the various file types */
39
40 #define DIR_LIMIT 256
41 static char *dir_list[DIR_LIMIT]; /* directories in directory menu */
42 static int num_dirs; /* number of directories in this list */
43
44
45 #ifdef DO_XPMS
46
47 #ifndef NO_TRANS_COLOR
48 static XpmColorSymbol attr_colorsymbols[] = {
49 {NULL, "none", 0}, /* transparent pixel to assign filled in later */
50 };
51 #endif
52
53 /* do we have to invert pixmap on monocrome displays so label gets it right */
54 static GC invert_pixmaps_gc = None;
55
56 #endif
57
58 /* ------------------------------------------------------------------------ */
59 /* --------------------- Item Allocation / Dellocation -------------------- */
60
61 Item *
alloc_item()62 alloc_item()
63 /* allocate and default a file item */
64 {
65 Item *item = (Item *) XtMalloc( sizeof(Item) );
66
67 item->next = NULL; /* set defaults */
68 item->fname[0] = '\0';
69 item->info[0] = '\0';
70 item->type = Unknown; /* type is unknown */
71 item->visible = False; /* not visible - yet */
72 item->index = -1; /* no widget assigned */
73 item->pixmap = (Pixmap)None; /* no image loaded */
74 item->mask = (Pixmap)None; /* no mask either (of course) */
75
76 items_allocated++;
77 return item;
78 }
79
80
81 static void
free_image(item)82 free_image(item)
83 /* Free any image that may be currently accociated with this item.
84 ** This is usally done either as a prelude to freeing the items
85 ** memory, or hiding the item from the user (why bother?).
86 */
87 Item *item;
88 {
89 /* remove images from widget if one is allocated */
90 if( item->index != -1 ) {
91 XtVaSetValues(widget_array[item->index],
92 XtNpixmap, (XtArgVal)None,
93 XtNmask, (XtArgVal)None,
94 XtNlabel, (XtArgVal)NULL, NULL);
95 }
96
97 /* Free Pixmap (Bitmap) of the image */
98 if( item->pixmap != (Pixmap)None &&
99 item->pixmap != sym_bmaps[item->type] ) {
100 XFreePixmap(display, item->pixmap );
101 #ifdef DO_XPMS
102 if( item->type == Xpm ) {
103 /* free colors and attributes that were used by this pixmap only */
104 XFreeColors(display, colormap, item->attr.pixels, item->attr.npixels, 0);
105 XpmFreeAttributes((XpmAttributes *)&item->attr);
106 }
107 #endif
108 }
109
110 /* Free Bitmap Mask of the image */
111 if( item->mask != (Pixmap)None &&
112 item->mask != sym_masks[item->type]) {
113 XFreePixmap(display, item->mask );
114 }
115 item->pixmap = (Pixmap)None;
116 item->mask = (Pixmap)None;
117 }
118
119
120 Item *
free_item(item)121 free_item(item)
122 /* Free the item and any aspect about that item. This is the ONLY place
123 ** where items are to be freed. Returns the next item in the current list!
124 */
125 Item *item;
126 {
127 Item *next = item->next;
128
129 free_image(item);
130 /* item->index = -1; */
131
132 XtFree( (char *) item );
133
134 items_allocated--;
135 return next;
136 }
137
138
139 void
free_list(list)140 free_list(list)
141 /* completely free all items in the given item list */
142 Item **list; /* pointer to a list pointer */
143 {
144 while( *list != NULL )
145 *list = free_item( *list );
146 }
147
148 /* ------------------------------------------------------------------------ */
149 /* --------------------------- Widget Control ----------------------------- */
150
151 static void
allocate_widgets(n)152 allocate_widgets( n )
153 /* create enough widgets to display n icon images */
154 int n;
155 {
156 char name[8];
157 Widget w;
158
159 if( allocated == n ) return; /* just right -- no need to do anthing */
160
161 if( allocated < n ) { /* ok allocate more widgets */
162
163 if(widget_array == NULL) {
164 widget_array = (Widget *)XtMalloc( n * sizeof(Widget) );
165 if( widget_array == NULL ) {
166 perror("xbmbrowser: XtMalloc widget_array");
167 abort();
168 }
169 } else {
170 widget_array = (Widget *)realloc(widget_array, n * sizeof(Widget) );
171 if( widget_array == NULL ) {
172 perror("xbmbrowser: realloc larger widget_array");
173 abort();
174 }
175 }
176
177 for( ; allocated < n; allocated++ ) {
178 sprintf(name, "%d", allocated);
179 w = XtVaCreateWidget(name, iconLabelWidgetClass, iconbox, NULL);
180 XtOverrideTranslations(w, XtParseTranslationTable(icon_trans));
181 widget_array[allocated] = w;
182 }
183 }
184
185 #if 0
186 /* This code will eventually cause a core dump when lots of directory
187 ** changes are performed by the user. The problem seems to occur when
188 ** widgets are really destroyed (they are just flaged for destruction).
189 ** I can't seem to find any problem with the code below however.
190 ** It just doesn't seem to work. Anthony
191 */
192 else { /* ok we have too many widgets -- remove about a 1/3 of them */
193 n = ( allocated + allocated + n ) / 3; /* the final level we want */
194
195 for( allocated--; allocated >= n ; allocated-- )
196 XtDestroyWidget( widget_array[allocated] );
197 allocated++;
198
199 widget_array = (Widget *)realloc(widget_array, n * sizeof(Widget) );
200 if( widget_array == NULL ) {
201 perror("xbmbrowser: realloc smaller widget_array");
202 abort();
203 }
204 }
205
206 /* insure that allocated is now equal to n (which may be calculated above */
207 assert( allocated == n );
208 #endif
209 }
210
211
212 static void
assign_widget(item)213 assign_widget(item)
214 /* Set up the widget to display this item (index already assigned)
215 ** and insure it is using the appropriate resource settings for
216 ** correct display occording to the current user options.
217 */
218 Item *item;
219 {
220 /* do we label the widget? */
221 Boolean label = app_data.label_all || (
222 item->type == Xbm ? app_data.label_icons :
223 item->type == Xpm ? app_data.label_icons :
224 ( app_data.label_syms || IsDirItem(item) && app_data.label_dirs ) );
225
226 XtVaSetValues( widget_array[item->index],
227 XtNinfoPtr, (XtArgVal)item, /* pointer to more info */
228 XtNpixmap, (XtArgVal)item->pixmap, /* the icon image */
229 XtNmask, (XtArgVal)item->mask, /* its mask if present */
230 XtNisBitmap, (XtArgVal)(item->type != Xpm), /* draw as a bitmap? */
231
232 XtNlabel, (XtArgVal)( /* display the filename? */
233 label ? item->fname : NULL ),
234 XtNshape, (XtArgVal)( /* shape window on? */
235 item->type == Xbm ? app_data.solid_bgnd :
236 item->type == Xpm ? app_data.solid_bgnd :
237 app_data.shape_syms ),
238 XtNforeground, (XtArgVal)( /* bitmap/label color */
239 item->type == Xbm ? app_data.icon_fg :
240 item->type == Xpm ? app_data.icon_fg :
241 app_data.sym_fg ),
242 XtNbackground, (XtArgVal)( /* background color */
243 item->type == Xbm ? app_data.icon_bg :
244 item->type == Xpm ? app_data.icon_tr :
245 app_data.sym_bg ),
246 NULL);
247 }
248
249
250 static void
assign_widgets()251 assign_widgets()
252 /* Assign all items to the widgets as required.
253 ** This allows us to adjust the current display after user option
254 ** changes without doing a full rescan of the current directory.
255 ** This should only be done when either
256 ** 1/ widgets are unmanaged during new directory scan/merge
257 ** 2/ none of the items have actually changed only the
258 ** assignments to the widgets themselves have changed.
259 */
260 {
261 Item *item;
262
263 managed = 0; /* re-calculating this now */
264
265 for( item = file_list; item != NULL; item = item->next ) {
266 if( item->visible ) {
267 assert( item->pixmap != (Pixmap)None ); /* a pixmap must be present */
268 item->index = managed++;
269 assign_widget(item); /* set up this widget to hold the item */
270 }
271 }
272
273 }
274
275 /* ------------------------------------------------------------------------ */
276 /* --------------------------- Item Image Loading ------------------------- */
277
278 static void
load_image(item)279 load_image(item)
280 /* Attempt to determine and set the type of the file given and
281 ** load the image (if present) which is stored in that file.
282 */
283 Item *item;
284 {
285 int i, status; /* junk integer, size of icon, return status */
286 int c; /* junk char -- integer for EOF test */
287 unsigned int x, y; /* size of bitmap/pixmap */
288 FILE *fp; /* file pointer */
289
290 /* insure the bitmap is not allocated already */
291 assert( item->pixmap == (Pixmap)None ||
292 item->pixmap == sym_bmaps[item->type]);
293
294 /* if the type is a X pixmap -- skip direct to load pixmap */
295 if( item->type == Xpm || item->type == XpmBad )
296 goto load_xpm;
297
298 /* Test if the file is not a binary file
299 * This should not be necessary, however the XReadBitmapFile and
300 * XpmReadPixmapFile functions have a nasty habit of crashing with
301 * some binary files. -- Ashley
302 */
303 /* open the file and look to see if the first few chars are binary */
304 if((fp = fopen(item->fname,"r")) == (FILE *) NULL) {
305 /* can't open file -- declare it as such */
306 item->type = Unknown;
307 item->pixmap = (Pixmap)None;
308 (void) sprintf(item->info, "\"%s\", unreadable", item->fname );
309 return;
310 } else {
311 for(i = 0; i < 100; i++) { /* check 100 chars */
312 c = getc(fp);
313 if(c == EOF)
314 break;
315 if( c > 127 || c < 7 ) { /* a char with non ascii values */
316 fclose(fp);
317 item->type = Binary;
318 item->pixmap = (Pixmap)None;
319 /* (void) sprintf(item->info, "\"%s\", binary (0x%02x at %d)",
320 ** item->fname, c, i ); /**/
321 return;
322 }
323 }
324 fclose(fp);
325 if( i == 0 ) { /* hey empty file -- declare it as such */
326 item->type = File; /* leave it as a plain file */
327 item->pixmap = (Pixmap)None;
328 (void) sprintf(item->info, "\"%s\", empty file", item->fname );
329 return;
330 }
331
332 } /* probably a non binary file so continue */
333
334 /* presumably a text file -- so try an load it as a bitmap */
335 item->pixmap = None; /* Precaution */
336 status = XReadBitmapFile(display, DefaultRootWindow(display),
337 item->fname, &x, &y, &item->pixmap, &i, &i);
338
339 if( status == BitmapSuccess && item->pixmap != None ) {
340 item->type = Xbm;
341 (void) sprintf(item->info, "\"%s\", %dx%d bitmap", item->fname, x, y );
342 return;
343 }
344
345 load_xpm:
346 /* Not a bitmap -- Ok try it as a Pixmap file */
347 #ifdef DO_XPMS
348 item->pixmap = (Pixmap)None; /* Precaution */
349 item->mask = (Pixmap)None;
350
351 /* Set the attributes */
352 #ifdef NO_TRANS_COLOR
353 item->attr.valuemask = XpmExactColors | XpmCloseness | XpmReturnPixels;
354 #else
355 item->attr.valuemask =
356 /* IN */ XpmColorSymbols | XpmExactColors | XpmCloseness
357 /* OUT */ | XpmReturnPixels;
358 item->attr.colorsymbols = attr_colorsymbols; /* setup in merge_init() */
359 item->attr.numsymbols = XtNumber(attr_colorsymbols);
360 #endif /* NO_TRANS_COLOR */
361 item->attr.exactColors = 0;
362 item->attr.closeness = 40000;
363
364 status = XpmReadPixmapFile(display, DefaultRootWindow(display),
365 item->fname, &item->pixmap, &item->mask, &item->attr);
366
367
368 /* save a copy of the number of pixels (the kludge below may change this) */
369 c = item->attr.npixels;
370
371 #ifndef NO_TRANS_COLOR
372 /*
373 ** WARNING: The Transparent color given to the Xpixmap library for the `None'
374 ** Color is returned in the item->attr.pixels array. This means I now have
375 ** to remove this color from the array so that it is not free'd later when we
376 ** are finished with the pixmap. This is only a problem when we use Color
377 ** Symbols to set the transparent color. For more information see the
378 ** Changes file.
379 **
380 ** Note before release 3.4d if a None color was in the pixmap but was NOT the
381 ** first element in the colortable, the first element in the pixels array was
382 ** missing, and of course with the Arnaud's `philosophy' the None color pixel
383 ** is present in the appropriate place. As such the first color is not free'd
384 ** and can remain allocated for the life of the programs execution.
385 ** IE: A Color Allocation Leak existed before version 3.4d!
386 **
387 ** NOTE: this also has to be done on Monocrome Displays, as well as color
388 ** displays.
389 */
390 if ( item->mask != None ) { /* None color present in xpimap? */
391 int i,j;
392
393 for( i = j = 0; i < item->attr.npixels; i++ ) {
394 if( item->attr.pixels[i] == app_data.icon_tr )
395 continue; /* don't include the none pixel color */
396 item->attr.pixels[j++] = item->attr.pixels[i];
397 }
398 item->attr.npixels = j; /* the number of pixels now */
399
400 #if XpmFormat == 3 && XpmVersion == 4 && XpmRevision <= 6
401 #else
402 /* Assuming that the None color was only in the X pixmap file once only
403 ** (rarely otherwise) reduce the number of pixels returned by one.
404 ** NOTE: a bug in the Xpm library before version 3.4d resulted in the
405 ** number of pixels returned being correct but results in a color
406 ** allocation leak, due to the first pixel value being missing. */
407 c--;
408 #endif
409 } /* if mask present */
410 #endif /* NO_TRANS_COLOR */
411
412 /* Check the return status of the Read Pixmap */
413 switch( status ) {
414 case XpmColorError:
415 case XpmSuccess:
416 item->type = Xpm;
417 if ( item->attr.width == 0 || item->attr.height == 0 ) {
418 /* this pixmap has NO PIXELS, and is a color table only!
419 ** remove the pixmap and let the default symbol be used
420 ** Suggestion by Thomas Cooke <cooke@newice.stortek.com> */
421 free_image(item);
422 }
423 (void) sprintf(item->info, "\"%s\", %dx%d pixmap (%d colors%s)",
424 item->fname, item->attr.width, item->attr.height, c,
425 item->mask != None ? " + mask" : "" );
426
427 if ( item->pixmap != None ) return; /* Return if success */
428 /* fall through if we failed after all! */
429
430 case XpmColorFailed:
431 case XpmNoMemory:
432 item->type = XpmBad;
433 /* if a pixmap was assigned -- remove it */
434 /* this actually should never be needed but just in case */
435 free_image(item);
436 return;
437
438 case XpmOpenFailed:
439 case XpmFileInvalid:
440 /* OK so it isn't a pixmap */
441 break;
442 }
443 #endif /* DO_XPMS */
444
445 /* Non Bitmap/Pixmap file -- it must be a plain text file */
446 item->type = Text;
447 item->pixmap = None;
448 return;
449 }
450
451
452 static void
load_item(item)453 load_item(item)
454 /* Given an item, fill out all the other information required
455 ** by that item, including the images needed.
456 */
457 Item *item;
458 {
459 item->visible = True;
460 if ( !app_data.show_hidden /* don't show hidden 'dot' files */
461 && item->fname[0] == '.' /* and is a hidden file? */
462 && item->type != DirUp ) { /* and is not the up directory */
463 item->visible = False;
464 }
465
466 /* Try to load a image from this file and determine file type
467 ** more closly. This may also set the info line for the file if a load
468 ** was successful. BadXpm's are NOT attempted again otherwise rescan's
469 ** become very very slow on large directories of X pixmaps.
470 */
471 if( item->type == File && item->visible )
472 load_image( item );
473
474 /* Determine item visiblity as appropiate for current options */
475 switch( item->type ) {
476 case Dir:
477 case DirUp:
478 case DirLink:
479 case DirBad: /* Directory Items */
480 item->visible = item->visible &&
481 !app_data.icons_only && app_data.show_dir;
482 break;
483 case Unknown: /* Special File -- pipe, device */
484 case Text: /* Plain Text file */
485 case Binary: /* Binary file */
486 case File: /* New or Empty file */
487 item->visible = item->visible &&
488 !app_data.icons_only && app_data.show_other;
489 break;
490 case XpmBad: /* x pixmap which failed this load attempt */
491 item->visible = item->visible &&
492 !app_data.icons_only && app_data.show_xpmbad;
493 break;
494 case Xbm: /* X bitmap file */
495 case Xpm: /* X pixmap file */
496 item->visible = True; /* pixmaps always visible */
497 break;
498 default: /* Unknown file type -- error should not happen */
499 item->visible = False; /* just not visible */
500 assert( False ); /* assertion failure */
501 }
502
503 /* if it is not visible -- finished */
504 if( !item->visible ) {
505 free_image(item); /* ???? insure no images is set */
506 return;
507 }
508
509 /* At this point the item must be visible (widget assigned latter) */
510
511 /* assign default bitmap is none present */
512 if( item->pixmap == (Pixmap)None ) {
513 item->pixmap = sym_bmaps[item->type];
514 item->mask = sym_masks[item->type];
515 }
516
517 /* assign a default info line if none present */
518 if( item->info[0] != '"' ) {
519 char *desc = "Description Error"; /* default description -- just in case */
520
521 switch ( item->type ) {
522 case Unknown: desc = "unknown"; break;
523 case Dir: desc = "directory"; break;
524 case DirUp: desc = "parent directory"; break;
525 case DirLink: desc = "directory sym-link"; break;
526 case DirBad: desc = "directory (no access)"; break;
527 case File: desc = "file (unknown)"; break;
528 case Text: desc = "text"; break;
529 case Binary: desc = "binary"; break;
530 case XpmBad: desc = "pixmap (unable to display)"; break;
531 }
532 (void) sprintf(item->info, "\"%s\", %s", item->fname, desc);
533 }
534
535 }
536
537 /*------------------------------------------------------------------------*/
538 /* -------------------- List Merging and Updating ----------------------- */
539
540 static void
merge_init()541 merge_init()
542 /* initialize the appropiate variables for to merge `new_file_list'
543 ** into the current `file_list'.
544 */
545 {
546 int i; /* looping variable */
547
548 /* first un-manage all the widgets and free the current file_list
549 ** This saves on multiple geometry requests while we do the work
550 */
551 if( managed > 0 ) {
552 XtUnmanageChildren(widget_array, managed);
553 managed = 0;
554 }
555
556 old_file_list = file_list; /* make the current list old */
557 file_list = NULL; /* empty destination of merged file_lists */
558 last_link = &file_list; /* last next ptr is the list ptr itself */
559
560 /* zero all the counts required */
561 num_files = 0; /* reset number of files in current list */
562 num_dirs = 0; /* number of directoires in new dirmenu list */
563 num_visible = 0; /* number of visible items requiring widgets */
564 for( i = 0 ; i < NumFileTypes ; i++ )
565 file_counts[i] = 0;
566
567 /* initialize the directory list */
568 /* FUTURE: initialise this from user preferences? */
569 dir_list[num_dirs++] = "/";
570 dir_list[num_dirs++] = "~/";
571
572 #ifdef DO_XPMS
573 #ifndef NO_TRANS_COLOR
574 /* set the transparent pixel color for X Pixmaps */
575 attr_colorsymbols[0].pixel = app_data.icon_tr;
576 #endif /* ! NO_TRANS_COLOR */
577 #endif /* DO_XPMS */
578
579 }
580
581
582 static void
merge_item(item)583 merge_item(item)
584 /* Add this item to the current (merging) `file_list'.
585 ** Assigning the appropiate information line, bitmap.
586 ** And adjusting all file counts appropiately.
587 */
588 Item *item;
589 {
590 /* add item to the file_list */
591 *last_link = item; /* append new item to merged list */
592 last_link = &(item->next); /* move last_link to new last next ptr */
593 /* *last_ptr = NULL; /* terminate current list (not needed?) */
594 num_files++; /* increment number of file in list */
595
596 /* if this item is a directory add it to the directory menu list */
597 /* NOTE: What should be done if num_dirs found > DIR_LIMIT */
598 if( IsDirItem(item) ) {
599 if( num_dirs < DIR_LIMIT-1 )
600 dir_list[num_dirs++] = item->fname;
601 }
602
603 /* Figure out the rest of the items requirments like
604 ** file type, load image, info line, if visible etc... */
605 load_item(item);
606
607 /* count up the items of each type */
608 file_counts[item->type]++;
609
610 /* This item is visible give it a widget */
611 if ( item->visible )
612 num_visible++;
613 }
614
615
616 static void
merge_finish()617 merge_finish()
618 /* Finialise the merger of the new and old file_lists, assign the
619 ** widgets, and set the default information line.
620 */
621 {
622 Item *item; /* looping variable */
623 int i; /* junk integer */
624
625 /* insure the last next pointer in the newly merged list is NULL */
626 *last_link = NULL;
627
628 /* finialise the directory menu list and install */
629 dir_list[num_dirs] = NULL;
630 XawListChange(dirlist, dir_list, 0, 0, True);
631 XtVaSetValues(dirlist, XtNdefaultColumns, (XtArgVal)(num_dirs/25+1), NULL);
632
633 /* allocate/deallocate widgets as needed */
634 allocate_widgets( num_visible );
635
636 /* Assign all items to the widgets appropriately */
637 assign_widgets();
638
639 /* manage the widgets */
640 if( managed > 0 )
641 XtManageChildren(widget_array, managed);
642
643 /* Set the default information label */
644 # define strend label_info+strlen(label_info)
645 label_info[0] = '\0'; /* empty the string */
646 if( num_files <= 1 ) /* only the ".." directory? */
647 strcpy(label_info, "Empty Directory" );
648 if( (i = file_counts[Xbm]) > 0 )
649 sprintf(strend, " %d Bitmaps ", i );
650 if( (i = file_counts[Xpm]) > 0 )
651 sprintf(strend, " %d Pixmaps ", i );
652 if( (i = file_counts[XpmBad]) > 0 )
653 sprintf(strend, " %d Unloadable ", i );
654 if( (i = file_counts[File] + file_counts[Text] + file_counts[Binary]) > 0 )
655 sprintf(strend, " %d Others ", i );
656 if( (i = file_counts[Dir] + file_counts[DirLink] + file_counts[DirBad]) > 0 )
657 sprintf(strend, " %d Dirs ", i );
658 if( (i = file_counts[Unknown]) > 0 )
659 sprintf(strend, " %d Unknown ", file_counts[Unknown] );
660
661 XtVaSetValues(label, XtNlabel, (XtArgVal)label_info, NULL);
662 # undef strend
663
664 /* check the results of the merger */
665 assert( managed == num_visible ); /* number of widgets */
666 assert( new_file_list == NULL ); /* both lists now empty */
667 assert( old_file_list == NULL );
668 assert( items_allocated == num_files ); /* allocation test */
669
670 }
671
672
673 static void
merge_file_lists()674 merge_file_lists()
675 /* Merge the old_file_list and the new_file_list. */
676 {
677 int cmp; /* comparision of top two elements of the lists */
678
679 merge_init();
680
681 while( old_file_list != NULL && new_file_list != NULL ) {
682 /* both lists have items in them */
683
684 cmp = strcmp( old_file_list->fname, new_file_list->fname );
685
686 if( cmp == 0 ) { /* the file names are the same */
687 if ( !IsFileItem(new_file_list) ||
688 old_file_list->mtime != new_file_list->mtime ) {
689
690 /* NOT A FILE -- mtime is non-sense so just add the new item */
691 /* MODIFIED -- same name but it has been modified or replaced */
692 old_file_list = free_item( old_file_list ); /* junk the old item */
693 cmp = 1; /* ok now pretend that this is a new item -- ADDITION */
694 /* FALL THROUGH -- to ADDITION */
695
696 } else {
697
698 /* NO CHANGE -- same file in both lists without any modifications */
699 new_file_list = free_item( new_file_list ); /* junk the new item */
700 merge_item(old_file_list); /* merge the old item */
701 old_file_list = *last_link; /* remove item from old list */
702 continue;
703 }
704 }
705
706 /* ADDITION -- a new file (or newly modified) to be merged */
707 if( cmp > 0 ) { /* name of new item is smaller than in old */
708 merge_item(new_file_list); /* merge the new item */
709 new_file_list = *last_link; /* remove item from new list */
710 continue;
711 }
712
713 /* DELETION -- the old file has been deleted */
714 if( cmp < 0 ) { /* Hey old item name is smaller then new item name */
715 old_file_list = free_item( old_file_list ); /* delete old item */
716 continue;
717 }
718
719 /* this point should never be reached */
720 /*NOTREACHED*/
721 assert( FALSE );
722 }
723
724 /* --------------
725 ** At this point either one or both of the merging file lists
726 ** is empty. As such we can just finish of the merged list quickly
727 */
728 assert( new_file_list == NULL || old_file_list == NULL );
729
730 /* ADD any more new items in the new_file_list */
731
732 while( new_file_list != NULL ) {
733 merge_item(new_file_list); /* merge the new item */
734 new_file_list = *last_link; /* remove item from new list */
735 }
736 new_file_list = NULL; /* new_file_list is now empty */
737
738 /* DELETE any old items left in the old_file_list */
739 free_list(&old_file_list);
740
741 /* -------------- */
742 /* Merger of file lists complete -- finialize */
743 merge_finish();
744 }
745
746
747 /*========================================================================*/
748 /* ------------------- Public Routines and Functions -------------------- */
749
750 void
rescan_item(item)751 rescan_item(item)
752 /* If the given item is a visible file, and is newer
753 ** then rescan it loading any new image it may have now
754 */
755 Item *item;
756 {
757 /* the files current modification time -- 0 if not a file or deleted */
758 time_t time;
759
760 if ( !item->visible )
761 return; /* not visible -- why were we called? */
762
763 if ( IsFileItem(item) ) {
764 if ( (time = check_file_time(item->fname)) == 0 )
765 return; /* it is deleted -- don't mess with things */
766
767 if ( time > item->mtime ) { /* Update this items image */
768 free_image(item); /* remove images from widget and free them */
769 load_image(item); /* load the file image */
770 load_item(item); /* set up the rest of the stuff */
771 assign_widget(item); /* setup the widget again */
772 }
773 }
774 }
775
776
777 void
redisplay_images(unmap)778 redisplay_images(unmap)
779 /* Just redisplay the widgets after a slight option change */
780 Boolean unmap; /* unmap the widget before reseting them? */
781 {
782 if( unmap && managed > 0 )
783 XtUnmanageChildren(widget_array, managed);
784
785 assign_widgets(); /* Reset all the widget settings -- correctly */
786
787 if( unmap && managed > 0 )
788 XtManageChildren(widget_array, managed);
789 }
790
791
792 void
reassign_images()793 reassign_images()
794 /* don't re-read the directory -- just re-assign the list */
795 {
796 new_file_list = file_list; /* pretend that this is the new list */
797 file_list = NULL;
798
799 /* totally reassign all items to the widgets */
800 merge_file_lists(); /* go through the list again */
801 }
802
803
804 void
rescan_images()805 rescan_images()
806 /* Do a fast rescan and merger of the images in the current directory.
807 ** The goal is to avoid re-reading files which were never changed.
808 */
809 {
810 new_file_list = get_files(); /* get items in the current directory */
811 merge_file_lists(); /* merge any changes into file_list */
812 }
813
814
815 void
scan_images()816 scan_images()
817 /* scan and display all the icon images in the current directory.
818 ** This is to be used when changing to new directories.
819 */
820 {
821 /* just free all the icon images and do a rescan which handles
822 ** the reading of new images perfectly fine on its own. We need
823 ** to unmanage them here, to avoid problems.
824 */
825 if( managed > 0 ) {
826 XtUnmanageChildren(widget_array, managed);
827 managed = 0;
828 }
829
830 free_list(&file_list);
831 assert( items_allocated == 0 ); /* their should be no items left */
832
833 rescan_images();
834 }
835
836 /*========================================================================*/
837