1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stddef.h>
4 #include <unistd.h>
5 #include <errno.h>
6 
7 #include <X11/Xlib.h>
8 #include <X11/Intrinsic.h>
9 #include <Xm/Xm.h>
10 #include <Xm/Label.h>
11 #include <Xm/RowColumn.h>
12 #include <Xm/PushB.h>
13 #include <Xm/Transfer.h>
14 #include <Xm/TransferP.h>
15 #include <Xm/Container.h>
16 #include <Xm/IconG.h>
17 #include <Xm/ScrolledW.h>
18 #include <Xm/SelectioB.h>
19 #include <Xm/Text.h>
20 
21 #include "RegEdit.h"
22 #include "list.h"
23 #include "ida.h"
24 #include "x11.h"
25 #include "icons.h"
26 #include "readers.h"
27 #include "filter.h"
28 #include "viewer.h"
29 #include "selections.h"
30 #include "filebutton.h"
31 #include "fileops.h"
32 #include "idaconfig.h"
33 
34 /*----------------------------------------------------------------------*/
35 
36 struct fileinfo {
37     struct list_head       list;
38     char                   *path;
39     struct ida_image_info  img;
40     Pixmap                 small;
41     Pixmap                 large;
42 };
43 
44 static LIST_HEAD(pcache);
45 static LIST_HEAD(pqueue);
46 static LIST_HEAD(files);
47 static XtWorkProcId pproc;
48 
49 /*----------------------------------------------------------------------*/
50 
51 static struct fileinfo*
fileinfo_cache_add(char * path,struct ida_image_info * img,Pixmap small,Pixmap large)52 fileinfo_cache_add(char *path, struct ida_image_info *img,
53 		   Pixmap small, Pixmap large)
54 {
55     struct fileinfo *item;
56 
57     item = malloc(sizeof(*item));
58     memset(item,0,sizeof(*item));
59     item->path  = strdup(path);
60     item->img   = *img;
61     item->small = small;
62     item->large = large;
63     list_add_tail(&item->list,&pcache);
64     return item;
65 }
66 
fileinfo_cache_del(char * path)67 static void fileinfo_cache_del(char *path)
68 {
69     struct list_head *item;
70     struct fileinfo *b;
71 
72     list_for_each(item,&pcache) {
73 	b = list_entry(item,struct fileinfo,list);
74 	if (0 == strcmp(path,b->path)) {
75 	    list_del(&b->list);
76 	    free(b);
77 	    return;
78 	}
79     }
80 }
81 
fileinfo_cache_get(char * path)82 static struct fileinfo* fileinfo_cache_get(char *path)
83 {
84     struct list_head *item;
85     struct fileinfo *b;
86 
87     list_for_each(item,&pcache) {
88 	b = list_entry(item,struct fileinfo,list);
89 	if (0 == strcmp(path,b->path))
90 	    return b;
91     }
92     return 0;
93 }
94 
95 /*----------------------------------------------------------------------*/
96 
97 static void
fileinfo_cleanup(struct file_button * file)98 fileinfo_cleanup(struct file_button *file)
99 {
100     switch (file->state) {
101     case 1:
102 	file->loader->done(file->wdata);
103 	break;
104     case 2:
105 	desc_resize.done(file->wdata);
106 	break;
107     }
108     file->state = 0;
109 
110     if (file->wimg.p) {
111         ida_image_free(&file->wimg);
112     }
113     if (file->simg.p) {
114         ida_image_free(&file->simg);
115     }
116     if (!list_empty(&file->queue)) {
117 	list_del_init(&file->queue);
118     }
119 }
120 
fileinfo_details(struct file_button * file)121 static void fileinfo_details(struct file_button *file)
122 {
123     struct ida_image_info *img;
124     struct ida_extra *extra;
125     char buf[80];
126 
127     img = &file->info->img;
128     snprintf(buf, sizeof(buf), "%dx%d",
129 	     img->thumbnail ? img->real_width  : img->width,
130 	     img->thumbnail ? img->real_height : img->height);
131     XmStringFree(file->details[DETAIL_SIZE]);
132     file->details[DETAIL_SIZE] = XmStringGenerate(buf, NULL, XmMULTIBYTE_TEXT,NULL);
133 
134     extra = load_find_extra(img, EXTRA_COMMENT);
135     if (extra) {
136 	XmStringFree(file->details[DETAIL_COMMENT]);
137 	file->details[DETAIL_COMMENT] =
138 	    XmStringGenerate(extra->data, NULL, XmMULTIBYTE_TEXT,NULL);
139     }
140 
141     XtVaSetValues(file->widget,
142 		  XmNdetail, file->details,
143 		  XmNdetailCount, DETAIL_COUNT,
144 		  NULL);
145 }
146 
147 static Boolean
fileinfo_loader(XtPointer clientdata)148 fileinfo_loader(XtPointer clientdata)
149 {
150     struct op_resize_parm resize;
151     struct ida_rect rect;
152     struct list_head *item;
153     struct file_button *file;
154     struct fileinfo *info;
155     Pixmap pix;
156     char blk[512];
157     FILE *fp;
158     float xs,ys,scale;
159     struct ida_image timg;
160     void *data;
161 
162     if (list_empty(&pqueue)) {
163 	/* nothing to do */
164 	pproc = 0;
165 	return TRUE;
166     }
167     file = list_entry(pqueue.next, struct file_button, queue);
168 
169     switch (file->state) {
170     case 0:
171 	/* ------------------- new file -------------------- */
172 	info = fileinfo_cache_get(file->filename);
173 	if (info) {
174 	    file_set_info(file,info);
175 	    goto next;
176 	}
177 
178 	/* open file */
179 	if (NULL == (fp = fopen(file->filename, "r"))) {
180 	    if (debug)
181 		fprintf(stderr,"open %s: %s\n",file->filename,
182 			strerror(errno));
183 	    goto unknown;
184 	}
185 	if (debug)
186 	    fprintf(stderr,"OPENED: %s\n",file->filename);
187 	fstat(fileno(fp),&file->st);
188 
189 	/* pick loader */
190 	memset(blk,0,sizeof(blk));
191 	fread(blk,1,sizeof(blk),fp);
192 	rewind(fp);
193 	list_for_each(item,&loaders) {
194 	    file->loader = list_entry(item, struct ida_loader, list);
195 	    if (NULL == file->loader->magic)
196 		continue;
197 	    if (0 == memcmp(blk+file->loader->moff,file->loader->magic,
198 			    file->loader->mlen))
199 		break;
200 	    file->loader = NULL;
201 	}
202 	if (NULL == file->loader) {
203 	    if (debug)
204 		fprintf(stderr,"%s: unknown format\n",file->filename);
205 	    fclose(fp);
206 	    goto unknown;
207 	}
208 
209 	/* load image */
210 	file->wdata = file->loader->init(fp, file->filename,
211 					 0, &file->wimg.i, 1);
212 	if (NULL == file->wdata) {
213 	    if (debug)
214 		fprintf(stderr,"loading %s [%s] FAILED\n",
215 			file->filename, file->loader->name);
216 	    goto unknown;
217 	}
218 
219         ida_image_alloc(&file->wimg);
220 	file->state = 1;
221 	file->y     = 0;
222 	return FALSE;
223 
224     case 1:
225 	/* ------------------- loading file -------------------- */
226 	if (file->y < file->wimg.i.height) {
227 	    file->loader->read(ida_image_scanline(&file->wimg, file->y),
228 			       file->y, file->wdata);
229 	    file->y++;
230 	    return FALSE;
231 	}
232 	file->loader->done(file->wdata);
233 	if (debug)
234 	    fprintf(stderr,"LOADED: %s [%ux%u]\n",
235 		    file->filename, file->wimg.i.width, file->wimg.i.height);
236 
237 	/* resize image */
238 	xs = (float)GET_ICON_LARGE() / file->wimg.i.width;
239 	ys = (float)GET_ICON_LARGE() / file->wimg.i.height;
240 	scale = (xs < ys) ? xs : ys;
241 	resize.width  = file->wimg.i.width  * scale;
242 	resize.height = file->wimg.i.height * scale;
243 	if (0 == resize.width)
244 	    resize.width = 1;
245 	if (0 == resize.height)
246 	    resize.height = 1;
247 
248 	rect.x1 = 0;
249 	rect.x2 = file->wimg.i.width;
250 	rect.y1 = 0;
251 	rect.y2 = file->wimg.i.height;
252 	file->wdata = desc_resize.init(&file->wimg,&rect,&file->simg.i,&resize);
253         ida_image_alloc(&file->simg);
254 
255 	file->state = 2;
256 	file->y     = 0;
257 	return FALSE;
258 
259     case 2:
260 	/* ------------------- scaling file -------------------- */
261 	if (file->y < file->simg.i.height) {
262 	    desc_resize.work(&file->wimg,&rect,
263                              ida_image_scanline(&file->simg, file->y),
264 			     file->y, file->wdata);
265 	    file->y++;
266 	    return FALSE;
267 	}
268 	desc_resize.done(file->wdata);
269 	if (debug)
270 	    fprintf(stderr,"SCALED: %s [%ux%u]\n",
271 		    file->filename,file->simg.i.width,file->simg.i.height);
272 
273 	/* scale once more (small icon) */
274 	xs = (float)GET_ICON_SMALL() / file->simg.i.width;
275 	ys = (float)GET_ICON_SMALL() / file->simg.i.height;
276 	scale = (xs < ys) ? xs : ys;
277 	resize.width  = file->simg.i.width  * scale;
278 	resize.height = file->simg.i.height * scale;
279 	if (0 == resize.width)
280 	    resize.width = 1;
281 	if (0 == resize.height)
282 	    resize.height = 1;
283 
284 	rect.x1 = 0;
285 	rect.x2 = file->simg.i.width;
286 	rect.y1 = 0;
287 	rect.y2 = file->simg.i.height;
288         memset(&timg, 0, sizeof(timg));
289 	data = desc_resize.init(&file->simg,&rect,&timg.i,&resize);
290 	ida_image_alloc(&timg);
291 
292 	for (file->y = 0; file->y < timg.i.height; file->y++)
293 	    desc_resize.work(&file->simg,&rect,
294                              ida_image_scanline(&timg, file->y),
295 			     file->y, data);
296 	desc_resize.done(data);
297 
298 	/* build, cache + install pixmap */
299 	info = fileinfo_cache_add(file->filename,&file->wimg.i,
300 				  image_to_pixmap(&timg),
301 				  image_to_pixmap(&file->simg));
302 	file_set_info(file,info);
303 	ida_image_free(&timg);
304 	file->state = 0;
305 	goto next;
306 
307     default:
308 	/* shouldn't happen */
309 	fprintf(stderr,"Oops: %s:%d\n",__FILE__,__LINE__);
310 	exit(1);
311     }
312 
313  unknown:
314     /* generic file icon */
315     pix = XmGetPixmap(file->screen,"unknown",0,0);
316     file_set_icon(file,pix,pix);
317 
318  next:
319     fileinfo_cleanup(file);
320     return FALSE;
321 }
322 
323 /*----------------------------------------------------------------------*/
324 
fileinfo_queue(struct file_button * file)325 void fileinfo_queue(struct file_button *file)
326 {
327     if (NULL == file->queue.next)
328 	INIT_LIST_HEAD(&file->queue);
329 
330     if (!list_empty(&file->queue)) {
331 	/* already queued */
332 	if (0 == file->state)
333 	    return;
334 	fileinfo_cleanup(file);
335     }
336 
337     file->state = 0;
338     memset(&file->wimg,0,sizeof(file->wimg));
339     memset(&file->simg,0,sizeof(file->simg));
340     list_add_tail(&file->queue,&pqueue);
341     if (0 == pproc)
342 	pproc = XtAppAddWorkProc(app_context,fileinfo_loader,NULL);
343 }
344 
fileinfo_invalidate(char * filename)345 void fileinfo_invalidate(char *filename)
346 {
347     struct file_button  *file;
348     struct list_head    *item;
349     Pixmap              pix;
350 
351     if (debug)
352 	fprintf(stderr,"fileinfo invalidate: %s\n",filename);
353     fileinfo_cache_del(filename);
354 
355     list_for_each(item,&files) {
356 	file = list_entry(item, struct file_button, global);
357 	if (0 != strcmp(file->filename,filename))
358 	    continue;
359 	if (debug)
360 	    fprintf(stderr,"  %p %s\n",file,filename);
361 	file->info = NULL;
362 	pix = XmGetPixmap(file->screen,"file",0,0);
363 	file_set_icon(file,pix,pix);
364 	fileinfo_queue(file);
365     }
366 }
367 
368 /*----------------------------------------------------------------------*/
369 
370 static void
container_ops_cb(Widget widget,XtPointer clientdata,XtPointer call_data)371 container_ops_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
372 {
373     Widget container = clientdata;
374     WidgetList children;
375     Cardinal nchildren,i;
376 
377     XtVaGetValues(container,
378 		  XmNselectedObjects,&children,
379 		  XmNselectedObjectCount,&nchildren,
380 		  NULL);
381     for (i = 0; i < nchildren; i++) {
382 	struct stat st;
383 	if (-1 == stat(XtName(children[i]),&st))
384 	    continue;
385 	if (!S_ISREG(st.st_mode))
386 	    continue;
387 	job_submit(XtName(widget),XtName(children[i]), NULL);
388     }
389 }
390 
391 static void
comment_box_cb(Widget widget,XtPointer clientdata,XtPointer calldata)392 comment_box_cb(Widget widget, XtPointer clientdata, XtPointer calldata)
393 {
394     Widget container = clientdata;
395     XmSelectionBoxCallbackStruct *cd = calldata;
396     WidgetList children;
397     Cardinal nchildren,i;
398     Widget text;
399     char *comment;
400 
401     if (XmCR_OK == cd->reason) {
402 	/* TODO */
403 	text = XmSelectionBoxGetChild(widget,XmDIALOG_TEXT);
404 	comment = XmTextGetString(text);
405 	XtVaGetValues(container,
406 		      XmNselectedObjects,&children,
407 		      XmNselectedObjectCount,&nchildren,
408 		      NULL);
409 	for (i = 0; i < nchildren; i++) {
410 	    struct stat st;
411 	    if (-1 == stat(XtName(children[i]),&st))
412 		continue;
413 	    if (!S_ISREG(st.st_mode))
414 		continue;
415 	    job_submit("comment",XtName(children[i]), comment);
416 	}
417     }
418     XtDestroyWidget(XtParent(widget));
419 }
420 
421 static void
container_comment_cb(Widget widget,XtPointer clientdata,XtPointer call_data)422 container_comment_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
423 {
424     Widget container = clientdata;
425     Widget box,text;
426     WidgetList children;
427     Cardinal nchildren;
428     static struct fileinfo *info;
429     struct ida_extra *extra;
430     char *comment = "";
431 
432     XtVaGetValues(container,
433 		  XmNselectedObjects,&children,
434 		  XmNselectedObjectCount,&nchildren,
435 		  NULL);
436     switch (nchildren) {
437     case 0:
438 	/* nothing to do */
439 	return;
440     case 1:
441 	/* get old comment */
442 	info = fileinfo_cache_get(XtName(children[0]));
443 	if (!info)
444 	    /* not a image */
445 	    return;
446 	extra = load_find_extra(&info->img, EXTRA_COMMENT);
447 	if (extra)
448 	    comment = extra->data;
449 	break;
450     default:
451 	/* start with a empty comment */
452 	break;
453     }
454 
455     /* dialog box */
456     box = XmCreatePromptDialog(container,"comment",NULL,0);
457     XtUnmanageChild(XmSelectionBoxGetChild(box,XmDIALOG_HELP_BUTTON));
458     XmdRegisterEditres(XtParent(box));
459     XtAddCallback(box,XmNokCallback,comment_box_cb,clientdata);
460     XtAddCallback(box,XmNcancelCallback,comment_box_cb,clientdata);
461     XtAddCallback(XtParent(box),XmNdestroyCallback,destroy_cb,XtParent(box));
462 
463     text = XmSelectionBoxGetChild(box,XmDIALOG_TEXT);
464     XmTextSetString(text,comment);
465     XmTextSetInsertionPosition(text,strlen(comment));
466     XtManageChild(box);
467 }
468 
container_menu_ops(Widget menu,Widget container)469 void container_menu_ops(Widget menu, Widget container)
470 {
471     Widget push;
472 
473     push = XtVaCreateManagedWidget("rotexif",xmPushButtonWidgetClass,menu,NULL);
474     XtAddCallback(push,XmNactivateCallback,container_ops_cb,container);
475     push = XtVaCreateManagedWidget("rotcw",xmPushButtonWidgetClass,menu,NULL);
476     XtAddCallback(push,XmNactivateCallback,container_ops_cb,container);
477     push = XtVaCreateManagedWidget("rotccw",xmPushButtonWidgetClass,menu,NULL);
478     XtAddCallback(push,XmNactivateCallback,container_ops_cb,container);
479     push = XtVaCreateManagedWidget("comment",xmPushButtonWidgetClass,menu,NULL);
480     XtAddCallback(push,XmNactivateCallback,container_comment_cb,container);
481 }
482 
483 /*----------------------------------------------------------------------*/
484 
485 void
container_resize_eh(Widget widget,XtPointer clientdata,XEvent * event,Boolean * d)486 container_resize_eh(Widget widget, XtPointer clientdata, XEvent *event, Boolean *d)
487 {
488     Widget clip,scroll,container;
489     Dimension width, height, ch;
490 
491     clip = widget;
492     scroll = XtParent(widget);
493     XtVaGetValues(scroll,XmNworkWindow,&container,NULL);
494 
495     XtVaGetValues(clip,
496 		  XtNwidth,  &width,
497 		  XtNheight, &height,
498 		  NULL);
499     XtVaGetValues(container,
500 		  XtNheight, &ch,
501 		  NULL);
502     if (ch < height-5)
503 	ch = height-5;
504     XtVaSetValues(container,
505 		  XtNwidth, width-5,
506 		  XtNheight,ch,
507 		  NULL);
508     container_relayout(container);
509 }
510 
511 void
container_spatial_cb(Widget widget,XtPointer clientdata,XtPointer call_data)512 container_spatial_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
513 {
514     Widget container = clientdata;
515     WidgetList children;
516     Cardinal nchildren;
517 
518     XtVaSetValues(container,
519 		  XmNlayoutType,    XmSPATIAL,
520 		  XmNspatialStyle,  XmNONE,
521 		  NULL);
522     nchildren = XmContainerGetItemChildren(container,NULL,&children);
523     if (nchildren) {
524 	XtFree((XtPointer)children);
525 	/* FIXME: Hmm, why ??? */
526 	XtVaSetValues(container,
527 		      XmNentryViewType, XmLARGE_ICON,
528 		      NULL);
529     }
530     container_relayout(container);
531 }
532 
container_detail_cb(Widget widget,XtPointer clientdata,XtPointer call_data)533 void container_detail_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
534 {
535     Widget container = clientdata;
536 
537     XtVaSetValues(container,
538 		  XmNlayoutType,    XmDETAIL,
539 		  XmNentryViewType, XmSMALL_ICON,
540 		  NULL);
541     container_relayout(container);
542 }
543 
544 void
container_traverse_cb(Widget scroll,XtPointer clientdata,XtPointer call_data)545 container_traverse_cb(Widget scroll, XtPointer clientdata, XtPointer call_data)
546 {
547     XmTraverseObscuredCallbackStruct *cd = call_data;
548 
549     if (cd->reason == XmCR_OBSCURED_TRAVERSAL)
550 	XmScrollVisible(scroll, cd->traversal_destination, 25, 25);
551 }
552 
553 void
container_convert_cb(Widget widget,XtPointer clientdata,XtPointer call_data)554 container_convert_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
555 {
556     XmConvertCallbackStruct *ccs = call_data;
557     char *file = NULL;
558     Atom *targs;
559     int i,n,len;
560     WidgetList children;
561     Cardinal nchildren;
562 
563     if (ccs->location_data) {
564 	Widget item = ccs->location_data;
565 	children  = &item;
566 	nchildren = 1;
567     } else {
568 	XtVaGetValues(widget,
569 		      XmNselectedObjects,&children,
570 		      XmNselectedObjectCount,&nchildren,
571 		      NULL);
572     }
573 
574     if (debug) {
575 	char *t = !ccs->target    ? NULL : XGetAtomName(dpy,ccs->target);
576 	char *s = !ccs->selection ? NULL : XGetAtomName(dpy,ccs->selection);
577 	fprintf(stderr,"drag: target=%s selection=%s [%d files,%p]\n",
578 		t, s, nchildren, ccs->location_data);
579 	if (t) XFree(t);
580 	if (s) XFree(s);
581     }
582 
583     if ((ccs->target == XA_TARGETS)                        ||
584 	(ccs->target == _MOTIF_CLIPBOARD_TARGETS)          ||
585 	(ccs->target == _MOTIF_EXPORT_TARGETS)) {
586 	targs = (Atom*)XtMalloc(sizeof(Atom)*8);
587 	n = 0;
588 	if (nchildren >= 1) {
589 	    targs[n++] = MIME_TEXT_URI_LIST;
590 	}
591 	if (1 == nchildren) {
592 	    targs[n++] = XA_FILE_NAME;
593 	    targs[n++] = XA_FILE;
594 	    targs[n++] = _NETSCAPE_URL;
595 	    targs[n++] = XA_STRING;
596 	}
597     	ccs->value  = targs;
598 	ccs->length = n;
599 	ccs->type   = XA_ATOM;
600 	ccs->format = 32;
601 	ccs->status = XmCONVERT_MERGE;
602 	return;
603     }
604 
605     if (ccs->target == _MOTIF_DEFERRED_CLIPBOARD_TARGETS) {
606 	targs = (Atom*)XtMalloc(sizeof(Atom)*8);
607 	n = 0;
608 	ccs->value  = targs;
609 	ccs->length = n;
610 	ccs->type   = XA_ATOM;
611 	ccs->format = 32;
612 	ccs->status = XmCONVERT_DONE;
613     }
614 
615     if ((ccs->target == _MOTIF_LOSE_SELECTION) ||
616 	(ccs->target == XA_DONE)) {
617 	/* free stuff */
618 	ccs->value  = NULL;
619 	ccs->length = 0;
620 	ccs->type   = XA_INTEGER;
621 	ccs->format = 32;
622 	ccs->status = XmCONVERT_DONE;
623 	return;
624     }
625 
626     if (ccs->target == XA_FILE_NAME ||
627 	ccs->target == XA_FILE      ||
628 	ccs->target == XA_STRING) {
629 	file = XtMalloc(strlen(XtName(children[0])+1));
630 	strcpy(file,XtName(children[0]));
631 	ccs->value  = file;
632 	ccs->length = strlen(file);
633 	ccs->type   = XA_STRING;
634 	ccs->format = 8;
635 	ccs->status = XmCONVERT_DONE;
636 	return;
637     }
638 
639     if (ccs->target == _NETSCAPE_URL ||
640 	ccs->target == MIME_TEXT_URI_LIST) {
641 	for (i = 0, len = 0; i < nchildren; i++)
642 	    len += strlen(XtName(children[i]));
643 	file = XtMalloc(len + 8 * nchildren);
644 	for (i = 0, len = 0; i < nchildren; i++)
645 	    len += sprintf(file+len,"file:%s\n",XtName(children[i]));
646 	ccs->value  = file;
647 	ccs->length = len;
648 	ccs->type   = XA_STRING;
649 	ccs->format = 8;
650 	ccs->status = XmCONVERT_DONE;
651 	return;
652     }
653 
654     ccs->status = XmCONVERT_DEFAULT;
655 }
656 
657 static void
container_copy_cb(Widget widget,XtPointer clientdata,XtPointer call_data)658 container_copy_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
659 {
660     Widget container = clientdata;
661     XmeClipboardSource(container,XmCOPY,XtLastTimestampProcessed(dpy));
662 }
663 
664 static void
container_paste_cb(Widget widget,XtPointer clientdata,XtPointer call_data)665 container_paste_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
666 {
667     Widget container = clientdata;
668     XmeClipboardSink(container,XmCOPY,NULL);
669 }
670 
671 static void
container_del_cb(Widget widget,XtPointer clientdata,XtPointer call_data)672 container_del_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
673 {
674     Widget container = clientdata;
675     WidgetList children,list;
676     Cardinal nchildren,i;
677 
678     XtVaGetValues(container,
679 		  XmNselectedObjects,&children,
680 		  XmNselectedObjectCount,&nchildren,
681 		  NULL);
682     list = malloc(sizeof(Widget*)*nchildren);
683     memcpy(list,children,sizeof(Widget*)*nchildren);
684 
685     XtVaSetValues(container,
686 		  XmNselectedObjectCount,0,
687 		  NULL);
688     XtUnmanageChildren(list,nchildren);
689     for (i = 0; i < nchildren; i++)
690         XtDestroyWidget(list[i]);
691     free(list);
692 }
693 
container_menu_edit(Widget menu,Widget container,int cut,int copy,int paste,int del)694 void container_menu_edit(Widget menu, Widget container,
695 			 int cut, int copy, int paste, int del)
696 {
697     Widget push;
698 
699 #if 0
700     if (cut) {
701 	push = XtVaCreateManagedWidget("cut",xmPushButtonWidgetClass,menu,NULL);
702 	XtAddCallback(push,XmNactivateCallback,
703 		      container_cut_cb,container);
704     }
705 #endif
706     if (copy) {
707 	push = XtVaCreateManagedWidget("copy",xmPushButtonWidgetClass,menu,NULL);
708 	XtAddCallback(push,XmNactivateCallback,
709 		      container_copy_cb,container);
710     }
711     if (paste) {
712 	push = XtVaCreateManagedWidget("paste",xmPushButtonWidgetClass,menu,NULL);
713 	XtAddCallback(push,XmNactivateCallback,
714 		      container_paste_cb,container);
715     }
716     if (del) {
717 	push = XtVaCreateManagedWidget("del",xmPushButtonWidgetClass,menu,NULL);
718 	XtAddCallback(push,XmNactivateCallback,
719 		      container_del_cb,container);
720     }
721 }
722 
container_menu_view(Widget menu,Widget container)723 void container_menu_view(Widget menu, Widget container)
724 {
725     Widget push;
726 
727     push = XtVaCreateManagedWidget("details",xmPushButtonWidgetClass,menu,NULL);
728     XtAddCallback(push,XmNactivateCallback,
729 		  container_detail_cb,container);
730     push = XtVaCreateManagedWidget("spatial",xmPushButtonWidgetClass,menu,NULL);
731     XtAddCallback(push,XmNactivateCallback,
732 		  container_spatial_cb,container);
733 }
734 
735 void
container_relayout(Widget container)736 container_relayout(Widget container)
737 {
738     Widget clip = XtParent(container);
739     WidgetList children;
740     Cardinal nchildren;
741     Dimension wwidth,wheight;
742     Dimension iwidth,iheight;
743     Position x,y;
744     unsigned char layout,style;
745     int i,margin = 10;
746 
747     XtVaGetValues(container,
748 		  XmNlayoutType,   &layout,
749 		  XmNspatialStyle, &style,
750 		  NULL);
751     if (XmSPATIAL != layout || XmNONE != style) {
752 	XmContainerRelayout(container);
753 	return;
754     }
755 
756     nchildren = XmContainerGetItemChildren(container,NULL,&children);
757     XtVaGetValues(clip,
758 		  XtNwidth,  &wwidth,
759 		  XtNheight, &wheight,
760 		  NULL);
761 
762     wwidth -= 5;
763     x = margin; y = margin;
764     for (i = 0; i < nchildren; i++) {
765 	if (!XtIsManaged(children[i]))
766 	    continue;
767 	XtVaGetValues(children[i],
768 		      XtNwidth,&iwidth,
769 		      XtNheight,&iheight,
770 		      NULL);
771 	if (x > 0 && x + iwidth + margin > wwidth) {
772 	    /* new row */
773 	    x = margin; y += iheight + margin;
774 	}
775 	XtVaSetValues(children[i],
776 		      XtNx,x, XtNy,y,
777 		      XmNpositionIndex,i,
778 		      NULL);
779 	x += iwidth + margin;
780     }
781 
782     if (wheight < y + iheight + margin)
783 	wheight = y + iheight + margin;
784     XtVaSetValues(container,
785 		  XtNwidth,  wwidth,
786 		  XtNheight, wheight,
787 		  NULL);
788     if (nchildren)
789 	XtFree((XtPointer)children);
790 }
791 
792 void
container_delwidgets(Widget container)793 container_delwidgets(Widget container)
794 {
795     WidgetList children;
796     Cardinal nchildren;
797     unsigned int i;
798 
799     /* delete widgets */
800     XtVaSetValues(container,
801 		  XmNselectedObjectCount,0,
802 		  NULL);
803     nchildren = XmContainerGetItemChildren(container,NULL,&children);
804     XtUnmanageChildren(children,nchildren);
805     for (i = 0; i < nchildren; i++)
806         XtDestroyWidget(children[i]);
807     if (nchildren)
808 	XtFree((XtPointer)children);
809 }
810 
811 /*----------------------------------------------------------------------*/
812 
file_set_icon(struct file_button * file,Pixmap s,Pixmap l)813 void file_set_icon(struct file_button *file, Pixmap s, Pixmap l)
814 {
815     Pixmap large, small;
816     Pixel background;
817 
818     if (file->info)
819 	return;
820 
821     XtVaGetValues(file->widget, XmNbackground,&background, NULL);
822     small = x11_icon_fit(DisplayOfScreen(file->screen), s, background,
823 			 GET_ICON_SMALL(), GET_ICON_SMALL());
824     large = x11_icon_fit(DisplayOfScreen(file->screen), l, background,
825 			 GET_ICON_LARGE(), GET_ICON_LARGE());
826     XtVaSetValues(file->widget,
827 		  XmNsmallIconPixmap, small,
828 		  XmNlargeIconPixmap, large,
829 		  NULL);
830     if (file->small)
831 	XFreePixmap(DisplayOfScreen(file->screen),file->small);
832     if (file->large)
833 	XFreePixmap(DisplayOfScreen(file->screen),file->large);
834     file->small = small;
835     file->large = large;
836 }
837 
file_set_info(struct file_button * file,struct fileinfo * info)838 void file_set_info(struct file_button *file, struct fileinfo *info)
839 {
840     file->info = NULL;
841     file_set_icon(file,info->small,info->large);
842     file->info = info;
843     fileinfo_details(file);
844 }
845 
846 #if 0
847 static void
848 file_copy_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
849 {
850     struct file_button *file = clientdata;
851 
852     XmeClipboardSource(file->widget,XmCOPY,XtLastTimestampProcessed(dpy));
853 }
854 #endif
855 
856 /*----------------------------------------------------------------------*/
857 
file_cmp_alpha(const struct file_button * aa,const struct file_button * bb)858 int file_cmp_alpha(const struct file_button *aa,
859 		   const struct file_button *bb)
860 {
861     if (S_ISDIR(aa->st.st_mode) != S_ISDIR(bb->st.st_mode))
862 	return S_ISDIR(aa->st.st_mode) ? -1 : 1;
863     return strcmp(aa->basename,bb->basename);
864 }
865 
866 static void
file_destroy_cb(Widget widget,XtPointer clientdata,XtPointer call_data)867 file_destroy_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
868 {
869     struct file_button *file = clientdata;
870     int i;
871 
872     if (debug)
873 	fprintf(stderr,"file: del %p [%s]\n",file,file->filename);
874 
875     if (NULL != file->queue.next)
876 	fileinfo_cleanup(file);
877 
878     if (file->basename)
879 	free(file->basename);
880     if (file->filename)
881 	free(file->filename);
882 
883     XtVaSetValues(file->widget,
884 		  XmNsmallIconPixmap, XmUNSPECIFIED_PIXMAP,
885 		  XmNlargeIconPixmap, XmUNSPECIFIED_PIXMAP,
886 		  NULL);
887     if (file->small)
888 	XFreePixmap(DisplayOfScreen(file->screen),file->small);
889     if (file->large)
890 	XFreePixmap(DisplayOfScreen(file->screen),file->large);
891 
892     if (file->label)
893 	XmStringFree(file->label);
894     for (i = 0; i < DETAIL_COUNT; i++)
895 	if (file->details[i])
896 	    XmStringFree(file->details[i]);
897 
898     list_del(&file->global);
899     list_del(&file->window);
900     free(file);
901 }
902 
file_createwidgets(Widget parent,struct file_button * file)903 int file_createwidgets(Widget parent, struct file_button *file)
904 {
905     struct fileinfo *info;
906     Pixmap pix;
907     Arg args[8];
908     int i, n = 0;
909 
910     if (debug)
911 	fprintf(stderr,"file: new %p [%s]\n",file,file->filename);
912 
913     file->screen = XtScreen(parent);
914     file->label  = XmStringGenerate(file->basename, NULL, XmMULTIBYTE_TEXT,NULL);
915     for (i = 0; i < DETAIL_COUNT; i++)
916 	file->details[i] = XmStringGenerate("-", NULL, XmMULTIBYTE_TEXT,NULL);
917 
918     XtSetArg(args[n], XmNlabelString,     file->label);   n++;
919     XtSetArg(args[n], XmNdetail,          file->details); n++;
920     XtSetArg(args[n], XmNdetailCount,     DETAIL_COUNT);  n++;
921     file->widget = XmCreateIconGadget(parent,file->filename,args,n);
922     XtAddCallback(file->widget,XtNdestroyCallback,file_destroy_cb,file);
923     list_add_tail(&file->global,&files);
924 
925     info = fileinfo_cache_get(file->filename);
926     if (info) {
927 	file_set_info(file,info);
928     } else {
929 	pix = XmGetPixmap(file->screen,"question",0,0);
930 	file_set_icon(file,pix,pix);
931     }
932     return 0;
933 }
934