void desktop_drop(BackdropInfo *info,DOpusAppMessage *msg,UWORD qual)
{
	BackdropObject *drop_obj;
	short ok=0,x,y;
	char *name,*source_path;
	short arg,action=DESKTOP_POPUP_LEFTOUT;
	struct ArgArray *array=0;
	struct ArgArrayEntry *aae;
	BOOL check;

	// Lock backdrop list
	lock_listlock(&info->objects,0);

	// See if we dropped stuff on an object
	if ((drop_obj=backdrop_get_object(info,msg->da_Msg.am_MouseX,msg->da_Msg.am_MouseY,0)))
	{
		// Is shift/alt down?
		if ((qual&(IEQUALIFIER_LSHIFT|IEQUALIFIER_LALT))==(IEQUALIFIER_LSHIFT|IEQUALIFIER_LALT))
		{
			char pathname[256];

			// Get path of first file
			GetWBArgPath(&msg->da_Msg.am_ArgList[0],pathname,256);

			// Replace the image
			backdrop_replace_icon_image(info,pathname,drop_obj);

			// Reply the message
			ReplyAppMessage(msg);
		}

		// Handle drop on an object
		else
		if (desktop_drop_on_object(info,&msg,drop_obj,qual))
		{
			// Reply the message
			ReplyAppMessage(msg);
		}

		// Not dropped
		else drop_obj=0;
	}

	// Unlock backdrop list
	unlock_listlock(&info->objects);

	// Dropped on an object?
	if (drop_obj) return;

	// Get buffer
	if (!(name=AllocVec(1024,MEMF_CLEAR))) return;
	source_path=name+512;

	// Popup menu?
	if (environment->env->env_flags&ENVF_DESKTOP_FOLDER)
	{
		UWORD res;

		// Activate the underlying menu
		ActivateWindow(info->window);

		// Default action set?
		if (environment->env->desktop_popup_default>DESKTOP_POPUP_NONE &&
			!(qual&(IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)))
		{
			// Use default action
			action=environment->env->desktop_popup_default;
		}

		// Ask user what they want to do
		else
		if ((res=DoPopUpMenu(info->window,&GUI->desktop_menu->ph_Menu,0,SELECTDOWN))==(UWORD)-1 || res==MENU_DESKTOP_CANCEL)
		{
			// Cancelled	
			FreeVec(name);
			return;
		}

		// Help?
		else
		if (res&POPUP_HELPFLAG)
		{
			// Do help
			help_menu_help(res&~POPUP_HELPFLAG,0);

			// Cancelled	
			FreeVec(name);
			return;
		}

		// Get action
		else
		if (res==MENU_DESKTOP_COPY) action=DESKTOP_POPUP_COPY;
		else
		if (res==MENU_DESKTOP_MOVE) action=DESKTOP_POPUP_MOVE;
	}
		
	// Set busy pointer
	SetBusyPointer(info->window);

	// DOpus message?
	check=CheckAppMessage(msg);

	// Go through arguments
	for (arg=0;arg<msg->da_Msg.am_NumArgs;arg++)
	{
		// What operation?
		switch (action)
		{
			// Leave out?
			case DESKTOP_POPUP_LEFTOUT:

				// Get path name
				GetWBArgPath(&msg->da_Msg.am_ArgList[arg],name,512);

				// Ignore if it's an icon or a disk
				if (!(isicon(name)) && name[strlen(name)-1]!=':')
				{
					short len,perm=0;
					BackdropObject *icon;

					// Permanent?
					if (GUI->flags2&GUIF2_BENIFY)
						perm=1;

					// Get position
					x=msg->da_Msg.am_MouseX;
					y=msg->da_Msg.am_MouseY;

					// Drop from DOpus?
					if (check)
					{
						// Adjust position for icon offset
						x+=msg->da_DragOffset.x+msg->da_DropPos[arg].x;
						y+=msg->da_DragOffset.y+msg->da_DropPos[arg].y;
					}

					// Strip trailing /
					len=strlen(name)-1;
					if (name[len]=='/') name[len]=0;

					// Leave this out
					if ((icon=backdrop_leave_out(info,name,(perm)?BLOF_PERMANENT:0,x,y)))
					{
						// Position it
						backdrop_place_object(info,icon);

						// Save for permanent leftout
						if (perm) backdrop_save_leftouts(info);
						ok=1;
					}
				}
				break;

			// Copy/Move
			case DESKTOP_POPUP_COPY:
			case DESKTOP_POPUP_MOVE:
				{	
					BOOL dir=0;

					// Create ArgArray if needed
					if (!array &&
						!(array=NewArgArray())) break;

					// Get path name
					GetWBArgPath(&msg->da_Msg.am_ArgList[arg],name,512);

					// Set flag if a directory
					if (!msg->da_Msg.am_ArgList[arg].wa_Name ||
						!*msg->da_Msg.am_ArgList[arg].wa_Name) dir=1;

					// Get source path
					if (!*source_path)
					{
						char *ptr;
	
						// Copy from name
						strcpy(source_path,name);

						// Strip last part
						if ((ptr=FilePart(source_path))) *ptr=0;
					}

					// Create argument
					if ((aae=NewArgArrayEntry(array,FilePart(name))))
					{
						// Set directory flag
						if (dir) aae->ae_Flags|=AEF_DIR;

						// Set OK flag
						ok=1;
					}
				}
				break;
		}
	}

	// Successful?
	if (ok)
	{
		// Left-outs?
		if (action==DESKTOP_POPUP_LEFTOUT)
		{
			// Refresh
			backdrop_show_objects(info,BDSF_RECALC);
		}

		// Otherwise, launch function
		else
		{
			// Launch the function
			function_launch(
				FUNCTION_RUN_FUNCTION_EXTERNAL,
				(action==DESKTOP_POPUP_COPY)?def_function_copy:def_function_move,
				0,
				FUNCF_ICONS|FUNCF_RESCAN_DESKTOP|FUNCF_DRAG_DROP|FUNCF_COPY_NO_MOVE,
				0,0,
				source_path,environment->env->desktop_location,
				array,
				0,
				(Buttons *)CopyAppMessage(msg,global_memory_pool));
		}
	}

	// Otherwise, free array
	else FreeArgArray(array);

	// Free buffer
	FreeVec(name);

	// Clear busy pointer
	ClearPointer(info->window);

	// Reply the message
	ReplyAppMessage(msg);
}
// Run a function on some icons
void icon_function(BackdropInfo *info,BackdropObject *only_one,char *data,Cfg_Function *func,ULONG flags)
{
	short count=0;
	struct ArgArray *array;
	BackdropObject *object;
	DirBuffer *buffer=0;
	char *source_path=0;

	// Lock backdrop list
	lock_listlock(&info->objects,1);

	// Go through backdrop list
	for (object=(BackdropObject *)info->objects.list.lh_Head;
		object->node.ln_Succ;
		object=(BackdropObject *)object->node.ln_Succ)
	{
		// Skip invalid icons
		if (object->type!=BDO_LEFT_OUT ||
			(!info->lister && !(object->flags&BDOF_DESKTOP_FOLDER))) continue;

		// Want this icon?
		if (!only_one || only_one==object)
		{
			// Is object selected?
			if ((only_one || object->state) && object->icon)
			{
				// Increment counts
				if (object->icon->do_Type==WBDRAWER ||
					object->icon->do_Type==WBGARBAGE ||
					object->icon->do_Type==WBPROJECT ||
					object->icon->do_Type==WBTOOL)
					++count;

				// Only doing one?
				if (only_one) break;
			}
		}
	}

	// Nothing to work on?
	if (count==0 ||
		!(array=NewArgArray()))
	{
		unlock_listlock(&info->objects);
		return;
	}

	// Got a lister?
	if (info->lister)
	{
		// Lock buffer
		buffer_lock((buffer=info->lister->cur_buffer),FALSE);
	}

	// Source path from icon?
	else
	if (only_one && only_one->path &&
		(source_path=AllocVec(strlen(only_one->path)+1,0)))
		strcpy(source_path,only_one->path);

	// Otherwise, assume this is the desktop folder
	else
	if (info->flags&BDIF_MAIN_DESKTOP &&
		(source_path=AllocVec(strlen(environment->env->desktop_location)+1,0)))
		strcpy(source_path,environment->env->desktop_location);

	// Go through backdrop list again
	for (object=(BackdropObject *)info->objects.list.lh_Head;
		object->node.ln_Succ;
		object=(BackdropObject *)object->node.ln_Succ)
	{
		// Skip invalid icons
		if (object->type!=BDO_LEFT_OUT ||
			(!info->lister && !(object->flags&BDOF_DESKTOP_FOLDER))) continue;

		// Want this icon?
		if (!only_one || only_one==object)
		{
			// Is object selected?
			if ((only_one || object->state) && object->icon)
			{
				char name[80];
				BOOL dir=0,link=0,icon=0;
				DirEntry *entry=0;
				struct ArgArrayEntry *aae;

				// Build name
				stccpy(name,object->name,sizeof(name));

				// Got a buffer?
				if (buffer)
				{
					// See if we can find this entry
					if ((entry=find_entry(&buffer->entry_list,object->name,0,buffer->more_flags&DWF_CASE)) ||
						(entry=find_entry(&buffer->reject_list,object->name,0,buffer->more_flags&DWF_CASE)))
					{
						// Directory?
						if (entry->de_Node.dn_Type>=ENTRY_DEVICE) dir=1;

						// Link?
						if (entry->de_Flags&ENTF_LINK) link=1;

						// See if entry has icon
						if (find_entry(&buffer->entry_list,object->name,0,(buffer->more_flags&DWF_CASE)|FINDENTRY_ICON) ||
							find_entry(&buffer->reject_list,object->name,0,(buffer->more_flags&DWF_CASE)|FINDENTRY_ICON))
							icon=1;
					}

					// If not, use the .info name
					else
					{
						// Add .info
						strcat(name,".info");
					}
				}

				// Desktop folder?
				else
				if (info->flags&BDIF_MAIN_DESKTOP)
				{
					// Assume the file has an icon
					icon=1;
				}

				// Get type from icon
				if (!entry)
				{
					if (object->icon->do_Type==WBDRAWER ||
						object->icon->do_Type==WBGARBAGE) dir=1;
					if (object->flags&BDOF_LINK_ICON) link=1;
				}

				// Tack on a / for directories
				if (dir) strcat(name,"/");

				// Allocate array entry
				if (aae=NewArgArrayEntry(array,name))
				{
					// Dir?
					if (dir) aae->ae_Flags|=AEF_DIR;

					// Link?
					if (link) aae->ae_Flags|=AEF_LINK;

					// No icon?
					if (!icon) aae->ae_Flags|=AEF_FAKE_ICON;
				}

				// Only doing one?
				if (only_one) break;
			}
		}
	}

	// Unlock buffer
	if (buffer) buffer_unlock(buffer);

	// Get flags we need
	flags|=(data && *data)?FUNCF_ICONS:FUNCF_ICONS|FUNCF_ASK_DEST;

	// Launch the function
	function_launch(
		FUNCTION_RUN_FUNCTION_EXTERNAL,
		func,
		0,
		flags,
		info->lister,0,
		(info->lister)?info->lister->cur_buffer->buf_Path:source_path,data,
		array,
		0,0);

	// Free source path
	FreeVec(source_path);

	// Unlock list
	unlock_listlock(&info->objects);
}