aboutsummaryrefslogtreecommitdiffstats
path: root/filebutton.c
diff options
context:
space:
mode:
Diffstat (limited to 'filebutton.c')
-rw-r--r--filebutton.c934
1 files changed, 934 insertions, 0 deletions
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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <X11/Xlib.h>
+#include <X11/Intrinsic.h>
+#include <Xm/Xm.h>
+#include <Xm/Label.h>
+#include <Xm/RowColumn.h>
+#include <Xm/PushB.h>
+#include <Xm/Transfer.h>
+#include <Xm/TransferP.h>
+#include <Xm/Container.h>
+#include <Xm/IconG.h>
+#include <Xm/ScrolledW.h>
+#include <Xm/SelectioB.h>
+#include <Xm/Text.h>
+
+#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;
+}