/*
     Filemaster - Multitasking directory utility.
     Copyright (C) 2000  Toni Wilen
     
     This program is free software; you can redistribute it and/or
     modify it under the terms of the GNU General Public License
     as published by the Free Software Foundation; either version 2
     of the License, or (at your option) any later version.
     
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
     
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#include <proto/all.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <libraries/gadtools.h>
#include <intuition/gadgetclass.h>
#include <workbench/workbench.h>
#include <workbench/startup.h>
#include <strings.h>
#include <stdio.h>
#include "fmnode.h"
#include "fmdos.h"
#include "child.h"
#include "fmlocale.h"
#include "fmgui.h"
#include "audio.h"
#include "commodity.h"

struct QuitConfig {
	unsigned areyousure:2;
};
struct SleepConfig {
	unsigned sleepwindow:2;
};

#define IDCMP IDCMP_MOUSEBUTTONS|IDCMP_GADGETDOWN|IDCMP_GADGETUP|IDCMP_RAWKEY|IDCMP_REFRESHWINDOW|IDCMP_NEWSIZE|IDCMP_CLOSEWINDOW|IDCMP_ACTIVEWINDOW|IDCMP_INACTIVEWINDOW

extern void __asm RealTimeScroll(register __a0 struct ReqScrollStruct*);
extern struct FMMain fmmain;
extern struct FMList fmlist[];
extern UBYTE workbench[];

void windownewsize(void);
void taskwindow(WORD);
void nextlist(struct ListInfo*,WORD);
void clickfile(void);
void parentpath(struct FMList*,BPTR);
WORD getparent(struct FMList*);
void setparent(struct FMList*);
void setcmenu(void);
void parse(void);
WORD suljenaytto(WORD);
WORD avaanaytto(WORD);
void freegadgets(struct Gadget*);
void askmodabort(void);
struct FMNode *iteratenode(struct FMNode**);
void gparent(void);
void aboutti(WORD);
void dirfileclick(struct FMList*,struct FMNode*,WORD);
void setnewconfig(void);
WORD config(void);

void operate(void);
void __asm jump(register __a0 APTR,register __a1 APTR);
extern APTR launchtable[];
extern struct FMMain fmmain;
extern struct FMConfig *fmconfig;
extern struct FMList fmlist[];

void getdir(void);
void dirmeters(void);
void drives(struct FMList*);

static WORD sleep(WORD sleepv)
{
WORD ret=0;

if(!sleepv) if (!suljenaytto(3)) {
	return(0);
}
SetSignal(0,SIGBREAKF_CTRL_F);
fmmain.sleepon=fmmain.quitti;
Signal((struct Task*)fmmain.timeproc,SIGBREAKF_CTRL_F);
while(fmmain.sleepon==fmmain.quitti) waitsig(SIGBREAKF_CTRL_F);
if(fmmain.sleepon) {
	for(;;) {
		ret=avaanaytto(3);
		if(ret) break;
		DisplayBeep(0);
		Delay(50);
	}
}
fmmain.sleepon=0;
return(1);
}

void setsource(struct FMList *list1)
{
struct FMList *vlist;

if(list1==fmmain.sourcedir) return;
if(list1==fmmain.destdir) {
	vlist=fmmain.sourcedir;
	fmmain.sourcedir=list1;
	fmmain.destdir=vlist;
} else {
	fmmain.sourcedir->flags&=~(LDESTINATION|LSOURCE);
	fmmain.sourcedir=list1;
}
fmmain.sourcedir->flags&=~LDESTINATION;
fmmain.sourcedir->flags|=LSOURCE;
fmmain.destdir->flags&=~LSOURCE;
fmmain.destdir->flags|=LDESTINATION;
fmmessage(list1);
dirmeters();
}

static struct FMNode *mousenode(struct FMList *list,WORD xx,WORD yy)
{
struct ListInfo *li;
struct FMNode *node;
WORD cnt,apu1;

li=list->li;
if (xx>=li->dirx && xx<=li->edirx && yy>=li->diry && yy<li->ediry) {
	node=(struct FMNode*)list;
	iteratenode(&node);
	cnt=list->firstline;
	yy-=li->diry; if (yy<0) return(0);
	yy/=fmmain.listysize;
	apu1=cnt+yy;
	while(cnt--) iteratenode(&node);
	while(node && yy--) iteratenode(&node);
	if (!node||!node->succ) return(0);
	fmmain.sourcedir->keyline=apu1;
	return(node);
}
return(0);
}

static WORD processclick(struct IntuiMessage *msg)
{
struct timeval tv1,tv2;
struct FMNode *node;
struct FMList *list1=0;
struct ListInfo *li;
WORD xx,yy,apu1,cnt1;
WORD dragtype=-1;

xx=msg->MouseX-fmmain.ikkuna->BorderLeft;
yy=msg->MouseY-fmmain.ikkuna->BorderTop;
if (msg->Code==MENUDOWN && xx>=fmmain.cmenux && xx<=fmmain.cmenux+fmmain.totalcmenuwidth && yy>=fmmain.cmenuy && yy<=fmmain.cmenuy+fmmain.totalcmenuheight) {
	fmmain.cmenu+=fmmain.cmenugadnumperline*fmconfig->cmenucolumns;
	apu1=0;
	for(cnt1=0;cnt1<TOTALCOMMANDS;cnt1++) {
		if(fmconfig->cmenuconfig[cnt1].position==1) apu1++;
	}
	if(fmmain.cmenu>apu1) fmmain.cmenu=0;
	setcmenu();
}
for(apu1=0;apu1<LISTS;apu1++) {
	li=fmlist[apu1].li;
	if(li&&xx>=li->x&&xx<=li->x+li->width&&yy>=li->y&&yy<=li->y+li->height) { 
		list1=&fmlist[apu1];
		break;
	}
}
if (yy>=fmmain.messageliney1 && msg->Code==MENUDOWN) askmodabort();

if (!list1||!li) return(dragtype);

if (msg->Code==MENUDOWN && fmmain.sourcedir->flags&LACTIVE) fmmain.sourcedir->flags|=LABORTREQ;

setsource(list1);

if(list1->flags&LALLOCATED) return(dragtype);

if(msg->Code==MENUDOWN) {
	if(xx>=li->slider1.LeftEdge&&xx<=li->slider1.LeftEdge+li->slider1.Width&&yy>=li->slider1.TopEdge&&yy<=li->slider1.TopEdge+li->slider1.Height) {
		launch(launchtable[PARENTCONFIG],getconfignumber(PARENTCONFIG),0,0);
//		gparent();
		return(dragtype);
	}
	if (yy>=li->topliney&&yy<=li->topliney+fmmain.txtysize+1) {
		if (list1->flags&LDIRLIST)
			launch((APTR)&getdir,0,0,MSUBPROC);
			else
			drives(list1);
	}
	if(fmconfig->rightmouse==1) {
		launch(launchtable[PARENTCONFIG],getconfignumber(PARENTCONFIG),0,0);
//		gparent();
		return(dragtype);
	}
}

node=mousenode(list1,xx,yy);
if(!node) return(dragtype);

if(msg->Code==MENUDOWN&&fmconfig->rightmouse==0) dirfileclick(list1,node,xx);
if (msg->Code==SELECTDOWN) {
	node->flags^=NSELECTED;
	if(node->flags&NSELECTED) dragtype=1; else dragtype=0;
	if (list1->flags&LDIRLIST&&node->flags&NSELECTED) endofdirtxt(list1,node);
	if (list1->flags&LDIRLIST&&!(node->flags&NSELECTED)) endofdirtxt(list1,0);
	outputlistline(list1,node);
	tv1.tv_secs=fmmain.secs;tv1.tv_micro=fmmain.mics;
	tv2.tv_secs=msg->Seconds;tv2.tv_micro=msg->Micros;
	SubTime(&tv2,&tv1);
	if (list1->lastclicked==node && !tv2.tv_secs && tv2.tv_micro/10000<=fmconfig->doubleclick) {
		dirfileclick(list1,node,xx);
		list1->lastclicked=0;
	} else {
		list1->lastclicked=node;
	}
	fmmain.secs=msg->Seconds; fmmain.mics=msg->Micros;
}
return(dragtype);
}


static void processgadget(WORD id,ULONG class)
{
if (id>=301 && id<(301+TOTALCOMMANDS)) {
	if(id-301<TOTALCOMMANDS) runcommand(&fmmain.gadkeytab[id-301+LISTGADGETS*WINDOWLISTS]);
}
	// slider1s 101->
	// slider2s 111->
	// string gadgets 201->
	// taskgadget 401->
	// ltaskgadget 411->
	// rtaskgadget 421->

if (id>=401&&id<=410) {
	setsource(fmmain.li[id-401]->list);
	taskwindow(id-401);
	return;
}
if (id>=411&&id<=420) {
	setsource(fmmain.li[id-411]->list);
	nextlist(fmmain.sourcedir->li,-1);
	return;
}
if (id>=421&&id<=430) {
	setsource(fmmain.li[id-421]->list);
	nextlist(fmmain.sourcedir->li,1);
	return;
}
if (id>=201&&id<=210) {
	setsource(fmmain.li[id-201]->list);
	setparent(fmmain.sourcedir);
	fmmain.sourcedir->fmmessage1[0]=0;
	fmmain.sourcedir->fmmessage2[0]=0;
	fmmessage(fmmain.sourcedir);
	launch((APTR)&getdir,0,0,MSUBPROC);
	return;
}
if (id>=101&&id<=110) {
	setsource(fmmain.li[id-101]->list);
	RealTimeScroll(&fmmain.sourcedir->li->rscroll1);
	fmmain.sourcedir->firstline=fmmain.sourcedir->li->rscroll1.TopEntryNumber;
	return;
}
if (id>=111&&id<=120) {
	setsource(fmmain.li[id-111]->list);
	RealTimeScroll(&fmmain.sourcedir->li->rscroll2);
	fmmain.sourcedir->firstlinew=fmmain.sourcedir->li->rscroll2.TopEntryNumber;
	return;
}
}


void runhotkey(WORD hotkey)
{
struct GadKeyTab *gkt;

gkt=&fmmain.gadkeytab[hotkey];
if((gkt->onelist&&gkt->listnum==fmmain.sourcedir->listnumber)||(!gkt->onelist)) {
	if(gkt->cmc) {
		runcommand(gkt);
	} else {
		processgadget(gkt->g->GadgetID,0);
	}
}
}

static void frameoutput(struct FMList *l)
{
fmmain.framenode=scrollifneeded(l,&l->keyline,&l->keylinew);
fmmain.framelist=l;
fmmain.framenode->flags|=NKEYBOARD;
outputlistline(fmmain.framelist,fmmain.framenode);
}
static WORD endframeoutput(void)
{
WORD was;

was=0;
if(fmmain.framenode) {
	fmmain.framenode->flags&=~NKEYBOARD;
	outputlistline(fmmain.framelist,fmmain.framenode);
	was=1;
}
fmmain.framenode=0;
fmmain.framelist=0;
return(was);
}

WORD smallevent(struct Window *win,ULONG *class,UWORD *code)
{
struct IntuiMessage *message;
ULONG sigs;

while(!(message=(struct IntuiMessage*)GetMsg(win->UserPort))) {
		sigs=Wait((1L<<win->UserPort->mp_SigBit)|SIGBREAKF_CTRL_C);
		if(sigs&SIGBREAKF_CTRL_C) {
			SetSignal(SIGBREAKF_CTRL_C,SIGBREAKF_CTRL_C);
			return(1);
		}
}
*class=message->Class;
*code=message->Code;
ReplyMsg((struct Message*)message);
return(0);
}

void getappdir(struct AppMessage *appmsg)
{
BPTR lock;

ActivateWindow(fmmain.ikkuna);
if(!(fmmain.sourcedir->flags&LALLOCATED)&&appmsg->am_NumArgs>=1) {
	lock=DupLock(appmsg->am_ArgList->wa_Lock);
	if(lock) {
		parentpath(fmmain.sourcedir,lock);
		launch((APTR)&getdir,0,0,MSUBPROC);
	}
}
}

void event(WORD sleepv)
{
ULONG class,signalmask,sigs;
struct IntuiMessage *message=0;
struct AppMessage *appwinmsg=0;
struct IntuiMessage fakeintu;
struct InputEvent ie;
struct FMNode *apunode1,*apunode2;
struct FMList *apulist;
UWORD code;
UBYTE asciicode;
WORD draggi=-1,dragged=0;
WORD apu1,apu2,apu3,framewas;
LONG apu4;
UBYTE chartab[2];
struct ReqScrollStruct *rss;
WORD waiti=0,superhotkey;

signalmask=1L<<fmmain.ikkuna->UserPort->mp_SigBit;
if(fmmain.appwinport) signalmask|=(1L<<fmmain.appwinport->mp_SigBit);
signalmask|=SIGBREAKF_CTRL_F;

ie.ie_Class=IECLASS_RAWKEY;
ie.ie_SubClass=0;
if(sleepv) {
	launch(launchtable[SLEEPCONFIG],getconfignumber(SLEEPCONFIG),0,0);
	sleep(1);
	if(fmmain.kill) return;
}
setsource(&fmlist[1]);
setsource(&fmlist[0]);
Signal((struct Task*)fmmain.timeproc,SIGBREAKF_CTRL_D);
fmmain.fmactive=1|2;

eventti:

framewas=0; class=0; code=0; fmmain.quitti=0;
superhotkey=-1;
while(!fmmain.quitti) {

	if(waiti) {
		if(framewas) frameoutput(fmmain.sourcedir);

		sigs=waitsig(signalmask);

		waiti=0;
		if(sigs&SIGBREAKF_CTRL_F) {
			if(fmmain.passhotkey) {
				runhotkey(fmmain.passhotkey-1);
				fmmain.passhotkey=0;
			} else {
				launch(launchtable[SLEEPCONFIG],getconfignumber(SLEEPCONFIG),0,0);
			}
		}
	}

	if(fmmain.appwinport) {
		appwinmsg=(struct AppMessage*)GetMsg(fmmain.appwinport);
		if(appwinmsg) {
			getappdir(appwinmsg);
			ReplyMsg((struct Message*)appwinmsg);
			appwinmsg=0;
			continue;
		}
	}
	if(superhotkey>=0) runhotkey(superhotkey);
	superhotkey=-1;

	message=(struct IntuiMessage*)GetMsg(fmmain.ikkuna->UserPort);

	if(!message) {
		waiti=1;
		continue;
	}
	superhotkey=checkhotkeys(message);
	framewas=endframeoutput();

	class=message->Class;
	code=message->Code;
	fakeintu.MouseX=message->MouseX;
	fakeintu.MouseY=message->MouseY;
	fakeintu.Seconds=message->Seconds;
	fakeintu.Micros=message->Micros;
	asciicode=0;
	if (class==IDCMP_RAWKEY&&!(code&0x80)&&!(fmmain.sourcedir->flags&LALLOCATED)) {
		switch(code)
		{
		case 0x4c:	//cursor up
		if(message->Qualifier&0x0003) fmmain.sourcedir->keyline-=fmmain.sourcedir->li->visiblelines-2;
		if(message->Qualifier&0x0008) fmmain.sourcedir->keyline=1;
		fmmain.sourcedir->keyline--;
		frameoutput(fmmain.sourcedir);
		break;
		case 0x4d:	//cursor down
		if(message->Qualifier&0x0003) fmmain.sourcedir->keyline+=fmmain.sourcedir->li->visiblelines-2;
		if(message->Qualifier&0x0008) fmmain.sourcedir->keyline=fmmain.sourcedir->totlines-2;
		fmmain.sourcedir->keyline++;
		frameoutput(fmmain.sourcedir);
		break;
		case 0x4e:	//cursor left
		if(message->Qualifier&0x0008)
			fmmain.sourcedir->keylinew=fmmain.sourcedir->totlinesw-1;
			else
			fmmain.sourcedir->keylinew+=fmmain.sourcedir->li->visiblelinesw;
		frameoutput(fmmain.sourcedir);
		break;
		case 0x4f:	//cursor right
		if(message->Qualifier&0x0008)
			fmmain.sourcedir->keylinew=0;
			else
			fmmain.sourcedir->keylinew-=fmmain.sourcedir->li->visiblelinesw;
		frameoutput(fmmain.sourcedir);
		break;
		}
	}
	if(class==IDCMP_RAWKEY) {
		apu1=0;
		switch(code)
		{
		case 0x00:	//~pushed
		if(fmmain.modflag==MODPLAY) *((UBYTE*)(fmmain.modptr))=1;
		apu1=1;
		break;
		case 0x80:	//~released
		if(fmmain.modflag==MODPLAY) *((UBYTE*)(fmmain.modptr))=0;
		apu1=1;
		break;
		}
		if(!apu1) {
			if (!(message->Code&0x80)) {
				ie.ie_Code=message->Code;
				ie.ie_Qualifier=message->Qualifier;
				ie.ie_EventAddress=(APTR*)*((ULONG*)message->IAddress);
				if (MapRawKey(&ie,chartab,2,0)==1) asciicode=ToUpper(chartab[0]);
			}
		}
	}

	if(asciicode) {
		framewas=0;
		if(asciicode==9) {
			apu1=fmmain.sourcedir->listnumber;
			for(;;) {
				if (message->Qualifier&0x03) apu1--; else apu1++;
				if (apu1==LISTS) apu1=0;
				if (apu1<0) apu1=LISTS-1;
				if(fmlist[apu1].li) {
					setsource(&fmlist[apu1]);
					break;
				}
			}
			if (!(fmmain.sourcedir->flags&LALLOCATED)) {
				frameoutput(fmmain.sourcedir);
			}
		} else if (!(fmmain.sourcedir->flags&LALLOCATED)&&asciicode) {
			switch(asciicode)
			{
			break;
			case 13:	//return
			fakeintu.MouseX=fmmain.sourcedir->li->dirx+fmmain.ikkuna->BorderLeft;
			fakeintu.MouseY=(fmmain.sourcedir->keyline-fmmain.sourcedir->firstline)*fmmain.listysize+fmmain.sourcedir->li->diry+fmmain.ikkuna->BorderTop;
			if(message->Qualifier&0x03) fakeintu.Code=MENUDOWN; else fakeintu.Code=SELECTDOWN;
			fakeintu.Class=IDCMP_MOUSEBUTTONS;
			processclick(&fakeintu);
			if(!(fmmain.sourcedir->flags&LALLOCATED)) {
				frameoutput(fmmain.sourcedir);
			}
			break;
			}
		}
	}

	switch(class)
	{
	case IDCMP_ACTIVEWINDOW:
	fmmain.fmactive|=2;
	framewas=0;
	break;
	case IDCMP_INACTIVEWINDOW:
	fmmain.fmactive&=~2;
	framewas=0;
	break;
	case IDCMP_RAWKEY:
	if(code&0x80&&fmmain.framenode&&!(fmmain.sourcedir->flags&LALLOCATED)) {
		frameoutput(fmmain.sourcedir);
	}
	break;
	case IDCMP_CLOSEWINDOW:
	framewas=0;
	launch(launchtable[QUITCONFIG],getconfignumber(QUITCONFIG),0,0);
	break;
	case IDCMP_REFRESHWINDOW:
	BeginRefresh(fmmain.ikkuna);
	EndRefresh(fmmain.ikkuna,1);
	break;
	case IDCMP_NEWSIZE:
	framewas=0;
	windownewsize();
	break;
	case IDCMP_DISKINSERTED:
	case IDCMP_DISKREMOVED:
	framewas=0;
	for(code=0;code<WINDOWLISTS;code++) {
		if (fmmain.li[code]&&!(fmmain.li[code]->list->flags&LALLOCATED)&&fmmain.li[code]->list->flags&LDEVLIST) drives(fmmain.li[code]->list);
	}
	break;
	case IDCMP_MOUSEMOVE:
	framewas=0;
	apu1=message->MouseY-fmmain.ikkuna->BorderTop;
	apulist=fmmain.sourcedir;
	if(draggi==-1||!(message->Qualifier&IEQUALIFIER_LEFTBUTTON)) {
		ReportMouse(0,fmmain.ikkuna);
		draggi=-1;dragged=0;
		break;
	}
	apunode1=mousenode(apulist,apulist->li->dirx,apu1);
	do {
		apu4=-1;
		if(!apunode1&&apu1>=0) {
			rss=&apulist->li->rscroll1;
			if(apu1<apulist->li->diry&&apulist->firstline) {
					apulist->firstline--;
					apu4=apulist->firstline;
			} else if (apu1>apulist->li->ediry&&apulist->firstline<apulist->totlines+apulist->li->visiblelines) {
					apulist->firstline++;
					apu4=apulist->firstline+apulist->li->visiblelines-1;
			}
			if(apu4>=0) {
				apunode2=(struct FMNode*)apulist;
				iteratenode(&apunode2);
				while(apu4--) iteratenode(&apunode2);
				if(apunode2&&apunode2->succ) {
					if(draggi)
						apunode2->flags|=NSELECTED;
						else
						apunode2->flags&=~NSELECTED;
				}
				apu3=rss->LineSpacing;
				rss->LineSpacing=1;
				apu2=rss->TopEntryNumber;
				updatelist(apulist);
				rss->TopEntryNumber=apu2;
				RealTimeScroll(rss);
				apulist->firstline=rss->TopEntryNumber;
				rss->LineSpacing=apu3;
				dragged=1;
			}
		}
	} while(apu1&&!fmmain.ikkuna->UserPort->mp_MsgList.lh_Head->ln_Succ);
	apu1=0;
	apunode2=(struct FMNode*)apulist;
	if(!(!apunode1||apunode1==apulist->lastclicked||!apulist->lastclicked||apunode1==apunode2||draggi<0)) {
		while(iteratenode(&apunode2)) {
			apu3=-1;
			if(apunode2==apunode1||apunode2==apulist->lastclicked) apu3=apu1^1;
			if(apu3==1) apu1=apu3;
			apu2=apunode2->flags&NSELECTED;
			if(apu1&&((apu2&&!draggi)|(!apu2&&draggi))) {
				apunode2->flags^=NSELECTED;
				outputlistline(apulist,apunode2);
				dragged=1;
			}
			if(!apu3) apu1=apu3;
		}
	}
	break;
	case IDCMP_GADGETUP:
	case IDCMP_GADGETDOWN:
	framewas=0;
	processgadget(((struct Gadget*)message->IAddress)->GadgetID,class);
	break;
	case IDCMP_MOUSEBUTTONS:
	framewas=0;
	if (code==SELECTUP||code==SELECTDOWN||code==MENUDOWN||code==MENUUP) {
		if(code==SELECTUP&&dragged) {
			endofdirtxt(fmmain.sourcedir,0);
			ReportMouse(0,fmmain.ikkuna);
			draggi=-1;
			dragged=0;
		} else {	
			draggi=processclick(message);
			if(code==SELECTDOWN&&draggi>=0) ReportMouse(1,fmmain.ikkuna);
		}
	}
	break;
	}
	ReplyMsg((struct Message*)message);
	message=0;

	fmmain.fmactive&=~1;
	if(fmmain.newconfig&0x0f) {
		if((fmmain.newconfig&0x0f)==3) {
			while(!suljenaytto(3));
			fmconfig->screentype=fmmain.newconfig>>8;
			if (!avaanaytto(3)) fmmain.quitti=1;
			for(apu1=0;apu1<LISTS;apu1++) if(fmlist[apu1].flags==0) drives(&fmlist[apu1]);
		} else if ((fmmain.newconfig&0x0f)==2) {
			while(!suljenaytto(2));
			fmconfig->screentype=fmmain.newconfig>>8;
			if (!avaanaytto(2)) fmmain.quitti=1;
		} else {
			windownewsize();
		}
		framewas=0;
	}
	fmmain.newconfig=0;
	fmmain.fmactive|=1;

}
if(fmmain.quitti>4) {
	if(fmmain.kill) return;
	sleep(0);
	if(fmmain.kill) return;
	goto eventti;
}
if(fmmain.ikkuna) {
	if(tstsubproc(1)) goto eventti;
} else {
	while(tstsubproc(0)) Delay(10);
}
if (fmmain.ikkuna&&fmmain.quitti==2&&!requestmsg(getstring(MSG_MAIN_QUIT),MSG_YES,MSG_NO,MSG_MAIN_AREYOUSURE)) goto eventti;
aboutti(1);
qquit:
while(tstsubproc(0)) Delay(10);
endframeoutput();
}

void dirfileclick(struct FMList *list1,struct FMNode *node,WORD xx)
{
setparent(list1);
if (node->flags & (NDEVICE|NASSIGN|NDIRECTORY)) {
	if (list1->flags & LDIRLIST) {
		AddPart(list1->path,NDFILE(node),PATH);
	} else {
		if (xx>=list1->li->dirx+8*fmmain.listxsize&&xx<list1->li->edirx&&NDCOMM(node)[0])
			strcpy(list1->path,NDCOMM(node));
			else
			strcpy(list1->path,NDFILE(node));
		if (node->flags&NASSIGN) parentpath(list1,0);
	}
	launch((APTR)&getdir,0,0,MSUBPROC);
} else {
	list1->fmmessage1[0]=0;
	list1->fmmessage2[0]=0;
	fmmessage(list1);
	list1->lastclicked=node;
	launch((APTR)&clickfile,0,0,MSUBPROC);
}
}

void gquit(void)
{
struct ProcMsg *pm;
struct QuitConfig *config;

pm=sinitproc();
config=getconfig(pm->cmc);
if(config->areyousure)
	fmmain.quitti=2;
	else
	fmmain.quitti=1;
deinitproc(pm);
}
WORD getappicon(void)
{
struct SleepConfig *sc;

sc=getconfignumber(SLEEPCONFIG)->moreconfig;
return((WORD)(sc->sleepwindow));
}
void gsleep(void)
{
struct ProcMsg *pm;
struct SleepConfig *config;

pm=sinitproc();
config=getconfig(pm->cmc);
if(config->sleepwindow)
	fmmain.quitti=6;
	else
	fmmain.quitti=5;
deinitproc(pm);
}
void gstod(void)
{
struct ProcMsg *pm;

pm=sinitproc();
if(((fmmain.sourcedir->flags|fmmain.destdir->flags)&LALLOCATED)==0) {
	clearlist(fmmain.destdir);
	duplist(fmmain.sourcedir,fmmain.destdir);
	fmmain.destdir->firstline=fmmain.sourcedir->firstline;
	fmmain.destdir->firstlinew=fmmain.sourcedir->firstlinew;
	strcpy(fmmain.destdir->path,fmmain.sourcedir->path);
	fmmain.destdir->flags&=~(LDIRLIST|LDEVLIST);
	fmmain.destdir->flags|=fmmain.sourcedir->flags&(LDIRLIST|LDEVLIST);
	if (fmmain.destdir->li) RefreshGList(&fmmain.destdir->li->string,fmmain.ikkuna,0,1);
	csortlist(fmmain.destdir);
	parselist(fmmain.destdir,0);
	updadirmeter(fmmain.destdir);
	outputlist(fmmain.destdir);
}
deinitproc(pm);
}

void gconfig(void)
{
struct ProcMsg *pm;
pm=sinitproc();
if(!tstsubproc(1)) {
	fmmain.newconfig=config();
	Signal((struct Task*)fmmain.timeproc,SIGBREAKF_CTRL_D);
}
deinitproc(pm);
}
void gdrives(void)
{
struct ProcMsg *pm;
pm=sinitproc();
if (!(fmmain.sourcedir->flags&LALLOCATED)) drives(fmmain.sourcedir);
deinitproc(pm);
}
void gparent(void)
{
struct ProcMsg *pm;
UBYTE *apup1;

pm=sinitproc();
if (!(fmmain.sourcedir->flags&LALLOCATED)) {
	if(*(fmmain.sourcedir->path+strlen(fmmain.sourcedir->path)-1)==':') {
		drives(fmmain.sourcedir);
	} else {
		apup1=PathPart(fmmain.sourcedir->path);*apup1=0; 
		if (apup1==&fmmain.sourcedir->path[0]) {
			drives(fmmain.sourcedir);
		} else {
			if (!getparent(fmmain.sourcedir)) launch((APTR)&getdir,0,0,MSUBPROC);
		}
	}
}
deinitproc(pm);
}
void ginvert(void)
{
struct ProcMsg *pm;
struct FMNode *node;

pm=sinitproc();
if (!(fmmain.sourcedir->flags&LALLOCATED)) {
	for(node=fmmain.sourcedir->head;node->succ;node=node->succ) {
		if(node->flags&NMATCHED) node->flags^=NSELECTED;
	}
	outputlist(fmmain.sourcedir);
	endofdirtxt(fmmain.sourcedir,0);
}
deinitproc(pm);
}
void gclear(void)
{
struct ProcMsg *pm;
struct FMNode *node;

pm=sinitproc();
if (!(fmmain.sourcedir->flags&LALLOCATED)) {
	for(node=fmmain.sourcedir->head;node->succ;node=node->succ) {
		node->flags&=~NSELECTED;
	}
	outputlist(fmmain.sourcedir);
	endofdirtxt(fmmain.sourcedir,0);
}
deinitproc(pm);
}

ULONG waitsig(ULONG sigs)
{
ULONG rsigs;

for(;;) {
	rsigs=Wait(sigs|SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D);
	if(rsigs&SIGBREAKF_CTRL_C) {
		Signal((struct Task*)fmmain.timeproc,SIGBREAKF_CTRL_C);
	}
	if(rsigs&SIGBREAKF_CTRL_D) {
		Signal((struct Task*)fmmain.timeproc,SIGBREAKF_CTRL_D);
	}
	rsigs&=~((LONG)(SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D));
	if(rsigs) break;
}
return(rsigs);
}


void *sleepconfigdefault(struct CMenuConfig *cmc)
{
struct SleepConfig *config;
WORD ret;

ret=allocconfig(cmc,sizeof(struct SleepConfig));
if(ret<0) return(cmc->moreconfig);
if(!ret) return(0);
config=(struct SleepConfig*)cmc->moreconfig;
config->sleepwindow|=2;
return(cmc->moreconfig);
}

WORD sleepconfig(struct GUIBase *gb,struct CMenuConfig *cmc)
{
WORD c;
struct SleepConfig *sc;
WORD sleepwindow,appwindow;

sc=getconfig(cmc);
setguigroup(gb,1,0);
reqinfomsg(gb,MSG_SLEEP_SLEEPWINDOW,200,guiUC|guiLEFT);
reqinfomsg(gb,MSG_SLEEP_APPICON,201,guiUC|guiLEFT);
setguigroup(gb,2,0);
sleepwindow=sc->sleepwindow&1;
appwindow=(sc->sleepwindow&2)?1:0;
reqcycle2msg(gb,200,&sleepwindow);
reqcycle2msg(gb,201,&appwindow);
commandanswer(gb);
c=quickreq(gb);
sc->sleepwindow=sleepwindow;
sc->sleepwindow|=appwindow<<1;
if(!appwindow) sc->sleepwindow|=1;
return(c);
}

void *quitconfigdefault(struct CMenuConfig *cmc)
{
struct QuitConfig *config;
WORD ret;

ret=allocconfig(cmc,sizeof(struct QuitConfig));
if(ret<0) return(cmc->moreconfig);
if(!ret) return(0);
config=(struct QuitConfig*)cmc->moreconfig;
config->areyousure=1;
return(cmc->moreconfig);
}

WORD quitconfig(struct GUIBase *gb,struct CMenuConfig *cmc)
{
WORD c;
struct QuitConfig *qc;
WORD ays;

qc=getconfig(cmc);
ays=qc->areyousure;
setguigroup(gb,1,0);
reqinfomsg(gb,MSG_MAIN_AREYOUSURE,200,guiUC|guiLEFT);
setguigroup(gb,2,0);
reqcycle2msg(gb,200,&ays);
commandanswer(gb);
c=quickreq(gb);
qc->areyousure=ays;
return(c);
}
