/*************************************************************************\
 *                                                                       *
 * Apdf.c                                                                *
 *                                                                       *
 * Copyright 1999-2000 Emmanuel Lesueur                                  *
 *                                                                       *
\*************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libraries/asl.h>
#include <libraries/mui.h>
#include <libraries/gadtools.h>
#include <libraries/iffparse.h>
#include <dos/dostags.h>
#include <exec/nodes.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>
#define NO_INLINE_STDARG
#include <proto/muimaster.h>
#undef NO_INLINE_STDARG
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#define NO_INLINE_STDARG
#include <proto/intuition.h>
#undef NO_INLINE_STDARG
#include <proto/utility.h>
#include <proto/icon.h>
#include <proto/iffparse.h>
#include <proto/keymap.h>
#include <proto/locale.h>
#ifdef HAVE_POWERUP
#   include <powerup/ppclib/ppc.h>
#   include <powerup/ppclib/tasks.h>
#   include <powerup/ppclib/message.h>
struct ModuleArgs;    /* avoid warnings */
struct PPCObjectInfo; /* avoid warnings */
#   include <powerup/proto/ppc.h>
#endif
#include "AComm.h"
#include "Apdf.h"
#include "document.h"
#include "docbitmap.h"
#include "docgroup.h"
#include "docwindow.h"
#include "prefs.h"
#include "msgs.h"

#ifndef AFF_68060
#   define AFF_68060 (1L<<7)
#endif

#define DB(x)   //x
#define Static  static

#ifdef __SASC
#   define SAVEDS   __saveds
#   define ASM      __asm
#   define REG(r,a) register __ ## r a
#elif defined(__GNUC__)
#   define SAVEDS
#   define ASM
#   define REG(r,a) a __asm(#r)
#endif

int create_ppc_server(struct server_info*,void*);
int create_m68k_server(struct server_info*,BPTR);

void* MyAllocMem(size_t sz) {
    /* needs a malloc that frees all remaining memory at exit */
    return malloc(sz);
}

void MyFreeMem(void* p) {
    free(p);
}

void CopyStr(char** p,const char* q) {
    if(q) {
	size_t l=strlen(q)+1;
	char* t=MyAllocMem(l);
	if(t) {
	    MyFreeMem(*p);
	    *p=t;
	    memcpy(t,q,l);
	}
    }
}

Object *config;

/*void lock(void) {}

void unlock(void) {}*/

static char* module_arg;
static char* config_arg;
static char* page_arg;
static int zoom_arg=-1;
#define TEMPLATE "PDFFILE,P=PAGE/K,Z=ZOOM/N/K,C=CONFIG/K," \
		 "MODULE/K,NOPOWERUP/S"
#define PDFFILE ((const char*)args[0])
#define PAGE    (args[1]?(char*)args[1]:page_arg)
#define ZOOM    (args[2]?*(int*)args[2]:zoom_arg)
#define CONFIG  (args[3]?(const char*)args[3]:(config_arg?config_arg:"PROGDIR:Apdf.config"))
#define MODULE  (args[4]?(char*)args[4]:module_arg)
#define NOPUP   (args[5])
#define NARGS   6
#define SET_ZOOM(x)    (args[2]=NULL,zoom_arg=x)
#define SET_NOPUP(x)   (args[5]=x)
static LONG args[NARGS];


#if defined(__SASC) || defined(__libnix__)
char __stdiowin[]="CON://600/200/Apdf/AUTO/WAIT/CLOSE";
extern struct WBStartup *_WBenchMsg;

Static void parse_tooltypes(BPTR lock,const char* name) {
    struct DiskObject *dob;
    BPTR olddir=CurrentDir(lock);
    if(dob=GetDiskObject((char*)name)) {
	if(dob->do_ToolTypes) {
	    char* s=(char*)FindToolType((UBYTE**)dob->do_ToolTypes,(UBYTE*)"PAGE");
	    if(s)
		CopyStr(&page_arg,s);
	    s=(char*)FindToolType((UBYTE**)dob->do_ToolTypes,(UBYTE*)"ZOOM");
	    if(s)
		SET_ZOOM(atoi(s));
	    s=(char*)FindToolType((UBYTE**)dob->do_ToolTypes,(UBYTE*)"CONFIG");
	    if(s)
		CopyStr(&config_arg,s);
	    s=(char*)FindToolType((UBYTE**)dob->do_ToolTypes,(UBYTE*)"MODULE");
	    if(s)
		CopyStr(&module_arg,s);
	    s=(char*)FindToolType((UBYTE**)dob->do_ToolTypes,(UBYTE*)"NOPOWERUP");
	    if(s)
		SET_NOPUP(TRUE);
	}
	FreeDiskObject(dob);
    }
    CurrentDir(olddir);
}
#endif


#define ID_ABOUT          1
#define ID_ABOUTMUI       2
#define ID_SEARCH         3
#define ID_OPEN           4
#define ID_SAVEAS         5
#define ID_WRITE          6
#define ID_MUIPREFS       7
#define ID_COPY           8
#define ID_DEFAULTFONTS   9
#define ID_DOCFONTS       11
#define ID_APPLYFONTMAP   12
#define ID_SCANFONTS      13
#define ID_OPENSCANFONTS  15
#define ID_PRINT          16
#define ID_HIDE           17
#define ID_NEW            18
#define ID_DELETE         19
#define ID_NEWVIEW        20
#define ID_LEFT           21
#define ID_RIGHT          22
#define ID_REFRESH        23
#define ID_CROP           24
#define ID_UNCROP         25
#define ID_OUTLINES       26
#define ID_INFO           27
#define ID_TEXTAA         28
#define ID_STROKEAA       29
#define ID_FILLAA         30
#define ID_PREFS          31
#define ID_SAVEPREFS      32
#define ID_USEPREFS       33
#define ID_CANCELPREFS    34
#define ID_LOG            35
#define ID_FONTS          36

#define MYASSERT(x) if(!(x)) { printf("Internal error: %s/%d\n",__FILE__,__LINE__); exit(EXIT_FAILURE); }


#if defined(__SASC) || defined(__libnix__)
long __stack=30000;
#endif

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct UtilityBase *UtilityBase;
struct Library *MUIMasterBase;
struct Library *IconBase;
struct Library *IFFParseBase;
struct Library *KeymapBase;
struct LocaleBase *LocaleBase;
#if defined(HAVE_CYBERGRAPHICS_CYBERGRAPHICS_H) || \
    defined(HAVE_CYBERGRAPHX_CYBERGRAPHICS_H)
struct Library *CyberGfxBase;
#endif
#ifdef HAVE_POWERUP
struct Library *PPCLibBase;
#endif

struct Catalog *catalog;
BPTR input,oldinput;
BPTR progdir,modules_dir;
char *progname;
struct RDArgs *rda;
struct DiskObject *diskobj;
struct MUI_CustomClass *docwindow_mcc;
Object *App;
Object *win;
Object *prefswin,*prefsobj;
Object *logwin,*logobj;
struct FileRequester *req;
static BPTR olddir;
APTR oldwindowptr;
static struct comm_info *ci;
static struct server_info sv;
static Object *toDelete;
static int win_count;
static BPTR seglist;
#ifdef HAVE_POWERUP
static void *elfobject;
#endif
static int sv_init;
struct Process* proc;
static ULONG err_quiet;

struct DocWindowData {
    struct DocWindowData *next;
    Object *obj;
    Object *doc;
    Object *groupobj;
    Object *menu;
};
typedef struct DocWindowData DocWindowData;

static DocWindowData *windows;

/*
 *  Misc functions.
 */

const char *get_prt_dev(void) {
    ULONG d=DoMethod(config,MUIM_Dataspace_Find,MYCFG_Apdf_PrintDev);
    return d?(const char*)d:"PRT:";
}

const char *get_def_icon(void) {
    ULONG d=DoMethod(config,MUIM_Dataspace_Find,MYCFG_Apdf_DefIcon);
    return d?(const char*)d:"ENV:sys/def_pdf";
}

Static int open_req(Object *win) {
    struct Screen *scr=NULL;
    if(win) {/* NULL for the initial requester */
	APTR w;
	get(win,MUIA_Window_Screen,&scr);
	get(win,MUIA_Window_Window,&w);
	if(w)
	    proc->pr_WindowPtr=w;
    }
    if((req ||
	(req=MUI_AllocAslRequestTags(ASL_FileRequest,
				     ASLFR_TitleText,STR(MSG_OPEN_REQ_TITLE),
				     ASLFR_PositiveText,STR(MSG_OPEN_REQ_POS),
				     ASLFR_NegativeText,STR(MSG_OPEN_REQ_NEG),
				     ASLFR_RejectIcons,TRUE,
				     ASLFR_DoPatterns,TRUE,
				     ASLFR_InitialPattern,"#?.pdf",
				     TAG_END))) &&
	MUI_AslRequestTags(req,
			   scr?ASLFR_Screen:TAG_IGNORE,scr,
			   TAG_END))
	return 1;
    proc->pr_WindowPtr=oldwindowptr;
    return 0;
}

/*
 *  Server communication functions.
 */

Static int init(struct comm_info *ci,int version) {
    struct msg_init *p=ci->cmddata;
    p->version=version;
    p->errors=1;
    return (*ci->sv->exchange_msg)(ci,&p->base,sizeof(*p),MSGID_INIT);
}

Static char *get_version(struct comm_info *ci) {
    struct msg_version *p=ci->cmddata;
    if((*ci->sv->exchange_msg)(ci,&p->base,sizeof(*p),MSGID_VERSION))
	return p->version;
    return "???";
}

Static int get_error(struct comm_info *ci,char *buf,size_t sz) {
    struct msg_error *p=ci->cmddata;
    if((*ci->sv->exchange_msg)(ci,&p->base,sizeof(*p),MSGID_GETERROR)) {
	strncpy(buf,p->msg,sz-1);
	buf[sz-1]='\0';
	return 1;
    } else
	return 0;
}

/*Static int scan_default_fonts(void) {
    struct msg_scan_fonts* p=cmddata;
    PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_DEFAULTFONTS);
    PPCWaitPort(reply_port);
    PPCGetMessage(reply_port);
    return p->base.success;
    return 0;
}*/


/*
 * Document window class
 */

#define DocWindowObject NewObject(docwindow_mcc->mcc_Class,NULL

Static struct NewMenu menudata[]={
    {NM_TITLE,(char*)MSG_PROJECT_MENU         ,0,0,0,NULL},
    {NM_ITEM ,(char*) MSG_ABOUT_MENU          ,0,0,0,(APTR)ID_ABOUT},
    {NM_ITEM ,(char*) MSG_ABOUT_MUI_MENU      ,0,0,0,(APTR)ID_ABOUTMUI},
    {NM_ITEM ,        NM_BARLABEL             ,0,0,0,NULL},
    {NM_ITEM ,(char*) MSG_NEW_DOC_MENU        ,0,0,0,(APTR)ID_NEW},
    {NM_ITEM ,(char*) MSG_NEW_VIEW_MENU       ,0,0,0,(APTR)ID_NEWVIEW},
    {NM_ITEM ,(char*) MSG_OPEN_MENU           ,0,0,0,(APTR)ID_OPEN},
    {NM_ITEM ,(char*) MSG_SAVEAS_MENU         ,0,0,0,(APTR)ID_SAVEAS},
    {NM_ITEM ,(char*) MSG_PRINT_MENU          ,0,0,0,(APTR)ID_PRINT},
    {NM_ITEM ,        NM_BARLABEL             ,0,0,0,NULL},
    {NM_ITEM ,(char*) MSG_HIDE_MENU           ,0,0,0,(APTR)ID_HIDE},
    {NM_ITEM ,(char*) MSG_QUIT_MENU           ,0,0,0,(APTR)MUIV_Application_ReturnID_Quit},
    {NM_TITLE,(char*)MSG_EDIT_MENU            ,0,0,0,NULL},
    {NM_ITEM ,(char*) MSG_COPY_MENU           ,0,0,0,(APTR)ID_COPY},
    {NM_TITLE,(char*)MSG_VIEW_MENU            ,0,0,0,NULL},
    {NM_ITEM ,(char*) MSG_REFRESH_MENU        ,0,0,0,(APTR)ID_REFRESH},
    {NM_ITEM ,(char*) MSG_CROP_MENU           ,0,0,0,(APTR)ID_CROP},
    {NM_ITEM ,(char*) MSG_UNCROP_MENU         ,0,0,0,(APTR)ID_UNCROP},
    {NM_ITEM ,(char*) MSG_ROTATE_LEFT_MENU    ,0,0,0,(APTR)ID_LEFT},
    {NM_ITEM ,(char*) MSG_ROTATE_RIGHT_MENU   ,0,0,0,(APTR)ID_RIGHT},
    {NM_ITEM ,        NM_BARLABEL             ,0,0,0,NULL},
    {NM_ITEM ,(char*) MSG_INFO_MENU           ,0,0,0,(APTR)ID_INFO},
#ifdef HAVE_MUI_LISTTREE_H
    {NM_ITEM ,(char*) MSG_OUTLINES_MENU       ,0,0,0,(APTR)ID_OUTLINES},
#endif
    {NM_ITEM ,(char*) MSG_FONTS_MENU          ,0,0,0,(APTR)ID_FONTS},
    {NM_ITEM ,(char*) MSG_ERRORS_LOG_MENU     ,0,0,0,(APTR)ID_LOG},
    {NM_TITLE,(char*)MSG_SETTINGS_MENU        ,0,0,0,NULL},
    {NM_ITEM ,(char*) MSG_GLOBAL_SETTINGS_MENU,0,0,0,(APTR)ID_PREFS},
    {NM_ITEM ,(char*) MSG_DOC_SETTINGS_MENU   ,0,0,0,(APTR)ID_DOCFONTS},
    {NM_ITEM ,(char*) MSG_MUI_MENU            ,0,0,0,(APTR)ID_MUIPREFS},
    {NM_ITEM ,        NM_BARLABEL             ,0,0,0,NULL},
    {NM_ITEM ,(char*) MSG_TEXT_AA_MENU        ,0,CHECKIT|MENUTOGGLE|CHECKED,0,(APTR)ID_TEXTAA},
    {NM_ITEM ,(char*) MSG_STROKE_AA_MENU      ,0,CHECKIT|MENUTOGGLE,0,(APTR)ID_STROKEAA},
    {NM_ITEM ,(char*) MSG_FILL_AA_MENU        ,0,CHECKIT|MENUTOGGLE,0,(APTR)ID_FILLAA},
    {NM_END  ,NULL                            ,0,0,0,NULL}
};

Static ULONG SAVEDS ASM appwin_func(REG(a2,Object* obj),REG(a1,struct AppMessage** p)) {
    struct AppMessage *msg=*p;
    Object *app;
    get(obj,MUIA_ApplicationObject,&app);
    if(msg->am_Version>=AM_VERSION && msg->am_NumArgs>=1)
	set(obj,MYATTR_DocWindow_Document,getDocument(ci,app,obj,msg->am_ArgList->wa_Lock,msg->am_ArgList->wa_Name));
    return 0;
}
Static struct Hook appwin_hook={{NULL,NULL},appwin_func};

Static ULONG dwNew(struct IClass *cl,Object *obj,struct opSet *msg) {
    DocWindowData* dat;
    struct TagItem tags[8];
    Object *menu,*groupobj;
    Object *doc=(Object*)GetTagData(MYATTR_DocWindow_Document,0,msg->ops_AttrList);
    int num_pages,page;
    const char *pagelabel;
    if(!doc)
	return 0;

    page=GetTagData(MYATTR_DocWindow_Page,-1,msg->ops_AttrList);
    pagelabel=(const char*)GetTagData(MYATTR_DocWindow_PageLabel,0,msg->ops_AttrList);

    tags[0].ti_Tag=MUIA_Window_Title;
    get(doc,MYATTR_Document_Name,&tags[0].ti_Data);
    tags[1].ti_Tag=MUIA_Window_ID;
    tags[1].ti_Data=MAKE_ID('A','P','D','F');
    tags[2].ti_Tag=MUIA_Window_Menustrip;
    tags[2].ti_Data=(ULONG)(menu=MUI_MakeObject(MUIO_MenustripNM,menudata,0));
    tags[3].ti_Tag=MUIA_Window_AppWindow;
    tags[3].ti_Data=TRUE;
    tags[4].ti_Tag=MUIA_Window_RootObject;
    tags[4].ti_Data=(ULONG)(groupobj=DocGroupObject,
	MYATTR_DocGroup_CommInfo,ci,
	MYATTR_DocGroup_Document,doc,
	page==-1?TAG_IGNORE:MYATTR_DocGroup_Page,page,
	pagelabel==NULL?TAG_IGNORE:MYATTR_DocGroup_PageLabel,pagelabel,
	End);
    tags[5].ti_Tag=MUIA_Window_DefaultObject;
    tags[5].ti_Data=tags[4].ti_Data;/*(ULONG)bitmapobj;*/
    tags[6].ti_Tag=MUIA_HelpNode;
    tags[6].ti_Data=(ULONG)"mainwin";
    tags[7].ti_Tag=TAG_MORE;
    tags[7].ti_Data=(ULONG)msg->ops_AttrList;
    msg->ops_AttrList=tags;

    if(obj=(Object *)DoSuperMethodA(cl,obj,(Msg)msg)) {
	int n;
	Object *tmp;
	dat=INST_DATA(cl,obj);
	dat->next=windows;
	windows=dat;
	dat->obj=obj;
	dat->doc=doc;
	dat->groupobj=groupobj;
	dat->menu=menu;

	DoMethod(obj,MUIM_Notify,MUIA_Window_CloseRequest,TRUE,
		 obj,1,MYM_DocWindow_Close);
	DoMethod(obj,MUIM_Notify,MUIA_AppMessage,MUIV_EveryTime,
		 obj,3,MUIM_CallHook,&appwin_hook,MUIV_TriggerValue);
	DoMethod(groupobj,MUIM_Notify,MYATTR_DocGroup_DocChanged,MUIV_EveryTime,
		 obj,3,MUIM_Set,MYATTR_DocWindow_Document,MUIV_TriggerValue);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_ABOUTMUI,
		 App,2,MUIM_Application_AboutMUI,obj);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_MUIPREFS,
		 App,2,MUIM_Application_OpenConfigWindow,0);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_PREFS,
		 prefswin,3,MUIM_Set,MUIA_Window_Open,TRUE);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_HIDE,
		 App,3,MUIM_Set,MUIA_Application_Iconified,TRUE);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_COPY,
		 groupobj,1,MYM_DocBitmap_ToClip);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_OPEN,
		 obj,2,MYM_DocWindow_Open,NULL);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_NEW,
		 obj,2,MYM_DocWindow_OpenNew,NULL);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_NEWVIEW,
		 obj,2,MYM_DocWindow_NewView,0);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_LEFT,
		 groupobj,1,MYM_DocBitmap_RLeft);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_RIGHT,
		 groupobj,1,MYM_DocBitmap_RRight);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_REFRESH,
		 groupobj,1,MYM_DocBitmap_Refresh);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_CROP,
		 groupobj,1,MYM_DocBitmap_Crop);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_UNCROP,
		 groupobj,1,MYM_DocBitmap_UnCrop);
#ifdef HAVE_MUI_LISTTREE_H
	get(doc,MYATTR_Document_HasOutlines,&n);
	DoMethod(dat->menu,MUIM_SetUData,ID_OUTLINES,MUIA_Menuitem_Enabled,n!=0);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_OUTLINES,
		 groupobj,1,MYM_DocGroup_OpenOutlines);
#endif
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_LOG,
		 logwin,3,MUIM_Set,MUIA_Window_Open,TRUE);
	tmp=(Object*)DoMethod(menu,MUIM_FindUData,ID_TEXTAA);
	DoMethod(tmp,MUIM_Notify,MUIA_Menuitem_Checked,MUIV_EveryTime,
		 groupobj,3,MUIM_Set,MYATTR_DocGroup_TextAA,MUIV_TriggerValue);
	get(doc,MYATTR_Document_OpenTextAA,&n);
	set(tmp,MUIA_Menuitem_Checked,GetTagData(MYATTR_DocWindow_TextAA,n,msg->ops_AttrList));
	tmp=(Object*)DoMethod(menu,MUIM_FindUData,ID_STROKEAA);
	DoMethod(tmp,MUIM_Notify,MUIA_Menuitem_Checked,MUIV_EveryTime,
		 groupobj,3,MUIM_Set,MYATTR_DocGroup_StrokeAA,MUIV_TriggerValue);
	get(doc,MYATTR_Document_OpenStrokeAA,&n);
	set(tmp,MUIA_Menuitem_Checked,GetTagData(MYATTR_DocWindow_StrokeAA,n,msg->ops_AttrList));
	tmp=(Object*)DoMethod(menu,MUIM_FindUData,ID_FILLAA);
	DoMethod(tmp,MUIM_Notify,MUIA_Menuitem_Checked,MUIV_EveryTime,
		 groupobj,3,MUIM_Set,MYATTR_DocGroup_FillAA,MUIV_TriggerValue);
	get(doc,MYATTR_Document_OpenFillAA,&n);
	set(tmp,MUIA_Menuitem_Checked,GetTagData(MYATTR_DocWindow_FillAA,n,msg->ops_AttrList));
	DoMethod(groupobj,MUIM_Notify,MYATTR_DocGroup_Run,MUIV_EveryTime,
		 obj,2,MYM_DocWindow_Run,MUIV_TriggerValue);
	DoMethod(groupobj,MUIM_Notify,MYATTR_DocGroup_URL,MUIV_EveryTime,
		 obj,2,MYM_DocWindow_URL,MUIV_TriggerValue);
	DoMethod(groupobj,MUIM_Notify,MYATTR_DocGroup_Open,MUIV_EveryTime,
		 obj,2,MYM_DocWindow_Open,MUIV_TriggerValue);
	DoMethod(groupobj,MUIM_Notify,MYATTR_DocGroup_OpenNew,MUIV_EveryTime,
		 obj,2,MYM_DocWindow_OpenNew,MUIV_TriggerValue);
	DoMethod(groupobj,MUIM_Notify,MYATTR_DocGroup_PageNew,MUIV_EveryTime,
		 obj,2,MYM_DocWindow_NewView,MUIV_TriggerValue);
	/* Don't trigger methods of the Document class directly,
	   because dat->doc can change. */
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_PRINT,
		 obj,1,MYM_DocWindow_OpenPrintWindow);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_SAVEAS,
		 obj,1,MYM_DocWindow_OpenSaveWindow);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_INFO,
		 obj,1,MYM_DocWindow_OpenInfoWindow);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_DOCFONTS,
		 obj,1,MYM_DocWindow_OpenFontMapWindow);
	DoMethod(obj,MUIM_Notify,MUIA_Window_MenuAction,ID_FONTS,
		 obj,1,MYM_DocWindow_OpenScanWindow);
	DoMethod(obj,MUIM_Notify,MUIA_Window_Activate,FALSE,
		 groupobj,1,MYM_DocBitmap_DestroyLens);
	++win_count;

	n=GetTagData(MYATTR_DocWindow_Zoom,minZoom-1,msg->ops_AttrList);
	if(n!=minZoom-1)
	    set(groupobj,MYATTR_DocGroup_Zoom,n);
	n=GetTagData(MYATTR_DocWindow_Rotate,-1,msg->ops_AttrList);
	if(n!=-1)
	    set(groupobj,MYATTR_DocGroup_Rotate,n);
	n=GetTagData(MYATTR_DocWindow_CropBox,0,msg->ops_AttrList);
	if(n!=0)
	    set(groupobj,MYATTR_DocGroup_CropBox,n);
    }
    msg->ops_AttrList=(struct TagItem*)tags[7].ti_Data;
    return (ULONG)obj;
}



Static ULONG dwDispose(struct IClass *cl,Object *obj,Msg msg) {
    DocWindowData *dat=INST_DATA(cl,obj);
    DocWindowData **p=&windows;
    while(*p!=dat)
	p=&(*p)->next;
    *p=dat->next;
    --win_count;
    return DoSuperMethodA(cl,obj,msg);
}

Static ULONG dwGet(struct IClass *cl,Object *obj,struct opGet *msg) {
    switch(msg->opg_AttrID) {
      case MYATTR_DocWindow_Document: {
	DocWindowData* dat=INST_DATA(cl,obj);
	*msg->opg_Storage=(ULONG)dat->doc;
	return TRUE;
      }
    }
    return DoSuperMethodA(cl,obj,(Msg)msg);
}

Static ULONG dwSet(struct IClass *cl,Object *obj,struct opSet *msg) {
    DocWindowData *dat=INST_DATA(cl,obj);
    struct TagItem *tags=msg->ops_AttrList;
    struct TagItem *tag;
    while(tag=NextTagItem(&tags)) {
	switch(tag->ti_Tag) {
	  case  MYATTR_DocWindow_Document: {
	    Object *doc=(Object*)tag->ti_Data;
	    const char *name;
	    if(doc && doc!=dat->doc) {
	       int f;
		dat->doc=doc;
		set(dat->groupobj,MYATTR_DocGroup_Document,doc);
#ifdef HAVE_MUI_LISTTREE_H
	       get(doc,MYATTR_Document_HasOutlines,&f);
	       DoMethod(dat->menu,MUIM_SetUData,ID_OUTLINES,MUIA_Menuitem_Enabled,f!=0);
#endif
	    }
	    get(dat->doc,MYATTR_Document_Name,&name);
	    set(obj,MUIA_Window_Title,name);
	    break ;
	  }
	  case MYATTR_DocWindow_Page:
	    set(dat->groupobj,MYATTR_DocGroup_Page,tag->ti_Data);
	    break;
	  case MYATTR_DocWindow_PageLabel:
	    set(dat->groupobj,MYATTR_DocGroup_PageLabel,tag->ti_Data);
	    break;
	  case MYATTR_DocWindow_Zoom:
	    set(dat->groupobj,MYATTR_DocGroup_Zoom,tag->ti_Data);
	    break;
	  case MYATTR_DocWindow_Rotate:
	    set(dat->groupobj,MYATTR_DocGroup_Rotate,tag->ti_Data);
	    break;
	}
    }
    return DoSuperMethodA(cl,obj,(Msg)msg);
}

struct MYP_DocWindow_Open {
    ULONG MethodID;
    const char *FileName;
};

Static ULONG dwOpen(struct IClass *cl,Object *obj,struct MYP_DocWindow_Open *msg) {
    DocWindowData *dat=INST_DATA(cl,obj);
    BPTR dir,olddir,lock=0;
    Object *app,*doc=NULL;
    const char *name=NULL;
    get(dat->doc,MYATTR_Document_Dir,&dir);
    olddir=CurrentDir(dir);
    get(obj,MUIA_ApplicationObject,&app);
    if(msg->FileName) {
	lock=DupLock(dir);
	name=msg->FileName;
	while(name[0]=='.' && name[1]=='.' && name[2]=='/') {
	    BPTR dir2=ParentDir(dir);
	    UnLock(dir);
	    dir=dir2;
	    name+=3;
	}
    } else if(open_req(obj)) {
	lock=Lock(req->fr_Drawer,ACCESS_READ);
	name=req->fr_File;
    }
    if(name)
	doc=getDocument(ci,app,obj,lock,name);
    UnLock(lock);
    if(doc)
	set(dat->groupobj,MYATTR_DocGroup_Document,doc);
    CurrentDir(olddir);
    return 0;
}

Static ULONG dwOpenNew(struct IClass *cl,Object *obj,struct MYP_DocWindow_Open *msg) {
    DocWindowData *dat=INST_DATA(cl,obj);
    BPTR dir,olddir,lock=0;
    Object *app;
    Object *doc=NULL;
    Object *w;
    const char *name=NULL;
    get(dat->doc,MYATTR_Document_Dir,&dir);
    olddir=CurrentDir(dir);
    get(obj,MUIA_ApplicationObject,&app);
    if(msg->FileName) {
	lock=DupLock(dir);
	name=msg->FileName;
	while(name[0]=='.' && name[1]=='.' && name[2]=='/') {
	    BPTR dir2=ParentDir(dir);
	    UnLock(dir);
	    dir=dir2;
	    name+=3;
	}
    } else if(open_req(obj)) {
	lock=Lock(req->fr_Drawer,ACCESS_READ);
	name=req->fr_File;
    }
    if(name)
	doc=getDocument(ci,app,NULL,lock,name);
    UnLock(lock);
    w=DocWindowObject,
	MYATTR_DocWindow_Document,doc,
	End;
    if(w) {
	DoMethod(app,OM_ADDMEMBER,w);
	set(w,MUIA_Window_Open,TRUE);
    }
    CurrentDir(olddir);
    return 0;
}

struct MYP_DocWindow_NewView {
    ULONG MethodID;
    int page;
};

Static ULONG dwNewView(struct IClass *cl,Object *obj,struct MYP_DocWindow_NewView *msg) {
    DocWindowData *dat=INST_DATA(cl,obj);
    Object *w;
    int page,zoom,rotate;
    struct MYS_DocBitmap_CropBox box;
    int textaa,fillaa,strokeaa;
    if(msg->page>=1)
	page=msg->page;
    else
	get(dat->groupobj,MYATTR_DocGroup_Page,&page);
    get(dat->groupobj,MYATTR_DocGroup_Zoom,&zoom);
    get(dat->groupobj,MYATTR_DocGroup_Rotate,&rotate);
    get(dat->groupobj,MYATTR_DocGroup_CropBox,&box);
    get(dat->groupobj,MYATTR_DocGroup_TextAA,&textaa);
    get(dat->groupobj,MYATTR_DocGroup_StrokeAA,&strokeaa);
    get(dat->groupobj,MYATTR_DocGroup_FillAA,&fillaa);
    w=DocWindowObject,
	MYATTR_DocWindow_Document,dat->doc,
	MYATTR_DocWindow_Page,page,
	MYATTR_DocWindow_Zoom,zoom,
	MYATTR_DocWindow_Rotate,rotate,
	MYATTR_DocWindow_CropBox,&box,
	MYATTR_DocWindow_TextAA,textaa,
	MYATTR_DocWindow_StrokeAA,strokeaa,
	MYATTR_DocWindow_FillAA,fillaa,
	End;
    if(w) {
	DoMethod(App,OM_ADDMEMBER,w);
	set(w,MUIA_Window_Open,TRUE);
    }
    return 0;
}

Static ULONG dwClose(struct IClass *cl,Object *obj) {
    toDelete=obj;
    DoMethod(App,MUIM_Application_ReturnID,ID_DELETE);
    return 0;
}

ULONG dwOpenPrintWindow(struct IClass *cl,Object *obj) {
    DocWindowData *dat=INST_DATA(cl,obj);
    return DoMethod(dat->doc,MYM_Document_OpenPrintWindow);
}

ULONG dwOpenSaveWindow(struct IClass *cl,Object *obj) {
    DocWindowData *dat=INST_DATA(cl,obj);
    return DoMethod(dat->doc,MYM_Document_OpenSaveWindow);
}

ULONG dwOpenInfoWindow(struct IClass *cl,Object *obj) {
    DocWindowData *dat=INST_DATA(cl,obj);
    return DoMethod(dat->doc,MYM_Document_OpenInfoWindow);
}

ULONG dwOpenFontMapWindow(struct IClass *cl,Object *obj) {
    DocWindowData *dat=INST_DATA(cl,obj);
    return DoMethod(dat->doc,MYM_Document_OpenPrefsWindow);
}

ULONG dwOpenScanWindow(struct IClass *cl,Object *obj) {
    DocWindowData *dat=INST_DATA(cl,obj);
    return DoMethod(dat->doc,MYM_Document_OpenScanWindow);
}

ULONG dwURL(struct IClass *cl,Object *obj,struct MYP_DocWindow_Open *msg) {
    ULONG d=DoMethod(config,MUIM_Dataspace_Find,MYCFG_Apdf_URLCmd);
    char buf2[256];
    buf2[0]='r';
    buf2[1]='u';
    buf2[2]='n';
    buf2[3]=' ';
    sprintf(buf2+4,d?(const char *)d:"OpenURL %s",msg->FileName);
    SystemTagList(buf2,NULL);
    return 0;
}

ULONG dwRun(struct IClass *cl,Object *obj,struct MYP_DocWindow_Open *msg) {
    Object *app;
    get(obj,MUIA_ApplicationObject,&app);
    if(MUI_Request(app,NULL,0,(char*)STR(MSG_EXECUTE_REQ),
		   (char*)STR(MSG_EXECUTE_REQ_ANSWERS),
		   (char*)msg->FileName))
	SystemTagList((char*)msg->FileName,NULL);
    return 0;
}


SAVEDS ASM ULONG dwDispatcher(REG(a0,struct IClass *cl),REG(a2,Object *obj),REG(a1,Msg msg)) {
    switch(msg->MethodID) {
      case OM_NEW:               return dwNew    (cl,obj,(APTR)msg);
      case OM_DISPOSE:           return dwDispose(cl,obj,msg);
      case OM_GET:               return dwGet    (cl,obj,(APTR)msg);
      case OM_SET:               return dwSet    (cl,obj,(APTR)msg);
      case MYM_DocWindow_Open:   return dwOpen   (cl,obj,(APTR)msg);
      case MYM_DocWindow_OpenNew:return dwOpenNew(cl,obj,(APTR)msg);
      case MYM_DocWindow_Close:  return dwClose  (cl,obj);
      case MYM_DocWindow_NewView:return dwNewView(cl,obj,(APTR)msg);
      case MYM_DocWindow_OpenPrintWindow: return dwOpenPrintWindow(cl,obj);
      case MYM_DocWindow_OpenSaveWindow:  return dwOpenSaveWindow(cl,obj);
      case MYM_DocWindow_OpenInfoWindow:  return dwOpenInfoWindow(cl,obj);
      case MYM_DocWindow_OpenFontMapWindow:  return dwOpenFontMapWindow(cl,obj);
      case MYM_DocWindow_OpenScanWindow:  return dwOpenScanWindow(cl,obj);
      case MYM_DocWindow_URL:    return dwURL    (cl,obj,(APTR)msg);
      case MYM_DocWindow_Run:    return dwRun    (cl,obj,(APTR)msg);
    }
    return DoSuperMethodA(cl,obj,msg);
}


void cleanup(void) {

    proc->pr_WindowPtr=oldwindowptr;

    if(MUIMasterBase) {
	MUI_FreeAslRequest(req);
       /* shouldn't be necessary, but without that,
	* there seems to be crashes when Apdf is quitted
	* while iconified. No idea why.
	*/
       while(windows) {
	   set(windows->obj,MUIA_Window_Open,FALSE);
	   DoMethod(App,OM_REMMEMBER,windows->obj);
	   MUI_DisposeObject(windows->obj);
       }
	if(App)
	    MUI_DisposeObject(App);
	if(docwindow_mcc)
	    MUI_DeleteCustomClass(docwindow_mcc);
	deleteDocBitmapClass();
	deleteDocGroupClass();
	deleteDocLensClass();
	deleteDocumentClass();
	deletePrefsClass();
	MUI_DisposeObject(config);
	CloseLibrary(MUIMasterBase);
    }

    if(ci)
	(*sv.delete_comm_info)(ci);
    if(sv_init)
	(*sv.destroy)(&sv);

    if(seglist)
	UnLoadSeg(seglist);
#ifdef HAVE_POWERUP
    if(elfobject)
	PPCUnLoadObject(elfobject);
    CloseLibrary(PPCLibBase);
#endif
    UnLock(modules_dir);

    if(diskobj)
	FreeDiskObject(diskobj);

    if(catalog) /* LocaleBase might be NULL */
	CloseCatalog(catalog);

#if defined(HAVE_CYBERGRAPHICS_CYBERGRAPHICS_H) || \
    defined(HAVE_CYBERGRAPHX_CYBERGRAPHICS_H)
    CloseLibrary(CyberGfxBase);
#endif
    CloseLibrary(KeymapBase);
    CloseLibrary(IFFParseBase);
    CloseLibrary(IconBase);
    CloseLibrary((struct Library*)LocaleBase);
    CloseLibrary((struct Library*)UtilityBase);
    CloseLibrary((struct Library*)GfxBase);
    CloseLibrary((struct Library*)IntuitionBase);

    FreeArgs(rda);
    CurrentDir(olddir);

    if(input) {
	SelectInput(oldinput);
	Close(input);
    }
}

Static ULONG SAVEDS rxopen(REG(a2,Object *app),REG(a1,ULONG *args)) {
    Object *doc=getDocument(ci,app,NULL,progdir,(const char *)args[0]);
    Object *w=DocWindowObject,
	MYATTR_DocWindow_Document,doc,
	MYATTR_DocWindow_PageLabel,args[1],
	args[2]?MYATTR_DocWindow_Zoom:TAG_IGNORE,args[2]?*(LONG*)args[2]+5:0,
	args[3]?MYATTR_DocWindow_Rotate:TAG_IGNORE,args[3]?90*((*(LONG*)args[3]/90)&3):0,
	End;
    if(w) {
	DoMethod(app,OM_ADDMEMBER,w);
	set(w,MUIA_Window_Open,TRUE);
	return 0;
    } else
	return 10;
}

static struct Hook rxopen_hook={{NULL,NULL},rxopen};

static struct MUI_Command rexxcmds[]={
    {"OPEN","FILE/A,P=PAGE/K,Z=ZOOM/N/K,R=ROTATE/N/K",4,&rxopen_hook},
    {NULL,NULL,0,NULL}
};

int main() {

    Object *saveprefsobj,*useprefsobj,*cancelprefsobj;
    Object *clearlogobj,*autoopenobj,*win;
    char* docname=NULL;
    BPTR docdir=0;
    BOOL running,ppcmodule;
    char *modules[16];
    char **pmodule;
    ULONG sigs;

    proc=(struct Process*)FindTask(NULL);

    if(LocaleBase=(struct LocaleBase*)OpenLibrary("locale.library",0))
	catalog=OpenCatalogA(NULL,"Apdf.catalog",NULL);

    /* This test is probably useless. If run on 68000 or */
    /* 68010, we have probably already crashed at this point. */
    if(!(SysBase->AttnFlags&AFF_68020)) {
	printf(STR(MSG_REQUIRES_68020_ERR));
	exit(EXIT_FAILURE);
    }


    olddir=CurrentDir(0);
    CurrentDir(olddir);
    oldwindowptr=proc->pr_WindowPtr;

    atexit(&cleanup);

    IntuitionBase=(struct IntuitionBase*)OpenLibrary("intuition.library",39);
    GfxBase=(struct GfxBase*)OpenLibrary("graphics.library",39);
    UtilityBase=(struct UtilityBase*)OpenLibrary("utility.library",39);
    IconBase=OpenLibrary("icon.library",39);
    IFFParseBase=OpenLibrary("iffparse.library",39);
    KeymapBase=OpenLibrary("keymap.library",0);
    if(!IntuitionBase || !GfxBase || !UtilityBase ||
       !IconBase || !IFFParseBase || !KeymapBase) {
	printf(STR(MSG_REQUIRES_3_0_ERR));
	exit(EXIT_FAILURE);
    }
    MUIMasterBase=OpenLibrary(MUIMASTER_NAME,MUIMASTER_VMIN);
    if(!MUIMasterBase) {
	printf(STR(MSG_NO_MUIMASTER_ERR));
	exit(EXIT_FAILURE);
    }

    docwindow_mcc=MUI_CreateCustomClass(NULL,MUIC_Window,NULL,sizeof(DocWindowData),dwDispatcher);
    if(!createDocBitmapClass() || !createDocGroupClass() ||
       !createDocumentClass() || !createDocLensClass() ||
       !createPrefsClass() || !docwindow_mcc) {
	printf(STR(MSG_CANT_CREATE_CC_ERR));
	exit(EXIT_FAILURE);
    }


    if(!(config=MUI_NewObjectA(MUIC_Dataspace,NULL))) {
	printf(STR(MSG_CANT_CREATE_CONFIG_OBJ_ERR));
	exit(EXIT_FAILURE);
    } else {
	Object *pend=MUI_NewObjectA(MUIC_Pendisplay,NULL);
	if(pend) {
	    struct MUI_PenSpec *spec;
	    DoMethod(pend,MUIM_Pendisplay_SetRGB,0xffffffff,0,0);
	    get(pend,MUIA_Pendisplay_Spec,&spec);
	    MUI_DisposeObject(pend);
	    if(!DoMethod(config,MUIM_Dataspace_Add,spec,sizeof(*spec),MYCFG_Apdf_SelectColor)) {
		printf(STR(MSG_CANT_CREATE_CONFIG_OBJ_ERR));
		exit(EXIT_FAILURE);
	    }
	}
    }

    if(proc->pr_CLI) {
	size_t l=16;
	while(1) {
	    progname=MyAllocMem(l);
	    if(!progname)
		break;
	    if(GetProgramName(progname,l))
		break;
	    MyFreeMem(progname);
	    l+=16;
	}
	if(!(rda=ReadArgs(TEMPLATE,args,NULL))) {
	    PrintFault(IoErr(),(char*)STR(MSG_ERROR_HEADER_ERR));
	    exit(EXIT_FAILURE);
	}
	if(PDFFILE) {
	    docdir=DupLock(olddir);
	    CopyStr(&docname,PDFFILE);
	}
    } else {
#if defined(__SASC) || defined(__libnix__)
	size_t l;
	if(_WBenchMsg && _WBenchMsg->sm_NumArgs>=1) {
	    CopyStr(&progname,_WBenchMsg->sm_ArgList[0].wa_Name);
	    if(_WBenchMsg->sm_NumArgs>=2) {
		docdir=DupLock(_WBenchMsg->sm_ArgList[1].wa_Lock);
		CopyStr(&docname,_WBenchMsg->sm_ArgList[1].wa_Name);
	    }
	} else {
	    /* should not happen ? */
	    printf("I don't understand the startup method !?\n");
	    exit(EXIT_FAILURE);
	}
#else
	/* adapt for other compilers/libraries */
	exit(EXIT_FAILURE);
#endif
    }

    progdir=GetProgramDir();

    /* gzip sometimes tries to open "*" for input, */
    /* which opens and locks the stdiowin. */
    /* Let's prevent that: */
    if(input=Open("NIL:",MODE_OLDFILE))
	oldinput=SelectInput(input);

    if(!docname && open_req(NULL)) {
	UnLock(docdir); /* there is a slight chance that docdir is locked... */
	docdir=Lock(req->fr_Drawer,ACCESS_READ);
	CopyStr(&docname,req->fr_File);
    }
    if(!progname || !docname) {
	UnLock(docdir);
	exit(EXIT_FAILURE);
    }

    parse_tooltypes(progdir,progname);
    parse_tooltypes(docdir,docname);

    load_prefs(config,CONFIG);

    ppcmodule=FALSE;
    if(!MODULE) {
	ULONG d=DoMethod(config,MUIM_Dataspace_Find,MYCFG_Apdf_Module);
	if(d)
	    CopyStr(&module_arg,(const char *)d);
    }
#ifdef HAVE_POWERUP
    if(MODULE && !NOPUP) {
	BPTR file=Open(MODULE,MODE_OLDFILE);
	if(file) {
	    char buf[4];
	    Read(file,buf,4);
	    if(buf[0]=='\133' && buf[1]=='E' && buf[2]=='L' && buf[3]=='F')
		ppcmodule=TRUE;
	    Close(file);
	}
    }
    if((!MODULE && !NOPUP) || ppcmodule)
	PPCLibBase=OpenLibrary("ppc.library",46);
#endif

    pmodule=modules;
    if(MODULE)
	*pmodule++=MODULE;
    else {

#ifdef HAVE_POWERUP
	if(PPCLibBase) {
	    ULONG cpu;
	    PPCGetAttrsTags(PPCINFOTAG_CPU,(ULONG)&cpu,TAG_END);
	    if(cpu==CPU_603e) {
		*pmodule++="Apdf_603e.module";
		*pmodule++="Apdf_604e.module";
	    } else {
		*pmodule++="Apdf_604e.module";
		*pmodule++="Apdf_603e.module";
	    }
	}
#endif

	if(SysBase->AttnFlags&AFF_68881) {
	    if(SysBase->AttnFlags&AFF_68060) {
		*pmodule++="Apdf_68060fpu.module";
		*pmodule++="Apdf_68040fpu.module";
	    } else if(SysBase->AttnFlags&AFF_68040) {
		*pmodule++="Apdf_68040fpu.module";
		*pmodule++="Apdf_68060fpu.module";
	    }
	    if(SysBase->AttnFlags&AFF_68030) {
		*pmodule++="Apdf_68030fpu.module";
		*pmodule++="Apdf_68020fpu.module";
	    } else if(SysBase->AttnFlags&AFF_68020) {
		*pmodule++="Apdf_68020fpu.module";
		*pmodule++="Apdf_68030fpu.module";
	    }
	}
	if(SysBase->AttnFlags&AFF_68060) {
	    *pmodule++="Apdf_68060.module";
	    *pmodule++="Apdf_68040.module";
	} else if(SysBase->AttnFlags&AFF_68040) {
	    *pmodule++="Apdf_68040.module";
	    *pmodule++="Apdf_68060.module";
	}
	if(SysBase->AttnFlags&AFF_68030) {
	    *pmodule++="Apdf_68030.module";
	    *pmodule++="Apdf_68020.module";
	} else if(SysBase->AttnFlags&AFF_68020) {
	    *pmodule++="Apdf_68020.module";
	    *pmodule++="Apdf_68030.module";
	}
    }
    *pmodule=NULL;


    {
	ULONG d=DoMethod(config,MUIM_Dataspace_Find,MYCFG_Apdf_ModulesDir);
	BPTR olddir;
	if(d)
	    modules_dir=Lock((char*)d,ACCESS_READ);
	else
	    modules_dir=DupLock(progdir);
	olddir=CurrentDir(modules_dir);
	for(pmodule=modules;*pmodule!=NULL;++pmodule) {
	    if(
#ifdef HAVE_POWERUP
	       (PPCLibBase && (elfobject=PPCLoadObject(*pmodule))) ||
#endif
	       (seglist=LoadSeg(*pmodule)))
		break;
	}
    }
    if(*pmodule==NULL) {
	printf(STR(MSG_CANT_FIND_MODULE_ERR));
	for(pmodule=modules;*pmodule!=NULL;++pmodule)
	    printf("\t%s\n",*pmodule);
	exit(EXIT_FAILURE);
    }

    if(
#ifdef HAVE_POWERUP
       (elfobject && !(sv_init=create_ppc_server(&sv,elfobject))) ||
#endif
       (seglist && !(sv_init=create_m68k_server(&sv,seglist))) ||
       !(ci=(*sv.create_comm_info)(&sv,sizeof(union msg_max)))) {
	printf(STR(MSG_CANT_CREATE_SERVER_ERR));
	exit(EXIT_FAILURE);
    }

    if(!init(ci,VMAGIC)) {
	printf(STR(MSG_SERVER_INIT_ERR));
	exit(EXIT_FAILURE);
    }

    {
	BPTR olddir=CurrentDir(progdir);
	ULONG d=DoMethod(config,MUIM_Dataspace_Find,MYCFG_Apdf_DiskObj);
	if(d)
	    diskobj=GetDiskObject((char*)d);
	else
	    diskobj=GetDiskObject(progname);
	CurrentDir(olddir);
    }

#if defined(HAVE_CYBERGRAPHICS_CYBERGRAPHICS_H) || \
    defined(HAVE_CYBERGRAPHX_CYBERGRAPHICS_H)
    CyberGfxBase=OpenLibrary("cybergraphics.library",41); /* may fail */
#endif

    use_prefs(ci,config);

    {
	struct NewMenu *p=menudata;
	while(p->nm_Type!=NM_END) {
	    if(p->nm_Label!=NM_BARLABEL) {
		const char *s=getString((int)p->nm_Label);
		if(s[1]=='\0') {
		    p->nm_CommKey=(STRPTR)s;
		    s+=2;
		}
		p->nm_Label=(STRPTR)s;
	    }
	    ++p;
	}
    }

    App=ApplicationObject,
	MUIA_Application_Title,         "Apdf",
	MUIA_Application_Version,       "$VER: " apdfVerString,
	MUIA_Application_Copyright,     "(c) 1996-1999 Derek B. Noonburg",
	MUIA_Application_Author,        "Derek B. Noonburg, Emmanuel Lesueur",
	MUIA_Application_Description,   STR(MSG_COMMODITY_DESCRIPTION),
	MUIA_Application_Base,          "Apdf",
	MUIA_Application_DiskObject,    diskobj,
	MUIA_Application_HelpFile,      "PROGDIR:Apdf.guide",
	MUIA_Application_Commands,      rexxcmds,

	SubWindow,prefswin=WindowObject,
	    MUIA_Window_Title,STR(MSG_GLOBAL_SETTINGS_WIN),
	    MUIA_Window_ID,MAKE_ID('P','R','F','S'),
	    MUIA_HelpNode,"glbsettings",
	    MUIA_Window_RootObject,VGroup,
		Child,prefsobj=PrefsObject,
		    End,
		Child,HGroup,
		    Child,saveprefsobj=SimpleButton(STR(MSG_SETTINGS_SAVE_GAD)),
		    Child,useprefsobj=SimpleButton(STR(MSG_SETTINGS_USE_GAD)),
		    Child,cancelprefsobj=SimpleButton(STR(MSG_SETTINGS_CANCEL_GAD)),
		    End,
		End,
	    End,

	SubWindow,logwin=WindowObject,
	    MUIA_Window_Title,STR(MSG_LOG_WIN),
	    MUIA_Window_ID,MAKE_ID('L','O','G','\0'),
	    MUIA_Window_RootObject,VGroup,
		Child,ListviewObject,
		    MUIA_Listview_Input,FALSE,
		    MUIA_Listview_List,logobj=ListObject,
			ReadListFrame,
			MUIA_List_ConstructHook,MUIV_List_ConstructHook_String,
			MUIA_List_DestructHook,MUIV_List_DestructHook_String,
			End,
		    End,
		Child,HGroup,
		    Child,autoopenobj=ImageObject,
			ImageButtonFrame,
			MUIA_InputMode,MUIV_InputMode_Toggle,
			MUIA_Image_Spec,MUII_CheckMark,
			MUIA_Image_FreeVert,TRUE,
			MUIA_Background,MUII_ButtonBack,
			MUIA_ShowSelState,FALSE,
			MUIA_ControlChar,'a',
			//MUIA_ShortHelp,"Open this window everytime\n"
			//               "a message is added ?",
			End,
		    Child,KeyLLabel1(KSTR(MSG_LOG_AUTO_OPEN_GAD),KEY(MSG_LOG_AUTO_OPEN_GAD)),
		    Child,RectangleObject,
			MUIA_Weight,300,
			End,
		    Child,clearlogobj=SimpleButton(STR(MSG_LOG_CLEAR_GAD)),
		    End,
		End,
	    End,
	End;

    if(App) {
	/* create the main window after, because the Document constructor
	   needs the 'App' object to add the fontmap subwindow */
	win=DocWindowObject,
	    MYATTR_DocWindow_Document,getDocument(ci,App,NULL,docdir,docname),
	    MYATTR_DocWindow_PageLabel,PAGE,
	    ZOOM==-1?TAG_IGNORE:MYATTR_DocWindow_Zoom,ZOOM+5,
	    End;
	if(win)
	    DoMethod(App,OM_ADDMEMBER,win);
    }

    UnLock(docdir);

    if(!App || !win) {
	if(!App)
	    printf(STR(MSG_CANT_CREATE_MUI_APP_ERR));
	else {
	    char msg[256];
	    while(get_error(ci,msg,sizeof(msg)))
		printf("%s\n",msg);
	    printf(STR(MSG_CANT_LOAD_DOC_ERR));
	}
	exit(EXIT_FAILURE);
    }

    DoMethod(prefswin,MUIM_Notify,MUIA_Window_CloseRequest,TRUE,
	     prefswin,3,MUIM_Set,MUIA_Window_Open,FALSE);
    DoMethod(saveprefsobj,MUIM_Notify,MUIA_Pressed,FALSE,
	     App,2,MUIM_Application_ReturnID,ID_SAVEPREFS);
    DoMethod(useprefsobj,MUIM_Notify,MUIA_Selected,FALSE,
	     App,2,MUIM_Application_ReturnID,ID_USEPREFS);
    DoMethod(cancelprefsobj,MUIM_Notify,MUIA_Pressed,FALSE,
	     App,2,MUIM_Application_ReturnID,ID_CANCELPREFS);
    DoMethod(logwin,MUIM_Notify,MUIA_Window_CloseRequest,TRUE,
	     logwin,3,MUIM_Set,MUIA_Window_Open,FALSE);
    DoMethod(logobj,MUIM_Notify,MUIA_List_Entries,41,
	     logobj,2,MUIM_List_Remove,MUIV_List_Remove_First);
    DoMethod(clearlogobj,MUIM_Notify,MUIA_Pressed,FALSE,
	     logobj,1,MUIM_List_Clear);
    DoMethod(autoopenobj,MUIM_Notify,MUIA_Selected,MUIV_EveryTime,
	     logobj,3,MUIM_WriteLong,MUIV_NotTriggerValue,&err_quiet);
    set(App,MUIA_Application_DropObject,win);

    DoMethod(prefsobj,MUIM_Settingsgroup_ConfigToGadgets,config);
    {
	ULONG d=DoMethod(config,MUIM_Dataspace_Find,MYCFG_Apdf_AutoOpenLog);
	err_quiet=d?!*(int*)d:0;
	set(autoopenobj,MUIA_Selected,!err_quiet);
    }

    set(win,MUIA_Window_Open,TRUE);
    {
	LONG x;
	get(win,MUIA_Window_Open,&x);
	if(!x)
	    exit(EXIT_FAILURE);
    }

    sigs=0;
    running=TRUE;
    do {
	void* msg;
	do {
	    LONG id=DoMethod(App,MUIM_Application_NewInput,&sigs);
	    switch(id) {
	      case MUIV_Application_ReturnID_Quit:
		running=FALSE;
		break;

	      case ID_ABOUT:
		MUI_Request(App,NULL/*win*/,0,"Apdf "apdfVersion,(char*)STR(MSG_REQ_OK),
			    MUIX_C
			    "Apdf "apdfVersion"\n"
			    "%s \"%s\"\n\n"
			    "%s",STR(MSG_USED_MODULE),*pmodule,get_version(ci));
		break;

	      case ID_DELETE:
		if(toDelete) {
		    DoMethod(App,OM_REMMEMBER,toDelete);
		    MUI_DisposeObject(toDelete);
		    toDelete=NULL;
		    if(win_count==0)
			running=FALSE;
		}
		break;

	      case ID_SAVEPREFS:
	      case ID_USEPREFS:
		DoMethod(prefsobj,MUIM_Settingsgroup_GadgetsToConfig,config);
		if(id==ID_SAVEPREFS)
		    save_prefs(config,CONFIG);
		set(App,MUIA_Application_Iconified,TRUE);
		set(prefswin,MUIA_Window_Open,FALSE);
		use_prefs(ci,config);
		set(App,MUIA_Application_Iconified,FALSE);
		break;

	      case ID_CANCELPREFS:
		set(prefswin,MUIA_Window_Open,FALSE);
		DoMethod(prefsobj,MUIM_Settingsgroup_ConfigToGadgets,config);
		break;

	      /*case ID_LASTSAVEDPREFS:
		load_prefs(config,CONFIG);
		DoMethod(prefsobj,MUIM_Settingsgroup_ConfigToGadgets,config);
		use_prefs(ci,config);
		break;*/
	    }
	} while(running && sigs==0);

	if(running) {
	    char msg[256];
	    BOOL err=FALSE;
	    while(get_error(ci,msg,sizeof(msg))) {
		DoMethod(logobj,MUIM_List_InsertSingle,msg,MUIV_List_Insert_Bottom);
		err=TRUE;
	    }
	    if(err && !err_quiet)
		set(logwin,MUIA_Window_Open,TRUE);
	    sigs=Wait(sigs|SIGBREAKF_CTRL_C);
	}
	if(sigs&SIGBREAKF_CTRL_C)
	    running=FALSE;

    } while(running);

    return EXIT_SUCCESS;
}


