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