/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

/*
B.Raoult
Fri Apr 10 10:05:19 BST 1992
*/

#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/cursorfont.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/extensions/shape.h>

#include <X11/Intrinsic.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/CoreP.h>
#include <X11/CompositeP.h>
#include <X11/ConstrainP.h>
#include <Xm/Xm.h>
#include <Xm/XmP.h>
#include <Xm/DrawingAP.h>
#include <Xm/ExtObjectP.h>
#include <Xm/ScrolledWP.h>
#include <Xm/TextF.h>
#include <Xm/TransltnsP.h>
#include <X11/xpm.h>
#include "Drag.h"
#include "DragP.h"

static Icon check_icon(DragWidget,Icon);
static void             Initialize();
static void             Initialize_class();
static void             Destroy();
static void             Redraw();
static Boolean          SetValues();
static void             Realize();
static void             Resize();
static XtGeometryResult QueryProc();

static void 			ShowLast();
static void 			KeySelect();
static void             SelectAll();
static void             SelectNone();

static void             StartSelect();
static void             DoSelect();
static void             EndSelect();


static void             CleanUp();
static void             ToggleSize();
static void             Sort();
static int              SortByXY();

static void add_folder(DragWidget,Widget);
static void	remove_folder(DragWidget,Widget);
static Boolean same_tree(Widget,Widget);
static void end_edit(DragWidget widget);

static Icon             find_icon();
static void draw_icons(DragWidget,Region);
static void place_icon(DragWidget,Icon,Boolean);
static void hide_icon(DragWidget,Icon);
static void check_size(DragWidget);
static void show_icon(DragWidget,Icon);
static void show_hide(DragWidget,Icon,Boolean);
static void raise_icon(DragWidget,Icon);
static void plot_icon(DragWidget,Display*,Window,GC,Icon,int,int);
static void             toggle_icon();
static void remove_icon(DragWidget,Icon,Boolean);
static void inval_icon(DragWidget,Icon);
static void blink_icon(DragWidget,Icon);
static void select_icon(DragWidget,Icon,XEvent*,Boolean);
static void             sort_icons();
static void             unselect_all_icons();
static void answer(DragWidget,Window,int,Icon,int,int,int,Window,int,int);
static void             message_event_handler();
static void             clip_event_handler();
static void             map_event_handler_1();
static void             map_event_handler_2();
static void notify_drop(Widget,XtPointer,XtPointer);
static void             destroy_callback();
static void	new_icon_xy(Icon,int,int);
static void register_widget(Widget,String);
static void set_drop_property(Widget,XtCallbackProc,XtPointer,Widget);
static void move_icon(DragWidget,Icon,int,int,int,int);
static void make_pixmaps(Widget widget,Icon icon,int n);

static Pixmap FindPixmap(const char*,unsigned int*,unsigned int*);
static void InstallPixmap(Pixmap,const char*,unsigned int,unsigned int,unsigned int,XImage*);
static void FreePixmap(Widget,Pixmap);

static void UnionRect(XRectangle*,XRectangle*,XRectangle*);
static Boolean InterRect(XRectangle*,XRectangle*);

/* Atoms */

#define ICON_CAN_DRAG_DROP      "ICON_CAN_DRAG_DROP"
#define ICON_DROP_WIN_ID        "ICON_DROP_WIN_ID"
#define ICON_DROP_MISC          "ICON_DROP_MISC"
#define ICON_DROP_WIN_NAME      "ICON_DROP_WIN_NAME"
#define ICON_DROP_ICON_CLASS    "ICON_DROP_ICON_CLASS"
#define ICON_DROP_ICON_NAME     "ICON_DROP_ICON_NAME"
#define ICON_DROP_BUF_LEN       "ICON_DROP_BUF_LEN"
#define ICON_DROP_BUF           "ICON_DROP_BUF"
#define ICON_DROP_END           "ICON_DROP_END"
#define ICON_DROP_ACK           "ICON_DROP_ACK"
#define ICON_DROP_INFO          "ICON_DROP_INFO"
#define ICON_DROP_BUF_LEN_EXT   "ICON_DROP_BUF_LEN_EXT"
#define ICON_DROP_BUF_EXT       "ICON_DROP_BUF_EXT"


static  Atom WinIDAtom      = NULL;
static  Atom MiscAtom       = NULL;
static  Atom WinNameAtom    = NULL;
static  Atom IconClassAtom  = NULL;
static  Atom IconNameAtom   = NULL;
static  Atom BufLenAtom     = NULL;
static  Atom BufAtom        = NULL;
static  Atom EndAtom        = NULL;
static  Atom AckAtom        = NULL;
static  Atom InfoAtom       = NULL;
static  Atom CanDropAtom    = NULL;
static  Atom BufLenExtAtom     = NULL;
static  Atom BufExtAtom        = NULL;

static XtResource resources[] = {
	{ XmNsmallIcons, XmCsmallIcons, XmRBoolean, sizeof (Boolean),
	XtOffset (DragWidget, drag.small_icons), XmRImmediate,(caddr_t)False},
	{ XmNshapeMode, XmCshapeMode, XmRInt, sizeof (int),
	XtOffset (DragWidget, drag.shape_mode), XmRImmediate,(caddr_t)FULL_SHAPE},
	{ XmNmarginWidth, XmCMargin, XmRInt, sizeof (int),
	XtOffset (DragWidget, drag.marginx), XmRImmediate, (caddr_t) 10},
	{ XmNmarginHeight, XmCMargin, XmRInt, sizeof (int),
	XtOffset (DragWidget, drag.marginy), XmRImmediate, (caddr_t) 10},
	{ XmNgrid, XmCgrid, XmRBoolean, sizeof (Boolean),
	XtOffset (DragWidget, drag.grid), XmRImmediate, (caddr_t) True},
	{ XmNallowResize, XmCResize, XmRBoolean, sizeof (Boolean),
	XtOffset (DragWidget, drag.can_resize), XmRImmediate, (caddr_t) True},
	{ XmNautoMove, XmCAuto, XmRBoolean, sizeof (Boolean),
	XtOffset (DragWidget, drag.auto_move), XmRImmediate, (caddr_t) True},
	{ XmNautoFolderMove, XmCAuto, XmRBoolean, sizeof (Boolean),
	XtOffset (DragWidget, drag.auto_folder_move), XmRImmediate, (caddr_t) False},
	{ XmNautoPlace, XmCAuto, XmRBoolean, sizeof (Boolean),
	XtOffset (DragWidget, drag.auto_place), XmRImmediate, (caddr_t) True},
	{ XmNautoSort, XmCAuto, XmRBoolean, sizeof (Boolean),
	XtOffset (DragWidget, drag.auto_sort), XmRImmediate, (caddr_t) False},
	{ XmNautoClean, XmCAuto, XmRBoolean, sizeof (Boolean),
	XtOffset (DragWidget, drag.auto_clean), XmRImmediate, (caddr_t) False},
	{ XmNacceptKeys, XmCAcceptKeys, XmRBoolean, sizeof (Boolean),
	XtOffset (DragWidget, drag.accept_keys), XmRImmediate, (caddr_t) True},
	{ XmNkeyThreshold, XmCThreshold, XmRInt, sizeof (int),
	XtOffset (DragWidget, drag.key_threshold), XmRImmediate, (caddr_t) 300},
	{ XmNsortProc, XmCSortProc, XmRsortProc, sizeof (XtPointer),
	XtOffset (DragWidget, drag.sort), XmRImmediate, (XtPointer)DragSortByName},
	{XmNsendmsgCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
	XtOffset (DragWidget, drag.build_message),XtRCallback,NULL},
	{XmNflyOverCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
	XtOffset (DragWidget, drag.fly_over),XtRCallback,NULL},
	{XmNrenamableCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
	XtOffset (DragWidget, drag.renamable),XtRCallback,NULL},
	{XmNrenameCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
	XtOffset (DragWidget, drag.rename),XtRCallback,NULL},
	{XmNdropCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
	XtOffset (DragWidget, drag.drop_message),XtRCallback,NULL},
	{XmNotherDropCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
	XtOffset (DragWidget, drag.other_drop),XtRCallback,NULL},
	{XmNanswerCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
	XtOffset (DragWidget, drag.answer),XtRCallback,NULL},
	{XmNmoveCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
	XtOffset (DragWidget, drag.moveicon),XtRCallback,NULL},
	{XmNkillIconCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
	XtOffset (DragWidget, drag.killicon),XtRCallback,NULL},
	{XmNselectCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
	XtOffset (DragWidget, drag.select),XtRCallback,NULL},
	{XmNdblClickCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
	XtOffset (DragWidget, drag.dblclick),XtRCallback,NULL},
	{XmNfolderMoveCallback,XtCCallback,XtRCallback,sizeof(void *),
	XtOffset (DragWidget, drag.folder_move),XtRCallback,NULL},
	{ XmNfontList, XmCFontList, XmRFontList, sizeof (XmFontList),
	XtOffset (DragWidget, drag.fontlist), XmRString, "fixed"},
	{ XmNparentFolder, XmCParentFolder, XmRWidget, sizeof (Widget),
	XtOffset (DragWidget, drag.parent_folder), XmRImmediate, NULL},
	{ XmNselectIcons, XmCSelectIcons, XmRBoolean, sizeof (Boolean),
	XtOffset (DragWidget, drag.can_select), XmRImmediate, (caddr_t) True},
	{ XmNsingleLine, XmCSingleLine, XmRBoolean, sizeof (Boolean),
	XtOffset (DragWidget, drag.single_line), XmRImmediate, (caddr_t) False},

	{ XmNeditNames, XmCEditNames, XmRBoolean, sizeof (Boolean),
	XtOffset (DragWidget, drag.edit_names), XmRImmediate, (caddr_t) False},

	{ XmNeditTimeout, XmCEditTimeout, XmRInt, sizeof (int),
	XtOffset (DragWidget, drag.edit_timeout), XmRImmediate, (caddr_t) 1000},

	{XmNgetFullNameCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
	XtOffset (DragWidget, drag.getFullName),XtRCallback,NULL},
};


static char defaultTranslations[] =
"<Btn1Down>:start_selection()\n\
<Btn1Motion>:do_selection()\n\
<Btn1Up>:end_selection()\n\
<Btn2Down>:start_selection()\n\
<Btn2Motion>:do_selection()\n\
<Btn2Up>:end_selection()\n\
<Key>osfHelp:DrawingAreaInput() ManagerGadgetHelp()\n\
Ctrl<Key>a:select_all()\n\
Ctrl<Key>n:select_none()\n\
Ctrl<Key>l:clean_up()\n\
Ctrl<Key>s:sort()\n\
Ctrl<Key>w:toggle_size()\n\
Ctrl<Key>z:show_last()\n\
None<KeyPress>:key_select()";


static XtActionsRec actionsList[] = {
	{ "start_selection",    (XtActionProc)StartSelect},
	{ "do_selection",       (XtActionProc)DoSelect},
	{ "end_selection",      (XtActionProc)EndSelect},
	{ "select_all",         (XtActionProc)SelectAll},
	{ "select_none",        (XtActionProc)SelectNone},
	{ "clean_up",           (XtActionProc)CleanUp},
	{ "toggle_size",        (XtActionProc)ToggleSize},
	{ "key_select",         (XtActionProc)KeySelect},
	{ "sort", 	            (XtActionProc)Sort},
	{ "show_last", 	        (XtActionProc)ShowLast},
};

static XtResource icon_resources [] = {
	{ XmNiconLargeBitmap, XmCIconLargeBitmap, XmRString, sizeof (String),
	XtOffset (Icon, pix_name[0]), XmRImmediate, "default"},
	{ XmNiconLargeMask, XmCIconLargeMask, XmRString, sizeof (String),
	XtOffset (Icon, mask_name[0]), XmRImmediate,NULL},
	{ XmNiconLargeOpenedBitmap,
	XmCIconLargeOpenedBitmap, XmRString, sizeof (String),
	XtOffset (Icon, open_name[0]), XmRImmediate,NULL},
	{ XmNiconSmallBitmap, XmCIconSmallBitmap, XmRString, sizeof (String),
	XtOffset (Icon, pix_name[1]), XmRImmediate, NULL},
	{ XmNiconSmallMask, XmCIconSmallMask, XmRString, sizeof (String),
	XtOffset (Icon, mask_name[1]), XmRImmediate,NULL},
	{ XmNiconSmallOpenedBitmap,
	XmCIconSmallOpenedBitmap, XmRString, sizeof (String),
	XtOffset (Icon, open_name[1]), XmRImmediate,NULL},
	{ XmNisFolder,
	XmCIsFolder, XmRBoolean, sizeof (Boolean),
	XtOffset (Icon, isfolder), XmRImmediate,(XtPointer)False},
	{ XmNiconForeground, XmCForeground, XmRPixel, sizeof (Pixel),
	XtOffset (Icon, foreground), XmRString, "black"},
	{ XmNiconBackground, XmCBackground, XmRPixel, sizeof (Pixel),
	XtOffset (Icon, background), XmRString, "white"},
	{ XmNiconHiliteForeground, XmCIconHiliteForeground, XmRPixel, sizeof (Pixel),
	XtOffset (Icon, hiliteforeground), XmRString, "white"},
	{ XmNiconHiliteBackground, XmCIconHiliteBackground, XmRPixel, sizeof (Pixel),
	XtOffset (Icon, hilitebackground), XmRString, "black"},


};


DragClassRec dragClassRec = {
	{
	/* core_class fields  */
	(WidgetClass) &xmDrawingAreaClassRec,/* superclass         */
	"Drag",                             /* class_name         */
	sizeof(DragRec),                  /* widget_size        */
	Initialize_class,                 /* class_init         */
	NULL,                             /* class_part_init    */
	FALSE,                            /* class_inited       */
	Initialize,                       /* initialize         */
	NULL,                             /* initialize_hook    */
	Realize,                          /* realize            */
	actionsList,                      /* actions            */
	XtNumber(actionsList),            /* num_actions        */
	resources,                        /* resources          */
	XtNumber(resources),              /* num_resources      */
	NULLQUARK,                        /* xrm_class          */
	TRUE,                             /* compress_motion    */
	XtExposeCompressMaximal,          /* compress_exposure  */
	TRUE,                             /* compress_enterleave*/
	TRUE,                             /* visible_interest   */
	Destroy,                          /* destroy            */
	Resize,                           /* resize             */
	Redraw,                           /* expose             */
	SetValues,                        /* set_values         */
	NULL,                             /* set_values_hook    */
	XtInheritSetValuesAlmost,         /* set_values_almost  */
	NULL,                             /* get_values_hook    */
	NULL,                             /* accept_focus       */
	XtVersion,                        /* version            */
	NULL,                             /* callback_private   */
	defaultTranslations,              /* tm_table           */
	QueryProc,                        /* query_geometry     */
	XtInheritDisplayAccelerator,      /* display_accelerator*/
	NULL,                             /* extension          */
	},
	{
	/* composite_class fields */
	NULL,                            /* geometry_manager    */
	NULL,                            /* change_managed      */
	XtInheritInsertChild,            /* insert_child        */
	XtInheritDeleteChild,            /* delete_child        */
	NULL,                            /* extension           */
	},
	{
	/* constraint_class fields */
	NULL,                             /* subresources        */
	0,                                /* subresource_count   */
	0,                                /* constraint_size     */
	NULL,                             /* initialize          */
	NULL,                             /* destroy             */
	NULL,                             /* set_values          */
	NULL,                             /* extension           */
	},
	{
	_XmDrawingA_traversalTranslations,          /* default translations */
	NULL,                           /* syn_resources          */
	0,                           /* num_syn_resources      */
	NULL,                        /* syn_cont_resources     */
	0,                           /* num_syn_cont_resources */
	XmInheritParentProcess,      /* parent_process */
	NULL,                        /* extension              */

	},
	{
	NULL,
	},
	{
	/* Drag class fields */
	NULL,                               /* ignore              */
	},
};

WidgetClass dragWidgetClass = (WidgetClass) &dragClassRec;

static XRectangle empty = {
	0,0,0,0,};

static Cursor open_cursor;
static Cursor close_cursor;
static Cursor drop_cursor;

#define open_hand_width 16
#define open_hand_height 16
#define open_hand_x_hot 8
#define open_hand_y_hot 8

static char open_hand_curs[] = {
	0x80, 0x01, 0x70, 0x1a, 0x48, 0x26, 0x4a, 0x26, 0x4d, 0x12, 0x49, 0x12,
	0x09, 0x68, 0x01, 0x98, 0x02, 0x88, 0x02, 0x40, 0x02, 0x20, 0x04, 0x20,
	0x04, 0x10, 0x08, 0x08, 0x08, 0x04, 0x08, 0x04, };

static char open_hand_mask[] = {
	0x80, 0x01, 0xf0, 0x1b, 0xf8, 0x3f, 0xfa, 0x3f, 0xff, 0x1f, 0xff, 0x1f,
	0xff, 0x6f, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0xfc, 0x3f,
	0xfc, 0x1f, 0xf8, 0x0f, 0xf8, 0x07, 0xf8, 0x07, };


static char close_hand_curs[] = {
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x06, 0x26, 0x09,
	0x05, 0x08, 0x01, 0x04, 0x01, 0x0c, 0x01, 0x10, 0x01, 0x10, 0x02, 0x10,
	0x02, 0x08, 0x04, 0x04, 0x04, 0x02, 0x04, 0x02, };

static char close_hand_mask[] = {
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x06, 0xfe, 0x0f,
	0xff, 0x0f, 0xff, 0x07, 0xff, 0x0f, 0xff, 0x1f, 0xff, 0x1f, 0xfe, 0x1f,
	0xfe, 0x0f, 0xfc, 0x07, 0xfc, 0x03, 0xfc, 0x03, };

/*==========================================================================*/
/*==========================================================================*/
/*==========================================================================*/

typedef struct PixmapCache {
	struct PixmapCache *next;
	String              name;
	unsigned int        width;
	unsigned int        height;
	unsigned int        depth;
	Pixmap              pixmap;
	XImage*             image;
	int                 count;
} PixmapCache;

static PixmapCache *cache = NULL;
static int icon_batch = 0; /* drop id */

static void InstallPixmap(Pixmap pixmap,const char* name,unsigned int width,
	unsigned int height,
	unsigned int depth,XImage* image)
{
	PixmapCache *p = XtNew(PixmapCache);

	p->pixmap      = pixmap;
	p->name        = XtNewString(name);
	p->width       = width;
	p->height      = height;
	p->depth       = depth;
	p->image       = image;
	p->count       = 1;

	p->next        = cache;
	cache          = p;

}

static Pixmap FindPixmap(const char* name,unsigned int *width,unsigned int *height)
{
	PixmapCache *p = cache;
	/* printf("FindPixmap : %s\n",name); */
	while(p)
	{
		if(strcmp(name,p->name) == 0)
		{
			*width  = p->width;
			*height = p->height;

			p->count++;
			return p->pixmap;
		}
		p = p->next;
	}
	return 0;
}

static XImage* PixmapImage(Widget w,Pixmap pixmap,
	unsigned int *width,unsigned int *height,unsigned int *depth)
{
	Display *dpy   = XtDisplay(w);
	int     screen = DefaultScreen(dpy);
	Window  root   = RootWindow(dpy,screen);
	int x,y;
	unsigned int dummy;

	PixmapCache *p = cache;
	/* printf("FindPixmap : %s\n",name); */
	while(p)
	{
		if(p->pixmap  == pixmap)
		{
			if(p->depth == 0) p->depth = DefaultDepth(dpy,screen);
			if(p->width == 0 || p->height == 0)
			{
				XGetGeometry(dpy,pixmap,&root,&x,&y,&p->width,
					&p->height,&dummy,&p->depth);
			}

			*width  = p->width;
			*height = p->height;
			*depth  = p->depth;

			/* printf("size in cache %s %d %d %d\n",p->name, */
				/* p->width,p->height,p->depth); */
			if(p->image == 0)
			{
				/* printf("image not in cache\n"); */
				p->image =  XGetImage(dpy,pixmap,0,0,*width,*height,
					AllPlanes,ZPixmap);
			}
			/* printf("image in cache\n"); */
			return XSubImage(p->image,0,0,p->width,p->height);
		}
		p = p->next;
	}

	/* printf("pixmap not in cache\n"); */
	XGetGeometry(dpy,pixmap,&root,&x,&y,width,height,&dummy,depth);
	return XGetImage(dpy,pixmap,0,0,*width,*height,AllPlanes,ZPixmap);
}

static Pixmap GetBitMap(Widget widget,const char* name,
	unsigned int *width,unsigned int *height)
{
	int dummy;
	Display *dpy   = XtDisplay(widget);
	int     screen = DefaultScreen(dpy);
	Window  root   = RootWindow(dpy,screen);
	Pixmap  bitmap;

	if(name == NULL) return NULL;

	if(bitmap = FindPixmap(name,width,height))
		return bitmap;

	if(XReadBitmapFile(dpy,root,name,width,height,
	    &bitmap,&dummy,&dummy)!=BitmapSuccess)
		return NULL;

	InstallPixmap(bitmap,name,*width,*height,1,0);

	return bitmap;

}

static void FreePixmap(Widget widget,Pixmap pixmap)
{
	PixmapCache *p = cache;
	PixmapCache *q = NULL;

	while(p)
	{
		if(p->pixmap == pixmap)
		{
			p->count--;
			if(p->count == 0)
			{
				if(q)
					q->next = p->next;
				else
					cache = p->next;

				XFreePixmap(XtDisplay(widget),p->pixmap);
				XtFree(p->name);
				XtFree((XtPointer)p);
				return;
			}
		}
		q = p;
		p = p->next;
	}

}
/*==========================================================================*/
/*==========================================================================*/
/*==========================================================================*/

#define defpix_width 32
#define defpix_height 32
static char defpix_bits[] = {
	0x00, 0xf0, 0x0f, 0x00, 0x00, 0x0e, 0x70, 0x00, 0x00, 0x01, 0x80, 0x00,
	0xc0, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x08,
	0x08, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x10, 0x04, 0x80, 0x0f, 0x20,
	0x02, 0xe0, 0x38, 0x40, 0x02, 0xe0, 0x30, 0x40, 0x02, 0x00, 0x30, 0x40,
	0x01, 0x00, 0x30, 0x80, 0x01, 0x00, 0x18, 0x80, 0x01, 0x00, 0x1c, 0x80,
	0x01, 0x00, 0x0e, 0x80, 0x01, 0x80, 0x03, 0x80, 0x01, 0x80, 0x00, 0x80,
	0x01, 0x80, 0x00, 0x80, 0x01, 0xc0, 0x00, 0x80, 0x02, 0x00, 0x00, 0x40,
	0x02, 0x00, 0x00, 0x40, 0x02, 0xe0, 0x00, 0x40, 0x04, 0xe0, 0x00, 0x20,
	0x08, 0xe0, 0x00, 0x10, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x08,
	0x20, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00,
	0x00, 0x0e, 0x70, 0x00, 0x00, 0xf0, 0x0f, 0x00, };

static Pixmap GetPixMap(Widget widget,const char* name,Pixel fore,Pixel back)
{
	Display *dpy = XtDisplay(widget);
	int     screen = DefaultScreen(dpy);
	Window  root   = RootWindow(dpy,screen);
	Pixmap  pixmap;
	unsigned int dummy;
	XpmAttributes atrib;
	static  Boolean first = True;
	XImage *image = 0;

	if(first)
	{
		InstallPixmap(
		    XCreatePixmapFromBitmapData(dpy,root,
		    defpix_bits,defpix_width,defpix_height,fore,back,
		    DefaultDepth(dpy,screen)),
		    "default",defpix_width,defpix_height,DefaultDepth(dpy,screen),0);
		first = False;
	}

	if(name == NULL) return NULL;

	if(pixmap = FindPixmap(name,&dummy,&dummy))
		return pixmap;

	/* pixmap = XmGetPixmap(XtScreen(widget),name,fore,back); */

	atrib.valuemask   = XpmExactColors | XpmCloseness;
	atrib.exactColors = 0;
	atrib.closeness   = 65535;
		/* shape = NULL; */


	if(XpmReadFileToImage(dpy,(char*)name,&image,NULL/*&shape*/,&atrib) != PixmapSuccess)
		image = NULL;

	atrib.valuemask   = XpmExactColors | XpmCloseness;
	atrib.exactColors = 0;
	atrib.closeness   = 65535;

	if(XpmReadFileToPixmap(dpy,root,(char*)name,&pixmap,NULL/*&shape*/,&atrib)
	    != PixmapSuccess) return NULL;

	InstallPixmap(pixmap,name,atrib.width,atrib.height,DefaultDepth(dpy,screen),image);

	return pixmap;

}

/*==========================================================================*/
/*==========================================================================*/
/*==========================================================================*/

static void CvtStringToSortProc(args,num_args,from,to)
XrmValuePtr args;
Cardinal    *num_args;
XrmValuePtr from,to;
{
	static XtPointer proc;
	char   *p = (char*)from->addr;

	if(!from->addr) return;

	proc = NULL;

	if(strcmp(p,"byname") == 0 )  proc = (XtPointer)DragSortByName;
	if(strcmp(p,"byclass") == 0 ) proc = (XtPointer)DragSortByClass;

	to->addr = (XtPointer)&proc;
	to->size = sizeof(XtPointer);


}

/*-----------------------------------------------------------------*/
/* Recieve a drop message                                          */
/*-----------------------------------------------------------------*/

static int icon_to_int(DragWidget drag,Icon p)
{
	return p?p->id:0;
}

static Icon int_to_icon(DragWidget drag,int n)
{
	if(drag && XtIsDrag((Widget)drag))
	{
		Icon p = drag->drag.icons;
		while(p)
		{
			if(p->id == n) return p;
			p = p->next;
		}
	}
	return NULL;
}

static void clip_event_handler(Widget widget,XtPointer cd,
	XEvent *event,Boolean *continue_dispatch)
{
	/* Try to pass it to the assosciated drag */
	XEvent ev = *event;
	ev.xany.window = XtWindow((Widget)cd);
	/* printf("Clip event !!!!\n"); */
	XtDispatchEvent(&ev);

	/* XSendEvent(XtDisplay(widget),XtWindow((Widget)cd), */
	    /* True,NoEventMask,event); */
	*continue_dispatch = False;
}

static void message_event_handler(widget,cd,event,continue_dispatch)
Widget widget;
XtPointer cd;
XEvent    *event;
Boolean   *continue_dispatch;
{

	static DragCallbackStruct cb;
	static char wind_name[24];
	static char icon_name[24];
	static char icon_clas[24];
	static char buffer[1024];
	static int  icon_id;

	static char *p;
	XClientMessageEvent cevent;
	DragWidget drag = (DragWidget)widget;
	Boolean is_drag = XtIsDrag(widget);

	/* On 64-bit platforms, there appears to be a problem when using the data.l[]
	   part of the XClientMessageEvent structure. This is most likely because it is
	   defined as an array of longs, but it is intended as an array of 32-bit integers
	   (event.format=32). When dealing with this array, some of the data is lost, probably
	   because the internal 'X' code assumes 32-bit values. Therefore, we explicitly
	   use an 'int' pointer to access this data structure so that we can use 32-bit
	   values in it which is what it thinks it's getting. If 'int' is ever defined
	   to be greater than 32, then this code will have to be revised.
	   Perhaps the only message for which this might be a problem is the WinIDAtom message
	   - can this number always be stored in an int? The other thing to note is that
	   where event.format was previously being set to 32, we now set it to 8. When
	   set to 32, some bytes were not being received for some reason. This is resolved
	   when set to 8 - it should not make a difference, so the idea is that if you tell
	   it that the message is a set of bytes, then it should make sure that it transfers
	   all of them rather than trying to interpret 32-bit ints as longs. */

	int *iarray = (int *)&event->xclient.data.l[0];

	if(event->type != ClientMessage)
		return;

	/*printf("message_event_handler(%s, %d)\n",XtName(widget),
	     event->xclient.message_type);*/

	if(event->xclient.message_type == WinIDAtom)
	{
		memset(&cb,0,sizeof(cb));
		cb.reason            = DRAG_DROP;
		cb.remote_window     = iarray[0];
		cb.x                 = iarray[1];
		cb.y                 = iarray[2];
		cb.remote_widget     = XtWindowToWidget(XtDisplay(widget),
		    cb.remote_window);
		icon_id              = iarray[3];
		cb.icon              = int_to_icon((DragWidget)cb.remote_widget,icon_id);
		cb.same_folder_tree  = is_drag?same_tree(widget,cb.remote_widget):False;
	}

	if(event->xclient.message_type == WinNameAtom)
		strcpy(wind_name,event->xclient.data.b);

	if(event->xclient.message_type == IconClassAtom)
		strcpy(icon_clas,event->xclient.data.b);

	if(event->xclient.message_type == IconNameAtom)
		strcpy(icon_name,event->xclient.data.b);

	if(event->xclient.message_type == BufLenAtom)
	{
		cb.msg_length = iarray[0];
		cb.icon_no    = iarray[1];
		cb.icon_count = iarray[2];
		cb.icon_batch = iarray[3];
		p = buffer;
	}

	if(event->xclient.message_type == MiscAtom)
	{
		cb.copy = iarray[0];
	}

	if(event->xclient.message_type == BufAtom )
	{
		memcpy(p,event->xclient.data.b,20);
		p += 20;
	}

	if(event->xclient.message_type == EndAtom )
	{
		int *oarray = (int *)&cevent.data.l[0];
		cb.same_window = (cb.remote_window == XtWindow(widget));
		cb.remote_name = wind_name;
		cb.icon_class  = icon_clas;
		cb.icon_name   = icon_name;
		cb.accept_it   = /*True*/False;
		cb.message     = buffer;
		cb.event       = event;

		if(is_drag)
			XtCallCallbacks(widget,XmNdropCallback,(XtPointer)&cb);
		else
			notify_drop(widget,cd,(XtPointer)&cb);

		/*
        if(widget->drag.drop_message == NULL)
            AddIcon(widget,cb.icon_class,cb.icon_name,NULL,cb.x,cb.y);

        */


		/* Send reply */

		cevent.display      = XtDisplay(widget);
		cevent.window       = cb.remote_window;
		cevent.type         = ClientMessage;
		cevent.format       = 8; /*32*/
		oarray[0]           = cb.accept_it;
		oarray[1]           = icon_id;
		oarray[2]           = XtWindow(widget);
		oarray[3]           = (cb.icon_no << 16) + cb.icon_count;
		oarray[4]           = cb.icon_batch;

		cevent.message_type = AckAtom;

		XSendEvent(XtDisplay(widget),cb.remote_window,
		    True,NoEventMask,(XEvent*)&cevent);
		XFlush(XtDisplay(widget));

	}

	if(!is_drag) return;

	if(event->xclient.message_type == AckAtom)
	{
		Icon icon = int_to_icon(drag,iarray[1]);
		if(!icon) return;

		answer(drag,(Window)iarray[2],
		    iarray[0]?DROP_OK:DROP_REFUSED,
		    icon,
		    iarray[3] >> 16,
		    iarray[3] % (1<<16),
		    iarray[4],NULL,
			0,0
		    );

		if(iarray[0])
		{
			/* if(drag->drag.moving) */
			if(icon->delete)
				remove_icon(drag,icon,True);
			else
			{
				show_icon(drag,icon);
				plot_icon(drag,XtDisplay(widget),XtWindow(widget),
				    drag->drag.gc,icon,0,0);
			}
		}
		else
		{
			icon->delete = False;
			show_icon(drag,icon);
			plot_icon(drag,XtDisplay(widget),XtWindow(widget),
			    drag->drag.gc,icon,0,0);
		}

	}


}

static void blink_draw(DragWidget drag,int onoff)
{
	Window  win  = XtWindow(drag);
	Display *dpy = XtDisplay(drag);
	int n  = drag->drag.small_icons;
	Icon icon  = drag->drag.blink_icon;
	GC  gc = drag->drag.gc;

	if(icon->pix[n] == NULL) make_pixmaps((Widget)drag,icon,n);

	XSetClipMask(dpy,gc,icon->mask[n]);
	XSetForeground(dpy,gc, icon->foreground);
	XSetBackground(dpy,gc, icon->background);

	XSetClipOrigin (dpy,gc,
	    icon->r_icon[n].x,
	    icon->r_icon[n].y);

	if(onoff)
		XFillRectangles(dpy,win,gc,&icon->r_icon[n],1);
	else
		XCopyArea(dpy,
		    icon->opened?icon->open_pix[n]:icon->pix[n],
		    win,
		    gc,0,0,
		    icon->r_icon[n].width,
		    icon->r_icon[n].height,
		    icon->r_icon[n].x,
		    icon->r_icon[n].y);

	XSetClipMask(dpy,gc,None);

}

static void blink_timeout(DragWidget drag,XtIntervalId id)
{
	int speed = 50; /* 10 mils */

	if(drag->drag.blink_icon && XtIsRealized((Widget)drag))
	{

		blink_draw(drag,drag->drag.blink_state%2);

		if(++drag->drag.blink_state <= 6)
			drag->drag.blink_timeout = XtAppAddTimeOut(
			    XtWidgetToApplicationContext((Widget)drag),
			    speed, /* half a sec */
			(XtTimerCallbackProc)blink_timeout,
			    (XtPointer)drag);
		else blink_icon(drag,NULL);
	}
}

static void blink_icon(DragWidget drag,Icon icon)
{
	if(drag->drag.blink_icon && (drag->drag.blink_state%2 != 0))
	{
		/* Erase left over */
		blink_draw(drag,0);
	}
	drag->drag.blink_icon  = icon;
	drag->drag.blink_state = 0;
	if(icon) blink_timeout(drag,NULL);
	end_edit(drag);
}

/*
static void set_icon_under(drag,icon)
DragWidget drag;
Icon	   icon;
{
	if(drag->drag.under)
	{
		plot_icon(drag,XtDisplay(drag),XtWindow(drag),drag->drag.gc,
			drag->drag.under,0,0);
	}
	drag->drag.under = icon?(icon->isfolder?icon:NULL):NULL;
	if(drag->drag.under)
	{
		plot_icon(drag,XtDisplay(drag),XtWindow(drag),drag->drag.gc,
			drag->drag.under,0,0);
	}
}
*/

static void Initialize(request, new)
DragWidget request, new;
{
	XmString dummy;

	if (request->core.width <= 50)
		new->core.width = 50;
	if (request->core.height <= 50)
		new->core.height = 50;

	XtAddEventHandler((Widget)new,NoEventMask,True,message_event_handler,NULL);


	new->drag.tag           = XtNewString(XmSTRING_DEFAULT_CHARSET);
	dummy = XmStringCreate("hg",new->drag.tag);
	new->drag.string_height=XmStringHeight(new->drag.fontlist,dummy);
	XmStringFree(dummy);

	new->drag.target = NULL;
	new->drag.icons = new->drag.last = NULL;

	new->drag.selecting = FALSE;
	new->drag.justclick = FALSE;
	new->drag.gridx = new->drag.gridy = 0;
	new->drag.child_count = new->drag.child_max = 0;
	new->drag.child_folders = NULL;
	new->drag.last_click    = 0;

	new->drag.blink_icon    = NULL;
	new->drag.last_added    = NULL;
	new->drag.edit_icon    = NULL;
	new->drag.blink_timeout = NULL;
	new->drag.blink_state   = 0;
	new->drag.clip          = 0;
	new->drag.edit_text     = 0;

	add_folder((DragWidget)new->drag.parent_folder,(Widget)new);

}

/*----------------------------------------------------------*/
/*----------------------------------------------------------*/

static void Destroy(widget)
DragWidget widget;
{
	int i;

	widget->drag.blink_icon    = NULL;
	if(widget->drag.blink_timeout)
		XtRemoveTimeOut(widget->drag.blink_timeout);

	XtRemoveEventHandler((Widget)widget,NoEventMask,True,
	    message_event_handler,NULL);

	if(widget->drag.gc)
		XFreeGC(XtDisplay(widget),widget->drag.gc);

	if(widget->drag.selgc)
		XtReleaseGC((Widget)widget,widget->drag.selgc);


	while(widget->drag.icons)
		remove_icon(widget,widget->drag.icons,False);

	remove_folder((DragWidget)widget->drag.parent_folder,(Widget)widget);

	for(i=0;i<widget->drag.child_count;i++)
		XtVaSetValues( widget->drag.child_folders[i],
		XmNparentFolder, (void*)0, (void*)0 );

	if(widget->drag.child_folders)
		XtFree((XtPointer)widget->drag.child_folders);

	XtFree(widget->drag.tag);

	if(widget->drag.clip)
		XtRemoveEventHandler(widget->drag.clip,
			KeyPressMask|KeyReleaseMask|
			ButtonPressMask|ButtonReleaseMask,
			True,clip_event_handler,(XtPointer)widget);
}

static void remove_folder(DragWidget drag,Widget widget)
{
	int i;
	if(drag == NULL || widget == NULL) return;

	for(i=0;i<drag->drag.child_count;i++)
	{
		if(drag->drag.child_folders[i] == widget)
		{
			int j;
			drag->drag.child_count--;

			for(j=i;j<drag->drag.child_count;j++)
				drag->drag.child_folders[j] =
				    drag->drag.child_folders[j+1];

			return;
		}
	}
	XtAppWarningMsg(XtWidgetToApplicationContext(widget),
	    "invalidWidget","invalidWidget","DragError",
	    "remove_folder : Not in the list",
	    (String *)NULL, (Cardinal *)NULL);
}

static void add_folder(DragWidget drag,Widget widget)
{
	int i;
	if(drag == NULL || widget == NULL) return;
	for(i=0;i<drag->drag.child_count;i++)
		if(drag->drag.child_folders[i] == widget)
		{
			XtAppWarningMsg(XtWidgetToApplicationContext(widget),
			    "invalidWidget","invalidWidget","DragError",
			    "add_folder : Already in the list",
			    (String *)NULL, (Cardinal *)NULL);
			return;
		}

	if(drag->drag.child_count == drag->drag.child_max)
	{
		drag->drag.child_max += 10;
		if(drag->drag.child_folders)
			drag->drag.child_folders =
			    (WidgetList)XtRealloc((XtPointer)drag->drag.child_folders,
			    sizeof(Widget)*drag->drag.child_max);
		else
			drag->drag.child_folders = (WidgetList)
			    XtMalloc(sizeof(Widget)*drag->drag.child_max);
	}
	drag->drag.child_folders[drag->drag.child_count++] = widget;

}


#define HAS_CHANGED(a)    (new->a != current->a)

static Boolean SetValues(current, request, new)
DragWidget current, request, new;
{
	int       redraw = FALSE;

	blink_icon(new,NULL);

	if(HAS_CHANGED(drag.small_icons))
	{
		new->drag.gridx = new->drag.gridy = 0;

		if(new->drag.grid)
		{

			if(new->drag.auto_clean)
				DragCleanUpIcons((Widget)new);
			else
			{
				Icon p = new->drag.icons;
				while(p)
				{
					place_icon(new,p,False);
					p = p->next;
				}
			}
		}

		check_size(new);
		redraw = True;
	}

	if(HAS_CHANGED(drag.can_resize))
		check_size(new);

	if(HAS_CHANGED(drag.parent_folder))
	{
		remove_folder((DragWidget)current->drag.parent_folder,
		    (Widget)current);
		add_folder((DragWidget)new->drag.parent_folder,
		    (Widget)new);
	}

	return (redraw);
}


static void Initialize_class (widget_class)
WidgetClass widget_class;
{
	XtAddConverter(XmRString,XmRsortProc,CvtStringToSortProc,NULL,0);
}

static XtGeometryResult QueryProc(DragWidget widget,
	XtWidgetGeometry *request,
	XtWidgetGeometry *ret)
{
	Icon p;
	int n = widget->drag.small_icons;
	XRectangle r;

	if(!XtIsRealized((Widget)widget)) return XtGeometryNo;
	if(!widget->drag.can_resize) return XtGeometryNo;

	p = widget->drag.icons;

	r.x      = r.y     = 0;
	r.height = r.width = 1;

	while(p)
	{
		UnionRect(&r,&p->r_all[n],&r);
		p = p->next;
	}

	r.width  += 1;
	r.height += 1;

	if(request->request_mode == 0)
	{
		ret->width  = r.width;
		ret->height = r.height;
		ret->request_mode = (CWWidth | CWHeight);
	}

	return (XtGeometryAlmost);
}

static void check_size(widget)
DragWidget widget;
{
	Dimension repw,reph;
	Icon p;
	int n = widget->drag.small_icons;
	XRectangle r;

	if(!XtIsRealized((Widget)widget)) return;
	if(!widget->drag.can_resize) return;

	p = widget->drag.icons;

	r.x      = r.y     = 0;
	r.height = r.width = 1;

	while(p)
	{
		UnionRect(&r,&p->r_all[n],&r);
		p = p->next;
	}

	if(widget->drag.edit_text && XtIsManaged(widget->drag.edit_text))
	{
		XRectangle* a = (XRectangle*)&widget->drag.edit_text->core.x;
		UnionRect(&r,a,&r);
	}

#if 0
	if(widget->drag.clip)
	{
		XmScrolledWindowWidget sw = (XmScrolledWindowWidget)
			XtParent(widget->drag.clip);
		XRectangle c;

		c.x = c.y = 0;
#if 0
		c.width = sw->swindow.AreaWidth - sw->swindow.WidthPad;
		c.height = sw->swindow.AreaHeight - sw->swindow.HeightPad;


		c.width  -= 5;
		c.height -= 5;
#else
		c.width  = widget->drag.clip->core.width;
		c.height = widget->drag.clip->core.height;
#endif

		UnionRect(&r,&c,&r);

	}
#endif

	r.width  += 1;
	r.height += 1;

	if((widget->core.width != r.width) || (widget->core.height != r.height))
	{
		if(XtMakeResizeRequest((Widget)widget,r.width,r.height,&repw,&reph)
		    == XtGeometryAlmost)
			XtMakeResizeRequest((Widget)widget,repw,reph,NULL,NULL);
	}

}

static void Resize(widget)
DragWidget widget;
{
	blink_icon(widget,NULL);
	if(widget->drag.auto_clean)
		DragCleanUpIcons((Widget)widget);
}

static void create_atoms(Display *dpy)
{
	int     screen = DefaultScreen(dpy);
	Window  root   = RootWindow(dpy,screen);
	Pixmap  source = XCreateBitmapFromData(dpy,root,open_hand_curs,
	    open_hand_width,open_hand_height);
	Pixmap  mask   = XCreateBitmapFromData(dpy,root,open_hand_mask,
	    open_hand_width,open_hand_height);
	XColor  white  = {
		0, 65535, 65535, 65535 		};
	XColor  black  = {
		0, 0,0,0 		};

	if(CanDropAtom == NULL)
	{
		WinIDAtom     = XInternAtom(dpy,ICON_DROP_WIN_ID,False);
		MiscAtom      = XInternAtom(dpy,ICON_DROP_MISC,False);
		WinNameAtom   = XInternAtom(dpy,ICON_DROP_WIN_NAME,False);
		IconClassAtom = XInternAtom(dpy,ICON_DROP_ICON_CLASS,False);
		IconNameAtom  = XInternAtom(dpy,ICON_DROP_ICON_NAME,False);
		BufLenAtom    = XInternAtom(dpy,ICON_DROP_BUF_LEN,False);
		BufAtom       = XInternAtom(dpy,ICON_DROP_BUF,False);
		EndAtom       = XInternAtom(dpy,ICON_DROP_END,False);
		AckAtom       = XInternAtom(dpy,ICON_DROP_ACK,False);
		CanDropAtom   = XInternAtom(dpy,ICON_CAN_DRAG_DROP,FALSE);
		InfoAtom      = XInternAtom(dpy,ICON_DROP_INFO,FALSE);
		BufLenExtAtom    = XInternAtom(dpy,ICON_DROP_BUF_LEN_EXT,False);
		BufExtAtom       = XInternAtom(dpy,ICON_DROP_BUF_EXT,False);


		open_cursor        = XCreatePixmapCursor(dpy,
		    source,
		    mask,
		    &black,
		    &white,
		    open_hand_x_hot,
		    open_hand_y_hot);

		source = XCreateBitmapFromData(dpy,root,close_hand_curs,
		    open_hand_width,open_hand_height);
		mask   = XCreateBitmapFromData(dpy,root,close_hand_mask,
		    open_hand_width,open_hand_height);
		close_cursor        = XCreatePixmapCursor(dpy,
		    source,
		    mask,
		    &black,
		    &white,
		    open_hand_x_hot,
		    open_hand_y_hot);

		drop_cursor = XCreateFontCursor(dpy,XC_box_spiral);

	}
}


static void register_widget(Widget widget,String name)
{
	/* Create atoms if they dont exist.
        Must go to class initalize, but where is the display ? */

	create_atoms(XtDisplay(widget));

	/* Register window for drop */

	XChangeProperty(
	    XtDisplay(widget),
	    XtWindow(widget),
	    CanDropAtom,
	    XA_WINDOW,
	    8,
	    PropModeReplace,
	    (unsigned char *)name,
	    strlen(name)+1);
}

static void clip_callback(Widget clip,DragWidget widget,DragCallbackStruct *cb)
{
	cb->x -= widget->core.x;
	cb->y -= widget->core.y;
	cb->same_window = (XtWindow(widget) == cb->remote_window);
	cb->remote_widget = XtWindowToWidget(XtDisplay(widget),cb->remote_window);
	cb->same_folder_tree = same_tree((Widget)widget,cb->remote_widget);
	XtCallCallbacks((Widget)widget,XmNdropCallback,(XtPointer)cb);
}

static void Realize (widget, value_mask, attributes)
DragWidget widget;
XtValueMask *value_mask;
XSetWindowAttributes *attributes;
{
	Window win;
	Display *dpy = XtDisplay(widget);
	int     screen = DefaultScreen(dpy);
	XGCValues values;
	XtGCMask  valueMask;
	Widget clip,scroll;
	/* Call inherited realize */


	((widget->core.widget_class->core_class.superclass)->core_class.realize)
	    ( (Widget) widget, value_mask, attributes);

	register_widget((Widget)widget,XtName((Widget)widget));

	win = XtWindow(widget);

	valueMask =  GCFunction | GCForeground | GCBackground | GCFont;

	values.function   = GXcopy;
	values.background = WhitePixel(dpy,screen);
	values.foreground = BlackPixel(dpy,screen);
	values.font       = XLoadFont(dpy,"fixed");

	widget->drag.gc = XCreateGC(dpy,win,valueMask,&values);

	/* valueMask |= GCFillStyle; */
	/* values.fill_style = FillSolid; */

	values.background = widget->core.background_pixel;
	values.foreground = values.foreground ^ values.background;
	values.background = values.foreground;
	values.function   = GXxor;

	widget->drag.selgc = XtGetGC((Widget)widget,valueMask,&values);
	widget->drag.clip = NULL;

	if(clip = XtParent(widget))
		if(scroll = XtParent(clip))
			if(XmIsScrolledWindow(scroll))
			{
				set_drop_property(clip,(XtCallbackProc)clip_callback,
				    (XtPointer)widget,(Widget)widget);
				widget->drag.clip = clip;
				XtAddEventHandler(clip,
					KeyPressMask|KeyReleaseMask|
					ButtonPressMask|ButtonReleaseMask,
					True,clip_event_handler,(XtPointer)widget);
			}
			else if(XmIsDrawingArea(clip))
			{
				set_drop_property(clip,(XtCallbackProc)clip_callback,
				    (XtPointer)widget,(Widget)widget);
			}

	check_size(widget);
}

static void plot_icon(DragWidget widget,Display *dpy,Window win,GC gc,Icon icon,int dx,int dy)
{
	int n = widget->drag.small_icons;
	if(icon->pix[n] == NULL) make_pixmaps((Widget)widget,icon,n);
	/*int under = icon == widget->drag.under;*/

	XSetForeground(dpy,gc, icon->foreground);
	XSetBackground(dpy,gc, icon->background);

	XSetClipMask(dpy,gc,icon->mask[n]);

	XSetClipOrigin (dpy,gc,
	    icon->r_icon[n].x+dx,
	    icon->r_icon[n].y+dy);

	if(icon->opened)
		XCopyArea(dpy,
		    icon->open_pix[n],
		    win,
		    gc,0,0,
		    icon->r_icon[n].width,
		    icon->r_icon[n].height,
		    icon->r_icon[n].x+dx,
		    icon->r_icon[n].y+dy);

	else
		XCopyArea(dpy,
		    icon->pix[n],
		    win,
		    gc,0,0,
		    icon->r_icon[n].width,
		    icon->r_icon[n].height,
		    icon->r_icon[n].x+dx,
		    icon->r_icon[n].y+dy);

	XSetClipMask(dpy,gc,None);


	if(icon->selected)
	{

		XSetForeground(dpy,gc, icon->hilitebackground);
		XSetBackground(dpy,gc, icon->hiliteforeground);
		XFillRectangle(dpy,win,gc,
		    icon->r_label[n].x+dx,
		    icon->r_label[n].y+dy,
		    icon->r_label[n].width,
		    icon->r_label[n].height);

		XSetForeground(dpy,gc, icon->hiliteforeground);
		XSetBackground(dpy,gc, icon->hilitebackground);

	}


	XmStringDraw(dpy,win,
	    widget->drag.fontlist,
	    icon->label,
	    gc,
	    icon->r_label[n].x+dx,
	    icon->r_label[n].y+dy,
	    icon->r_label[n].width,
	    XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, NULL);
}

static void draw_icons(widget,region)
DragWidget   widget;
Region region;
{
	Display         *dpy = XtDisplay(widget);
	Window          win  = XtWindow(widget);
	GC              gc = widget->drag.gc;
	int				n = widget->drag.small_icons;

	if(widget->core.visible)
	{
		Icon icon = widget->drag.icons;
		while(icon)
		{
			if(icon->visible)
				if( !region ||
				    XRectInRegion(region,
				    icon->r_all[n].x,
				    icon->r_all[n].y,
				    icon->r_all[n].width,
				    icon->r_all[n].height) != RectangleOut)
					plot_icon(widget,dpy,win,gc,icon,0,0);
			icon = icon->next;
		}

	}
}

static void Redraw(DragWidget widget,XEvent *event,Region region)
{
	XEvent          ev;
	Display         *dpy = XtDisplay(widget);
	Window          win  = XtWindow(widget);

	while(XCheckWindowEvent(dpy,win,ExposureMask,&ev))
		XtAddExposureToRegion(&ev,region);

	if(widget->core.visible)
	{
		draw_icons(widget,region);
		_XmRedisplayGadgets((Widget)widget, event,region);
		/*

		if(widget->drag.grid && widget->drag.gridx && widget->drag.gridy)
		{
			int i,j;
			for(i=0;i<widget->core.width;i+=widget->drag.gridx)
				XDrawLine(dpy,win,widget->drag.gc,i,0,i,widget->core.height);
			for(i=0;i<widget->core.height;i+=widget->drag.gridy)
				XDrawLine(dpy,win,widget->drag.gc,0,i,widget->core.width,i);
		}
		*/
	}
}

/*========================================================================================*/

static void edit_activate_callback(Widget text,XtPointer w,XtPointer cbdata)
{
	DragCallbackStruct cb;
	DragWidget drag = (DragWidget)w;

	char *p = XmTextFieldGetString(text);
	Icon icon = drag->drag.edit_icon;

	end_edit(drag);

	memset(&cb,0,sizeof(cb));
	cb.reason  = DRAG_RENAME;
	cb.event   = 0;
	cb.icon_class = icon->class;
	cb.icon_name  = icon->name;
	cb.icon_data  = icon->data;
	cb.icon       = icon;
	cb.new_name   = p;
	XtCallCallbacks ((Widget)drag,XmNrenameCallback,(XtPointer)&cb);


	XtFree(p);

	XmProcessTraversal((Widget)drag,XmTRAVERSE_CURRENT);
}

static void start_edit(DragWidget widget,Icon icon)
{
	int n = widget->drag.small_icons;
	Position x = icon->r_label[n].x;
	Position y = icon->r_label[n].y;
	Dimension width = icon->r_label[n].width;
	DragCallbackStruct cb;

	memset(&cb,0,sizeof(cb));
	cb.reason  = DRAG_RENAMABLE;
	cb.event   = 0;
	cb.icon_class = icon->class;
	cb.icon_name  = icon->name;
	cb.icon_data  = icon->data;
	cb.icon       = icon;
	cb.rename_it  = True;

	XtCallCallbacks ((Widget)widget,XmNrenamableCallback,(XtPointer)&cb);

	if(!cb.rename_it)
		return;

	end_edit(widget);
	widget->drag.edit_icon = icon;

	if(widget->drag.edit_text == NULL)
	{
		widget->drag.edit_text = XmCreateTextField((Widget)widget,"edit_text",0,0);
		XtAddCallback(widget->drag.edit_text,XmNactivateCallback,edit_activate_callback,(XtPointer)widget);

		XtVaSetValues(widget->drag.edit_text,
			XmNhighlightThickness,  (Dimension)1,
			XmNshadowThickness,  (Dimension)0,
			XmNfontList, widget->drag.fontlist,
			(void*)0);
	}

	if(width < 100)
	{
		int diff = 100 - width;
		width = 100;
		x -= diff/2;
		if(x < 0) x = 0;
	}
	if(x + width > widget->core.width)
	{
		x = widget->core.width - width;
		if(x < 0) x = 0;
	}

	XtVaSetValues(widget->drag.edit_text,
		XmNx,      x,
		XmNy,      y,
		XmNwidth,  width,
		/*XmNheight, height,*/
		(void*)0);

	XmTextFieldSetString(widget->drag.edit_text,icon->name);
	/*
	XmTextFieldSetSelection(widget->drag.edit_text,0,
		XmTextFieldGetLastPosition(widget->drag.edit_text),CurrentTime);
		*/

	XtManageChild(widget->drag.edit_text);
	XmProcessTraversal(widget->drag.edit_text,XmTRAVERSE_CURRENT);

	check_size(widget);

}

static void end_edit(DragWidget widget)
{
	if(widget->drag.edit_text)
		XtUnmanageChild(widget->drag.edit_text);
	widget->drag.edit_icon = 0;
}

/*========================================================================================*/

/*=====================================*/
/* Check if a window is register for drop */
/*=====================================*/

static Boolean check_valid_drop(Widget widget,Display* dpy,Window win,char **name)
{
	Atom type;
	int format;
	unsigned long nitems, left;
	char *retdata = NULL;

	if(!win) return False;

	if(XGetWindowProperty(dpy,win, CanDropAtom, 0,4,False,XA_WINDOW,
	    &type, &format, &nitems,&left, (unsigned char**) &retdata) == Success)
		if(type == XA_WINDOW)
		{
			if(*name) XtFree(*name);
			*name = XtNewString(retdata);
			return True;
		}

	/*else
	{
			int atomnum=0;
			Atom *atomlist=XListProperties(dpy,win,&atomnum);
			int i;
			printf("atom num: %d\n",atomnum);
			for(i=0; i< atomnum; i++)
			{
				 char *s =XGetAtomName(dpy, atomlist[i]);
				 printf(" %s \n",s);
				 XGetWindowProperty(dpy,win,atomlist[i] , 0,4,False,AnyPropertyType,
				    &type, &format, &nitems,&left,&retdata);

				 printf("  type: %d format: %d byte: %d left: %d\n",type,format,nitems,left);
				 if(strcmp(s,"_NET_WM_NAME") == 0)
				 {
					if(strstr("Syntax Highlight",retdata) != 0)
					{
						if(*name) XtFree(*name);
						*name = XtNewString(retdata);
						XFree(atomlist);
						return True;

					}
					printf("  data: %s\n",retdata);
				 }

				XFree(s);
	   		}

			XFree(atomlist);
	}*/

	return False;
}


/* Get The window tree */
/* We assume that no window will open/close while we drag */

typedef struct Site {
	Window       window;
	int          x;
	int          y;
	unsigned int width;
	unsigned int height;
	Boolean     is_drag;
	Widget      widget;
} Site;

static Site* sites     = 0;
static int   num_sites = 0;
static int   max_sites = 0;

static void get_tree(Display *dpy,Window w)
{
	Window  root;
	Window  parent;
	Window* children;
	unsigned int num = 0;
	int i;

	XQueryTree(dpy,w,&root,&parent,&children,&num);

	for(i = 0; i < num; i++)
	{
		Window child = children[i];
		Atom  type;
		int format;
		unsigned long nitems, left;
		unsigned char *retdata;
		if(XGetWindowProperty(dpy,child, CanDropAtom, 0,4,False,XA_WINDOW,
		    &type, &format, &nitems,&left,&retdata) == Success)
		{
			if(type == XA_WINDOW)
			{
				Site* s;
				unsigned int dummy;
				Window dw;

				if(num_sites == max_sites)
				{
					max_sites += 10;
					sites = (Site*)XtRealloc((XtPointer)sites,max_sites*sizeof(Site));
				}

				s = &sites[num_sites++];
				s->window = child;
				XGetGeometry(dpy,child,&root,
					&s->x,&s->y,&s->width,&s->height,&dummy,&dummy);

				XTranslateCoordinates(dpy,child,root,
					s->x,s->y,&s->x,&s->y,&dw);

				s->widget    = XtWindowToWidget(dpy,child);
				s->is_drag   = s->widget ? XtIsDrag(s->widget):0;
			}
		}

		get_tree(dpy,child);

	}
	XtFree((XtPointer)children);
}

static void get_window_tree(Display *dpy)
{
#if 0
	int     screen = DefaultScreen(dpy);
	Window  root   = RootWindow(dpy,screen);
	num_sites = 0;
	printf("->get_tree\n");
	get_tree(dpy,root);
	printf("<-get_tree\n");
#endif
}


/* Find which window is under the cursor */

static Window find_window(Display *dpy,Window *other,
Window win,int x,int y,int *wx,int *wy)
{
	Window child = 0,target = 0;
	int nx = 0,ny = 0;
	XWindowAttributes wattr;
	Window root = *other;

	*wx = *wy  =0;

	do
	{
		XTranslateCoordinates(dpy,root,win,x,y,&nx,&ny,&child);
		if(child)
		{
			*other = child;
			XGetWindowAttributes (dpy, child, &wattr);
			if(wattr.class == InputOutput) /* Fix for GKX */
			{
				Atom  type;
				int format;
				unsigned long nitems, left;
				unsigned char *retdata;

				/*int qtfound=0;
				int atomnum=0;
				Atom *atomlist=XListProperties(dpy,child,&atomnum);
				int i;
				printf("atom num: %d\n",atomnum);
				for(i=0; i< atomnum; i++)
				{
				 char *s =XGetAtomName(dpy, atomlist[i]);
				 printf(" %s \n",s);
				 XGetWindowProperty(dpy,child,atomlist[i] , 0,4,False,AnyPropertyType,
				    &type, &format, &nitems,&left,&retdata);

				 printf("  type: %d format: %d byte: %d left: %d\n",type,format,nitems,left);
				 if(strcmp(s,"_NET_WM_NAME") == 0)
				 {
					if(strstr("Syntax Highlight",retdata) != 0)
					{
						qtfound=1;
					}
					printf("  data: %s\n",retdata);
				 }
				 XFree(s);
				}
				XFree(atomlist);*/

				if(XGetWindowProperty(dpy,child, CanDropAtom, 0,4,False,XA_WINDOW,
				    &type, &format, &nitems,&left,&retdata) == Success)
					if(type == XA_WINDOW)
					{
						target = child;
						/* *wx = nx; */
						/* *wy = ny; */
						/* return here ??? */
						/* return target; */
					}
				/*else if(qtfound==1)
				{
					target = child;
				}*/

			}
		}
		root = win;
		win  = child;
		x = nx;
		y = ny;
	} while(child);

	*wx = nx;
	*wy = ny;

	return target;

}


static void send_drop_events(DragWidget widget,DragCallbackStruct *cb)
{
	XClientMessageEvent event;
	Display *dpy = XtDisplay(widget);
	Window   win = cb->remote_window;
	char buf[21];
	char *p;
	char buf_ext[400];
	int buf_ext_len;

	/* On 64-bit platforms, there appears to be a problem when using the data.l[]
	   part of the XClientMessageEvent structure. This is most likely because it is
	   defined as an array of longs, but it is intended as an array of 32-bit integers
	   (event.format=32). When dealing with this array, some of the data is lost, probably
	   because the internal 'X' code assumes 32-bit values. Therefore, we explicitly
	   use an 'int' pointer to access this data structure so that we can use 32-bit
	   values in it which is what it thinks it's getting. If 'int' is ever defined
	   to be greater than 32, then this code will have to be revised.
	   Perhaps the only message for which this might be a problem is the WinIDAtom message
	   - can this number always be stored in an int? The other thing to note is that
	   where event.format was previously being set to 32, we now set it to 8. When
	   set to 32, some bytes were not being received for some reason. This is resolved
	   when set to 8 - it should not make a difference, so the idea is that if you tell
	   it that the message is a set of bytes, then it should make sure that it transfers
	   all of them rather than trying to interpret 32-bit ints as longs. */
	
	int *iarray = (int *)&event.data.l[0];

	event.display = dpy;
	event.window  = win;
	event.type    = ClientMessage;

	/* Sebd window id */

	event.format       = 8; /*32*/
	event.message_type = WinIDAtom;
	iarray[0]    = XtWindow(widget);
	iarray[1]    = cb->x>0?cb->x:0;
	iarray[2]    = cb->y>0?cb->y:0;
	iarray[3]    = cb->icon?icon_to_int(widget,cb->icon):0;
	XSendEvent(dpy,win,True,NoEventMask,(XEvent*)&event);
	XFlush(dpy);

	event.format       = 8; /*32*/
	event.message_type = MiscAtom;
	iarray[0]    = widget->drag.copy;
	iarray[1]    = 0;
	iarray[2]    = 0;
	iarray[3]    = 0;
	XSendEvent(dpy,win,True,NoEventMask,(XEvent*)&event);
	XFlush(dpy);

	strncpy(buf,XtName((Widget)widget),20);
	buf[19] = 0;
	event.format = 8;
	event.message_type = WinNameAtom;
	strncpy(event.data.b,buf,20);
	XSendEvent(dpy,win,True,NoEventMask,(XEvent*)&event);
	XFlush(dpy);

	strncpy(buf,cb->icon?cb->icon->class:"",20);
	buf[19] = 0;
	event.format = 8;
	event.message_type = IconClassAtom;
	strcpy(event.data.b,buf);
	XSendEvent(dpy,win,True,NoEventMask,(XEvent*)&event);
	XFlush(dpy);

	strncpy(buf,cb->icon?cb->icon->name:"",20);
	buf[19] = 0;
	event.format = 8;
	event.message_type = IconNameAtom;
	strcpy(event.data.b,buf);
	XSendEvent(dpy,win,True,NoEventMask,(XEvent*)&event);
	XFlush(dpy);

	event.format       = 8; /*32*/
	event.message_type = BufLenAtom;
	iarray[0]    = cb->msg_length;
	iarray[1]    = cb->icon_no;
	iarray[2]    = cb->icon_count;
	iarray[3]    = cb->icon_batch;
	XSendEvent(dpy,win,True,NoEventMask,(XEvent*)&event);
	XFlush(dpy);

	p = cb->message;
	while(cb->msg_length > 0)
	{
		int n = cb->msg_length > 20 ? 20 : cb->msg_length;
		int i;

		for(i=0;i<n;i++)
		{
			event.format = 8;
			event.message_type = BufAtom;
			event.data.b[i] = *p++;
		}

		XSendEvent(dpy,win,True,NoEventMask,(XEvent*)&event);
		XFlush(dpy);

		cb->msg_length -= n;

	}

	//Messages to QT
	XtCallCallbacks (widget, XmNgetFullNameCallback,(XtPointer)cb);


        strncpy(buf_ext,cb->icon_fullName,strlen(cb->icon_fullName));
	buf_ext[strlen(cb->icon_fullName)]='\0';

	buf_ext_len=strlen(buf_ext);

	event.format       = 8; /*32*/
	event.message_type = BufLenExtAtom;
	iarray[0]    = buf_ext_len;
	iarray[1]    = cb->icon_no;
	iarray[2]    = cb->icon_count;
	iarray[3]    = cb->icon_batch;
	XSendEvent(dpy,win,True,NoEventMask,(XEvent*)&event);
	XFlush(dpy);

	p = &buf_ext[0];
	while(buf_ext_len > 0)
	{
		int n = buf_ext_len > 20 ? 20 : buf_ext_len;
		int i;

		for(i=0;i<n;i++)
		{
			event.format = 8;
			event.message_type = BufExtAtom;
			event.data.b[i] = *p++;
		}

		XSendEvent(dpy,win,True,NoEventMask,(XEvent*)&event);
		XFlush(dpy);

		buf_ext_len -= n;
	}



	event.format = 8; /*32*/;
	event.message_type = EndAtom;
	XSendEvent(dpy,win,True,NoEventMask,(XEvent*)&event);
	XFlush(dpy);
}

static void send_drop_msg(widget,win,x,y,icon,no,count,batch)
DragWidget widget;
Window win;
Icon icon;
int no;
int count;
int batch;
{
	DragCallbackStruct cb;

	memset(&cb,0,sizeof(cb));
	cb.reason = DRAG_SEND;
	cb.event         = &widget->drag.event;
	cb.send_it       = True;
	cb.delete_it     = False;
	cb.same_window   = (win == XtWindow(widget));
	cb.remote_window = win;
	cb.remote_name   = widget->drag.target;

	cb.x             = x;
	cb.y             = y;
	cb.icon_class    = icon->class;
	cb.icon_name     = icon->name ;
	cb.icon_data     = icon->data ;
	cb.icon          = icon;
	cb.copy          = widget->drag.copy;

	cb.message       = NULL;
	cb.msg_length    = 0;
	cb.remote_widget = XtWindowToWidget(XtDisplay(widget),cb.remote_window);

	/* Check for clip windows */

	if(cb.remote_widget && XmIsDrawingArea(cb.remote_widget))
	{
		Widget w = XtParent(cb.remote_widget);
		if(w && XmIsScrolledWindow(w))
		{
			int n;
			WidgetList child;
			XtVaGetValues(cb.remote_widget,XtNnumChildren,&n,
				XtNchildren,&child,NULL);
			w = cb.remote_widget;

			if(n && child[0])
			{
				w = child[0];
				if(XtIsDrag(w))
				{
					cb.remote_widget = w;
					cb.remote_window = XtWindow(w);
				}
			}
		}
	}


	cb.same_folder_tree = same_tree((Widget)widget,cb.remote_widget);

	cb.icon_no        = no;
	cb.icon_count     = count;
	cb.icon_batch     = batch;


	if(widget->drag.auto_folder_move && cb.same_folder_tree &&
		XtIsDrag(cb.remote_widget))
	{
		Icon p = widget->drag.icons;
		Icon q = NULL;
		DragWidget target = (DragWidget)cb.remote_widget;

		cb.reason    = DRAG_FOLDER_MOVE;
		XtCallCallbacks ((Widget)widget,XmNfolderMoveCallback,(XtPointer)&cb);
		icon->delete = False;

		if(cb.send_it)
		{
			while(p)
			{
				if(p == icon)
				{
					if(q)
						q->next = p->next;
					else
						widget->drag.icons = p->next;

					if(!p->next)
						widget->drag.last = q;

					icon->next         = target->drag.icons;
					target->drag.icons = icon;
					icon->parent       = (Widget)target;
					move_icon(target,icon,x,y,-1,-1);
					show_icon(target,icon);

				}

				q = p;
				p = p->next;

			}
			check_size(widget);
		}
		else show_icon(widget,icon);

	}
	else
	{

		XtCallCallbacks ((Widget)widget,XmNsendmsgCallback,(XtPointer)&cb);

		if(cb.send_it)
		{
			icon->delete = cb.delete_it;
			send_drop_events(widget,&cb);
		}
	}
}

static Icon find_icon(DragWidget widget,XEvent* event,Boolean* label)
{
	Icon icon = widget->drag.icons;
	int n = widget->drag.small_icons;

	while(icon)
	{
		if(icon->visible)
		{
			if(event->xbutton.x > icon->r_icon[n].x &&
			    event->xbutton.y > icon->r_icon[n].y &&
			    event->xbutton.x < (int) (icon->r_icon[n].x+icon->r_icon[n].width)
			    &&
			    event->xbutton.y < (int) (icon->r_icon[n].y+icon->r_icon[n].height))
			{
				*label = False;
				return icon;
			}

			if(event->xbutton.x > icon->r_label[n].x &&
			    event->xbutton.y > icon->r_label[n].y &&
			    event->xbutton.x < (int) (icon->r_label[n].x+icon->r_label[n].width)
			    &&
			    event->xbutton.y < (int) (icon->r_label[n].y+icon->r_label[n].height))
			{
				*label = True;
				return icon;
			}
		}

		icon = icon->next;
	}
	return NULL;
}

static void show_hide(DragWidget widget,Icon icon,Boolean vis)
{
	if(icon && (icon->visible != vis))
	{
		icon->visible = vis;
		inval_icon(widget,icon);
	}
}

static void raise_icon(DragWidget widget,Icon icon)
{
	Icon p = widget->drag.icons;
	Icon q = NULL;

	if(icon == widget->drag.last) return;

	while(p)
	{
		if(p == icon)
		{
			if(q)
				q->next = icon->next;
			else
				widget->drag.icons = icon->next;

			widget->drag.last->next = icon;
			widget->drag.last = icon;
			icon->next = NULL;
			break;
		}
		q = p;
		p = p->next;
	}
	inval_icon(widget,icon);
}

static void move_icon(widget,icon,newx,newy,real_x,real_y)
DragWidget widget;
Icon icon;
int newx,newy;
int real_x,real_y;
{
	DragCallbackStruct cb;
	int n = widget->drag.small_icons;
	int oldx = icon->r_all[n].x;
	int oldy = icon->r_all[n].y;

	new_icon_xy(icon,newx,newy);
	place_icon(widget,icon,False);

	newx = icon->r_all[n].x;
	newy = icon->r_all[n].y;


	memset(&cb,0,sizeof(cb));
	cb.reason = DRAG_MOVE;
	cb.move_it = True;

	cb.event = 0;
	if(real_x >= 0 && real_y >= 0)
	{
		cb.event = &widget->drag.event;
		cb.event->xbutton.x = real_x;
		cb.event->xbutton.y = real_y;
		cb.copy  = widget->drag.copy;
	}

	cb.icon_class = icon->class;
	cb.icon_name = icon->name;
	cb.icon_data = icon->data;
	cb.icon      = icon;


	cb.x = newx;
	cb.y = newy;
	XtCallCallbacks ((Widget)widget,XmNmoveCallback,(XtPointer)&cb);

	if(!cb.move_it)
		new_icon_xy(icon,oldx,oldy);

	if(newx != cb.x || newy != cb.y)
		place_icon(widget,icon,False);

	hide_icon(widget,icon);
	/*  raise_icon(widget,icon);*/
	show_icon(widget,icon);
	check_size(widget);


}

static void hide_icon(DragWidget widget,Icon icon)
{
	show_hide(widget,icon,False);
}

static void show_icon(DragWidget widget,Icon icon)
{
	show_hide(widget,icon,True);
}

static void inval_icon(widget,icon)
DragWidget widget;
Icon icon;
{
	int n = widget->drag.small_icons;

	if(XtIsRealized((Widget)widget))
	{
		XClearArea(XtDisplay(widget),XtWindow(widget),
		    icon->r_icon[n].x,
		    icon->r_icon[n].y,
		    icon->r_icon[n].width,
		    icon->r_icon[n].height,
		    True);

		XClearArea(XtDisplay(widget),XtWindow(widget),
		    icon->r_label[n].x,
		    icon->r_label[n].y,
		    icon->r_label[n].width,
		    icon->r_label[n].height,
		    True);
	}

}

static void remove_icon(DragWidget widget,Icon icon,Boolean resize)
{
	Icon p = widget->drag.icons;
	Icon q = NULL;
	DragCallbackStruct cb;
	int i;

	while(p)
	{
		if(p == icon)
		{
			if(q)
				q->next = p->next;
			else
				widget->drag.icons = p->next;

			if(!p->next)
				widget->drag.last = q;

			memset(&cb,0,sizeof(cb));
			cb.reason = DRAG_KILL;
			cb.event = &widget->drag.event;
			cb.icon_class = icon->class;
			cb.icon_name = icon->name;
			cb.icon_data = icon->data;
			cb.icon      = icon;
			XtCallCallbacks((Widget)widget,XmNkillIconCallback,(XtPointer)&cb);

			inval_icon(widget,icon);

			/* if(p->r_all[n].width  == widget->drag.gridx) */
			widget->drag.gridx = 0;

			/* if(p->r_all[n].height == widget->drag.gridy) */
			widget->drag.gridy = 0;

			XtFree(p->name);
			XtFree(p->class);
			XmStringFree(p->label);

			widget->drag.gridx = 0;
			widget->drag.gridy = 0;

			for(i=0;i<2;i++)
			{
				FreePixmap((Widget)widget,icon->pix[i]);
				FreePixmap((Widget)widget,icon->open_pix[i]);
				FreePixmap((Widget)widget,icon->mask[i]);

				/* XtFree(icon->pix_name[i]); */
				/* XtFree(icon->open_name[i]); */
				/* XtFree(icon->mask_name[i]); */
			}

			XtFree((XtPointer)p);
			if(resize)
				if(widget->drag.auto_clean)
					DragCleanUpIcons((Widget)widget);
				else
					check_size(widget);
			break;
		}
		q = p;
		p = p->next;
	}
}

static void answer(DragWidget widget,Window win,int code,Icon icon,
int no,int count,int batch,Window other,int x,int y)
{
	DragCallbackStruct cb;

	memset(&cb,0,sizeof(cb));
	cb.reason = DRAG_ANSWER;
	cb.event         = &widget->drag.event;
	cb.code          = code;

	cb.same_window   = (win == XtWindow(widget));
	cb.remote_window = win;
	cb.remote_name   = widget->drag.target;
	cb.remote_widget = XtWindowToWidget(XtDisplay(widget),cb.remote_window);
	cb.same_folder_tree = same_tree((Widget)widget,cb.remote_widget);

	cb.icon_class    =  icon->class;
	cb.icon_name     =  icon->name ;
	cb.icon_data     =  icon->data ;
	cb.icon          =  icon;
	cb.icon_no       =  no;
	cb.icon_count    =  count;
	cb.icon_batch    =  batch;
	cb.x             = x;
	cb.y             = y;

	if(code == DROP_ABORTED)
	{
		cb.reason        = DRAG_OTHER_DROP;
		cb.remote_window = other;
		XtCallCallbacks ((Widget)widget,XmNotherDropCallback,(XtPointer)&cb);
	}
	else
		XtCallCallbacks ((Widget)widget,XmNanswerCallback,(XtPointer)&cb);
}

static void new_icon_xy(Icon icon,int x,int y)
{
	int i;

	for(i=0;i<2;i++)
	{
		icon->r_icon[i].x  -= icon->r_all[i].x;
		icon->r_label[i].x -= icon->r_all[i].x;
		icon->r_icon[i].y  -= icon->r_all[i].y;
		icon->r_label[i].y -= icon->r_all[i].y;

		icon->r_all[i].x = x;
		icon->r_all[i].y = y;

		icon->r_icon[i].x  += icon->r_all[i].x;
		icon->r_label[i].x += icon->r_all[i].x;
		icon->r_icon[i].y  += icon->r_all[i].y;
		icon->r_label[i].y += icon->r_all[i].y;
	}
}

static void place_icon(DragWidget widget,Icon icon,Boolean resize)
{
	Boolean go_on = True;
	int	    n = widget->drag.small_icons;
	Dimension maxw;

	if(widget->drag.grid)
	{
		/* Compute new grid if needed */

		if(widget->drag.gridx == 0 || widget->drag.gridy == 0)
		{
			Icon p = widget->drag.icons;

			widget->drag.gridx = widget->drag.gridy = 1;

			while(p)
			{
				widget->drag.gridx = MAX(widget->drag.gridx,((int)p->r_all[n].width));
				widget->drag.gridy = MAX(widget->drag.gridy,((int)p->r_all[n].height));
				p = p->next;
			}

			widget->drag.gridx += widget->drag.marginx;
			widget->drag.gridy += widget->drag.marginy;
		}

		maxw = widget->core.width;
		if(widget->drag.clip)
			if(widget->drag.clip->core.width > maxw)
				maxw = widget->drag.clip->core.width;

		while(go_on)
		{
			int newx = icon->r_all[n].x;
			int newy = icon->r_all[n].y;
			int ix,iy,gx,gy;

			go_on = False;

			if(n)
			{
				ix = 0;
				iy = icon->r_all[n].height;
				gx = widget->drag.marginx / 2 ;
				gy = widget->drag.gridy;
			}
			else
			{
				ix = icon->r_all[n].width /2;
				iy = icon->r_all[n].height;
				gx = widget->drag.gridx/2;
				gy = widget->drag.gridy;
			}

			newx += ix;
			newy += iy;

			newx = ((newx-gx)/widget->drag.gridx)*widget->drag.gridx + gx;
			newy = ((newy-gy)/widget->drag.gridy)*widget->drag.gridy + gy;

			newx -= ix;
			newy -= iy;

			new_icon_xy(icon,newx,newy);

			if(widget->drag.auto_place)
			{
				Icon p = widget->drag.icons;

				while(p && !go_on)
				{
					if(p != icon && InterRect(&p->r_all[n],&icon->r_all[n]))
						go_on = True;
					p = p->next;
				}
				if(go_on)
				{
					if((Dimension) (icon->r_all[n].x + icon->r_all[n].width
					    + widget->drag.gridx) < maxw)
					{
						newx = icon->r_all[n].x + widget->drag.gridx;
						newy = icon->r_all[n].y;
					}
					else
					{
						newx = 0;
						newy = icon->r_all[n].y + widget->drag.gridy;
					}
					new_icon_xy(icon,newx,newy);
				}
			}

		}
	}

	if(resize)
		check_size(widget);
}


/*=================================*/

static Window create_drag_window(Widget w,XEvent *event,Pixmap pix,int dx,int dy,
int width,int height)
{
	/* Create drag window */


	Display *dpy   = XtDisplay(w);
	int     screen = DefaultScreen(dpy);
	Window  root   = RootWindow(dpy,screen);

	unsigned long mask;
	XSetWindowAttributes att;
	Window drag;

	mask = CWCursor | CWOverrideRedirect | CWSaveUnder | CWBackPixmap;
	att.override_redirect = TRUE;
	att.save_under        = TRUE;
	att.background_pixmap = pix;
	att.cursor            = close_cursor;

	drag = XCreateWindow(dpy,root,
	    event->xbutton.x_root - dx,
	    event->xbutton.y_root - dy,
	    width,
	    height,
	    0,
	    /*0*/ CopyFromParent,
	    InputOutput,CopyFromParent,mask,&att);

	XSelectInput(dpy,drag,ButtonPressMask|
	    PointerMotionMask | LeaveWindowMask |
	    ButtonMotionMask  | ButtonReleaseMask);

	XDefineCursor(dpy,drag,close_cursor);
	XDefineCursor(dpy,XtWindow(w),close_cursor);

	return drag;
}

static void drag_over(Widget widget,Window drag,XEvent* ev)
{
	Icon p = ((DragWidget)widget)->drag.icons;
	DragCallbackStruct cb;
	int i;
	int x = 0;
	int y = 0;
	Site * hit = 0;

	for(i  = 0; i < num_sites; i++)
	{
		Site* s = &sites[i];
		if(
			s->x <= ev->xbutton.x_root &&
			s->y <= ev->xbutton.y_root &&
			s->x + s->width >= ev->xbutton.x_root &&
			s->y + s->height >= ev->xbutton.y_root)
				hit = s;
	}

	if(!hit) return;
	if(!hit->is_drag) return;

	x = ev->xbutton.x_root - hit->x;
	y = ev->xbutton.y_root - hit->y;

	 /* NOTE: Callback done on OTHER widget.... */

	while(p)
	{
		if(p->selected)
		{
			memset(&cb,0,sizeof(cb));
			cb.event      = ev;
			cb.reason     = DRAG_FLY_OVER;
			cb.icon_class = p->class;
			cb.icon_name  = p->name;
			cb.icon_data  = p->data;
			cb.icon       = p;
			cb.same_window   = (hit->widget == widget);
			cb.remote_name   = XtName(widget);
			cb.remote_window = XtWindow(widget);
			cb.remote_widget = widget;
			cb.x = x;
			cb.y = y;
			XtCallCallbacks (hit->widget,XmNflyOverCallback,(XtPointer)&cb);
		}
		p = p->next;
	}

}

static Window drag_window(Widget widget,
	Window drag,int dx,int dy, int *wx,
	int *wy,Window *other)
{
	XEvent  ev;
	Display *dpy       = XtDisplay(widget);
	int     screen     = DefaultScreen(dpy);
	Window  root       = RootWindow(dpy,screen);
	Boolean save_under = DoesSaveUnders(XtScreen(widget));
	Boolean done       = False;
	Window  target     = 0;

	get_window_tree(dpy);

	*other = root;

	XMapWindow(dpy,drag);
	while(!done)
	{
		XNextEvent(dpy,&ev);
		if(!save_under &&ev.type == Expose) XtDispatchEvent(&ev);

		switch(ev.type)
		{

		case ButtonRelease:

			XDestroyWindow(dpy,drag);

			XSync(dpy,False);

			*other = root;
			target = find_window(dpy,other,root,
			    ev.xbutton.x_root,
			    ev.xbutton.y_root,wx,wy);

			done = True;
			break;

		case LeaveNotify:
		case MotionNotify:
			while(XCheckWindowEvent(dpy,drag,PointerMotionMask,&ev))
				;
			while(XCheckWindowEvent(dpy,drag,ButtonMotionMask,&ev))
				;
			XMoveWindow(dpy,drag,
			    ev.xmotion.x_root-dx,
			    ev.xmotion.y_root-dy);

			drag_over(widget,drag,&ev);

			break;
		}
	}
	return target;
}

static void drag_and_drop(DragWidget widget,XEvent *event)
{
	Display *dpy   = XtDisplay(widget);
	int     screen = DefaultScreen(dpy);
	Window  root   = RootWindow(dpy,screen);
	Pixmap pix;
	int wx,wy;
	XRectangle  frame;
	int         i,count = 0;
	int      n = widget->drag.small_icons;



	Window target = NULL;
	Window drag;
	Window other;
	int width;
	int height;

	Position dx,dy;
	Boolean label;
	Icon icon = find_icon(widget,event,&label);
	Icon p;


	if(!icon ||  widget->drag.selecting || widget->drag.justclick)
		return;

	select_icon(widget,icon,event,
	    (event->xbutton.state & ShiftMask) == 0);

	if(!widget->drag.copy)
	{
		p = widget->drag.icons;
		while(p)
		{
			if(p->selected)
				hide_icon(widget,p);
			p = p->next;
		}
	}
	draw_icons(widget,NULL);


	/* Get rectangle containing all selected icons */


	frame = icon->r_all[n];
	p = widget->drag.icons;
	while(p)
	{
		if(p->selected)
			UnionRect(&frame,&p->r_all[n],&frame);
		p = p->next;
	}

	/* Get offset of cursor within pixmap */

	dx = event->xbutton.x - frame.x;
	dy = event->xbutton.y - frame.y;

	width  = frame.width;
	height = frame.height;

	widget->drag.event = *event; /* save event */

	pix = XCreatePixmap(dpy,root,width,height,DefaultDepth(dpy,screen));
	XSetForeground(dpy,widget->drag.gc,widget->core.background_pixel);
	XFillRectangle(dpy,pix,widget->drag.gc,0,0,width,height);

	p = widget->drag.icons;
	while(p)
	{
		if(p->selected)
		{
			plot_icon(widget,dpy,pix,widget->drag.gc,p,-frame.x,-frame.y);
			count++;
		}
		p = p->next;
	}


	/* Create drag window */

	drag = create_drag_window((Widget)widget, event, pix, dx,dy, width,height);


	if(widget->drag.shape_mode != NO_SHAPE)
	{


		XShapeCombineRectangles(dpy,drag,ShapeBounding,
		    0,0,&empty,1,ShapeSet,Unsorted);


		p = widget->drag.icons;
		while(p)
		{
			if(p->selected && p->mask[n])
			{

				if(widget->drag.shape_mode == RECT_SHAPE1)
				{
					XShapeCombineRectangles(dpy,drag,ShapeBounding,
					    -frame.x,
					    -frame.y,
					    &p->r_all[n],1,ShapeUnion,Unsorted);
				}
				else
				{
					if(widget->drag.shape_mode == RECT_SHAPE2)
						XShapeCombineRectangles(dpy,drag,ShapeBounding,
						    -frame.x,
						    -frame.y,
						    &p->r_icon[n],1,ShapeUnion,Unsorted);
					else

						XShapeCombineMask(dpy,drag,ShapeBounding,
						    p->r_icon[n].x - frame.x,
						    p->r_icon[n].y - frame.y,
						    p->mask[n],ShapeUnion);


					XShapeCombineRectangles(dpy,drag,ShapeBounding,
					    -frame.x,
					    -frame.y,
					    &p->r_label[n],1,ShapeUnion,Unsorted);
				}



			}
			p = p->next;
		}
	}


	target  = drag_window((Widget)widget,drag,dx,dy,&wx,&wy,&other);
	XFreePixmap(dpy,pix);


	if(target && widget->drag.clip && (target == XtWindow(widget->drag.clip)))
	{
		target = XtWindow(widget);
		dx -= 0; /* todo */
		dy -= 0; /* todo */
	}

	if(check_valid_drop((Widget)widget,dpy,target,&widget->drag.target))
	{


		icon_batch++;

		if(wx < dx ) dx = wx;
		if(wy < dy ) dy = wy;

		p = widget->drag.icons;
		i = 0;
		while(p)
		{
			Icon q = p->next;
			if(p->selected)
			{

				if(/*move && */ widget->drag.auto_move && target == XtWindow(widget))
				{
					widget->drag.event.xbutton.x = wx;
					widget->drag.event.xbutton.y = wy;

					move_icon(widget,p,
					    wx  + (p->r_all[n].x - frame.x) -dx,
					    wy  + (p->r_all[n].y - frame.y) -dy,
						wx,
						wy
					    );
				}
				else
					send_drop_msg(widget,target,
					    wx  + (p->r_all[n].x - frame.x) -dx,
					    wy  + (p->r_all[n].y - frame.y) -dy,
					    p,
					    ++i,
					    count,
					    icon_batch);
			}
			p = q;
		}
	}
	else
	{
		i = 0;
		p = widget->drag.icons;
		while(p)
		{
			if(p->selected)
			{
				int x = wx + (p->r_all[n].x - frame.x) -dx;
				int y = wy + (p->r_all[n].y - frame.y) -dy;
				answer(widget,target,DROP_ABORTED,p,++i,count,
				    icon_batch,other,x,y);
			}
			p = p->next;
		}

		p = widget->drag.icons;
		while(p)
		{
			if(p->selected) show_icon(widget,p);
			p = p->next;
		}
	}

	XUndefineCursor(dpy,XtWindow(widget));
	/* set_icon_under(widget,NULL); */
	draw_icons(widget,NULL);

}

/*=================================*/

static void unselect_icon_tree(DragWidget widget,XEvent  *event)
{
	Icon p = widget->drag.icons;
	DragCallbackStruct cb;
	int i;

	while(p)
	{
		if(p->selected)
		{
			p->selected = False;
			inval_icon(widget,p);

			memset(&cb,0,sizeof(cb));
			cb.event = event;
			cb.reason = DRAG_SELECT;
			cb.selected = False;
			cb.icon_class = p->class;
			cb.icon_name = p->name;
			cb.icon_data = p->data;
			cb.icon      = p;
			XtCallCallbacks ((Widget)widget,XmNselectCallback,(XtPointer)&cb);
		}
		p = p->next;
	}

	for(i=0;i<widget->drag.child_count;i++)
		unselect_icon_tree((DragWidget)widget->drag.child_folders[i],event);
}

static Boolean same_tree(Widget w1,Widget w2)
{
	if(w1 == NULL || w2 == NULL) return False;
	if(!XtIsDrag((Widget)w1) || !XtIsDrag((Widget)w2)) return False;

	while(((DragWidget)w1)->drag.parent_folder)
		w1 = ((DragWidget)w1)->drag.parent_folder;
	while(((DragWidget)w2)->drag.parent_folder)
		w2 = ((DragWidget)w2)->drag.parent_folder;

	return w1 == w2;
}

static void unselect_all_icons(widget,event)
DragWidget widget;
XEvent *event;
{
	while(widget->drag.parent_folder)
		widget = (DragWidget)widget->drag.parent_folder;

	unselect_icon_tree(widget,event);
}

static void select_icon(DragWidget widget,Icon icon,XEvent *event,Boolean unsel)
{
	DragCallbackStruct cb;


	if(icon && icon->selected) return;

	/* unselect fisrt */

	if(unsel) unselect_all_icons(widget,event);

	if(icon)
	{
		icon->selected = True;
		inval_icon(widget,icon);

		memset(&cb,0,sizeof(cb));
		cb.event = event;
		cb.reason = DRAG_SELECT;
		cb.icon_class = icon->class;
		cb.icon_name = icon->name;
		cb.icon_data = icon->data;
		cb.icon      = icon;
		cb.selected = True;
		XtCallCallbacks ((Widget)widget,XmNselectCallback,(XtPointer)&cb);
	}
}

static void toggle_icon(widget,icon,event)
DragWidget widget;
Icon icon;
XEvent *event;
{
	DragCallbackStruct cb;


	if(!icon) return;

	icon->selected = !icon->selected;

	inval_icon(widget,icon);

	memset(&cb,0,sizeof(cb));
	cb.event = event;
	cb.reason = DRAG_SELECT;
	cb.icon_class = icon->class;
	cb.icon_name = icon->name;
	cb.icon_data = icon->data;
	cb.icon      = icon;
	cb.selected = icon->selected;
	XtCallCallbacks ((Widget)widget,XmNselectCallback,(XtPointer)&cb);
}

/*=================================*/

static int dist(char *a,char *b,int len)
{
	int i = 0;
	while(len--)
	{
		char c = islower(*a) ? toupper(*a) : *a;
		char d = islower(*b) ? toupper(*b) : *b;

		if(c != d ) return len-i+1;

		i++;
		a++;
		b++;
	}
	return -1;
}

void DragShowLast(w)
Widget w;
{
	DragWidget widget = (DragWidget) w;
	widget->drag.last_added = check_icon(widget,widget->drag.last_added);
	if(widget->drag.last_added)
		DragDisplayIcon((Widget)widget,
		    widget->drag.last_added,
		    DRAG_DISPLAY_VISUAL_FEEDBACK);
}

void DragBlinkIcon(Widget w,Icon n)
{
	DragWidget widget = (DragWidget) w;
	n =  check_icon(widget,n);
	if(n) DragDisplayIcon((Widget)widget,n,DRAG_DISPLAY_VISUAL_FEEDBACK);
}

static void ShowLast(widget,event,args,nargs)
DragWidget widget;
XEvent     *event;
char       **args;
int        nargs;
{
	widget->drag.last_added = check_icon(widget,widget->drag.last_added);
	if(widget->drag.last_added)
		DragDisplayIcon((Widget)widget,
		    widget->drag.last_added,
		    DRAG_DISPLAY_VISUAL_FEEDBACK);
}

static void KeySelect(widget,event,args,nargs)
DragWidget widget;
XEvent     *event;
char       **args;
int        nargs;
{
	static char buf[32];
	static int  pos = 0;
	int n;
	static Time last = 0;

	if(!widget->drag.accept_keys) return;

	if(event->xkey.time - last > widget->drag.key_threshold)
		pos = 0;

	blink_icon(widget,NULL);
	last = event->xkey.time;


	/*-- if((n = XLookupString(&event->xkey,buf+pos,sizeof(buf)-1-pos,NULL,NULL))>0)  --*/
	/*-- Q&D fix to prevent coredump when key is pressed continuously (vk 1999-01-28) --*/
	if( pos < sizeof(buf) )
	    n = XLookupString(&event->xkey,buf+pos,sizeof(buf)-1-pos,NULL,NULL);
	else
	    n = 0;

	printf("key select %s %d\n",buf,buf[0]);

	if( n > 0 )
	{
		Icon p   = widget->drag.icons;
		Icon q   = NULL;
		int  min = 90000;

		pos     += n;
		buf[pos] = 0;

		while(p)
		{
			int d = dist(p->name,buf,pos);
			if(d<min)
			{
				min = d;
				q   = p;
			}
			p = p->next;
		}

		if(q)
		{
			raise_icon(widget,q);
			select_icon(widget,q,event,True);
			DragDisplayIcon((Widget)widget,q,DRAG_DISPLAY_NO_EFFECT);
		}
	}
}

void DragToggleSizeIcons(widget)
Widget widget;
{
	ToggleSize((DragWidget)widget, NULL, 0, NULL);
}

Boolean DragAreSmallIconsUsed(widget)
Widget widget;
{
	return ((DragWidget)widget)->drag.small_icons;
}

void DragUseSmallIcons(Widget widget, Boolean use)
{
	if(((DragWidget)widget)->drag.small_icons != use)
	{
		((DragWidget)widget)->drag.small_icons = !use;
		DragToggleSizeIcons(widget);
	}
}


static void ToggleSize(widget,event,args,nargs)
DragWidget widget;
XEvent     *event;
char       **args;
int        nargs;
{
	blink_icon(widget,NULL);
	widget->drag.small_icons = !widget->drag.small_icons;

	widget->drag.gridx = 0;

	if(widget->drag.grid)
	{
		Icon p = widget->drag.icons;
		while(p)
		{
			place_icon(widget,p,False);
			p = p->next;
		}
		if(widget->drag.auto_clean)
			DragCleanUpIcons((Widget)widget);
	}
	check_size(widget);
	if(XtIsRealized((Widget)widget))
		XClearArea(XtDisplay(widget),XtWindow(widget),0,0,0,0,True);
}

/*
static void DragMove(widget,event,args,nargs)
DragWidget widget;
XEvent     *event;
char       **args;
int        nargs;
{
	drag_and_drop(widget,event,True);
}
*/

int DragSortByName(widget,icon1,icon2)
Widget widget;
Icon icon1,icon2;
{
	int n = strcasecmp(icon1->name,icon2->name);
	return n?n:strcasecmp(icon1->class,icon2->class);
}

int DragSortByClass(widget,icon1,icon2)
Widget widget;
Icon icon1,icon2;
{
	int n = strcasecmp(icon1->class,icon2->class);
	return n?n:strcasecmp(icon1->name,icon2->name);
}

static int SortByXY(widget,icon1,icon2)
DragWidget widget;
Icon icon1,icon2;
{
	int n = icon1->r_all[widget->drag.small_icons].y
	- icon2->r_all[widget->drag.small_icons].y;
	return n?n:icon1->r_all[widget->drag.small_icons].x
	    - icon2->r_all[widget->drag.small_icons].x;
}


static void all_moved(DragWidget widget,XEvent *event)
{
	DragCallbackStruct cb;
	int n  = widget->drag.small_icons;
	Icon p = widget->drag.icons;

	memset(&cb,0,sizeof(cb));
	cb.reason = DRAG_MOVE;
	cb.event = event;

	while(p)
	{
		cb.icon_class = p->class;
		cb.icon_name = p->name;
		cb.icon_data = p->data;
		cb.icon      = p;
		cb.x = p->r_all[n].x;
		cb.y = p->r_all[n].y;
		XtCallCallbacks ((Widget)widget,XmNmoveCallback,(XtPointer)&cb);
		p = p->next;
	}

}

static void sort_icons(widget,sort)
DragWidget widget;
int (*sort)();
{
	Icon p,q,r;
	Boolean swap = True;
	Boolean grid = widget->drag.grid;
	Boolean place = widget->drag.auto_place;

	/* silly bubble sort */
	while(swap)
	{
		swap = False;
		p = widget->drag.icons;
		r = NULL;
		while(p)
		{
			q = p->next;
			if(q)
			{
				if((*sort)(widget,p,q)>0)
				{
					swap = True;
					if(r)
						r->next = q;
					else
						widget->drag.icons = q;

					p->next = q->next;
					q->next = p;

					if(q == widget->drag.last)
						widget->drag.last = p;

					break;
				}
			}
			r = p;
			p = q;
		}
	}

	p = widget->drag.icons;
	while(p)
	{
		new_icon_xy(p,widget->core.width+20,widget->core.height+20);
		p = p->next;
	}

	widget->drag.grid = True;
	widget->drag.auto_place = True;

	p = widget->drag.icons;
	while(p)
	{
		new_icon_xy(p,0,0);
		place_icon(widget,p,False);
		p = p->next;
	}
	check_size(widget);

	if(XtIsRealized((Widget)widget))
		XClearArea(XtDisplay(widget),XtWindow(widget),0,0,0,0,True);

	widget->drag.grid = grid;
	widget->drag.auto_place = place;

}

static void Sort(widget,event,args,nargs)
DragWidget widget;
XEvent     *event;
char       **args;
int        nargs;
{
	int (*sort)() = widget->drag.sort;
	blink_icon(widget,NULL);

	if(event->xkey.state & ShiftMask) sort = DragSortByClass;

	if(!sort) return;
	sort_icons(widget,sort);
	all_moved(widget,NULL);
}


static void CleanUp(widget,event,args,nargs)
DragWidget widget;
XEvent     *event;
char       **args;
int        nargs;
{
	int (*sort)() = SortByXY;
	blink_icon(widget,NULL);

	if(widget->drag.auto_sort && widget->drag.sort)
		sort = widget->drag.sort;

	sort_icons(widget,sort);
	all_moved(widget,NULL);
}

static void StartSelect(widget,event,args,nargs)
DragWidget widget;
XEvent     *event;
char       **args;
int        nargs;
{
	Display *dpy = XtDisplay(widget);
	int     screen = DefaultScreen(dpy);
	Icon    icon;
	Boolean label;

	blink_icon(widget,NULL);

	XmProcessTraversal((Widget)widget,XmTRAVERSE_CURRENT);

	widget->drag.copy    = (event->xbutton.button == 2);

	if((icon = find_icon(widget,event,&label))==NULL)
	{
		widget->drag.selecting = TRUE;
		widget->drag.justclick = FALSE;

		widget->drag.selextend =
		    (event->xbutton.state & ShiftMask) != 0;
		widget->drag.startx = widget->drag.lastx = event->xbutton.x;
		widget->drag.starty = widget->drag.lasty = event->xbutton.y;

		widget->drag.r_select.x = widget->drag.startx ;
		widget->drag.r_select.y = widget->drag.starty;
		widget->drag.r_select.width =  widget->drag.r_select.height = 0;
		XSetForeground(dpy,widget->drag.gc,BlackPixel(dpy,screen));
	}
	else
	{

		widget->drag.selecting = False;
		widget->drag.justclick = FALSE;

		if( (event->xbutton.time - widget->drag.last_click) > XtGetMultiClickTime(dpy) )
		{
			raise_icon(widget,icon);
			XDefineCursor(XtDisplay(widget),XtWindow(widget),open_cursor);
			if((event->xbutton.state & ShiftMask) != 0)
				toggle_icon(widget,icon,event);
			else {
				select_icon(widget,icon,event,True);
				if(label && widget->drag.edit_names)
					start_edit(widget,icon);
			}
		}
		else
		{
			DragCallbackStruct cb;
			memset(&cb,0,sizeof(cb));
			cb.reason = DRAG_DBL_CLICK;
			cb.icon_class = icon->class;
			cb.icon_name = icon->name;
			cb.icon_data = icon->data;
			cb.icon      = icon;

			cb.event     = event; /* br */

			XtCallCallbacks ((Widget)widget,XmNdblClickCallback,(XtPointer)&cb);
			widget->drag.justclick = TRUE;
		}

		widget->drag.last_click = event->xbutton.time;
	}
}

static void DoSelect(widget,event,args,nargs)
DragWidget widget;
XEvent     *event;
char       **args;
int        nargs;
{

	end_edit(widget);

	if(widget->drag.selecting)
	{
		int newx = event->xbutton.x;
		int newy = event->xbutton.y;

		if(newx != widget->drag.lastx && newy != widget->drag.lasty)
		{
			XDrawRectangle(XtDisplay(widget),XtWindow(widget),
			    widget->drag.selgc,
			    widget->drag.r_select.x,
			    widget->drag.r_select.y,
			    widget->drag.r_select.width,
			    widget->drag.r_select.height);


			widget->drag.lastx = newx;
			widget->drag.lasty = newy;

			widget->drag.r_select.x = MIN(newx,widget->drag.startx);
			widget->drag.r_select.y = MIN(newy,widget->drag.starty);

			widget->drag.r_select.width  = MAX(newx,widget->drag.startx)
			    - widget->drag.r_select.x;
			widget->drag.r_select.height = MAX(newy,widget->drag.starty)
			    - widget->drag.r_select.y;

			XDrawRectangle(XtDisplay(widget),XtWindow(widget),
			    widget->drag.selgc,
			    widget->drag.r_select.x,
			    widget->drag.r_select.y,
			    widget->drag.r_select.width,
			    widget->drag.r_select.height);
		}
	}
	else
		drag_and_drop(widget,event);
}

static Boolean InterRect(XRectangle *r1,XRectangle *r2)
{
	if ((short) (r1->x + r1->width) < r2->x || (short) (r1->y + r1->height) < r2->y)
		return False;
	if (r1->x > (short) (r2->x + r2->width) || r1->y > (short) (r2->y + r2->height))
		return False;
	return True;
}

static void UnionRect(XRectangle *r1,XRectangle *r2,XRectangle *r3)
{
	int dx,dy;

	dx  = MAX(r1->x+r1->width,r2->x+r2->width);
	dy  = MAX(r1->y+r1->height,r2->y+r2->height);
	r3->x = MIN(r1->x,r2->x);
	r3->y = MIN(r1->y,r2->y);

	r3->width  = dx - r3->x;
	r3->height = dy - r3->y;

}

static void EndSelect(widget,event,args,nargs)
DragWidget widget;
XEvent     *event;
char       **args;
int        nargs;
{
	int n = widget->drag.small_icons;

	if(widget->drag.selecting)
	{
		Icon p = widget->drag.icons;

		XDrawRectangle(XtDisplay(widget),XtWindow(widget),
		    widget->drag.selgc,
		    widget->drag.r_select.x,
		    widget->drag.r_select.y,
		    widget->drag.r_select.width,
		    widget->drag.r_select.height);

		if(!widget->drag.selextend)
			unselect_all_icons(widget,event);

		while(p)
		{
			if(InterRect(&widget->drag.r_select,&p->r_all[n]))
				select_icon(widget,p,event,False);
			p = p->next;
		}

	}
	else {
/*
		Boolean label;
		Icon icon;
		if( (icon = find_icon(widget,event,&label)) != NULL)
			if(label && event->xbutton.time - widget->drag.last_click > widget->drag.edit_timeout)
				if(widget->drag.edit_names)
					start_edit(widget,icon);
*/
	}

	widget->drag.selecting = False;
	XUndefineCursor(XtDisplay(widget),XtWindow(widget));
}

static void SelectAll(widget,event,args,nargs)
DragWidget widget;
XEvent     *event;
char       **args;
int        nargs;
{
	Icon p = widget->drag.icons;
	blink_icon(widget,NULL);


	while(p)
	{
		select_icon(widget,p,event,False);
		p = p->next;
	}

}

static void SelectNone(widget,event,args,nargs)
DragWidget widget;
XEvent     *event;
char       **args;
int        nargs;
{
	blink_icon(widget,NULL);
	unselect_all_icons(widget,event);
}

static Icon check_icon(widget,icon)
DragWidget widget;
Icon icon;
{
	Icon p = widget->drag.icons;
	while(p)
	{
		if(p == icon) return icon;
		p = p->next;
	}
	return NULL;
}

/*=================================*/

Widget CreateDragWidget(Widget parent,const char* name,ArgList al,int ac)
{
	return XtCreateWidget(name,dragWidgetClass,parent,al, ac);
}


static Pixmap half_image(widget,pixmap,name,newname)
Widget widget;
Pixmap     pixmap;
String     name;
String     *newname;
{
	char    buf[1024];
	Display *dpy   = XtDisplay(widget);
	int     screen = DefaultScreen(dpy);
	Window  root   = RootWindow(dpy,screen);
	XImage   *image;
	Pixel     p[4];
	int  		x,y;
	unsigned int width;
	unsigned int height;
	unsigned int depth;
	int c[4],i,j;
	Pixmap pix;
	GC  gc;

	if (name && newname) {
		int len = strlen(name)-1;
		while(len>0 && name[len] != '.' && name[len] != '/') len--;
		if(len>0 && name[len] == '.')
		{
			strcpy(buf,name);
			buf[len] = 0;
			strcat(buf,".half");
		}
		else
			sprintf(buf,"%s.half",name);
		/* printf("half is %s\n",buf); */
		*newname = XtNewString(buf);
		if(pix = GetPixMap((Widget)widget,buf,1,0))
			return pix;

		/*-- 'mvmon' crashed when default.half was needed...  --*/
		/*-- Q&D & blind fix: get & use 'default' (011113/vk) --*/
		if( pixmap == NULL )
		  pixmap = GetPixMap((Widget)widget,"default",1,0);
	}

#if 0
	XGetGeometry(dpy,pixmap,&root,&x,&y,&width,&height,&dummy,&depth);
	image  = XGetImage(dpy,pixmap,0,0,width,height,AllPlanes,ZPixmap);
#endif
	image = PixmapImage(widget,pixmap,&width,&height,&depth);
	pixmap = XCreatePixmap(dpy,root,width/2,height/2,depth);


	for(x = 0 ; x < width/2 ;x++)
		for(y = 0 ; y < height/2; y++)
		{
			p[0] = XGetPixel(image,2*x  ,2*y );
			p[1] = XGetPixel(image,2*x+1,2*y );
			p[2] = XGetPixel(image,2*x  ,2*y+1);
			p[3] = XGetPixel(image,2*x+1,2*y+1);

			c[0] = c[1] = c[2] = c[3] = 0;

			for(i=0;i<4;i++)
				for(j=0;j<4;j++)
					if(p[i] == p[j]) c[i]++;

			j = 0;
			for(i=0;i<4;i++)
				if(c[i] > c[j]) j = i;

			XPutPixel(image,x,y,p[j]);
		}

	gc = XCreateGC(dpy,pixmap,0,NULL);
	XPutImage(dpy,pixmap,gc,image,0,0,0,0,width/2,height/2);
	XFreeGC(dpy,gc);

	if (name && newname) {
		InstallPixmap(pixmap,buf,width,height,depth,image);
	}
	else XDestroyImage(image);

	return pixmap;
}

Pixmap MakeHalfPixmap(Widget widget, Pixmap pixmap)
{
	return half_image(widget, pixmap, NULL, NULL);
}

Pixmap DragGetPixmap(Widget w,const char* name)
{
	Pixmap p = GetPixMap(w,(String)name,1,0);
	return p ? p : XmUNSPECIFIED_PIXMAP;
}

static Pixmap open_image(Widget widget,Pixmap pixmap,String name,Pixel black)
{
	char    buf[1024];
	Display *dpy   = XtDisplay(widget);
	int     screen = DefaultScreen(dpy);
	Window  root   = RootWindow(dpy,screen);
	XImage   *image;
	Pixel     p;
	int  		x,y;
	unsigned int width;
	unsigned int height;
	unsigned int dummy;
	unsigned int depth;
	Pixmap pix;
	GC  gc;

	if (name) {
		sprintf(buf,"{%s}",name);

		if(pix = FindPixmap(buf,&dummy,&dummy))
			return pix;
	}


#if 0
	XGetGeometry(dpy,pixmap,&root,&x,&y,&width,&height,&dummy,&depth);
	image  = XGetImage(dpy,pixmap,0,0,width,height,AllPlanes,ZPixmap);
#endif
	image = PixmapImage((Widget)widget,pixmap,&width,&height,&depth);
	pixmap = XCreatePixmap(dpy,root,width,height,depth);

	for(x = 0 ; x < width ;x++)
		for(y = 0 ; y < height; y++)
		{
			if((x+y)%2)
				p = black;
			else
				p = XGetPixel(image,x,y);
			XPutPixel(image,x,y,p);
		}

	gc = XCreateGC(dpy,pixmap,0,NULL);
	XPutImage(dpy,pixmap,gc,image,0,0,0,0,width,height);
	XFreeGC(dpy,gc);

	if (name) InstallPixmap(pixmap,buf,width,height,depth,image);
	else
	XDestroyImage(image);

	return pixmap;
}

Pixmap MakeOpenPixmap(widget, pixmap)
Widget widget;
Pixmap pixmap;
{
	Display *dpy   = XtDisplay(widget);
	int     screen = DefaultScreen(dpy);
	Pixel   black  = BlackPixel(dpy,screen);
	return open_image(widget, pixmap, NULL,black);
}

Pixmap MakeDisabledPixmap(widget, pixmap)
Widget widget;
Pixmap pixmap;
{
	return open_image(widget, pixmap, NULL,widget->core.background_pixel);
}

static Pixmap mask_image(widget,pixmap,name,white,w,h)
Widget     widget;
Pixmap     pixmap;
Pixel      white;
String     name;
unsigned int *w;
unsigned int *h;
{
	char    buf[1024];
	Display *dpy   = XtDisplay(widget);
	int     screen = DefaultScreen(dpy);
	Window  root   = RootWindow(dpy,screen);
	XImage   *image;
	Pixel     p;
	int  		x,y;
	unsigned int depth;
	unsigned int width;
	unsigned int width8;
	unsigned int height;
	Pixmap pix;
	char *data;
	static unsigned char bits[] = {
		1,2,4,8,16,32,64,128,		};
	Boolean *mask1,*mask2;
	Boolean more = True;

	if(name)
	{
		sprintf(buf,"[%s]",name);
		if(pix = FindPixmap(buf,w,h)) return pix;
	}

#if 0
	XGetGeometry(dpy,pixmap,&root,&x,&y,&width,&height,&dummy,&depth);
	image  = XGetImage(dpy,pixmap,0,0,width,height,AllPlanes,ZPixmap);
#endif
	image = PixmapImage(widget,pixmap,&width,&height,&depth);

	width8 = ((width+7)/8)*8;

	data   = XtCalloc(1,width8 * height);
	mask1  = XtCalloc(sizeof(Boolean),width8*height);
	mask2  = XtCalloc(sizeof(Boolean),width8*height);

	/* buf fix. I should look closer */
	white = WhitePixel(dpy,screen);


#define XY(x,y) ((x)+(y)*width8)

	for(y = 0 ; y < height; y++)
		for(x = 0 ; x < width ;x++)
		{
			p = XGetPixel(image,x,y);
			mask1[XY(x,y)] = (p == white);
		}

	/* look if white of border */
	for(y = 0 ; y < height ; y++)
	{
		x = 0;
		mask2[XY(x,y)] = mask1[XY(x,y)];
		x = width-1;
		mask2[XY(x,y)] = mask1[XY(x,y)];
	}

	for(x = 0 ; x < width ; x++)
	{
		y = 0;
		mask2[XY(x,y)] = mask1[XY(x,y)];
		y = height-1;
		mask2[XY(x,y)] = mask1[XY(x,y)];
	}


	/* now look if a inner pixel touches a white on */

	while(more)
	{
		more = False;


		for(y = 1 ; y < height-1; y++)
			for(x = 1 ; x < width-1 ;x++)
			{
				if(mask1[XY(x,y)] && !mask2[XY(x,y)])
				{
					if(
					    mask2[XY(x-1,y  )] ||
					    mask2[XY(x  ,y-1)] ||
					    mask2[XY(x  ,y+1)] ||
					    mask2[XY(x+1,y  )] )

					{
						more = True;
						mask2[XY(x,y)] = True;
					}
				}
			}
	}

	for(y = 0 ; y < height; y++)
		for(x = 0 ; x < width ;x++)
		{
			int bit = XY(x,y);
			if(!mask2[bit])
				data[bit/8] |= bits[bit%8];
		}

#undef XY

	pixmap = XCreateBitmapFromData(dpy,root,data,width,height);
	XtFree(data);
	XtFree(mask1);
	XtFree(mask2);
	/* XWriteBitmapFile(dpy,"default",pixmap,width,height,0,0); */

	if(name) InstallPixmap(pixmap,buf,width,height,1,0);

	*w = width;
	*h = height;

	XDestroyImage(image);

	return pixmap;
}

Pixmap MakeMaskBitmap(widget, pixmap, white)
Widget widget;
Pixmap pixmap;
Pixel  white;
{
	unsigned int w, h;
	return mask_image(widget, pixmap, NULL, white, &w, &h);
}

Pixmap CopyBackground(Widget widget,Pixmap pixmap)
{
	Arg al[64];
	Pixel fg, bg;
	Display *dpy = XtDisplay(widget);
	int     screen = DefaultScreen(dpy);
	Window  root   = RootWindow(dpy,screen);
	Pixmap  mask = MakeMaskBitmap(widget,pixmap,WhitePixel(dpy,screen));
	Pixmap  pix;
	GC      gc;

	int  		x,y;
	unsigned int dummy;
	unsigned int depth;
	unsigned int width;
	unsigned int height;
	int ac = 0;

	XtSetArg(al[ac], XmNforeground, &fg );
	ac++;
	XtSetArg(al[ac], XmNbackground, &bg );
	ac++;
	XtGetValues(widget, al, ac );

	XGetGeometry(dpy,pixmap,&root,&x,&y,&width,&height,&dummy,&depth);

	pix = XCreatePixmap(dpy,root,width,height,depth);

	/* Fill new pixmap with background color */

	gc = XCreateGC(dpy,pix,0,NULL);
	XSetForeground(dpy,gc, bg);
	XFillRectangle(dpy,pix,gc,0,0,width,height);
	XSetForeground(dpy,gc, BlackPixel(dpy,screen));

	XSetClipMask(dpy,gc, mask);
	/* XSetClipOrigin(dpy,gc,0,0); */

	XCopyArea(dpy,pixmap,pix,gc,0,0,width,height,0,0);

	/* XSetClipMask(dpy,gc,None); */
	XFreeGC(dpy,gc);
	XFreePixmap(dpy,mask);

	return pix;

}

Pixmap OverlayPixmaps(Widget widget,Pixmap lower,Pixmap upper,int dx,int dy)
{
	Display *dpy = XtDisplay(widget);
	int     screen = DefaultScreen(dpy);
	Window  root   = RootWindow(dpy,screen);
	Pixmap  pix;
	Pixmap  mask = MakeMaskBitmap(widget,upper,WhitePixel(dpy,screen));

	int         x,y;
	unsigned int dummy;
	unsigned int depth;
	unsigned int width1;
	unsigned int height1;
	unsigned int width2;
	unsigned int height2;
	GC gc;


	XGetGeometry(dpy,lower,&root,&x,&y,&width1,&height1,&dummy,&depth);
	XGetGeometry(dpy,upper,&root,&x,&y,&width2,&height2,&dummy,&depth);

	pix = XCreatePixmap(dpy,root,width1,height1,depth);
	gc = XCreateGC(dpy,pix,0,NULL);
	XCopyArea(dpy,lower,pix,gc,0,0,width1,height1,0,0);

	x = (dx != -1) ? dx : (width1 - width2)   / 2;
	y = (dy != -1) ? dy : (height1 - height2) / 2;


	XSetClipMask(dpy,gc, mask);
	XSetClipOrigin(dpy,gc,x,y);

	XCopyArea(dpy,upper,pix,gc,0,0,width2,height2,x,y);

	XFreeGC(dpy,gc);
	XFreePixmap(dpy,mask);
	return pix;
}

Pixmap StackPixmaps(Widget widget,Pixmap pixmap,int count,int dx,int dy)
{
	Display *dpy   = XtDisplay(widget);
	int     screen = DefaultScreen(dpy);
	Window  root   = RootWindow(dpy,screen);
	Pixmap  pix;
 	Pixmap  mask;

	int         x,y;
	int i;
	unsigned int dummy;
	unsigned int depth;
	unsigned int width,w;
	unsigned int height,h;
	GC gc;

	int dx1 = dx>0?dx:-dx;
	int dy1 = dy>0?dy:-dy;
	int dd  = dx1>dy1?dx1:dy1;

	if(pixmap == XmUNSPECIFIED_PIXMAP || pixmap == 0)
		return XmUNSPECIFIED_PIXMAP;

 	mask = MakeMaskBitmap(widget,pixmap,WhitePixel(dpy,screen));
	XGetGeometry(dpy,pixmap,&root,&x,&y,&width,&height,&dummy,&depth);

	w = width  + dd*count;
	h = height + dd*count;

	pix = XCreatePixmap(dpy,root,w,h,depth);
	gc  = XCreateGC(dpy,pix,0,NULL);
	XSetForeground(dpy,gc, WhitePixel(dpy,screen));

	XSetBackground(dpy,gc, BlackPixel(dpy,screen));
	XFillRectangle(dpy,pix,gc,0,0,w,h);


	x = dx>0 ? 0 : w - width;
	y = dy>0 ? 0 : h - height;

	XSetClipMask(dpy,gc, mask);
	for(i=0;i<count;i++)
	{
		XSetClipOrigin(dpy,gc,x,y);
		XCopyArea(dpy,pixmap,pix,gc,0,0,width,height,x,y);
		x += dx;
		y += dy;
	}

	XFreeGC(dpy,gc);
	XFreePixmap(dpy,mask);
	return pix;
}

static void compute_rects(DragWidget widget,Icon icon)
{
	int i;
	unsigned int width = 32,height = 32;

	for(i=0;i<2;i++)
	{

		icon->r_label[i].width=XmStringWidth(widget->drag.fontlist,icon->label);
		icon->r_label[i].height=widget->drag.string_height;

#if 0
		/* main pixmap */

		icon->pix[i] = GetPixMap(widget,
		    icon->pix_name[i],
		    icon->foreground,
		    icon->background);

		if(icon->pix[i] == NULL)
			if(i)
				icon->pix[i] = half_image(widget,icon->pix[0],
				    icon->pix_name[0],&icon->pix_name[i]);
			else
				icon->pix[i] = GetPixMap(widget,"default",
				    icon->foreground,icon->background);


		/* Open state icon */

		icon->open_pix[i] = GetPixMap(widget,
		    icon->open_name[i],
		    icon->foreground,icon->background);

		if(icon->open_pix[i] == NULL)
			icon->open_pix[i] = open_image(widget,icon->pix[i],
			    icon->pix_name[i],black);

		icon->mask[i] = GetBitMap(widget,icon->mask_name[i],&width,&height);
		if(icon->mask[i] == NULL)
			icon->mask[i] = mask_image(widget,icon->pix[i],
			    icon->pix_name[i],icon->background,&width,&height);
#endif

		icon->r_icon[i].width = width;
		icon->r_icon[i].height = height;

		icon->r_label[i].x = icon->r_label[i].y = 0;
		icon->r_icon[i].x = icon->r_icon[i].y = 0;

		width /= 2;
		height /= 2;
	}


	/* Layout for large icons */


	if(icon->r_icon[0].width > icon->r_label[0].width)
		icon->r_label[0].x = (short) (icon->r_icon[0].width-icon->r_label[0].width)/ 2;
	else
		icon->r_icon[0].x = (short) (icon->r_label[0].width-icon->r_icon[0].width)/ 2;

	icon->r_label[0].y = icon->r_icon[0].height + 1;


	/* Layout for small icons */

	icon->r_label[1].x = icon->r_icon[1].width + 1;
	if(icon->r_icon[1].height < icon->r_label[1].height)
		icon->r_icon[1].y  = icon->r_label[1].height - icon->r_icon[1].height;
	else
		icon->r_label[1].y = icon->r_icon[1].height - icon->r_label[1].height;

	UnionRect(&icon->r_icon[0],&icon->r_label[0],&icon->r_all[0]);
	UnionRect(&icon->r_icon[1],&icon->r_label[1],&icon->r_all[1]);
}

static void make_pixmaps(Widget widget,Icon icon,int i)
{
	unsigned int width,height;
	Display *dpy   = XtDisplay(widget);
	int     screen = DefaultScreen(dpy);
	Pixel    black = BlackPixel(dpy,screen);

	if(icon->pix[i] != NULL)
		return;


	/* printf("Make pixmap %s %d\n",icon->name,i); */


	/* main pixmap */

	icon->pix[i] = GetPixMap(widget,
	    icon->pix_name[i],
	    icon->foreground,
	    icon->background);

	if(icon->pix[i] == NULL)
		if(i)
			icon->pix[i] = half_image(widget,icon->pix[0],
			    icon->pix_name[0],&icon->pix_name[i]);
		else
			icon->pix[i] = GetPixMap(widget,"default",
			    icon->foreground,icon->background);


	/* Open state icon */

	icon->open_pix[i] = GetPixMap(widget,
	    icon->open_name[i],
	    icon->foreground,icon->background);

	if(icon->open_pix[i] == NULL)
		icon->open_pix[i] = open_image(widget,icon->pix[i],
		    icon->pix_name[i],black);

	icon->mask[i] = GetBitMap(widget,icon->mask_name[i],&width,&height);
		if(icon->mask[i] == NULL)
			icon->mask[i] = mask_image(widget,icon->pix[i],
			    icon->pix_name[i],icon->background,&width,&height);

}


void DragAddIconPixmap(Widget widget,Icon icon,const char* name,int dx,int dy)
{
	Pixmap pix;
	char buf[1024];
	unsigned int dummy;
	int i;

	if(icon->pix[0] == NULL) make_pixmaps(widget,icon,0);

	sprintf(buf,"%s:%s(%d,%d)",icon->pix_name[0],name,dx,dy);

	/* look in cache */
	pix = FindPixmap(buf,&dummy,&dummy);

	if(!pix)
	{
		pix = GetPixMap(widget,name, icon->foreground, icon->background);
		if(!pix) return;

		pix = OverlayPixmaps(widget,icon->pix[0],pix,dx,dy);
		InstallPixmap(pix,buf,0,0,0,0); /* store in cache */
	}

	for(i=0;i<2;i++)
	{
		FreePixmap(widget,icon->pix[i]);
		FreePixmap(widget,icon->open_pix[i]);
		FreePixmap(widget,icon->mask[i]);
	}

	icon->pix_name[0] = XtNewString(buf);
	icon->pix[0]      = pix;
	icon->pix[1]      = half_image(widget,icon->pix[0], icon->pix_name[0],&icon->pix_name[1]);

	for(i=0;i<2;i++)
	{
		icon->open_pix[i] = open_image(widget,icon->pix[i], icon->pix_name[i],0);
		icon->mask[i]     = mask_image(widget,icon->pix[i],
		    icon->pix_name[i],icon->background,&dummy,&dummy);
	}

}

Icon DragAddIcon(Widget widget,const char *class,const char *name,
	XtPointer data,int x,int y)
{
	Icon icon = (Icon)XtCalloc(1,sizeof(_IconRec));
	static int ids = 0;
	DragWidget drag = (DragWidget)widget;

	blink_icon((DragWidget)widget,NULL);
	drag->drag.last_added = icon;

	XtGetSubresources(widget,(XtPointer)icon,
		/*name*/ "" ,
		class,
	    icon_resources,XtNumber(icon_resources),NULL,0);

	icon->parent = widget;
	icon->selected = False;
	icon->delete = False;
	icon->opened = False;
	icon->visible = True;
	icon->data = data;
	icon->class = XtNewString(class);
	icon->name  = XtNewString(name);
	icon->id    = ++ids;

	icon->label = XmStringCreate((char*)name,((DragWidget)widget)->drag.tag);

	compute_rects((DragWidget)widget,icon);
	new_icon_xy(icon,x,y);

	if(drag->drag.icons == NULL)
		drag->drag.icons = icon;
	else
		drag->drag.last->next = icon;
	drag->drag.last = icon;

	/* Force new grid computation */

	if((int)icon->r_all[drag->drag.small_icons].width > drag->drag.gridx)
		drag->drag.gridx = 0;

	if((int)icon->r_all[drag->drag.small_icons].height > drag->drag.gridy)
		drag->drag.gridy = 0;

	/* BR: auto place when grid is off */

	if( (drag->drag.auto_place )  || ( x <=0 && y <=0))
	{
		Boolean save = drag->drag.grid;
		Icon      p = drag->drag.icons;

#if 0
		Boolean   over = ( x <=0 && y <=0);
		int	    n = drag->drag.small_icons;

		/* check if icons overlap */
		while(p)
		{
			if(p != icon && InterRect(&p->r_all[n],&icon->r_all[n]))
				over = True;
			p = p->next;
		}

		if(over)
#endif
			drag->drag.grid = True;

		place_icon(drag,icon,True);

		drag->drag.grid = save;

	}
	else place_icon(drag,icon,True);



	inval_icon(drag,icon);

	if(drag->drag.auto_clean)
		DragCleanUpIcons(widget);


	return icon;

}


Widget DragIconToWidget(icon)
Icon icon;
{
	if(!icon) return NULL;
	return icon->parent;
}


Icon DragFindIconByName(Widget widget,const char* class,const char* name)
{
	Icon p = ((DragWidget)widget)->drag.icons;
	while(p)
	{
		if ((class == NULL || strcmp(class,p->class)==0) &&
		    (name == NULL || strcmp(name,p->name) == 0))
			return p;
		p = p->next;
	}
	return NULL;
}

Icon DragFindIconByData(Widget widget,XtPointer data)
{
	Icon p = ((DragWidget)widget)->drag.icons;
	while(p)
	{
		if(p->data == data)
			return p;
		p = p->next;
	}
	return NULL;
}

static Icon find_folders(DragWidget w,const char *class,const char *name)
{
	Icon p = w->drag.icons;
	int  i;

	while(p)
	{
		if ( (class == NULL || strcmp(class,p->class)==0) &&
		    (name == NULL || strcmp(name,p->name) == 0))
			return p;
		p = p->next;
	}

	for(i=0;i<w->drag.child_count;i++)
		if(p = find_folders((DragWidget)w->drag.child_folders[i],class,name))
			return p;

	return NULL;
}

Icon DragFindIconByNameFolders(Widget widget,const char *class,const char *name)
{
	DragWidget w = (DragWidget)widget;

	while(w->drag.parent_folder)
		w = (DragWidget)w->drag.parent_folder;

	return find_folders(w,class,name);
}

void DragDeleteIcon(Widget widget,Icon icon)
{
	blink_icon((DragWidget)widget,NULL);
	icon = check_icon((DragWidget)widget,icon);
	if(icon) remove_icon((DragWidget)widget,icon,True);
}

void DragShowIcon(Widget widget, Icon icon, Boolean vis)
{
	blink_icon((DragWidget)widget,NULL);
	icon = check_icon((DragWidget)widget,icon);
	if(icon) show_hide((DragWidget)widget,icon,vis);
}

void DragSetIconColor(Widget widget, Icon icon, Pixel pix)
{
	icon = check_icon((DragWidget)widget,icon);

	if(icon->hilitebackground == pix &&
		icon->foreground == pix) return;

	blink_icon((DragWidget)widget,NULL);
	if(icon)
	{
		icon->hilitebackground = pix;
		icon->foreground       = pix;
		inval_icon((DragWidget)widget,icon);
	}
}


void DragScanIcons(widget,cb,data)
Widget widget;
DragScanProc cb;
XtPointer data;
{
	Icon p = ((DragWidget)widget)->drag.icons;
	Icon pnext;
	blink_icon((DragWidget)widget,NULL);
	while(p)
	{
		pnext = p->next;
		if(!(*cb)(widget,p,data))
			return;
		p = pnext;
	}
}

static Boolean scan_folders(DragWidget w,DragScanProc cb,XtPointer data)
{
	Icon p = w->drag.icons;
	Icon pnext;
	int  i;

	while(p)
	{
		pnext = p->next;
		if(!(*cb)((Widget)w,p,data))
			return False;
		p = pnext;
	}

	for(i=0;i<w->drag.child_count;i++)
		if(!scan_folders((DragWidget)w->drag.child_folders[i],cb,data))
			return False;

	return True;
}

void DragScanIconsFolders(Widget widget,DragScanProc cb,XtPointer data)
{
	DragWidget w = (DragWidget)widget;
	blink_icon((DragWidget)widget,NULL);

	while(w->drag.parent_folder)
		w = (DragWidget)w->drag.parent_folder;

	scan_folders(w,cb,data);
}

void DragDeleteAllIcons(widget)
Widget widget;
{
	DragWidget w = (DragWidget)widget;
	blink_icon((DragWidget)widget,NULL);
	while(w->drag.icons)
		remove_icon(w,w->drag.icons,w->drag.icons->next == NULL);
}

Pixmap DragGetIconPixmap(widget,icon)
Widget widget;
Icon icon;
{
	icon = check_icon((DragWidget)widget,icon);
	if(icon)
	{
		if(icon->pix[0] == NULL) make_pixmaps(widget,icon,0);
		return icon->pix[0];
	}
	else
		return XmUNSPECIFIED_PIXMAP;
}

void DragSortIcons(Widget widget, DragSortProc f)
{
	DragWidget drag = (DragWidget)widget;
	int (*sort)() = (f) ? f : drag->drag.sort;
	blink_icon((DragWidget)widget,NULL);

	if(!sort) return;

	sort_icons(drag,sort);
	all_moved(drag,NULL);
}


void DragCleanUpIcons(widget)
Widget widget;
{
	blink_icon((DragWidget)widget,NULL);
	CleanUp((DragWidget)widget,NULL,NULL,0);
}

Boolean DragIsIconSelected(Widget widget, Icon icon)
{
	return icon->selected;
}

void DragDisplayIcon(Widget widget, Icon icon,int flags)
{
	DragWidget drag = (DragWidget)widget;
	blink_icon((DragWidget)widget,NULL);
	if(drag->drag.clip)
	{

		int n = drag->drag.small_icons;
		Widget scroll = XtParent(drag->drag.clip);
		Widget h_scroll,v_scroll;
		Position    x_clip,y_clip;
		Dimension   h_clip,w_clip;
		Position    x_icon,y_icon;
		Dimension   h_icon,w_icon;
		Position x,y;
		Position    dv=0,dh=0;
		int min,max;
		int v_val,v_size,v_inc,v_page;
		int h_val,h_size,h_inc,h_page;


		XtVaGetValues(scroll,
		    XmNhorizontalScrollBar, &h_scroll ,
		    XmNverticalScrollBar,   &v_scroll,NULL);

		x_icon = icon->r_all[n].x;
		y_icon = icon->r_all[n].y;
		h_icon = icon->r_all[n].height;
		w_icon = icon->r_all[n].width;

		XtTranslateCoords(widget,x_icon,y_icon,&x_icon,&y_icon);
		XtTranslateCoords(drag->drag.clip,0,0,&x_clip,&y_clip);

		x = x_icon - x_clip;
		y = y_icon - y_clip;

		h_clip = drag->drag.clip->core.height;
		w_clip = drag->drag.clip->core.width;

		if( y < 0 || y + h_icon > h_clip)
		{
			dv = (y + h_icon / 2)  - h_clip / 2;

			XtVaGetValues(v_scroll,XmNminimum,&min,XmNmaximum,&max,NULL);

			XmScrollBarGetValues(v_scroll,&v_val,&v_size,&v_inc,&v_page);

			max -= v_size;

			if( dv + v_val > max )
			   dv = max - v_val;
			if( dv + v_val < min )
			   dv = min - v_val;


		}

		if( x < 0 || x + w_icon > w_clip)
		{
			dh = (x + w_icon / 2)  - w_clip / 2;

			XtVaGetValues(h_scroll,XmNminimum,&min,XmNmaximum,&max,NULL);

			XmScrollBarGetValues(h_scroll,&h_val,&h_size,&h_inc,&h_page);

			max -= h_size;

			if( dh + h_val > max )
			   dh = max - h_val;
			if( dh + h_val < min )
			   dh = min - h_val;

		}


		if(dv || dh)
		{
#if 0
			XtVaGetValues((Widget)drag,XmNx,&x,XmNy,&y,NULL);
			x -= dh;
			y -= dv;
			/*-- skip this move as it messes up with scroll bars (050421/vk) --*/
			XtVaSetValues((Widget)drag,XmNx,x,XmNy,y,NULL);
#endif

			if(dv)
				XmScrollBarSetValues(v_scroll, v_val+dv, 0, 0, 0, TRUE);
			if(dh)
				XmScrollBarSetValues(h_scroll, h_val+dh, 0, 0, 0, TRUE);

		}
	}

	if((flags&DRAG_DISPLAY_ADD_TO_SELECTION) != 0)
		DragSelectIcon((Widget)drag,icon,True,
		    (flags&DRAG_DISPLAY_SELECT_UNIQUE) == 0);

	if((flags&DRAG_DISPLAY_VISUAL_FEEDBACK) != 0)
		blink_icon(drag,icon);
}

void DragSelectIcon(Widget widget, Icon icon, Boolean selected,Boolean expand)
{
	XAnyEvent event;
	blink_icon((DragWidget)widget,NULL);

	event.type        = 0;
	event.serial      = 0;
	event.send_event  = True;
	event.display     = XtDisplay(widget);
	event.window      = XtWindow(widget);

	if(icon == DRAG_ALL_ICONS)
	{
		Icon p = ((DragWidget)widget)->drag.icons;
		while(p)
		{
			if(p->selected != selected)
				toggle_icon((DragWidget)widget,p,(XEvent*)&event);
			p = p->next;
		}
	}
	else
	{
		icon = check_icon((DragWidget)widget,icon);
		if(icon)
		{
			if(selected && !expand)
				select_icon((DragWidget)widget,icon,(XEvent*)&event,True);
			else
				if(icon->selected != selected)
					toggle_icon((DragWidget)widget,icon,(XEvent*)&event);
		}
	}
}

XtPointer DragGetIconData(widget,icon)
Widget widget;
Icon icon;
{
	icon = check_icon((DragWidget)widget,icon);
	return icon?icon->data:NULL;
}

void DragSetIconData(widget,icon,data)
Widget widget;
Icon icon;
XtPointer data;
{
	icon = check_icon((DragWidget)widget,icon);
	if(icon) icon->data = data;
}

void DragOpenIcon(Widget widget, Icon icon, Boolean opened)
{
	blink_icon((DragWidget)widget,NULL);
	icon = check_icon((DragWidget)widget,icon);
	if(icon)
		if(icon->opened != opened)
		{
			icon->opened = opened;
			inval_icon((DragWidget)widget,icon);
		}
}

void DragSetFontTag(Widget widget,const char *tag)
{
	DragWidget drag = (DragWidget)widget;
	if(strcmp(tag,drag->drag.tag) == 0) return;
	XtFree(drag->drag.tag);
	drag->drag.tag = XtNewString(tag);
}

void DragSetIconName(Widget widget,Icon icon,const char *newname)
{
	blink_icon((DragWidget)widget,NULL);
	icon = check_icon((DragWidget)widget,icon);
	if(icon)
	{
		int n = ((DragWidget)widget)->drag.small_icons;
		int x = icon->r_all[n].x;
		int y = icon->r_all[n].y;
		int w = icon->r_all[n].width;

		printf("w = %d\n",w);

		inval_icon((DragWidget)widget,icon);

		XtFree(icon->name);
		icon->name  = XtNewString(newname);

		XmStringFree(icon->label);
		icon->label = XmStringCreate((char*)newname,
			((DragWidget)widget)->drag.tag);

		compute_rects((DragWidget)widget,icon);


		if(n == 0)
		{
			printf("x = %d w = %d w2 = %d\n",x,w,icon->r_all[n].width);
			x = x - (icon->r_all[n].width - w)/2;
			 printf("x2  = %d \n",x );
		}
		new_icon_xy(icon,x,y);

		inval_icon((DragWidget)widget,icon);
		/* place_icon((DragWidget)widget,icon,True); */
		check_size((DragWidget)widget);

	}
}

const char* DragGetIconName(Widget widget,Icon icon)
{
	icon = check_icon((DragWidget)widget,icon);
	return (icon ? icon->name : NULL);
}

const char* DragGetIconClass(Widget widget,Icon icon)
{
	icon = check_icon((DragWidget)widget,icon);
	return (icon ? icon->class : NULL);
}

Icon DragFindIconByPosition(Widget widget,Position x, Position y)
{
	XEvent ev;
	Boolean label;

	ev.xbutton.x = x;
	ev.xbutton.y = y;

	return find_icon((DragWidget)widget,&ev,&label);
}

void DragSetPositionIcon(Widget widget, Icon icon, Position x, Position y)
{
	icon = check_icon((DragWidget)widget,icon);
	if(icon) move_icon((DragWidget)widget,icon,x,y,-1,-1);
}

void DragFindPositionIcon(Widget widget, Icon icon, Position* x, Position* y)
{
	DragWidget drag = (DragWidget)widget;
	int n = drag->drag.small_icons;
	Position x1, x2;
	Position y1, y2;

	x1 = (Position) (icon->r_label[n].x + icon->r_label[n].width)/2;
	x2 = (Position) (icon->r_icon[n].x + icon->r_icon[n].width)/2;

	*x = (x1<x2) ? x1 : x2;

	y1 = (Position) (icon->r_label[n].y + icon->r_label[n].height)/2;
	y2 = (Position) (icon->r_icon[n].y + icon->r_icon[n].height)/2;

	*y = (y1<y2) ? y1 : y2;

	*x = (Position) icon->r_all[n].x;
	*y = (Position) icon->r_all[n].y;

}

/*-------------------------------------------------------------------

 Add the drop facility to other widgets

------------------------------------------------------------------*/

typedef	struct {
	Widget          widget;
	XtCallbackProc  callback;
	XtPointer		closure;
} accept_drop;


static void set_drop_property(Widget widget,XtCallbackProc callback,
XtPointer closure,Widget subwidget)
{
	accept_drop *info;

	if(!XtIsWidget(widget))
	{
		XtAppWarningMsg(XtWidgetToApplicationContext(widget),
		    "invalidWidget","invalidWidget","DragError",
		    "DragAcceptDropCallback : Not a widget",
		    (String *)NULL, (Cardinal *)NULL);

		return;
	}

	if(!subwidget) subwidget = widget;

	info            = XtNew(accept_drop);
	info->callback  = callback;
	info->closure   = closure;
	info->widget    = subwidget;

	XtAddEventHandler((Widget)widget,
	    NoEventMask,
	    True,
	    message_event_handler,
	    (XtPointer)info);

	XtAddCallback(widget,XtNdestroyCallback,destroy_callback,
	    (XtPointer)info);

	if(XtIsRealized(widget))
		register_widget(widget,XtName(subwidget));
	else
		XtAddEventHandler(widget,
		    VisibilityChangeMask,True,(XtEventHandler)map_event_handler_1,
		    (XtPointer)info);

}

typedef struct relay {
	Widget widget;
} relay;

void DragAcceptDropCallback(widget,callback,closure)
Widget          widget;
XtCallbackProc  callback;
XtPointer       closure;
{
	Widget clip,scroll;
	set_drop_property(widget,callback,closure,widget);
	if(clip = XtParent(widget))
		if(scroll = XtParent(clip))
			if(XmIsScrolledWindow(scroll))
				set_drop_property(clip,callback,closure,widget);
}

void DragSetInfo(Widget widget,const char *info)
{
	Widget clip,scroll;
	create_atoms(XtDisplay(widget));

	if(!XtIsRealized(widget))
		XtAddEventHandler(widget,
		    VisibilityChangeMask,True,(XtEventHandler)map_event_handler_2,
		    (XtPointer)XtNewString(info));
	else
		XChangeProperty(
		    XtDisplay(widget),
		    XtWindow(widget),
		    InfoAtom,
		    XA_WINDOW,
		    8,
		    PropModeReplace,
		    (unsigned char *)info,
		    strlen(info)+1);

	/* Copy to scrolled window .. */
	if(clip = XtParent(widget))
		if(scroll = XtParent(clip))
			if(XmIsScrolledWindow(scroll))
				DragSetInfo(clip,info);
}

const char *DragGetInfo(DragCallbackStruct *cb)
{
	Atom type;
	int format;
	unsigned long nitems, left;
	static char *retdata = NULL;

	if(retdata) {
		XtFree(retdata);
		retdata = NULL;
	}

	if(cb->remote_window == NULL)
		return NULL;

	if(XGetWindowProperty(
	    cb->event->xany.display,
	    cb->remote_window,
	    InfoAtom,0,4,
	    False,XA_WINDOW,
	    &type, &format, &nitems,&left,
	    (unsigned char**) &retdata) == Success)
		if(type == XA_WINDOW)
			return retdata;

	return NULL;
}

static void map_event_handler_1(widget,info,event,continue_dispatch)
Widget widget;
accept_drop *info;
XEvent    *event;
Boolean   *continue_dispatch;
{

	if(XtIsRealized(widget))
		register_widget(widget,XtName(info->widget));
	else
		XtAppWarningMsg(XtWidgetToApplicationContext(widget),
		    "invalidWidget","invalidWidget","DragError",
		    "DragAcceptDropCallback : Widget cannot be registered (not realized)",
		    (String *)NULL, (Cardinal *)NULL);

	XtRemoveEventHandler(widget,
	    VisibilityChangeMask,True,(XtEventHandler)map_event_handler_1,
	    (XtPointer)info);

}

static void map_event_handler_2(widget,info,event,continue_dispatch)
Widget    widget;
char      *info;
XEvent    *event;
Boolean   *continue_dispatch;
{

	if(XtIsRealized(widget))
		DragSetInfo(widget,info);
	else
		XtAppWarningMsg(XtWidgetToApplicationContext(widget),
		    "invalidWidget","invalidWidget","DragError",
		    "DragAddInfo : Widget cannot be registered (not realized)",
		    (String *)NULL, (Cardinal *)NULL);

	XtRemoveEventHandler(widget,
	    VisibilityChangeMask,True,(XtEventHandler)map_event_handler_2,
	    (XtPointer)info);

	XtFree((XtPointer)info);
}

/*----------------------------------------------------------------------

 The other widget is destroyed

----------------------------------------------------------------------*/

static void destroy_callback(widget,info,cb)
Widget widget;
accept_drop *info;
XtPointer cb;
{
	XtRemoveEventHandler((Widget)widget,NoEventMask,True,
	    message_event_handler,(XtPointer)info);
	XtFree((XtPointer)info);
}

/*----------------------------------------------------------------------

 Notify other widgets

----------------------------------------------------------------------*/

static void notify_drop(Widget widget,XtPointer cd,XtPointer cb)
{
	accept_drop *info = (accept_drop*)cd;
	(*info->callback)(info->widget,info->closure,cb);
}

void DragDropSend(Widget widget,DragCallbackStruct *cb)
{
	send_drop_events((DragWidget)widget,cb);
}

/*-------------------------------------------------------------------

 Add the drag facility of any objects

------------------------------------------------------------------*/

DragCallbackStruct* DragDropObject(Widget widget,
XEvent   *ev,
Position  x,    Position  y,
Dimension width,Dimension height,
DragDrawProc draw,
XtPointer data)
{
	static  DragCallbackStruct cb;
	static  char     *name = NULL;

	Display *dpy   = XtDisplay(widget);
	int     screen = DefaultScreen(dpy);
	Window  root   = RootWindow(dpy,screen);
	Pixmap  pix,mask;
	GC      gc;
	int     dummy;
	XRectangle rect;
	Window drag,target,other;
	int wx,wy;

	create_atoms(dpy); /* the atoms should exist */

	rect.x      = 0;
	rect.y      = 0;
	rect.width  = width;
	rect.height = height;

	pix = XCreatePixmap(dpy,root,width,height,DefaultDepth(dpy,screen));

	gc = XCreateGC(dpy,pix,0,NULL);

	XSetForeground(dpy,gc, WhitePixel(dpy,screen));
	XSetBackground(dpy,gc, BlackPixel(dpy,screen));

	XFillRectangle(dpy,pix,gc,0,0,width,height);

	XSetForeground(dpy,gc, BlackPixel(dpy,screen));
	XSetBackground(dpy,gc, WhitePixel(dpy,screen));


	(*draw)(widget,&rect,pix,gc,data);

	mask = mask_image(widget,pix,NULL,
	    WhitePixel(dpy,screen),&dummy,&dummy);


	drag = create_drag_window(widget,ev,pix,
	    x,y,width,height);

	XWriteBitmapFile(dpy,"bm",mask,
	    width,height,0,0);

	XShapeCombineMask(dpy,drag,ShapeBounding,0,0,mask,ShapeSet);

	target  = drag_window(widget,drag,x,y,&wx,&wy,&other);

	XFreePixmap(dpy,mask);
	XFreePixmap(dpy,pix);
	XFreeGC(dpy,gc);
	XUndefineCursor(dpy,XtWindow(widget));

	if(check_valid_drop(widget,dpy,target,&name))
	{
		memset(&cb,0,sizeof(cb));
		cb.reason        = DRAG_SEND;
		cb.event         = ev;
		cb.same_window   = (target == XtWindow(widget));
		cb.remote_window = target;
		cb.remote_name   = name;
		cb.remote_widget = XtWindowToWidget(dpy,target);
		cb.x             = wx - x ;
		cb.y             = wy - y ;
		cb.icon_no       = 1;
		cb.icon_count    = 1;
		cb.icon_batch    = ++icon_batch;

		return &cb;
	}
	return NULL;
}
