From e9e9684117719204929821028ba9dbb7915ea119 Mon Sep 17 00:00:00 2001 From: kraxel Date: Sun, 28 Mar 2004 11:31:57 +0000 Subject: Initial revision --- filebutton.c | 934 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 934 insertions(+) create mode 100644 filebutton.c (limited to 'filebutton.c') diff --git a/filebutton.c b/filebutton.c new file mode 100644 index 0000000..3f922e2 --- /dev/null +++ b/filebutton.c @@ -0,0 +1,934 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "RegEdit.h" +#include "list.h" +#include "ida.h" +#include "x11.h" +#include "icons.h" +#include "readers.h" +#include "filter.h" +#include "viewer.h" +#include "selections.h" +#include "filebutton.h" +#include "fileops.h" +#include "idaconfig.h" + +/*----------------------------------------------------------------------*/ + +struct fileinfo { + struct list_head list; + char *path; + struct ida_image_info img; + Pixmap small; + Pixmap large; +}; + +static LIST_HEAD(pcache); +static LIST_HEAD(pqueue); +static LIST_HEAD(files); +static XtWorkProcId pproc; + +/*----------------------------------------------------------------------*/ + +static struct fileinfo* +fileinfo_cache_add(char *path, struct ida_image_info *img, + Pixmap small, Pixmap large) +{ + struct fileinfo *item; + + item = malloc(sizeof(*item)); + memset(item,0,sizeof(*item)); + item->path = strdup(path); + item->img = *img; + item->small = small; + item->large = large; + list_add_tail(&item->list,&pcache); + return item; +} + +static void fileinfo_cache_del(char *path) +{ + struct list_head *item; + struct fileinfo *b; + + list_for_each(item,&pcache) { + b = list_entry(item,struct fileinfo,list); + if (0 == strcmp(path,b->path)) { + list_del(&b->list); + free(b); + return; + } + } +} + +static struct fileinfo* fileinfo_cache_get(char *path) +{ + struct list_head *item; + struct fileinfo *b; + + list_for_each(item,&pcache) { + b = list_entry(item,struct fileinfo,list); + if (0 == strcmp(path,b->path)) + return b; + } + return 0; +} + +/*----------------------------------------------------------------------*/ + +static void +fileinfo_cleanup(struct file_button *file) +{ + switch (file->state) { + case 1: + file->loader->done(file->wdata); + break; + case 2: + desc_resize.done(file->wdata); + break; + } + file->state = 0; + + if (file->wimg.data) { + free(file->wimg.data); + file->wimg.data = NULL; + } + if (file->simg.data) { + free(file->simg.data); + file->simg.data = NULL; + } + if (!list_empty(&file->queue)) { + list_del_init(&file->queue); + } +} + +static void fileinfo_details(struct file_button *file) +{ + struct ida_image_info *img; + struct ida_extra *extra; + char buf[80]; + + img = &file->info->img; + snprintf(buf, sizeof(buf), "%dx%d", + img->thumbnail ? img->real_width : img->width, + img->thumbnail ? img->real_height : img->height); + XmStringFree(file->details[DETAIL_SIZE]); + file->details[DETAIL_SIZE] = XmStringGenerate(buf, NULL, XmMULTIBYTE_TEXT,NULL); + + extra = load_find_extra(img, EXTRA_COMMENT); + if (extra) { + XmStringFree(file->details[DETAIL_COMMENT]); + file->details[DETAIL_COMMENT] = + XmStringGenerate(extra->data, NULL, XmMULTIBYTE_TEXT,NULL); + } + + XtVaSetValues(file->widget, + XmNdetail, file->details, + XmNdetailCount, DETAIL_COUNT, + NULL); +} + +static Boolean +fileinfo_loader(XtPointer clientdata) +{ + struct op_resize_parm resize; + struct ida_rect rect; + struct list_head *item; + struct file_button *file; + struct fileinfo *info; + Pixmap pix; + char blk[512]; + FILE *fp; + float xs,ys,scale; + struct ida_image timg; + void *data; + + if (list_empty(&pqueue)) { + /* nothing to do */ + pproc = 0; + return TRUE; + } + file = list_entry(pqueue.next, struct file_button, queue); + + switch (file->state) { + case 0: + /* ------------------- new file -------------------- */ + info = fileinfo_cache_get(file->filename); + if (info) { + file_set_info(file,info); + goto next; + } + + /* open file */ + if (NULL == (fp = fopen(file->filename, "r"))) { + if (debug) + fprintf(stderr,"open %s: %s\n",file->filename, + strerror(errno)); + goto unknown; + } + if (debug) + fprintf(stderr,"OPENED: %s\n",file->filename); + fstat(fileno(fp),&file->st); + + /* pick loader */ + memset(blk,0,sizeof(blk)); + fread(blk,1,sizeof(blk),fp); + rewind(fp); + list_for_each(item,&loaders) { + file->loader = list_entry(item, struct ida_loader, list); + if (NULL == file->loader->magic) + continue; + if (0 == memcmp(blk+file->loader->moff,file->loader->magic, + file->loader->mlen)) + break; + file->loader = NULL; + } + if (NULL == file->loader) { + if (debug) + fprintf(stderr,"%s: unknown format\n",file->filename); + fclose(fp); + goto unknown; + } + + /* load image */ + file->wdata = file->loader->init(fp, file->filename, + 0, &file->wimg.i, 1); + if (NULL == file->wdata) { + if (debug) + fprintf(stderr,"loading %s [%s] FAILED\n", + file->filename, file->loader->name); + goto unknown; + } + + file->wimg.data = malloc(file->wimg.i.width * file->wimg.i.height * 3); + file->state = 1; + file->y = 0; + return FALSE; + + case 1: + /* ------------------- loading file -------------------- */ + if (file->y < file->wimg.i.height) { + file->loader->read(file->wimg.data + + 3 * file->y * file->wimg.i.width, + file->y, file->wdata); + file->y++; + return FALSE; + } + file->loader->done(file->wdata); + if (debug) + fprintf(stderr,"LOADED: %s [%dx%d]\n", + file->filename, file->wimg.i.width, file->wimg.i.height); + + /* resize image */ + xs = (float)GET_ICON_LARGE() / file->wimg.i.width; + ys = (float)GET_ICON_LARGE() / file->wimg.i.height; + scale = (xs < ys) ? xs : ys; + resize.width = file->wimg.i.width * scale; + resize.height = file->wimg.i.height * scale; + if (0 == resize.width) + resize.width = 1; + if (0 == resize.height) + resize.height = 1; + + rect.x1 = 0; + rect.x2 = file->wimg.i.width; + rect.y1 = 0; + rect.y2 = file->wimg.i.height; + file->wdata = desc_resize.init(&file->wimg,&rect,&file->simg.i,&resize); + file->simg.data = malloc(file->simg.i.width * file->simg.i.height * 3); + + file->state = 2; + file->y = 0; + return FALSE; + + case 2: + /* ------------------- scaling file -------------------- */ + if (file->y < file->simg.i.height) { + desc_resize.work(&file->wimg,&rect, file->simg.data + + 3 * file->simg.i.width * file->y, + file->y, file->wdata); + file->y++; + return FALSE; + } + desc_resize.done(file->wdata); + if (debug) + fprintf(stderr,"SCALED: %s [%dx%d]\n", + file->filename,file->simg.i.width,file->simg.i.height); + + /* scale once more (small icon) */ + xs = (float)GET_ICON_SMALL() / file->simg.i.width; + ys = (float)GET_ICON_SMALL() / file->simg.i.height; + scale = (xs < ys) ? xs : ys; + resize.width = file->simg.i.width * scale; + resize.height = file->simg.i.height * scale; + if (0 == resize.width) + resize.width = 1; + if (0 == resize.height) + resize.height = 1; + + rect.x1 = 0; + rect.x2 = file->simg.i.width; + rect.y1 = 0; + rect.y2 = file->simg.i.height; + data = desc_resize.init(&file->simg,&rect,&timg.i,&resize); + timg.data = malloc(timg.i.width * timg.i.height * 3); + + for (file->y = 0; file->y < timg.i.height; file->y++) + desc_resize.work(&file->simg,&rect, + timg.data + 3 * timg.i.width * file->y, + file->y, data); + desc_resize.done(data); + + /* build, cache + install pixmap */ + info = fileinfo_cache_add(file->filename,&file->wimg.i, + image_to_pixmap(&timg), + image_to_pixmap(&file->simg)); + file_set_info(file,info); + free(timg.data); + file->state = 0; + goto next; + + default: + /* shouldn't happen */ + fprintf(stderr,"Oops: %s:%d\n",__FILE__,__LINE__); + exit(1); + } + + unknown: + /* generic file icon */ + pix = XmGetPixmap(file->screen,"unknown",0,0); + file_set_icon(file,pix,pix); + + next: + fileinfo_cleanup(file); + return FALSE; +} + +/*----------------------------------------------------------------------*/ + +void fileinfo_queue(struct file_button *file) +{ + if (NULL == file->queue.next) + INIT_LIST_HEAD(&file->queue); + + if (!list_empty(&file->queue)) { + /* already queued */ + if (0 == file->state) + return; + fileinfo_cleanup(file); + } + + file->state = 0; + memset(&file->wimg,0,sizeof(file->wimg)); + memset(&file->simg,0,sizeof(file->simg)); + list_add_tail(&file->queue,&pqueue); + if (0 == pproc) + pproc = XtAppAddWorkProc(app_context,fileinfo_loader,NULL); +} + +void fileinfo_invalidate(char *filename) +{ + struct file_button *file; + struct list_head *item; + Pixmap pix; + + if (debug) + fprintf(stderr,"fileinfo invalidate: %s\n",filename); + fileinfo_cache_del(filename); + + list_for_each(item,&files) { + file = list_entry(item, struct file_button, global); + if (0 != strcmp(file->filename,filename)) + continue; + if (debug) + fprintf(stderr," %p %s\n",file,filename); + file->info = NULL; + pix = XmGetPixmap(file->screen,"file",0,0); + file_set_icon(file,pix,pix); + fileinfo_queue(file); + } +} + +/*----------------------------------------------------------------------*/ + +static void +container_ops_cb(Widget widget, XtPointer clientdata, XtPointer call_data) +{ + Widget container = clientdata; + WidgetList children; + Cardinal nchildren,i; + + XtVaGetValues(container, + XmNselectedObjects,&children, + XmNselectedObjectCount,&nchildren, + NULL); + for (i = 0; i < nchildren; i++) { + struct stat st; + if (-1 == stat(XtName(children[i]),&st)) + continue; + if (!S_ISREG(st.st_mode)) + continue; + job_submit(XtName(widget),XtName(children[i]), NULL); + } +} + +static void +comment_box_cb(Widget widget, XtPointer clientdata, XtPointer calldata) +{ + Widget container = clientdata; + XmSelectionBoxCallbackStruct *cd = calldata; + WidgetList children; + Cardinal nchildren,i; + Widget text; + char *comment; + + if (XmCR_OK == cd->reason) { + /* TODO */ + text = XmSelectionBoxGetChild(widget,XmDIALOG_TEXT); + comment = XmTextGetString(text); + XtVaGetValues(container, + XmNselectedObjects,&children, + XmNselectedObjectCount,&nchildren, + NULL); + for (i = 0; i < nchildren; i++) { + struct stat st; + if (-1 == stat(XtName(children[i]),&st)) + continue; + if (!S_ISREG(st.st_mode)) + continue; + job_submit("comment",XtName(children[i]), comment); + } + } + XtDestroyWidget(XtParent(widget)); +} + +static void +container_comment_cb(Widget widget, XtPointer clientdata, XtPointer call_data) +{ + Widget container = clientdata; + Widget box,text; + WidgetList children; + Cardinal nchildren; + static struct fileinfo *info; + struct ida_extra *extra; + char *comment = ""; + + XtVaGetValues(container, + XmNselectedObjects,&children, + XmNselectedObjectCount,&nchildren, + NULL); + switch (nchildren) { + case 0: + /* nothing to do */ + return; + case 1: + /* get old comment */ + info = fileinfo_cache_get(XtName(children[0])); + if (!info) + /* not a image */ + return; + extra = load_find_extra(&info->img, EXTRA_COMMENT); + if (extra) + comment = extra->data; + break; + default: + /* start with a empty comment */ + break; + } + + /* dialog box */ + box = XmCreatePromptDialog(container,"comment",NULL,0); + XtUnmanageChild(XmSelectionBoxGetChild(box,XmDIALOG_HELP_BUTTON)); + XmdRegisterEditres(XtParent(box)); + XtAddCallback(box,XmNokCallback,comment_box_cb,clientdata); + XtAddCallback(box,XmNcancelCallback,comment_box_cb,clientdata); + XtAddCallback(XtParent(box),XmNdestroyCallback,destroy_cb,XtParent(box)); + + text = XmSelectionBoxGetChild(box,XmDIALOG_TEXT); + XmTextSetString(text,comment); + XmTextSetInsertionPosition(text,strlen(comment)); + XtManageChild(box); +} + +void container_menu_ops(Widget menu, Widget container) +{ + Widget push; + + push = XtVaCreateManagedWidget("rotexif",xmPushButtonWidgetClass,menu,NULL); + XtAddCallback(push,XmNactivateCallback,container_ops_cb,container); + push = XtVaCreateManagedWidget("rotcw",xmPushButtonWidgetClass,menu,NULL); + XtAddCallback(push,XmNactivateCallback,container_ops_cb,container); + push = XtVaCreateManagedWidget("rotccw",xmPushButtonWidgetClass,menu,NULL); + XtAddCallback(push,XmNactivateCallback,container_ops_cb,container); + push = XtVaCreateManagedWidget("comment",xmPushButtonWidgetClass,menu,NULL); + XtAddCallback(push,XmNactivateCallback,container_comment_cb,container); +} + +/*----------------------------------------------------------------------*/ + +void +container_resize_eh(Widget widget, XtPointer clientdata, XEvent *event, Boolean *d) +{ + Widget clip,scroll,container; + Dimension width, height, ch; + + clip = widget; + scroll = XtParent(widget); + XtVaGetValues(scroll,XmNworkWindow,&container,NULL); + + XtVaGetValues(clip, + XtNwidth, &width, + XtNheight, &height, + NULL); + XtVaGetValues(container, + XtNheight, &ch, + NULL); + if (ch < height-5) + ch = height-5; + XtVaSetValues(container, + XtNwidth, width-5, + XtNheight,ch, + NULL); + container_relayout(container); +} + +void +container_spatial_cb(Widget widget, XtPointer clientdata, XtPointer call_data) +{ + Widget container = clientdata; + WidgetList children; + Cardinal nchildren; + + XtVaSetValues(container, + XmNlayoutType, XmSPATIAL, + XmNspatialStyle, XmNONE, + NULL); + nchildren = XmContainerGetItemChildren(container,NULL,&children); + if (nchildren) { + XtFree((XtPointer)children); + /* FIXME: Hmm, why ??? */ + XtVaSetValues(container, + XmNentryViewType, XmLARGE_ICON, + NULL); + } + container_relayout(container); +} + +void container_detail_cb(Widget widget, XtPointer clientdata, XtPointer call_data) +{ + Widget container = clientdata; + + XtVaSetValues(container, + XmNlayoutType, XmDETAIL, + XmNentryViewType, XmSMALL_ICON, + NULL); + container_relayout(container); +} + +void +container_traverse_cb(Widget scroll, XtPointer clientdata, XtPointer call_data) +{ + XmTraverseObscuredCallbackStruct *cd = call_data; + + if (cd->reason == XmCR_OBSCURED_TRAVERSAL) + XmScrollVisible(scroll, cd->traversal_destination, 25, 25); +} + +void +container_convert_cb(Widget widget, XtPointer clientdata, XtPointer call_data) +{ + XmConvertCallbackStruct *ccs = call_data; + char *file = NULL; + Atom *targs; + int i,n,len; + WidgetList children; + Cardinal nchildren; + + if (ccs->location_data) { + Widget item = ccs->location_data; + children = &item; + nchildren = 1; + } else { + XtVaGetValues(widget, + XmNselectedObjects,&children, + XmNselectedObjectCount,&nchildren, + NULL); + } + + if (debug) { + char *t = !ccs->target ? NULL : XGetAtomName(dpy,ccs->target); + char *s = !ccs->selection ? NULL : XGetAtomName(dpy,ccs->selection); + fprintf(stderr,"drag: target=%s selection=%s [%d files,%p]\n", + t, s, nchildren, ccs->location_data); + if (t) XFree(t); + if (s) XFree(s); + } + + if ((ccs->target == XA_TARGETS) || + (ccs->target == _MOTIF_CLIPBOARD_TARGETS) || + (ccs->target == _MOTIF_EXPORT_TARGETS)) { + targs = (Atom*)XtMalloc(sizeof(Atom)*8); + n = 0; + if (nchildren >= 1) { + targs[n++] = MIME_TEXT_URI_LIST; + } + if (1 == nchildren) { + targs[n++] = XA_FILE_NAME; + targs[n++] = XA_FILE; + targs[n++] = _NETSCAPE_URL; + targs[n++] = XA_STRING; + } + ccs->value = targs; + ccs->length = n; + ccs->type = XA_ATOM; + ccs->format = 32; + ccs->status = XmCONVERT_MERGE; + return; + } + + if (ccs->target == _MOTIF_DEFERRED_CLIPBOARD_TARGETS) { + targs = (Atom*)XtMalloc(sizeof(Atom)*8); + n = 0; + ccs->value = targs; + ccs->length = n; + ccs->type = XA_ATOM; + ccs->format = 32; + ccs->status = XmCONVERT_DONE; + } + + if ((ccs->target == _MOTIF_LOSE_SELECTION) || + (ccs->target == XA_DONE)) { + /* free stuff */ + ccs->value = NULL; + ccs->length = 0; + ccs->type = XA_INTEGER; + ccs->format = 32; + ccs->status = XmCONVERT_DONE; + return; + } + + if (ccs->target == XA_FILE_NAME || + ccs->target == XA_FILE || + ccs->target == XA_STRING) { + file = XtMalloc(strlen(XtName(children[0])+1)); + strcpy(file,XtName(children[0])); + ccs->value = file; + ccs->length = strlen(file); + ccs->type = XA_STRING; + ccs->format = 8; + ccs->status = XmCONVERT_DONE; + return; + } + + if (ccs->target == _NETSCAPE_URL || + ccs->target == MIME_TEXT_URI_LIST) { + for (i = 0, len = 0; i < nchildren; i++) + len += strlen(XtName(children[i])); + file = XtMalloc(len + 8 * nchildren); + for (i = 0, len = 0; i < nchildren; i++) + len += sprintf(file+len,"file:%s\n",XtName(children[i])); + ccs->value = file; + ccs->length = len; + ccs->type = XA_STRING; + ccs->format = 8; + ccs->status = XmCONVERT_DONE; + return; + } + + ccs->status = XmCONVERT_DEFAULT; +} + +static void +container_copy_cb(Widget widget, XtPointer clientdata, XtPointer call_data) +{ + Widget container = clientdata; + XmeClipboardSource(container,XmCOPY,XtLastTimestampProcessed(dpy)); +} + +static void +container_paste_cb(Widget widget, XtPointer clientdata, XtPointer call_data) +{ + Widget container = clientdata; + XmeClipboardSink(container,XmCOPY,NULL); +} + +static void +container_del_cb(Widget widget, XtPointer clientdata, XtPointer call_data) +{ + Widget container = clientdata; + WidgetList children,list; + Cardinal nchildren,i; + + XtVaGetValues(container, + XmNselectedObjects,&children, + XmNselectedObjectCount,&nchildren, + NULL); + list = malloc(sizeof(Widget*)*nchildren); + memcpy(list,children,sizeof(Widget*)*nchildren); + + XtVaSetValues(container, + XmNselectedObjectCount,0, + NULL); + XtUnmanageChildren(list,nchildren); + for (i = 0; i < nchildren; i++) + XtDestroyWidget(list[i]); + free(list); +} + +void container_menu_edit(Widget menu, Widget container, + int cut, int copy, int paste, int del) +{ + Widget push; + +#if 0 + if (cut) { + push = XtVaCreateManagedWidget("cut",xmPushButtonWidgetClass,menu,NULL); + XtAddCallback(push,XmNactivateCallback, + container_cut_cb,container); + } +#endif + if (copy) { + push = XtVaCreateManagedWidget("copy",xmPushButtonWidgetClass,menu,NULL); + XtAddCallback(push,XmNactivateCallback, + container_copy_cb,container); + } + if (paste) { + push = XtVaCreateManagedWidget("paste",xmPushButtonWidgetClass,menu,NULL); + XtAddCallback(push,XmNactivateCallback, + container_paste_cb,container); + } + if (del) { + push = XtVaCreateManagedWidget("del",xmPushButtonWidgetClass,menu,NULL); + XtAddCallback(push,XmNactivateCallback, + container_del_cb,container); + } +} + +void container_menu_view(Widget menu, Widget container) +{ + Widget push; + + push = XtVaCreateManagedWidget("details",xmPushButtonWidgetClass,menu,NULL); + XtAddCallback(push,XmNactivateCallback, + container_detail_cb,container); + push = XtVaCreateManagedWidget("spatial",xmPushButtonWidgetClass,menu,NULL); + XtAddCallback(push,XmNactivateCallback, + container_spatial_cb,container); +} + +void +container_relayout(Widget container) +{ + Widget clip = XtParent(container); + WidgetList children; + Cardinal nchildren; + Dimension wwidth,wheight; + Dimension iwidth,iheight; + Position x,y; + unsigned char layout,style; + int i,margin = 10; + + XtVaGetValues(container, + XmNlayoutType, &layout, + XmNspatialStyle, &style, + NULL); + if (XmSPATIAL != layout || XmNONE != style) { + XmContainerRelayout(container); + return; + } + + nchildren = XmContainerGetItemChildren(container,NULL,&children); + XtVaGetValues(clip, + XtNwidth, &wwidth, + XtNheight, &wheight, + NULL); + + wwidth -= 5; + x = margin; y = margin; + for (i = 0; i < nchildren; i++) { + if (!XtIsManaged(children[i])) + continue; + XtVaGetValues(children[i], + XtNwidth,&iwidth, + XtNheight,&iheight, + NULL); + if (x > 0 && x + iwidth + margin > wwidth) { + /* new row */ + x = margin; y += iheight + margin; + } + XtVaSetValues(children[i], + XtNx,x, XtNy,y, + XmNpositionIndex,i, + NULL); + x += iwidth + margin; + } + + if (wheight < y + iheight + margin) + wheight = y + iheight + margin; + XtVaSetValues(container, + XtNwidth, wwidth, + XtNheight, wheight, + NULL); + if (nchildren) + XtFree((XtPointer)children); +} + +void +container_delwidgets(Widget container) +{ + WidgetList children; + Cardinal nchildren; + unsigned int i; + + /* delete widgets */ + XtVaSetValues(container, + XmNselectedObjectCount,0, + NULL); + nchildren = XmContainerGetItemChildren(container,NULL,&children); + XtUnmanageChildren(children,nchildren); + for (i = 0; i < nchildren; i++) + XtDestroyWidget(children[i]); + if (nchildren) + XtFree((XtPointer)children); +} + +/*----------------------------------------------------------------------*/ + +void file_set_icon(struct file_button *file, Pixmap s, Pixmap l) +{ + Pixmap large, small; + Pixel background; + + if (file->info) + return; + + XtVaGetValues(file->widget, XmNbackground,&background, NULL); + small = x11_icon_fit(DisplayOfScreen(file->screen), s, background, + GET_ICON_SMALL(), GET_ICON_SMALL()); + large = x11_icon_fit(DisplayOfScreen(file->screen), l, background, + GET_ICON_LARGE(), GET_ICON_LARGE()); + XtVaSetValues(file->widget, + XmNsmallIconPixmap, small, + XmNlargeIconPixmap, large, + NULL); + if (file->small) + XFreePixmap(DisplayOfScreen(file->screen),file->small); + if (file->large) + XFreePixmap(DisplayOfScreen(file->screen),file->large); + file->small = small; + file->large = large; +} + +void file_set_info(struct file_button *file, struct fileinfo *info) +{ + file->info = NULL; + file_set_icon(file,info->small,info->large); + file->info = info; + fileinfo_details(file); +} + +#if 0 +static void +file_copy_cb(Widget widget, XtPointer clientdata, XtPointer call_data) +{ + struct file_button *file = clientdata; + + XmeClipboardSource(file->widget,XmCOPY,XtLastTimestampProcessed(dpy)); +} +#endif + +/*----------------------------------------------------------------------*/ + +int file_cmp_alpha(const struct file_button *aa, + const struct file_button *bb) +{ + if (S_ISDIR(aa->st.st_mode) != S_ISDIR(bb->st.st_mode)) + return S_ISDIR(aa->st.st_mode) ? -1 : 1; + return strcmp(aa->basename,bb->basename); +} + +static void +file_destroy_cb(Widget widget, XtPointer clientdata, XtPointer call_data) +{ + struct file_button *file = clientdata; + int i; + + if (debug) + fprintf(stderr,"file: del %p [%s]\n",file,file->filename); + + if (NULL != file->queue.next) + fileinfo_cleanup(file); + + if (file->basename) + free(file->basename); + if (file->filename) + free(file->filename); + + XtVaSetValues(file->widget, + XmNsmallIconPixmap, XmUNSPECIFIED_PIXMAP, + XmNlargeIconPixmap, XmUNSPECIFIED_PIXMAP, + NULL); + if (file->small) + XFreePixmap(DisplayOfScreen(file->screen),file->small); + if (file->large) + XFreePixmap(DisplayOfScreen(file->screen),file->large); + + if (file->label) + XmStringFree(file->label); + for (i = 0; i < DETAIL_COUNT; i++) + if (file->details[i]) + XmStringFree(file->details[i]); + + list_del(&file->global); + list_del(&file->window); + free(file); +} + +int file_createwidgets(Widget parent, struct file_button *file) +{ + struct fileinfo *info; + Pixmap pix; + Arg args[8]; + int i, n = 0; + + if (debug) + fprintf(stderr,"file: new %p [%s]\n",file,file->filename); + + file->screen = XtScreen(parent); + file->label = XmStringGenerate(file->basename, NULL, XmMULTIBYTE_TEXT,NULL); + for (i = 0; i < DETAIL_COUNT; i++) + file->details[i] = XmStringGenerate("-", NULL, XmMULTIBYTE_TEXT,NULL); + + XtSetArg(args[n], XmNlabelString, file->label); n++; + XtSetArg(args[n], XmNdetail, file->details); n++; + XtSetArg(args[n], XmNdetailCount, DETAIL_COUNT); n++; + file->widget = XmCreateIconGadget(parent,file->filename,args,n); + XtAddCallback(file->widget,XtNdestroyCallback,file_destroy_cb,file); + list_add_tail(&file->global,&files); + + info = fileinfo_cache_get(file->filename); + if (info) { + file_set_info(file,info); + } else { + pix = XmGetPixmap(file->screen,"question",0,0); + file_set_icon(file,pix,pix); + } + return 0; +} -- cgit