home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 110 / EnigmaAmiga110CD.iso / indispensabili / utility / apdf / xpdf-0.80 / xpdf / apdf.c < prev    next >
C/C++ Source or Header  |  1999-07-12  |  106KB  |  4,068 lines

  1. //========================================================================
  2. //
  3. // Apdf.c
  4. //
  5. // Copyright 1999 Emmanuel Lesueur
  6. //
  7. //========================================================================
  8.  
  9. //#define DEBUGMSG
  10. #include <stdlib.h>
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <libraries/asl.h>
  14. #include <libraries/mui.h>
  15. #include <libraries/gadtools.h>
  16. #include <libraries/iffparse.h>
  17. #include <dos/dostags.h>
  18. #include <exec/nodes.h>
  19. #include <exec/memory.h>
  20. #include <exec/execbase.h>
  21. #include <graphics/layers.h>
  22. #include <hardware/blit.h>
  23. #include <cybergraphics/cybergraphics.h>
  24. #include <workbench/startup.h>
  25. #include <workbench/workbench.h>
  26. #define NO_INLINE_STDARG
  27. #include <proto/muimaster.h>
  28. #undef NO_INLINE_STDARG
  29. #include <proto/exec.h>
  30. #include <proto/dos.h>
  31. #include <proto/graphics.h>
  32. #define NO_INLINE_STDARG
  33. #include <proto/intuition.h>
  34. #undef NO_INLINE_STDARG
  35. #include <proto/layers.h>
  36. #include <proto/utility.h>
  37. #include <proto/cybergraphics.h>
  38. #include <proto/icon.h>
  39. #include <proto/diskfont.h>
  40. #include <proto/iffparse.h>
  41. #include "config.h"
  42. #include "AComm.h"
  43.  
  44. #ifdef POWERUP
  45. #   include <powerup/ppclib/message.h>
  46. #   include <powerup/ppclib/tasks.h>
  47. #   include <powerup/proto/ppc.h>
  48. #   include "AGfxcomm.h"
  49. #endif
  50.  
  51. #ifndef AFF_68060
  52. #   define AFF_68060 (1L<<7)
  53. #endif
  54.  
  55. #define DB(x)   //x
  56.  
  57. #ifdef __SASC
  58. #   define SAVEDS   __saveds
  59. #   define ASM      __asm
  60. #   define REG(r,a) register __ ## r a
  61. #elif defined(__GNUC__)
  62. #   define SAVEDS
  63. #   define ASM
  64. #   define STR(x)   #x
  65. #   define REG(r,a) a __asm(STR(r))
  66. #endif
  67.  
  68. static void copystr(char** p,const char* q) {
  69.     if(q) {
  70.     size_t l=strlen(q)+1;
  71.     char* t=malloc(l);
  72.     if(t) {
  73.         if(*p)
  74.         free(*p);
  75.         *p=t;
  76.         memcpy(t,q,l);
  77.     }
  78.     }
  79. }
  80.  
  81. static char* gzipcmd_arg;
  82. static char* urlcmd_arg;
  83. static char* deficon_arg;
  84. static char* diskobj_arg;
  85. static int page_arg=1;
  86. static int zoom_arg=1;
  87. static int colors_arg=16;
  88. static int cachesz_arg=256;
  89. static int blocsz_arg=4;
  90. #define TEMPLATE "PDFFILE,P=PAGE/N/K,Z=ZOOM/N/K,C=COLORS/N/K,G=GZIPCMD/K,U=URLCMD/K,I=DEFICON/K,F=FONTMAP/M,D=DISKOBJECT/K,S=CACHESIZE/N/K,B=CACHEBLOCSIZE/N/K"
  91. #define PDFFILE ((const char*)args[0])
  92. #define PAGE    (args[1]?*(int*)args[1]:page_arg)
  93. #define ZOOM    (args[2]?*(int*)args[2]:zoom_arg)
  94. #define COLORS  (args[3]?*(int*)args[3]:16)
  95. #define GZIPCMD (args[4]?(const char*)args[4]:(gzipcmd_arg?gzipcmd_arg:"gzip -d -q"))
  96. #define URLCMD  (args[5]?(const char*)args[5]:(urlcmd_arg?urlcmd_arg:"OpenURL %s"))
  97. #define DEFICON (args[6]?(const char*)args[6]:(deficon_arg?deficon_arg:"env:sys/def_pdf"))
  98. #define FONTMAP ((const char**)args[7])
  99. #define DISKOBJ (args[8]?(const char*)args[8]:diskobj_arg)
  100. #define CACHESZ (args[9]?*(int*)args[9]:cachesz_arg)
  101. #define BLOCSZ  (args[10]?*(int*)args[10]:blocsz_arg)
  102. #define NARGS   11
  103. #define SET_PAGE(x)    (args[1]=NULL,page_arg=x)
  104. #define SET_ZOOM(x)    (args[2]=NULL,zoom_arg=x)
  105. #define SET_COLORS(x)  (args[3]=NULL,colors_arg=x)
  106. #define SET_CACHESZ(x) (args[9]=NULL,cachesz_arg=x)
  107. #define SET_BLOCSZ(x)  (args[10]=NULL,blocsz_arg=x)
  108. static LONG args[NARGS];
  109.  
  110.  
  111. #if defined(__SASC) || defined(__libnix__)
  112. char __stdiowin[]="CON://600/200/Apdf/AUTO/WAIT/CLOSE";
  113. extern struct WBStartup *_WBenchMsg;
  114.  
  115. static void parse_tooltypes(BPTR lock,const char* name) {
  116.     struct DiskObject *dob;
  117.     BPTR olddir=CurrentDir(lock);
  118.     if(dob=GetDiskObject((char*)name)) {
  119.     if(dob->do_ToolTypes) {
  120.         char* s=FindToolType(dob->do_ToolTypes,"PAGE");
  121.         if(s)
  122.         SET_PAGE(atoi(s));
  123.         s=FindToolType(dob->do_ToolTypes,"ZOOM");
  124.         if(s)
  125.         SET_ZOOM(atoi(s));
  126.         s=FindToolType(dob->do_ToolTypes,"COLORS");
  127.         if(s)
  128.         SET_COLORS(atoi(s));
  129.         s=FindToolType(dob->do_ToolTypes,"GZIPCMD");
  130.         if(s)
  131.         copystr(&gzipcmd_arg,s);
  132.         s=FindToolType(dob->do_ToolTypes,"URLCMD");
  133.         if(s)
  134.         copystr(&urlcmd_arg,s);
  135.         s=FindToolType(dob->do_ToolTypes,"DEFICON");
  136.         if(s)
  137.         copystr(&deficon_arg,s);
  138.         s=FindToolType(dob->do_ToolTypes,"DISKOBJECT");
  139.         if(s)
  140.         copystr(&diskobj_arg,s);
  141.         s=FindToolType(dob->do_ToolTypes,"CACHESIZE");
  142.         if(s)
  143.         SET_CACHESZ(atoi(s));
  144.         s=FindToolType(dob->do_ToolTypes,"CACHEBLOCSIZE");
  145.         if(s)
  146.         SET_BLOCSZ(atoi(s));
  147.     }
  148.     FreeDiskObject(dob);
  149.     }
  150.     CurrentDir(olddir);
  151. }
  152. #endif
  153.  
  154.  
  155.  
  156. #define MYTAG_START       TAG_USER
  157. #define MYATTR_Page       (MYTAG_START+1)
  158. #define MYATTR_Zoom       (MYTAG_START+2)
  159. #define MYATTR_Selected   (MYTAG_START+5)
  160. #define MYATTR_Selection  (MYTAG_START+6)
  161. #define MYATTR_NewDoc     (MYTAG_START+7)
  162. #define MYATTR_NumPages   (MYTAG_START+8)
  163. #define MYATTR_Value      (MYTAG_START+9)
  164. #define MYATTR_ListID     (MYTAG_START+10)
  165.  
  166. #define MYM_Reset         (MYTAG_START+100)
  167.  
  168. #define ID_ABOUT          1
  169. #define ID_ABOUTMUI       2
  170. #define ID_SEARCH         3
  171. #define ID_OPEN           4
  172. #define ID_SAVEAS         5
  173. #define ID_WRITE          6
  174. #define ID_MUIPREFS       7
  175. #define ID_COPY           8
  176. #define ID_DEFAULTFONTS   9
  177. #define ID_DEFFONTS       10
  178. #define ID_DOCFONTS       11
  179. #define ID_APPLYFONTMAP   12
  180. #define ID_SCANFONTS      13
  181. #define ID_ABORT          14
  182. #define ID_OPENSCANFONTS  15
  183. #define ID_PRINT          16
  184. #define ID_HIDE           17
  185.  
  186. #define MYASSERT(x) if(!(x)) { printf("Internal error: %s/%d\n",__FILE__,__LINE__); exit(EXIT_FAILURE); }
  187.  
  188. #define  ID_FTXT        MAKE_ID('F','T','X','T')
  189. #define  ID_CHRS        MAKE_ID('C','H','R','S')
  190.  
  191. #if defined(__SASC) || defined(__libnix__)
  192. long __stack=30000;
  193. #endif
  194.  
  195. #define btop    1
  196. #define bbottom 1
  197. #define bleft   1
  198. #define bright  1
  199.  
  200. struct IntuitionBase* IntuitionBase;
  201. struct GfxBase* GfxBase;
  202. struct Library* LayersBase;
  203. struct UtilityBase* UtilityBase;
  204. struct Library* MUIMasterBase;
  205. struct Library* PPCLibBase;
  206. struct Library* CyberGfxBase;
  207. struct Library* IconBase;
  208. struct Library* DiskfontBase;
  209. struct Library* IFFParseBase;
  210.  
  211. /* zoom factor is 1.2 (similar to DVI magsteps) */
  212. #define minZoom -5
  213. #define maxZoom  5
  214. static int zoomDPI[maxZoom - minZoom + 1] = {
  215.   29, 35, 42, 50, 60,
  216.   72,
  217.   86, 104, 124, 149, 179
  218. };
  219. #define defZoom 1
  220.  
  221. BPTR input,oldinput;
  222. BPTR progdir;
  223. char* progname;
  224. BPTR docdir;
  225. char* docname;
  226. struct RDArgs* rda;
  227. struct DiskObject* diskobj;
  228. struct MUI_CustomClass* mcc;
  229. struct MUI_CustomClass* slider_mcc;
  230. struct MUI_CustomClass* rotate_slider_mcc;
  231. struct MUI_CustomClass* list_mcc;
  232. Object* App;
  233. Object* pageobj;
  234. Object* zoomobj;
  235. Object* bitmapobj;
  236. Object* vgroup;
  237. Object* win;
  238. Object* linkobj;
  239. Object* searchobj;
  240. Object* psstartobj;
  241. Object* psstopobj;
  242. Object* scanstartobj;
  243. Object* scanstopobj;
  244. Object* pagegroup;
  245. Object* gaugewin;
  246. Object* gaugeobj;
  247. Object* abortobj;
  248. struct FileRequester* req;
  249. BPTR olddir;
  250. #ifdef POWERUP
  251. void* elfobject;
  252. PPCPort* port;
  253. PPCPort* reply_port;
  254. PPCPortList* portlist;
  255. PPCMsg* startupmsg;
  256. struct StartupData* startup_data;
  257. size_t startup_length;
  258. PPCTask* ppctask;
  259. PPCPort* ports[3];
  260. PPCMsg* quitmsg;
  261. PPCMsg* cmdmsg;
  262. BOOL cmd_sent;
  263. void* cmddata;
  264. PPCPort* ppcport;
  265. BOOL quitting=FALSE;
  266. BOOL ppc_quitted=TRUE;
  267. #endif
  268.  
  269. struct clip_rect {
  270.     struct clip_rect *next;
  271.     short minx;
  272.     short miny;
  273.     short maxx;
  274.     short maxy;
  275. };
  276.  
  277. struct clip_poly {
  278.     struct clip_poly *next;
  279.     int num;
  280.     short data[1];
  281. };
  282.  
  283. struct font_entry {
  284.     struct TextFont *font;
  285.     short style;
  286.     short pad;
  287. };
  288.  
  289. static short area_minx,area_miny,area_maxx,area_maxy;
  290. static short* area_buf;
  291.  
  292. void cleararea(void) {
  293.     DB(printf("--cleararea\n");)
  294.     if(area_buf) {
  295.     free(area_buf);
  296.     area_buf=NULL;
  297.     }
  298. }
  299.  
  300. void initarea(struct RastPort* rp,int n) {
  301.     static struct AreaInfo areainfo;
  302.     DB(printf("--initarea(%d)\n",n);)
  303.     cleararea();
  304.     if(area_buf=malloc((n+1)*5)) {
  305.     InitArea(&areainfo,area_buf,n+1);
  306.     rp->AreaInfo=&areainfo;
  307.     }
  308.     area_minx=32767;
  309.     area_miny=32767;
  310.     area_maxx=-32768;
  311.     area_maxy=-32768;
  312. }
  313.  
  314. void areapoly(struct RastPort* rp,int n,short* p,short dx,short dy) {
  315.     DB(printf("--areapoly(%d,%d,%d)\n",n,dx,dy);)
  316.     if(rp->AreaInfo) {
  317.     int k=n;
  318.     while(--k>=0) {
  319.         if(*p>area_maxx)
  320.         area_maxx=*p;
  321.         if(*p<area_minx)
  322.         area_minx=*p;
  323.         ++p;
  324.         if(*p>area_maxy)
  325.         area_maxy=*p;
  326.         if(*p<area_miny)
  327.         area_miny=*p;
  328.         ++p;
  329.     }
  330.     p-=2*n;
  331.     AreaMove(rp,p[0]-dx,p[1]-dy);
  332.     while(--n) {
  333.         p+=2;
  334.         AreaDraw(rp,p[0]-dx,p[1]-dy);
  335.     }
  336.     }
  337. }
  338.  
  339. void areaend(struct RastPort* rp) {
  340.     DB(printf("--areaend\n");)
  341.     if(rp->AreaInfo) {
  342.     int w=area_maxx-area_minx+17;
  343.     int h=area_maxy-area_miny+1;
  344.     void* plane;
  345.     if(plane=AllocRaster(w,h)) {
  346.         struct TmpRas tmpras;
  347.         InitTmpRas(&tmpras,plane,RASSIZE(w,h));
  348.         rp->TmpRas=&tmpras;
  349.         AreaEnd(rp);
  350.         WaitBlit();
  351.         rp->TmpRas=NULL;
  352.         FreeRaster(plane,w,h);
  353.     }
  354.     free(area_buf);
  355.     area_buf=NULL;
  356.     rp->AreaInfo=NULL;
  357.     }
  358. }
  359.  
  360.  
  361.  
  362.  
  363. /* workaround for a bug in egcs */
  364. static void MyReadPixelArray(APTR dest,UWORD dx,UWORD dy,UWORD mod,struct RastPort* rp,UWORD x,UWORD y,UWORD w,UWORD h,UBYTE fmt) {
  365.     ReadPixelArray(dest,dx,dy,mod,rp,x,y,w,h,fmt);
  366. }
  367. static void MyWritePixelArray(APTR src,UWORD sx,UWORD sy,UWORD mod,struct RastPort* rp,UWORD x,UWORD y,UWORD w,UWORD h,UBYTE fmt) {
  368.     WritePixelArray(src,sx,sy,mod,rp,x,y,w,h,fmt);
  369. }
  370.  
  371.  
  372. struct DocData {
  373.     int width;
  374.     int height;
  375.     int page;
  376.     int num_pages;
  377.     int page_width;
  378.     int page_height;
  379.     int zoom;
  380.     int last_page;
  381.     int last_width;
  382.     int last_height;
  383.     int last_zoom;
  384.     struct ColorMap* colormap;
  385.     struct BitMap *friendbm;
  386.     struct BitMap *bm;
  387.     struct Layer_Info *layerinfo;
  388.     struct Layer *layer;
  389.     struct Region *region;
  390.     struct BitMap *clipbm;
  391.     struct Layer_Info *cliplayerinfo;
  392.     struct Layer *cliplayer;
  393.     struct Region *clipregion;
  394.     struct Region *clipregion2;
  395.     struct clip_rect *rects;
  396.     struct clip_poly *polys;
  397.     Object* obj;
  398.     struct Rectangle selection;
  399.     struct Rectangle old_selection;
  400.     struct font_entry *fonts;
  401.     int maxfont;
  402.     ULONG* pens;
  403.     int curpen;
  404.     int maxpen;
  405.     struct RastPort rp;
  406.     short depth;
  407.     short dx;
  408.     short dy;
  409.     short clipwidth;
  410.     short clipheight;
  411.     short minx;
  412.     short maxx;
  413.     short miny;
  414.     short maxy;
  415.     BOOL hidden;
  416.     BOOL selected;
  417.     BOOL selecting;
  418.     BOOL select_displayed;
  419. #ifndef POWERUP
  420.     struct RastPort** rpp;
  421.     short* dxp;
  422.     short* dyp;
  423. #endif
  424. };
  425. typedef struct DocData DocData;
  426.  
  427. #ifndef POWERUP
  428. void initgfx(DocData** dp,struct RastPort** rpp,short* dxp,short* dyp) {
  429.     DocData* dat=INST_DATA(mcc->mcc_Class,bitmapobj);
  430.     *dp=dat;
  431.     *rpp=&dat->rp;
  432.     dat->rpp=rpp;
  433.     dat->dxp=dxp;
  434.     dat->dyp=dyp;
  435. }
  436. #endif
  437.  
  438. /*
  439.  *  Pen sharing functions.
  440.  */
  441.  
  442. ULONG get_pen(DocData* dat,short n) {
  443.     DB(printf("--getpen(%d)\n",n);)
  444.     return n<dat->maxpen?dat->pens[n]:1;
  445. }
  446.  
  447. static void clear_pens(DocData* dat) {
  448.     ULONG* p=dat->pens;
  449.     int n;
  450.     for(n=dat->curpen<dat->maxpen?dat->curpen:dat->maxpen;--n>=0;)
  451.     ReleasePen(dat->colormap,p[n]);
  452.     dat->curpen=0;
  453. }
  454.  
  455. ULONG add_pen(DocData* dat,ULONG r,ULONG g,ULONG b) {
  456.     DB(printf("--addpen %d=%08lx,%08lx,%08lx\n",dat->curpen,r,g,b);)
  457.     if(dat->curpen>=dat->maxpen) {
  458.     int maxpen=((dat->curpen*3)>>1)+16;
  459.     ULONG* p=realloc(dat->pens,maxpen*sizeof(*dat->pens));
  460.     if(p) {
  461.         dat->maxpen=maxpen;
  462.         dat->pens=p;
  463.     }
  464.     }
  465.     if(dat->curpen<dat->maxpen)
  466.     return dat->pens[dat->curpen++]=ObtainBestPenA(dat->colormap,r,g,b,NULL);
  467.     else
  468.     return 1;
  469. }
  470.  
  471. void add_pens(DocData* dat,ULONG* t,int num) {
  472.     while(--num>=0) {
  473.     t[0]=add_pen(dat,t[1],t[2],t[3]);
  474.     GetRGB32(dat->colormap,t[0],1,t+1);
  475.     t+=4;
  476.     }
  477. }
  478.  
  479. void reset_pens(DocData* dat) {
  480.     clear_pens(dat);
  481.     add_pen(dat,0,0,0);
  482.     add_pen(dat,0xffffffffUL,0xffffffffUL,0xffffffffUL);
  483. }
  484.  
  485. /*
  486.  *  Font handling functions.
  487.  */
  488.  
  489. void openfont(DocData* dat,int id,const char* name,short size,short style) {
  490.     if(id>=dat->maxfont) {
  491.     int maxfont=(id*3)/2+16;
  492.     struct font_entry* p=realloc(dat->fonts,maxfont*sizeof(*p));
  493.     if(p) {
  494.         memset(p+dat->maxfont,0,(maxfont-dat->maxfont)*sizeof(*p));
  495.         dat->fonts=p;
  496.         dat->maxfont=maxfont;
  497.     }
  498.     }
  499.     if(id<dat->maxfont) {
  500.     struct TextAttr ta;
  501.     ta.ta_Name=(char*)name;
  502.     ta.ta_YSize=size;
  503.     ta.ta_Style=style;
  504.     ta.ta_Flags=0;
  505.     dat->fonts[id].style=style;
  506.     if(!(dat->fonts[id].font=OpenDiskFont(&ta)))
  507.         printf("Can't open font \"%s\"/%d.\n",name,size);
  508.     }
  509. }
  510.  
  511.  
  512. void closefont(DocData* dat,int id) {
  513.     if(id<dat->maxfont && dat->fonts[id].font) {
  514.     CloseFont(dat->fonts[id].font);
  515.     dat->fonts[id].font=NULL;
  516.     }
  517. }
  518.  
  519. void setfont(DocData* dat,int id) {
  520.     if(id<dat->maxfont && dat->fonts[id].font) {
  521.     SetFont(&dat->rp,dat->fonts[id].font);
  522.     SetSoftStyle(&dat->rp,dat->fonts[id].style,FSF_BOLD|FSF_ITALIC);
  523.     }
  524. }
  525.  
  526. static void clear_fonts(DocData* dat) {
  527.     int k;
  528.     for(k=0;k<dat->maxfont;++k)
  529.     if(dat->fonts[k].font)
  530.         CloseFont(dat->fonts[k].font);
  531.     free(dat->fonts);
  532.     dat->fonts=NULL;
  533.     dat->maxfont=0;
  534. }
  535.  
  536. /*
  537.  *  Clip handling functions.
  538.  */
  539.  
  540. static void free_clip_polys(DocData *dat) {
  541.     struct clip_poly *p;
  542.     DB(printf("--free_clip_polys\n");)
  543.     p=dat->polys;
  544.     while(p) {
  545.     struct clip_poly *q=p->next;
  546.     free(p);
  547.     p=q;
  548.     }
  549.     dat->polys=NULL;
  550. }
  551.  
  552. static void free_clip_rects(DocData *dat) {
  553.     struct clip_rect *p;
  554.     DB(printf("--free_clip_rects\n");)
  555.     p=dat->rects;
  556.     while(p) {
  557.     struct clip_rect *q=p->next;
  558.     free(p);
  559.     p=q;
  560.     }
  561.     dat->rects=NULL;
  562. }
  563.  
  564. static void clip_path(DocData* dat,int n,short* p) {
  565.     short dx=dat->dx;
  566.     short dy=dat->dy;
  567.     if(dx || dy) {
  568.     while(--n>=0) {
  569.         *p++-=dx;
  570.         *p++-=dy;
  571.     }
  572.     }
  573. }
  574.  
  575. static void tfr_clip(DocData *dat) {
  576.     DB(printf("--tfr_clip\n");)
  577.     if(dat->bm && dat->polys && dat->clipbm) {
  578.     /*
  579.      * Non rectangular clipping region.
  580.      *
  581.      * Ideally, we would draw a mask and call
  582.      * BltMaskBitMapRastPort. However, due to the
  583.      * bogus way the mask parameter is given to this function
  584.      * it is quite unusable with anything but standard
  585.      * non-interleaved bitmaps. So we emulate this
  586.      * function instead. This is slow, uses lots of memory
  587.      * and is non-optimal, but this is rarely used anyway...
  588.      */
  589.     struct BitMap *bm1;
  590.     struct BitMap *bm2;
  591.     struct RastPort rp1;
  592.     struct RastPort rp2;
  593.     UBYTE* mask;
  594.     UBYTE* src;
  595.     UBYTE* dest;
  596.     size_t sz=((dat->clipwidth+15)&~15)*dat->clipheight+4;
  597.     DB(printf("--non trivial tfr_clip\n");)
  598.     InitRastPort(&rp1);
  599.     if(mask=malloc(sz)) {
  600.         if(bm1=AllocBitMap(dat->clipwidth,dat->clipheight,1,BMF_MINPLANES,dat->bm)) {
  601.         if(bm2=AllocBitMap(dat->clipwidth,1,1,BMF_MINPLANES,bm1)) {
  602.             struct Layer_Info *layerinfo;
  603.             struct Layer *layer;
  604.             rp1.BitMap=bm1;
  605.             if(layerinfo=NewLayerInfo()) {
  606.             if(layer=CreateUpfrontLayer(layerinfo,bm1,0,0,dat->clipwidth-1,dat->clipheight-1,LAYERSIMPLE,NULL)) {
  607.                 int n;
  608.                 struct clip_rect *q;
  609.                 struct clip_poly *p;
  610.                 InstallClipRegion(dat->cliplayer,NULL);
  611.                 InstallClipRegion(layer,dat->clipregion2);
  612.                 rp1.Layer=layer;
  613.                 SetAPen(&rp1,1);
  614.                 for(q=dat->rects;q;q=q->next)
  615.                 RectFill(&rp1,q->minx-dat->dx,q->miny-dat->dy,q->maxx-dat->dx,q->maxy-dat->dy);
  616.                 n=0;
  617.                 for(p=dat->polys;p;p=p->next)
  618.                 n+=p->num+1;
  619.                 initarea(&rp1,n);
  620.                 for(p=dat->polys;p;p=p->next)
  621.                 areapoly(&rp1,p->num,p->data,dat->dx,dat->dy);
  622.                 areaend(&rp1);
  623.                 InstallClipRegion(layer,NULL);
  624.                 InstallClipRegion(dat->cliplayer,dat->clipregion2);
  625.                 rp1.Layer=NULL;
  626.                 rp2=rp1;
  627.                 rp2.BitMap=bm2;
  628.                 ReadPixelArray8(&rp1,0,0,dat->clipwidth-1,dat->clipheight-1,mask,&rp2);
  629.                 DeleteLayer(0,layer);
  630.             }
  631.             DisposeLayerInfo(layerinfo);
  632.             }
  633.             FreeBitMap(bm2);
  634.         }
  635.         FreeBitMap(bm1);
  636.         }
  637.         if(dat->depth<=8) {
  638.         if(src=malloc(sz)) {
  639.             if(bm2=AllocBitMap(dat->clipwidth,1,dat->depth,BMF_MINPLANES,dat->bm)) {
  640.             rp2=dat->rp;
  641.             rp2.BitMap=bm2;
  642.             rp2.Layer=NULL;
  643.             dat->rp.BitMap=dat->clipbm;
  644.             dat->rp.Layer=NULL;
  645.             ReadPixelArray8(&dat->rp,0,0,dat->clipwidth-1,dat->clipheight-1,src,&rp2);
  646.             if(dest=malloc(sz)) {
  647.                 UBYTE *s=src;
  648.                 UBYTE *d=dest;
  649.                 UBYTE *m=mask;
  650.                 UBYTE x=(1<<dat->depth)-1;
  651.                 dat->rp.BitMap=dat->bm;
  652.                 ReadPixelArray8(&dat->rp,dat->dx,dat->dy,dat->dx+dat->clipwidth-1,dat->dy+dat->clipheight-1,dest,&rp2);
  653.                 do {
  654.                 UBYTE t=((BYTE)(*m<<7)>>7)&x;
  655.                 *d=(*d&~t)|(*s&t);
  656.                 ++d;
  657.                 ++s;
  658.                 ++m;
  659.                 } while(--sz);
  660.                 dat->rp.Layer=dat->layer;
  661.                 WritePixelArray8(&dat->rp,dat->dx,dat->dy,dat->dx+dat->clipwidth-1,dat->dy+dat->clipheight-1,dest,&rp2);
  662.                 free(dest);
  663.             }
  664.             FreeBitMap(bm2);
  665.             }
  666.             free(src);
  667.         }
  668.         } else {
  669.         if(src=malloc(sz*3)) {
  670.             UWORD mod=((dat->clipwidth+15)&~15)*3;
  671.             dat->rp.BitMap=dat->clipbm;
  672.             dat->rp.Layer=NULL;
  673.             MyReadPixelArray(src,0,0,mod,&dat->rp,0,0,dat->clipwidth,dat->clipheight,RECTFMT_RGB);
  674.             if(dest=malloc(sz*3)) {
  675.             UBYTE *s=src;
  676.             UBYTE *d=dest;
  677.             UBYTE *m=mask;
  678.             dat->rp.BitMap=dat->bm;
  679.             MyReadPixelArray(dest,0,0,mod,&dat->rp,dat->dx,dat->dy,dat->clipwidth,dat->clipheight,RECTFMT_RGB);
  680.             do {
  681.                 UBYTE t=(BYTE)(*m<<7)>>7;
  682.                 *d=(*d&~t)|(*s&t);
  683.                 ++d;
  684.                 ++s;
  685.                 *d=(*d&~t)|(*s&t);
  686.                 ++d;
  687.                 ++s;
  688.                 *d=(*d&~t)|(*s&t);
  689.                 ++d;
  690.                 ++s;
  691.                 ++m;
  692.             } while(--sz);
  693.             dat->rp.Layer=dat->layer;
  694.             MyWritePixelArray(dest,0,0,mod,&dat->rp,dat->dx,dat->dy,dat->clipwidth,dat->clipheight,RECTFMT_RGB);
  695.             free(dest);
  696.             }
  697.             free(src);
  698.         }
  699.         }
  700.         free(mask);
  701.     }
  702.     }
  703. }
  704.  
  705. void clear_clip(DocData* dat) {
  706.     DB(printf("--clear_clip\n");)
  707.     if(dat->polys) {
  708.     tfr_clip(dat);
  709.     free_clip_polys(dat);
  710.     }
  711.     free_clip_rects(dat);
  712.     dat->rp.Layer=dat->layer;
  713.     dat->rp.BitMap=dat->bm;
  714.     if(dat->clipregion) {
  715.     InstallClipRegion(dat->layer,dat->region);
  716.     DisposeRegion(dat->clipregion);
  717.     dat->clipregion=NULL;
  718.     }
  719.     if(dat->clipregion2) {
  720.     InstallClipRegion(dat->cliplayer,NULL);
  721.     DisposeRegion(dat->clipregion2);
  722.     dat->clipregion2=NULL;
  723.     }
  724.     if(dat->cliplayer) {
  725.     DeleteLayer(0,dat->cliplayer);
  726.     dat->cliplayer=NULL;
  727.     }
  728.     if(dat->cliplayerinfo) {
  729.     DisposeLayerInfo(dat->cliplayerinfo);
  730.     dat->cliplayerinfo=NULL;
  731.     }
  732.     FreeBitMap(dat->clipbm);
  733.     dat->clipbm=NULL;
  734.     dat->dx=0;
  735.     dat->dy=0;
  736. #ifndef POWERUP
  737.     *dat->dxp=0;
  738.     *dat->dyp=0;
  739. #endif
  740. }
  741.  
  742. void init_clip(DocData* dat) {
  743.     DB(printf("--init_clip\n");)
  744.     clear_clip(dat);
  745.     dat->minx=dat->width;
  746.     dat->miny=dat->height;
  747.     dat->maxx=-1;
  748.     dat->maxy=-1;
  749. }
  750.  
  751. void rect_clip(DocData* dat,short x1,short y1,short x2,short y2) {
  752.     struct clip_rect *q;
  753.     DB(printf("--rect_clip (%d,%d)-(%d,%d)\n",x1,y1,x2,y2);)
  754.     if(dat->minx>x1)
  755.     dat->minx=x1;
  756.     if(dat->miny>y1)
  757.     dat->miny=y1;
  758.     if(dat->maxx<x2)
  759.     dat->maxx=x2;
  760.     if(dat->maxy<y2)
  761.     dat->maxy=y2;
  762.     if(q=malloc(sizeof(*q))) {
  763.     q->next=dat->rects;
  764.     dat->rects=q;
  765.     q->minx=x1;
  766.     q->miny=y1;
  767.     q->maxx=x2;
  768.     q->maxy=y2;
  769.     }
  770. }
  771.  
  772. void poly_clip(DocData *dat,int n,short* p) {
  773.     DB(printf("--poly_clip %d:",n);)
  774.     if(n) {
  775.     size_t sz=sizeof(struct clip_poly)+(n*2-1)*sizeof(short);
  776.     struct clip_poly *q;
  777.     if(q=malloc(sz)) {
  778.         q->next=dat->polys;
  779.         dat->polys=q;
  780.         q->num=n;
  781.         memcpy(q->data,p,n*2*sizeof(short));
  782.     }
  783.     do {
  784.         DB(printf(" (%d,%d)",p[0],p[1]);)
  785.         if(dat->minx>p[0])
  786.         dat->minx=p[0];
  787.         if(dat->maxx<p[0])
  788.         dat->maxx=p[0];
  789.         if(dat->miny>p[1])
  790.         dat->miny=p[1];
  791.         if(dat->maxy<p[1])
  792.         dat->maxy=p[1];
  793.         p+=2;
  794.     } while(--n);
  795.     }
  796.     DB(printf("\n");)
  797. }
  798.  
  799. void install_clip(DocData* dat) {
  800.     DB(printf("--install_clip\n");)
  801.     dat->rp.Layer=dat->layer;
  802.     if(dat->polys) {
  803.     if(dat->minx<0)
  804.         dat->minx=0;
  805.     if(dat->miny<0)
  806.         dat->miny=0;
  807.     if(dat->maxx>dat->width-1)
  808.         dat->maxx=dat->width-1;
  809.     if(dat->maxy>dat->height-1)
  810.         dat->maxy=dat->height-1;
  811.     dat->clipwidth=dat->maxx-dat->minx+1;
  812.     dat->clipheight=dat->maxy-dat->miny+1;
  813.     DB(printf("--install_clip %d×%d\n",dat->clipwidth,dat->clipheight);)
  814.     if(dat->clipwidth>0 && dat->clipheight>0 &&
  815.        (dat->clipbm=AllocBitMap(dat->clipwidth,dat->clipheight,dat->depth,BMF_MINPLANES,dat->bm))) {
  816.         if(dat->cliplayerinfo=NewLayerInfo()) {
  817.         if(dat->cliplayer=CreateUpfrontHookLayer(dat->cliplayerinfo,
  818.                              dat->clipbm,
  819.                              0,0,
  820.                              dat->clipwidth-1,
  821.                              dat->clipheight-1,
  822.                              LAYERSIMPLE,
  823.                              LAYERS_NOBACKFILL,
  824.                              NULL)) {
  825.             if(dat->clipregion2=NewRegion()) {
  826.             struct Rectangle rect;
  827.             rect.MinX=0;
  828.             rect.MinY=0;
  829.             rect.MaxX=dat->clipwidth-1;
  830.             rect.MaxY=dat->clipheight-1;
  831.             if(OrRectRegion(dat->clipregion2,&rect)) {
  832.                 InstallClipRegion(dat->cliplayer,dat->clipregion2);
  833.                 DB(printf("--installed.\n");)
  834.                 dat->rp.BitMap=dat->clipbm;
  835.                 dat->rp.Layer=dat->cliplayer;
  836.                 dat->dx=dat->minx;
  837.                 dat->dy=dat->miny;
  838. #ifndef POWERUP
  839.                 *dat->dxp=dat->dx;
  840.                 *dat->dyp=dat->dy;
  841. #endif
  842.                 BltBitMapRastPort(dat->bm,dat->dx,dat->dy,&dat->rp,0,0,dat->clipwidth,dat->clipheight,0xc0);
  843.                 return;
  844.             }
  845.             DisposeRegion(dat->clipregion2);
  846.             dat->clipregion2=NULL;
  847.             }
  848.             DeleteLayer(0,dat->cliplayer);
  849.             dat->cliplayer=NULL;
  850.         }
  851.         DisposeLayerInfo(dat->cliplayerinfo);
  852.         dat->cliplayerinfo=NULL;
  853.         }
  854.         FreeBitMap(dat->clipbm);
  855.         dat->clipbm=NULL;
  856.     } else
  857.         printf("Can't allocate bitmap\n");
  858.     } else if(dat->rects) {
  859.     if(dat->clipregion=NewRegion()) {
  860.         struct clip_rect *p;
  861.         struct Rectangle rect;
  862.         for(p=dat->rects;p;p=p->next) {
  863.         rect.MinX=p->minx;
  864.         rect.MinY=p->miny;
  865.         rect.MaxX=p->maxx;
  866.         rect.MaxY=p->maxy;
  867.         OrRectRegion(dat->clipregion,&rect);
  868.         }
  869.         rect.MinX=0;
  870.         rect.MinY=0;
  871.         rect.MaxX=dat->width-1;
  872.         rect.MaxY=dat->height-1;
  873.         AndRectRegion(dat->clipregion,&rect); /* Can't fail */
  874.         InstallClipRegion(dat->layer,dat->clipregion);
  875.     } else
  876.         InstallClipRegion(dat->layer,dat->region);
  877.     } else {
  878.     DB(printf("--simple install_clip\n");)
  879.     InstallClipRegion(dat->layer,dat->region);
  880.     }
  881. }
  882.  
  883. /*
  884.  *  Misc functions.
  885.  */
  886.  
  887. static void sleep(BOOL x) {
  888.     if(App)
  889.     set(App,MUIA_Application_Sleep,x);
  890. }
  891.  
  892. static void quit(void) {
  893. #ifdef POWERUP
  894.     if(!quitting && !ppc_quitted) {
  895.     PPCSendMessage(ppcport,quitmsg,NULL,0,MSGID_QUIT);
  896.     PPCWaitPort(reply_port);
  897.     PPCGetMessage(reply_port);
  898.     }
  899.     quitting=TRUE;
  900. #else
  901.     exit(EXIT_SUCCESS);
  902. #endif
  903. }
  904.  
  905.  
  906. /*
  907.  *  PowerUP inter process communication functions.
  908.  */
  909.  
  910. #ifdef POWERUP
  911.  
  912. static int get_info(int* num_pages) {
  913.     struct msg_info* p=cmddata;
  914.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_INFO);
  915.     PPCWaitPort(reply_port);
  916.     PPCGetMessage(reply_port);
  917.     *num_pages=p->num_pages;
  918.     return p->base.success;
  919. }
  920.  
  921. static int get_page_size(int page,int* width,int* height) {
  922.     struct msg_pagesize* p=cmddata;
  923.     p->page=page;
  924.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_PAGESIZE);
  925.     PPCWaitPort(reply_port);
  926.     PPCGetMessage(reply_port);
  927.     *width=p->width;
  928.     *height=p->height;
  929.     return p->base.success;
  930. }
  931.  
  932. static int create_doc(BPTR dir,const char* filename,size_t cachesz,size_t blocsz) {
  933.     if(!quitting && !ppc_quitted) {
  934.     struct msg_createdoc* p=cmddata;
  935.     p->dir=dir;
  936.     strncpy(p->filename,filename,sizeof(p->filename)-1);
  937.     p->filename[sizeof(p->filename)-1]='\0';
  938.     p->cachesz=cachesz;
  939.     p->blocsz=blocsz;
  940.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_CREATEDOC);
  941.     PPCWaitPort(reply_port);
  942.     PPCGetMessage(reply_port);
  943.     return p->base.success;
  944.     }
  945.     return 0;
  946. }
  947.  
  948. #if 0
  949. static void delete_doc(void) {
  950.     if(!quitting && !ppc_quitted) {
  951.     PPCSendMessage(ppcport,cmdmsg,NULL,0,MSGID_DELETEDOC);
  952.     PPCWaitPort(reply_port);
  953.     PPCGetMessage(reply_port);
  954.     }
  955. }
  956. #endif
  957.  
  958. static void create_output_dev(int depth,struct ColorMap* colormap) {
  959.     if(!quitting && !ppc_quitted) {
  960.     struct msg_create_output_dev* p=(struct msg_create_output_dev*)cmddata;
  961.     p->depth=depth;
  962.     p->colormap=colormap;
  963.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_CREATEOUTPUTDEV);
  964.     PPCWaitPort(reply_port);
  965.     PPCGetMessage(reply_port);
  966.     }
  967. }
  968.  
  969. static void delete_output_dev(void) {
  970.     if(!quitting && !ppc_quitted) {
  971.     PPCSendMessage(ppcport,cmdmsg,NULL,0,MSGID_DELETEOUTPUTDEV);
  972.     PPCWaitPort(reply_port);
  973.     PPCGetMessage(reply_port);
  974.     }
  975. }
  976.  
  977. static int simple_find(const char* str,int top,int* xmin,int* ymin,int* xmax,int* ymax) {
  978.     if(!quitting && !ppc_quitted) {
  979.     struct msg_find* p=cmddata;
  980.     p->top=top;
  981.     p->xmin=*xmin;
  982.     p->ymin=*ymin;
  983.     p->xmax=*xmax;
  984.     p->ymax=*ymax;
  985.     strcpy(p->str,str);
  986.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_SIMPLEFIND);
  987.     PPCWaitPort(reply_port);
  988.     PPCGetMessage(reply_port);
  989.     *xmin=p->xmin;
  990.     *ymin=p->ymin;
  991.     *xmax=p->xmax;
  992.     *ymax=p->ymax;
  993.     return p->base.success;
  994.     }
  995.     return 0;
  996. }
  997.  
  998. static int init_find(const char* str) {
  999.     if(!quitting && !ppc_quitted) {
  1000.     struct msg_find* p=cmddata;
  1001.     strcpy(p->str,str);
  1002.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_INITFIND);
  1003.     PPCWaitPort(reply_port);
  1004.     PPCGetMessage(reply_port);
  1005.     return p->base.success;
  1006.     }
  1007.     return 0;
  1008. }
  1009.  
  1010. static int find(int start,int stop,int* xmin,int* ymin,int* xmax,int* ymax,int* page) {
  1011.     if(!quitting && !ppc_quitted) {
  1012.     struct msg_find* p=cmddata;
  1013.     p->top=start;
  1014.     p->bottom=stop;
  1015.     /*p->xmin=*xmin;
  1016.     p->ymin=*ymin;
  1017.     p->xmax=*xmax;
  1018.     p->ymax=*ymax;
  1019.     p->page=*page;*/
  1020.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_FIND);
  1021.     PPCWaitPort(reply_port);
  1022.     PPCGetMessage(reply_port);
  1023.     *xmin=p->xmin;
  1024.     *ymin=p->ymin;
  1025.     *xmax=p->xmax;
  1026.     *ymax=p->ymax;
  1027.     *page=p->page;
  1028.     return p->base.success;
  1029.     }
  1030.     return 0;
  1031. }
  1032.  
  1033. static void end_find() {
  1034.     if(!quitting && !ppc_quitted) {
  1035.     PPCSendMessage(ppcport,cmdmsg,NULL,0,MSGID_ENDFIND);
  1036.     PPCWaitPort(reply_port);
  1037.     PPCGetMessage(reply_port);
  1038.     }
  1039. }
  1040.  
  1041. static int chklink(int x,int y,void** action,char* str,size_t len) {
  1042.     if(!quitting && !ppc_quitted) {
  1043.     struct msg_chklink* p=cmddata;
  1044.     p->x=x;
  1045.     p->y=y;
  1046.     p->action=*action;
  1047.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_CHKLINK);
  1048.     PPCWaitPort(reply_port);
  1049.     PPCGetMessage(reply_port);
  1050.     strncpy(str,p->str,len);
  1051.     *action=p->action;
  1052.     return p->base.success;
  1053.     }
  1054.     return 0;
  1055. }
  1056.  
  1057. static int dolink(int* x,int* y,int* state,int* page,char* buf,size_t len) {
  1058.     if(!quitting && !ppc_quitted) {
  1059.     struct msg_dolink* p=cmddata;
  1060.     p->x=*x;
  1061.     p->y=*y;
  1062.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_DOLINK);
  1063.     PPCWaitPort(reply_port);
  1064.     PPCGetMessage(reply_port);
  1065.     *state=p->state;
  1066.     *page=p->page;
  1067.     *x=p->x;
  1068.     *y=p->y;
  1069.     strncpy(buf,p->str,len);
  1070.     return p->base.success;
  1071.     }
  1072.     return 0;
  1073. }
  1074.  
  1075. static int init_write(const char* filename,int first_page,int last_page,int zoom,int rotate,int type) {
  1076.     if(!quitting && !ppc_quitted) {
  1077.     struct msg_write* p=cmddata;
  1078.     strncpy(p->filename,filename,sizeof(p->filename)-1);
  1079.     p->filename[sizeof(p->filename)-1]='\0';
  1080.     p->first_page=first_page;
  1081.     p->last_page=last_page;
  1082.     p->zoom=zoom;
  1083.     p->rotate=rotate;
  1084.     p->type=type;
  1085.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_INITWRITE);
  1086.     PPCWaitPort(reply_port);
  1087.     PPCGetMessage(reply_port);
  1088.     return p->base.success;
  1089.     }
  1090.     return 0;
  1091. }
  1092.  
  1093. static void writefile(int first_page,int last_page) {
  1094.     if(!quitting && !ppc_quitted) {
  1095.     struct msg_write* p=cmddata;
  1096.     p->first_page=first_page;
  1097.     p->last_page=last_page;
  1098.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_WRITE);
  1099.     PPCWaitPort(reply_port);
  1100.     PPCGetMessage(reply_port);
  1101.     }
  1102. }
  1103.  
  1104. static void end_write() {
  1105.     if(!quitting && !ppc_quitted) {
  1106.     PPCSendMessage(ppcport,cmdmsg,NULL,0,MSGID_ENDWRITE);
  1107.     PPCWaitPort(reply_port);
  1108.     PPCGetMessage(reply_port);
  1109.     }
  1110. }
  1111.  
  1112. static char* gettext(int xmin,int ymin,int xmax,int ymax) {
  1113.     char* r=NULL;
  1114.     if(!quitting && !ppc_quitted) {
  1115.     struct msg_gettext* p=cmddata;
  1116.     p->xmin=xmin;
  1117.     p->ymin=ymin;
  1118.     p->xmax=xmax;
  1119.     p->ymax=ymax;
  1120.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_GETTEXT);
  1121.     PPCWaitPort(reply_port);
  1122.     PPCGetMessage(reply_port);
  1123.     if(p->base.success) {
  1124.         char* buf=NULL;
  1125.         size_t sz=p->size+1;
  1126.         char* q;
  1127.         if(sz>sizeof(union msg_max)) {
  1128.         buf=PPCAllocVec(sz,MEMF_ANY);
  1129.         if(buf)
  1130.             q=buf;
  1131.         else {
  1132.             q=cmddata;
  1133.             sz=sizeof(union msg_max);
  1134.         }
  1135.         } else
  1136.         q=cmddata;
  1137.         PPCSendMessage(ppcport,cmdmsg,q,sz,MSGID_GETTEXT);
  1138.         PPCWaitPort(reply_port);
  1139.         PPCGetMessage(reply_port);
  1140.         if(r=malloc(sz))
  1141.         memcpy(r,q,sz);
  1142.         if(buf)
  1143.         PPCFreeVec(buf);
  1144.     }
  1145.     }
  1146.     return r;
  1147. }
  1148.  
  1149. static void add_fontmap(const char* pdffont,const char* afont,
  1150.             int m,int style,int encoding) {
  1151.     if(!quitting && !ppc_quitted) {
  1152.     struct msg_fontmap* p=cmddata;
  1153.     strncpy(p->pdffont,pdffont,sizeof(p->pdffont)-1);
  1154.     p->pdffont[sizeof(p->pdffont)-1]='\0';
  1155.     strncpy(p->afont,afont,sizeof(p->afont)-1);
  1156.     p->afont[sizeof(p->afont)-1]='\0';
  1157.     p->m=m;
  1158.     p->style=style;
  1159.     p->encoding=encoding;
  1160.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_ADDFONTMAP);
  1161.     PPCWaitPort(reply_port);
  1162.     PPCGetMessage(reply_port);
  1163.     }
  1164. }
  1165.  
  1166. #if 0
  1167. static void rem_fontmap(const char* pdffont) {
  1168.     if(!quitting && !ppc_quitted) {
  1169.     struct msg_fontmap* p=cmddata;
  1170.     strncpy(p->pdffont,pdffont,sizeof(p->pdffont)-1);
  1171.     p->pdffont[sizeof(p->pdffont)-1]='\0';
  1172.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_REMFONTMAP);
  1173.     PPCWaitPort(reply_port);
  1174.     PPCGetMessage(reply_port);
  1175.     }
  1176. }
  1177. #endif
  1178.  
  1179. static int init_scan(void) {
  1180.     if(!quitting && !ppc_quitted) {
  1181.     struct msg_scan_fonts* p=cmddata;
  1182.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_INITSCAN);
  1183.     PPCWaitPort(reply_port);
  1184.     PPCGetMessage(reply_port);
  1185.     return p->base.success;
  1186.     }
  1187.     return 0;
  1188. }
  1189.  
  1190. static int scan_fonts(int first_page,int last_page) {
  1191.     if(!quitting && !ppc_quitted) {
  1192.     struct msg_scan_fonts* p=cmddata;
  1193.     p->first_page=first_page;
  1194.     p->last_page=last_page;
  1195.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_SCANFONTS);
  1196.     PPCWaitPort(reply_port);
  1197.     PPCGetMessage(reply_port);
  1198.     return p->base.success;
  1199.     }
  1200.     return 0;
  1201. }
  1202.  
  1203. static int scan_default_fonts(void) {
  1204.     if(!quitting && !ppc_quitted) {
  1205.     struct msg_scan_fonts* p=cmddata;
  1206.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_DEFAULTFONTS);
  1207.     PPCWaitPort(reply_port);
  1208.     PPCGetMessage(reply_port);
  1209.     return p->base.success;
  1210.     }
  1211.     return 0;
  1212. }
  1213.  
  1214. static void end_scan_fonts(void) {
  1215.     if(!quitting && !ppc_quitted) {
  1216.     PPCSendMessage(ppcport,cmdmsg,NULL,0,MSGID_ENDSCANFONTS);
  1217.     PPCWaitPort(reply_port);
  1218.     PPCGetMessage(reply_port);
  1219.     }
  1220. }
  1221.  
  1222. static int get_font(int n,char* pdffont,int pdffontlen,
  1223.              char* afont,int afontlen,
  1224.              int* m,int* style,int* encoding) {
  1225.     if(!quitting && !ppc_quitted) {
  1226.     struct msg_fontmap* p=cmddata;
  1227.     p->m=n;
  1228.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_GETFONT);
  1229.     PPCWaitPort(reply_port);
  1230.     PPCGetMessage(reply_port);
  1231.     strncpy(pdffont,p->pdffont,pdffontlen-1);
  1232.     pdffont[pdffontlen-1]='\0';
  1233.     strncpy(afont,p->afont,afontlen-1);
  1234.     afont[afontlen-1]='\0';
  1235.     *m=p->m;
  1236.     *style=p->style;
  1237.     *encoding=p->encoding;
  1238.     return p->base.success;
  1239.     } else
  1240.     return 0;
  1241. }
  1242.  
  1243.  
  1244. static void clear_fontmap(void) {
  1245.     if(!quitting && !ppc_quitted) {
  1246.     PPCSendMessage(ppcport,cmdmsg,NULL,0,MSGID_CLEARFONTMAP);
  1247.     PPCWaitPort(reply_port);
  1248.     PPCGetMessage(reply_port);
  1249.     }
  1250. }
  1251.  
  1252. /*static void set_fontmap(void) {
  1253.     if(!quitting && !ppc_quitted) {
  1254.     PPCSendMessage(ppcport,cmdmsg,NULL,0,MSGID_SETFONTMAP);
  1255.     PPCWaitPort(reply_port);
  1256.     PPCGetMessage(reply_port);
  1257.     }
  1258. }*/
  1259.  
  1260. static PPCMsg* putimage(DocData* dat,PPCMsg* msg,short x,short y,short w,short h) {
  1261.     UBYTE* pic;
  1262.     struct BitMap* bm;
  1263.     PPCReplyMessage(msg);
  1264.     PPCWaitPort(port);
  1265.     msg=PPCGetMessage(port);
  1266.     pic=(UBYTE*)PPCGetMessageAttr(msg,PPCMSGTAG_DATA);
  1267.     if(bm=AllocBitMap((w+15)&~15,1,8,BMF_MINPLANES,dat->bm)) {
  1268.     struct RastPort rp2;
  1269.     rp2=dat->rp;
  1270.     rp2.Layer=NULL;
  1271.     rp2.BitMap=bm;
  1272.     WritePixelArray8(&dat->rp,x,y,x+w-1,y+h-1,pic,&rp2);
  1273.     WaitBlit();
  1274.     FreeBitMap(bm);
  1275.     }
  1276.     return msg;
  1277. }
  1278.  
  1279. static PPCMsg* getimage(DocData* dat,PPCMsg* msg,short x,short y,short w,short h) {
  1280.     UBYTE* pic;
  1281.     struct BitMap* bm;
  1282.     PPCReplyMessage(msg);
  1283.     PPCWaitPort(port);
  1284.     msg=PPCGetMessage(port);
  1285.     pic=(UBYTE*)PPCGetMessageAttr(msg,PPCMSGTAG_DATA);
  1286.     if(bm=AllocBitMap((w+15)&~15,1,8,BMF_MINPLANES,dat->bm)) {
  1287.     struct RastPort rp2;
  1288.     rp2=dat->rp;
  1289.     rp2.Layer=NULL;
  1290.     rp2.BitMap=bm;
  1291.     ReadPixelArray8(&dat->rp,x,y,x+w-1,y+h-1,pic,&rp2);
  1292.     FreeBitMap(bm);
  1293.     }
  1294.     return msg;
  1295. }
  1296.  
  1297. static PPCMsg* putimage24(DocData* dat,PPCMsg* msg,short x,short y,short w,short h) {
  1298.     UBYTE* pic;
  1299.     PPCReplyMessage(msg);
  1300.     PPCWaitPort(port);
  1301.     msg=PPCGetMessage(port);
  1302.     pic=(UBYTE*)PPCGetMessageAttr(msg,PPCMSGTAG_DATA);
  1303.     MyWritePixelArray(pic,0,0,w*3,&dat->rp,x,y,w,h,RECTFMT_RGB);
  1304.     return msg;
  1305. }
  1306.  
  1307. static PPCMsg* getimage24(DocData* dat,PPCMsg* msg,short x,short y,short w,short h) {
  1308.     UBYTE* pic;
  1309.     PPCReplyMessage(msg);
  1310.     PPCWaitPort(port);
  1311.     msg=PPCGetMessage(port);
  1312.     pic=(UBYTE*)PPCGetMessageAttr(msg,PPCMSGTAG_DATA);
  1313.     MyReadPixelArray(pic,0,0,w*3,&dat->rp,x,y,w,h,RECTFMT_RGB);
  1314.     return msg;
  1315. }
  1316.  
  1317. static PPCMsg* decode(DocData* dat,PPCMsg* msg,short* p,short* q) {
  1318.     while(p<q) {
  1319.     switch(*p++) {
  1320.       case AGFX_STARTPAGE:
  1321.         reset_pens(dat);
  1322.         SetRast(&dat->rp,get_pen(dat,1));
  1323.         SetAPen(&dat->rp,get_pen(dat,0));
  1324.         break;
  1325.       /*case AGFX_ENDPAGE:
  1326.         ***
  1327.         break;*/
  1328.       case AGFX_PENCOLOR: {
  1329.         ULONG r=((ULONG*)p)[0];
  1330.         ULONG g=((ULONG*)p)[1];
  1331.         ULONG b=((ULONG*)p)[2];
  1332.         p+=6;
  1333.         add_pen(dat,r,g,b);
  1334.         break;
  1335.       }
  1336.       case AGFX_SETAPEN:
  1337.         SetAPen(&dat->rp,get_pen(dat,*p++));
  1338.         break;
  1339.       case AGFX_OPENFONT:
  1340.         openfont(dat,*(int*)p,(const char*)(p+3),p[p[2]+3],p[p[2]+4]);
  1341.         p+=p[2]+5;
  1342.         break;
  1343.       case AGFX_CLOSEFONT:
  1344.         closefont(dat,*(int*)p);
  1345.         p+=2;
  1346.         break;
  1347.       case AGFX_SETFONT:
  1348.         setfont(dat,*(int*)p);
  1349.         p+=2;
  1350.         break;
  1351.       case AGFX_LINEPTRN:
  1352.         dat->rp.LinePtrn=*p++;
  1353.         dat->rp.linpatcnt=*p++;
  1354.         break;
  1355.       case AGFX_POLYDRAW:
  1356.         ++p;
  1357.         if(p[-1]) {
  1358.         clip_path(dat,p[-1],p);
  1359.         Move(&dat->rp,p[0],p[1]);
  1360.         PolyDraw(&dat->rp,p[-1]-1,p+2);
  1361.         }
  1362.         p+=p[-1]*2;
  1363.         break;
  1364.       case AGFX_ADDCHAR:
  1365.         clip_path(dat,1,p);
  1366.         Move(&dat->rp,p[0],p[1]);
  1367.         Text(&dat->rp,((char*)p)+5,1);
  1368.         p+=3;
  1369.         break;
  1370.       case AGFX_RECTFILL:
  1371.         clip_path(dat,2,p);
  1372.         RectFill(&dat->rp,p[0],p[1],p[2],p[3]);
  1373.         p+=4;
  1374.         break;
  1375.       case AGFX_INITAREA:
  1376.         initarea(&dat->rp,*p++);
  1377.         break;
  1378.       case AGFX_AREAPOLY:
  1379.         ++p;
  1380.         if(p[-1]) {
  1381.         clip_path(dat,p[-1],p);
  1382.         areapoly(&dat->rp,p[-1],p,0,0);
  1383.         }
  1384.         p+=p[-1]*2;
  1385.         break;
  1386.       case AGFX_AREAEND:
  1387.         areaend(&dat->rp);
  1388.         break;
  1389.       case AGFX_INITCLIP:
  1390.         init_clip(dat);
  1391.         break;
  1392.       case AGFX_POLYCLIP:
  1393.         ++p;
  1394.         poly_clip(dat,p[-1],p);
  1395.         p+=p[-1]*2;
  1396.         break;
  1397.       case AGFX_RECTCLIP:
  1398.         rect_clip(dat,p[0],p[1],p[2],p[3]);
  1399.         p+=4;
  1400.         break;
  1401.       case AGFX_INSTALLCLIP:
  1402.         install_clip(dat);
  1403.         break;
  1404.       case AGFX_GETCOLORS: {
  1405.         int num=*p++;
  1406.         ULONG* t;
  1407.         PPCReplyMessage(msg);
  1408.         PPCWaitPort(port);
  1409.         msg=PPCGetMessage(port);
  1410.         p=q=NULL;
  1411.         t=(ULONG*)PPCGetMessageAttr(msg,PPCMSGTAG_DATA);
  1412.         add_pens(dat,t,num);
  1413.         break;
  1414.       }
  1415.       case AGFX_IMAGE:
  1416.         clip_path(dat,1,p);
  1417.         msg=putimage(dat,msg,p[0],p[1],p[2],p[3]);
  1418.         p=q=NULL;
  1419.         break;
  1420.       case AGFX_IMAGE24:
  1421.         clip_path(dat,1,p);
  1422.         msg=putimage24(dat,msg,p[0],p[1],p[2],p[3]);
  1423.         p=q=NULL;
  1424.         break;
  1425.       case AGFX_GETIMAGE:
  1426.         clip_path(dat,1,p);
  1427.         msg=getimage(dat,msg,p[0],p[1],p[2],p[3]);
  1428.         p=q=NULL;
  1429.         break;
  1430.       case AGFX_GETIMAGE24:
  1431.         clip_path(dat,1,p);
  1432.         msg=getimage24(dat,msg,p[0],p[1],p[2],p[3]);
  1433.         p=q=NULL;
  1434.         break;
  1435.       default:
  1436.         MYASSERT(FALSE);
  1437.         break;
  1438.     }
  1439.     }
  1440.     return msg;
  1441. }
  1442.  
  1443. static void show_page(DocData* dat,int page,int zoom) {
  1444.     if(!quitting && !ppc_quitted && dat->rp.BitMap) {
  1445.     struct msg_page* p=(struct msg_page*)cmddata;
  1446.  
  1447.     p->page_num=page;
  1448.     p->zoom=zoom;
  1449.     PPCSendMessage(ppcport,cmdmsg,p,sizeof(*p),MSGID_PAGE);
  1450.  
  1451.     while(1) {
  1452.         PPCMsg* msg;
  1453.  
  1454.         PPCWaitPortList(portlist);
  1455.  
  1456.         while(msg=PPCGetMessage(port)) {
  1457.         switch(PPCGetMessageAttr(msg,PPCMSGTAG_MSGID)) {
  1458. #ifdef USE_GFX_PIPE
  1459.           case MSGID_GFXPIPE: {
  1460.             volatile struct GfxPipe *pipe=(volatile struct GfxPipe *)PPCGetMessageAttr(msg,PPCMSGTAG_DATA);
  1461.             short* p=pipe->readp;
  1462.             while(!pipe->done) {
  1463.             short* q=pipe->writep;
  1464.             if(p<q) {
  1465.                 msg=decode(dat,msg,p,q);
  1466.                 p=q;
  1467.                 pipe->readp=q;
  1468.             }
  1469.             }
  1470.             msg=decode(dat,msg,p,pipe->writep);
  1471.             break;
  1472.           }
  1473. #endif
  1474.           case MSGID_GFX: {
  1475.             short* p=(short*)PPCGetMessageAttr(msg,PPCMSGTAG_DATA);
  1476.             short* q=p+PPCGetMessageAttr(msg,PPCMSGTAG_DATALENGTH)/2;
  1477.             msg=decode(dat,msg,p,q);
  1478.             break;
  1479.           }
  1480.  
  1481.           default:
  1482.             MYASSERT(FALSE);
  1483.             break;
  1484.         }
  1485.         WaitBlit();
  1486.         PPCReplyMessage(msg);
  1487.         }
  1488.         if(msg=PPCGetMessage(reply_port)) {
  1489.         if(msg==startupmsg)   // should not happen, but if the user
  1490.             ppc_quitted=TRUE; // kills the ppc task for some reason,
  1491.                       // this helps cleanup a bit.
  1492.         else {
  1493.             MYASSERT(msg==cmdmsg);
  1494.         }
  1495.         break;
  1496.         }
  1497.     }
  1498.     }
  1499. }
  1500. #else
  1501. int get_info(int* num_pages);
  1502. int get_page_size(int page,int* width,int* height);
  1503. int create_doc(BPTR,const char* filename,size_t,size_t);
  1504. int create_output_dev(int depth,struct ColorMap* colormap);
  1505. void delete_output_dev(void);
  1506. int simple_find(const char* str,int top,int* xmin,int* ymin,int* xmax,int* ymax);
  1507. int init_find(const char* str);
  1508. int find(int start,int stop,int* xmin,int* ymin,int* xmax,int* ymax,int* page);
  1509. void end_find(void);
  1510. int chklink(int x,int y,void** action,char* str,size_t len);
  1511. int dolink(int* x,int* y,int* state,int* page,char* buf,size_t len);
  1512. int init_file(const char* filename,int first_page,int last_page,int zoom,int rotate,int type);
  1513. void writefile(int first_page,int last_page);
  1514. void end_write(void);
  1515. char* gettext(int xmin,int ymin,int xmax,int ymax);
  1516. int show_page(int page,int zoom);
  1517. int init(int,const char*);
  1518. void add_fontmap(const char*,const char*,int,int,int);
  1519. /*void rem_fontmap(const char*);*/
  1520. void clear_fontmap(void);
  1521. /*void set_fontmap(void);*/
  1522. int init_scan(void);
  1523. int scan_fonts(int,int);
  1524. int scan_default_fonts(void);
  1525. void end_scan_fonts(void);
  1526. int get_font(int,char*,int,char*,int,int*,int*,int*);
  1527.  
  1528. #endif
  1529.  
  1530. static BOOL setbitmap(DocData*);
  1531.  
  1532. static void display_page(DocData* dat) {
  1533.     if(dat->last_page!=dat->page ||
  1534.        dat->last_zoom!=dat->zoom) {
  1535.     if(dat->last_width!=dat->width || dat->last_height!=dat->height)
  1536.         setbitmap(dat);
  1537.     if(dat->rp.BitMap) {
  1538.         sleep(TRUE);
  1539.         dat->selected=FALSE;
  1540.  
  1541. #ifdef POWERUP
  1542.         show_page(dat,dat->page,zoomDPI[dat->zoom-minZoom]);
  1543. #else
  1544.         show_page(dat->page,zoomDPI[dat->zoom-minZoom]);
  1545. #endif
  1546.         tfr_clip(dat);
  1547.         clear_clip(dat);
  1548.         dat->last_page=dat->page;
  1549.         dat->last_zoom=dat->zoom;
  1550.         sleep(FALSE);
  1551.     }
  1552.     }
  1553. }
  1554.  
  1555. static void search(const char* str) {
  1556.     struct Rectangle rect;
  1557.     int pg,pages;
  1558.     int page,top,bottom,xmin,ymin,xmax,ymax;
  1559.     BOOL found=FALSE;
  1560.     get(bitmapobj,MYATTR_Page,&page);
  1561.     get(bitmapobj,MYATTR_Selection,&rect);
  1562.     bottom=0;
  1563.  
  1564.     if(rect.MinX==-1)
  1565.     top=1;
  1566.     else {
  1567.     top=0;
  1568.     xmin=rect.MaxX;
  1569.     ymin=(rect.MinY+rect.MaxY)/2;
  1570.     xmax=0;
  1571.     ymax=0;
  1572.     if(simple_find(str,top,&xmin,&ymin,&xmax,&ymax))
  1573.         found=TRUE;
  1574.     }
  1575.     if(!found) {
  1576.     int k,l=0;
  1577.     struct List* winlist;
  1578.     Object* o;
  1579.     struct Node* state;
  1580.     ULONG sigs=0;
  1581.     get(pageobj,MUIA_Numeric_Max,&pages);
  1582.     get(App,MUIA_Application_WindowList,&winlist);
  1583.     for(state=winlist->lh_Head;o=NextObject(&state);)
  1584.         if(o!=gaugewin)
  1585.         set(o,MUIA_Window_Sleep,TRUE);
  1586.     SetAttrs(gaugeobj,
  1587.          MUIA_Gauge_Current,0,
  1588.          MUIA_Gauge_Max,pages,
  1589.          TAG_END);
  1590.     SetAttrs(gaugewin,
  1591.          MUIA_Window_Title,"Searching...",
  1592.          MUIA_Window_Open,TRUE,
  1593.          TAG_END);
  1594.     pg=page;
  1595.     if(init_find(str)) {
  1596.         LONG r=0;
  1597.         for(k=pg+1;k<=pages;++k) {
  1598.         if(find(k,k+1,&xmin,&ymin,&xmax,&ymax,&page)) {
  1599.             found=TRUE;
  1600.             break;
  1601.         }
  1602.         set(gaugeobj,MUIA_Gauge_Current,++l);
  1603.         r=DoMethod(App,MUIM_Application_NewInput,&sigs);
  1604.         if(r==MUIV_Application_ReturnID_Quit ||
  1605.            r==ID_ABORT)
  1606.            break;
  1607.         }
  1608.         if(!found && r!=ID_ABORT && r!=MUIV_Application_ReturnID_Quit) {
  1609.         for(k=1;k<pg;++k) {
  1610.             if(find(k,k+1,&xmin,&ymin,&xmax,&ymax,&page)) {
  1611.             found=TRUE;
  1612.             break;
  1613.             }
  1614.             set(gaugeobj,MUIA_Gauge_Current,++l);
  1615.             r=DoMethod(App,MUIM_Application_NewInput,&sigs);
  1616.             if(r==MUIV_Application_ReturnID_Quit ||
  1617.                r==ID_ABORT)
  1618.             break;
  1619.         }
  1620.         }
  1621.         end_find();
  1622.     }
  1623.     if(found) {
  1624.         set(pageobj,MYATTR_Value,page);
  1625.         simple_find(str,TRUE,&xmin,&ymin,&xmax,&ymax);
  1626.     }
  1627.     set(gaugewin,MUIA_Window_Open,FALSE);
  1628.     get(App,MUIA_Application_WindowList,&winlist);
  1629.     for(state=winlist->lh_Head;o=NextObject(&state);)
  1630.         if(o!=gaugewin)
  1631.         set(o,MUIA_Window_Sleep,FALSE);
  1632.     }
  1633.     if(found) {
  1634.     LONG left,width,top,height,t;
  1635.     rect.MinX=xmin;
  1636.     rect.MinY=ymin;
  1637.     rect.MaxX=xmax;
  1638.     rect.MaxY=ymax;
  1639.     set(bitmapobj,MYATTR_Selection,&rect);
  1640.     xmin+=bleft;
  1641.     ymin+=btop;
  1642.     xmax+=bleft;
  1643.     ymax+=btop;
  1644.     get(vgroup,MUIA_Width,&width);
  1645.     get(vgroup,MUIA_InnerRight,&t);
  1646.     width-=t;
  1647.     get(vgroup,MUIA_InnerLeft,&t);
  1648.     width-=t;
  1649.     get(vgroup,MUIA_Height,&height);
  1650.     get(vgroup,MUIA_InnerBottom,&t);
  1651.     height-=t;
  1652.     get(vgroup,MUIA_InnerTop,&t);
  1653.     height-=t;
  1654.     get(vgroup,MUIA_Virtgroup_Left,&left);
  1655.     get(vgroup,MUIA_Virtgroup_Top,&top);
  1656.     if(xmin<left)
  1657.         left=xmin;
  1658.     else if(xmax>left+width)
  1659.         left=xmax-width;
  1660.     if(ymin<top)
  1661.         top=ymin;
  1662.     else if(ymax>top+height)
  1663.         top=ymax-height;
  1664.     SetAttrs(vgroup,
  1665.          MUIA_Virtgroup_Left,left,
  1666.          MUIA_Virtgroup_Top,top,
  1667.          TAG_END);
  1668.     } else {
  1669.     set(pageobj,MYATTR_Selection,NULL);
  1670.     set(linkobj,MUIA_Text_Contents,"Not found");
  1671.     }
  1672. }
  1673.  
  1674. static void save(const char* filename,int first_page,int last_page,int zoom,int rotate,int type) {
  1675.     int k,l=0;
  1676.     struct List* winlist;
  1677.     Object* o;
  1678.     struct Node* state;
  1679.     ULONG sigs=0;
  1680.     get(App,MUIA_Application_WindowList,&winlist);
  1681.     for(state=winlist->lh_Head;o=NextObject(&state);)
  1682.     if(o!=gaugewin)
  1683.         set(o,MUIA_Window_Sleep,TRUE);
  1684.     SetAttrs(gaugeobj,
  1685.          MUIA_Gauge_Current,0,
  1686.          MUIA_Gauge_Max,last_page-first_page+1,
  1687.          TAG_END);
  1688.     SetAttrs(gaugewin,
  1689.          MUIA_Window_Title,"Saving...",
  1690.          MUIA_Window_Open,TRUE,
  1691.          TAG_END);
  1692.     if(init_write(filename,first_page,last_page,zoom,rotate,type)) {
  1693.     LONG r;
  1694.     for(k=first_page;k<=last_page;++k) {
  1695.         writefile(k,k+1);
  1696.         set(gaugeobj,MUIA_Gauge_Current,++l);
  1697.         r=DoMethod(App,MUIM_Application_NewInput,&sigs);
  1698.         if(r==MUIV_Application_ReturnID_Quit ||
  1699.            r==ID_ABORT)
  1700.         break;
  1701.     }
  1702.     end_write();
  1703.     } else
  1704.     set(linkobj,MUIA_Text_Contents,"Failed...");
  1705.     set(gaugewin,MUIA_Window_Open,FALSE);
  1706.     get(App,MUIA_Application_WindowList,&winlist);
  1707.     for(state=winlist->lh_Head;o=NextObject(&state);)
  1708.     if(o!=gaugewin)
  1709.         set(o,MUIA_Window_Sleep,FALSE);
  1710. }
  1711.  
  1712. static int scan_doc_fonts(int first_page,int last_page) {
  1713.     int k,l=0;
  1714.     struct List* winlist;
  1715.     Object* o;
  1716.     struct Node* state;
  1717.     ULONG sigs=0;
  1718.     int ret=0;
  1719.     get(App,MUIA_Application_WindowList,&winlist);
  1720.     for(state=winlist->lh_Head;o=NextObject(&state);)
  1721.     if(o!=gaugewin)
  1722.         set(o,MUIA_Window_Sleep,TRUE);
  1723.     SetAttrs(gaugeobj,
  1724.          MUIA_Gauge_Current,0,
  1725.          MUIA_Gauge_Max,last_page-first_page+1,
  1726.          TAG_END);
  1727.     SetAttrs(gaugewin,
  1728.          MUIA_Window_Title,"Scanning...",
  1729.          MUIA_Window_Open,TRUE,
  1730.          TAG_END);
  1731.     if(init_scan()) {
  1732.     LONG r;
  1733.     for(k=first_page;k<=last_page;++k) {
  1734.         ret=scan_fonts(k,k+1);
  1735.         set(gaugeobj,MUIA_Gauge_Current,++l);
  1736.         r=DoMethod(App,MUIM_Application_NewInput,&sigs);
  1737.         if(r==MUIV_Application_ReturnID_Quit ||
  1738.            r==ID_ABORT)
  1739.         break;
  1740.     }
  1741.     if(!ret)
  1742.         end_scan_fonts();
  1743.     }
  1744.     set(gaugewin,MUIA_Window_Open,FALSE);
  1745.     get(App,MUIA_Application_WindowList,&winlist);
  1746.     for(state=winlist->lh_Head;o=NextObject(&state);)
  1747.     if(o!=gaugewin)
  1748.         set(o,MUIA_Window_Sleep,FALSE);
  1749.     return ret;
  1750. }
  1751.  
  1752. static void check_link(int x,int y) {
  1753.     static void* last_action;
  1754.     void* action=last_action;
  1755.     char str[256];
  1756.     if(chklink(x,y,&action,str,sizeof(str))) {
  1757.     if(action!=last_action) {
  1758.         last_action=action;
  1759.         set(linkobj,MUIA_Text_Contents,str);
  1760.     }
  1761.     } else if(last_action) {
  1762.     last_action=NULL;
  1763.     set(linkobj,MUIA_Text_Contents,NULL);
  1764.     }
  1765. }
  1766.  
  1767. static void get_page_info(void) {
  1768.     int num_pages;
  1769.     get_info(&num_pages);
  1770.     SetAttrs(bitmapobj,
  1771.          MYATTR_Zoom,defZoom,
  1772.          MYATTR_NumPages,num_pages,
  1773.          MYATTR_Page,1,
  1774.          MYATTR_NewDoc,TRUE,
  1775.          TAG_END);
  1776.     SetAttrs(pageobj,
  1777.          MUIA_Numeric_Max,num_pages,
  1778.          MYATTR_Value,1,
  1779.          TAG_END);
  1780.     set(psstartobj,MUIA_Numeric_Max,num_pages);
  1781.     set(psstopobj,MUIA_Numeric_Max,num_pages);
  1782.     set(scanstartobj,MUIA_Numeric_Max,num_pages);
  1783.     set(scanstopobj,MUIA_Numeric_Max,num_pages);
  1784.     set(zoomobj,MYATTR_Value,defZoom);
  1785. }
  1786.  
  1787. static int do_link(int x,int y) {
  1788.     int state,page,r;
  1789.     char buf[256];
  1790.     if(r=dolink(&x,&y,&state,&page,buf,sizeof(buf))) {
  1791.     switch(state) {
  1792.       case st_changed:
  1793.         copystr(&docname,buf);
  1794.         get_page_info();
  1795.         /* fall through */
  1796.       case st_unchanged:
  1797.         if(page!=-1)
  1798.         set(pageobj,MYATTR_Value,page);
  1799.         set(linkobj,MUIA_Text_Contents,NULL);
  1800.         break;
  1801.  
  1802.       case st_run:
  1803.         if(MUI_Request(App,win,0,"Execute command ?","Ok|Cancel",buf))
  1804.         system(buf);
  1805.         break;
  1806.  
  1807.       case st_url:
  1808.         if(URLCMD) {
  1809.         char buf2[256];
  1810.         buf2[0]='r';
  1811.         buf2[1]='u';
  1812.         buf2[2]='n';
  1813.         buf2[3]=' ';
  1814.         sprintf(buf2+4,URLCMD,buf);
  1815.         system(buf2);
  1816.         }
  1817.         break;
  1818.     }
  1819.     if(x!=-1 || y!=-1)
  1820.         SetAttrs(vgroup,
  1821.              x==-1?TAG_IGNORE:MUIA_Virtgroup_Left,x,
  1822.              y==-1?TAG_IGNORE:MUIA_Virtgroup_Top,y,
  1823.              TAG_END);
  1824.     }
  1825.     return r;
  1826. }
  1827.  
  1828. static void toclip(int x1,int y1,int x2,int y2) {
  1829.     char* txt;
  1830.     if(x1>x2) {
  1831.     int t=x1;
  1832.     x1=x2;
  1833.     x2=t;
  1834.     }
  1835.     if(y1>y2) {
  1836.     int t=y1;
  1837.     y1=y2;
  1838.     y2=t;
  1839.     }
  1840.     if(txt=gettext(x1,y1,x2,y2)) {
  1841.     struct IFFHandle *iff;
  1842.     if(iff=AllocIFF()) {
  1843.         if(iff->iff_Stream=(ULONG)OpenClipboard(PRIMARY_CLIP)) {
  1844.         size_t sz=strlen(txt);
  1845.         InitIFFasClip(iff);
  1846.         if(!OpenIFF(iff,IFFF_WRITE)) {
  1847.            if(PushChunk(iff,ID_FTXT,ID_FORM,IFFSIZE_UNKNOWN) ||
  1848.               PushChunk(iff,0,ID_CHRS,sz) ||
  1849.               WriteChunkBytes(iff,txt,sz)!=sz ||
  1850.               PopChunk(iff) ||
  1851.               PopChunk(iff))
  1852.                printf("Error writing to clipboard.\n");
  1853.            CloseIFF(iff);
  1854.         }
  1855.         CloseClipboard((struct ClipboardHandle *)iff->iff_Stream);
  1856.         }
  1857.         FreeIFF(iff);
  1858.     }
  1859.     free(txt);
  1860.     }
  1861. }
  1862.  
  1863.  
  1864. static void clearbitmap(DocData* dat) {
  1865.     dat->rp.BitMap=NULL;
  1866.     dat->rp.Layer=NULL;
  1867.     if(dat->region) {
  1868.     InstallClipRegion(dat->layer,NULL);
  1869.     DisposeRegion(dat->region);
  1870.     dat->region=NULL;
  1871.     }
  1872.     if(dat->layer) {
  1873.     DeleteLayer(0,dat->layer);
  1874.     dat->layer=NULL;
  1875.     }
  1876.     if(dat->layerinfo) {
  1877.     DisposeLayerInfo(dat->layerinfo);
  1878.     dat->layerinfo=NULL;
  1879.     }
  1880.     WaitBlit();
  1881.     FreeBitMap(dat->bm);
  1882.     dat->bm=NULL;
  1883. }
  1884.  
  1885. static BOOL setbitmap(DocData* dat) {
  1886.     if(!dat->hidden && (!dat->bm ||
  1887.             dat->width!=dat->last_width ||
  1888.             dat->height!=dat->last_height)) {
  1889.     clearbitmap(dat);
  1890.     dat->last_width=dat->width;
  1891.     dat->last_height=dat->height;
  1892.  
  1893.     if(dat->bm=AllocBitMap(dat->width,dat->height,dat->depth,BMF_MINPLANES,dat->friendbm)) {
  1894.         dat->dx=0;
  1895.         dat->dy=0;
  1896.         if((dat->layerinfo=NewLayerInfo()) &&
  1897.            (dat->layer=CreateUpfrontLayer(dat->layerinfo,dat->bm,0,0,dat->width-1,dat->height-1,LAYERSIMPLE,NULL)) &&
  1898.            (dat->region=NewRegion())) {
  1899.         struct Rectangle rect;
  1900.         rect.MinX=0;
  1901.         rect.MinY=0;
  1902.         rect.MaxX=dat->width-1;
  1903.         rect.MaxY=dat->height-1;
  1904.         if(OrRectRegion(dat->region,&rect)) {
  1905.             InstallClipRegion(dat->layer,dat->region);
  1906.             dat->rp.Layer=dat->layer;
  1907.             dat->rp.BitMap=dat->bm;
  1908.             return TRUE;
  1909.         }
  1910.         }
  1911.         printf("Can't install clipping region.\n");
  1912.     } else
  1913.         printf("Can't alloc bitmap.\n");
  1914.     clearbitmap(dat);
  1915.     return FALSE;
  1916.     }
  1917.     return TRUE;
  1918. }
  1919.  
  1920. #define DocObject NewObject(mcc->mcc_Class,NULL
  1921.  
  1922. static ULONG mNew(struct IClass *cl,Object *obj,Msg msg) {
  1923.     DocData* dat;
  1924.  
  1925.     if(obj=(Object *)DoSuperMethodA(cl,obj,msg)) {
  1926.     dat=INST_DATA(cl,obj);
  1927.     memset(dat,0,sizeof(*dat));
  1928.     InitRastPort(&dat->rp);
  1929.     SetDrMd(&dat->rp,JAM1);
  1930.     dat->hidden=TRUE;
  1931.     dat->last_page=-1;
  1932.     dat->obj=obj;
  1933.     set(obj,MUIA_FillArea,FALSE);
  1934.     }
  1935.     return (ULONG)obj;
  1936. }
  1937.  
  1938. static ULONG mDispose(struct IClass *cl,Object *obj,Msg msg) {
  1939.     DocData* dat=INST_DATA(cl,obj);
  1940.     free(dat->pens);
  1941.     clear_fonts(dat);
  1942.     return DoSuperMethodA(cl,obj,msg);
  1943. }
  1944.  
  1945. static ULONG mSet(struct IClass *cl,Object *obj,struct opSet *msg) {
  1946.     DocData *dat=INST_DATA(cl,obj);
  1947.     struct TagItem *tags=msg->ops_AttrList;
  1948.     struct TagItem *tag;
  1949.     BOOL redraw=FALSE;
  1950.     while(tag=NextTagItem(&tags)) {
  1951.     switch(tag->ti_Tag) {
  1952.       case MYATTR_NumPages:
  1953.         dat->num_pages=(int)tag->ti_Data;
  1954.         break;
  1955.  
  1956.       case MYATTR_Page:
  1957.         if(dat->page!=(int)tag->ti_Data) {
  1958.         dat->page=(int)tag->ti_Data;
  1959.         if(dat->page<1)
  1960.             dat->page=1;
  1961.         else if(dat->page>dat->num_pages)
  1962.             dat->page=dat->num_pages;
  1963.         redraw=TRUE;
  1964.         set(vgroup,MUIA_Virtgroup_Top,0);
  1965.         }
  1966.         break;
  1967.  
  1968.       case MYATTR_Zoom:
  1969.         if(dat->zoom!=(int)tag->ti_Data) {
  1970.         dat->zoom=(int)tag->ti_Data;
  1971.         redraw=TRUE;
  1972.         }
  1973.         break;
  1974.  
  1975.       case MYATTR_Selection:
  1976.         if(tag->ti_Data) {
  1977.         dat->selection=*(struct Rectangle*)tag->ti_Data;
  1978.         dat->selected=TRUE;
  1979.         redraw=TRUE;
  1980.         } else if(dat->selected) {
  1981.         dat->selected=FALSE;
  1982.         redraw=TRUE;
  1983.         }
  1984.         break;
  1985.       case MYATTR_NewDoc:
  1986.         dat->last_page=-1;
  1987.         dat->last_zoom=-1;
  1988.         redraw=TRUE;
  1989.         break;
  1990.     }
  1991.     }
  1992.     if(redraw) {
  1993.     if(get_page_size(dat->page,&dat->page_width,&dat->page_height)) {
  1994.         dat->width=(dat->page_width*zoomDPI[dat->zoom-minZoom])/72;
  1995.         dat->height=(dat->page_height*zoomDPI[dat->zoom-minZoom])/72;
  1996.         if(dat->width!=dat->last_width || dat->height!=dat->last_height) {
  1997.         DoMethod(vgroup,MUIM_Group_InitChange);
  1998.         DoMethod(vgroup,MUIM_Group_ExitChange);
  1999.         } else
  2000.         MUI_Redraw(obj,MADF_DRAWOBJECT);
  2001.     }
  2002.     }
  2003.     return DoSuperMethodA(cl,obj,(Msg)msg);
  2004. }
  2005.  
  2006.  
  2007. static ULONG mGet(struct IClass *cl,Object *obj,struct opGet *msg) {
  2008.     DocData* dat=INST_DATA(cl,obj);
  2009.     switch(msg->opg_AttrID) {
  2010.       case MYATTR_Page:
  2011.     *msg->opg_Storage=dat->page;
  2012.     return TRUE;
  2013.       case MYATTR_Selected:
  2014.     *msg->opg_Storage=dat->selected;
  2015.     break;
  2016.       case MYATTR_Selection:
  2017.     *(struct Rectangle*)msg->opg_Storage=dat->selection;
  2018.     return TRUE;
  2019.     }
  2020.     return DoSuperMethodA(cl,obj,(Msg)msg);
  2021. }
  2022.  
  2023. static ULONG mSetup(struct IClass *cl,Object *obj,Msg msg) {
  2024.     DocData* dat=INST_DATA(cl,obj);
  2025.  
  2026.     if(!DoSuperMethodA(cl,obj,(Msg)msg))
  2027.     return FALSE;
  2028.  
  2029.     dat->colormap=_screen(obj)->ViewPort.ColorMap;
  2030.     dat->depth=GetBitMapAttr(_screen(obj)->RastPort.BitMap,BMA_DEPTH);
  2031.     if(dat->depth>8 && !CyberGfxBase)
  2032.     dat->depth=8;
  2033.     sleep(TRUE);
  2034.     create_output_dev(dat->depth,dat->colormap);
  2035.     sleep(FALSE);
  2036.     dat->friendbm=_screen(obj)->RastPort.BitMap;
  2037.     dat->hidden=FALSE;
  2038.     dat->selected=FALSE;
  2039.     dat->selecting=FALSE;
  2040.     setbitmap(dat);
  2041.     MUI_RequestIDCMP(obj,IDCMP_MOUSEMOVE|IDCMP_MOUSEBUTTONS|IDCMP_VANILLAKEY|IDCMP_RAWKEY);
  2042.     return TRUE;
  2043. }
  2044.  
  2045. static ULONG mCleanup(struct IClass *cl,Object *obj,Msg msg) {
  2046.     DocData* dat=INST_DATA(cl,obj);
  2047.     MUI_RejectIDCMP(obj,IDCMP_MOUSEMOVE|IDCMP_MOUSEBUTTONS|IDCMP_VANILLAKEY|IDCMP_RAWKEY);
  2048.     clearbitmap(dat);
  2049.     clear_pens(dat);
  2050.     dat->hidden=TRUE;
  2051.     delete_output_dev();
  2052.     dat->last_page=-1;
  2053.     clear_fonts(dat);
  2054.     return DoSuperMethodA(cl,obj,msg);
  2055. }
  2056.  
  2057. static ULONG mReset(struct IClass *cl,Object *obj,Msg msg) {
  2058.     DocData* dat=INST_DATA(cl,obj);
  2059.     if(!dat->hidden) {
  2060.     sleep(TRUE);
  2061.     delete_output_dev();
  2062.     dat->last_page=-1;
  2063.     clear_fonts(dat);
  2064.     create_output_dev(dat->depth,dat->colormap);
  2065.     MUI_Redraw(obj,MADF_DRAWOBJECT);
  2066.     sleep(FALSE);
  2067.     }
  2068.     return 0;
  2069. }
  2070.  
  2071. static ULONG mAskMinMax(struct IClass *cl,Object *obj,struct MUIP_AskMinMax *msg) {
  2072.     DocData* dat=INST_DATA(cl,obj);
  2073.     int w=dat->width+bright+bleft;
  2074.     int h=dat->height+bbottom+btop;
  2075.     DoSuperMethodA(cl,obj,(Msg)msg);
  2076.     msg->MinMaxInfo->MinWidth+=w;
  2077.     msg->MinMaxInfo->DefWidth+=w;
  2078.     msg->MinMaxInfo->MaxWidth+=MUI_MAXMAX;
  2079.     msg->MinMaxInfo->MinHeight+=h;
  2080.     msg->MinMaxInfo->DefHeight+=h;
  2081.     msg->MinMaxInfo->MaxHeight+=MUI_MAXMAX;
  2082.     return 0;
  2083. }
  2084.  
  2085. static ULONG mDraw(struct IClass *cl,Object *obj,struct MUIP_Draw *msg) {
  2086.     DocData* dat=INST_DATA(cl,obj);
  2087.     int x,y,w,h;
  2088.     struct RastPort *rp;
  2089.     DoSuperMethodA(cl,obj,(Msg)msg);
  2090.     x=_mleft(obj);
  2091.     y=_mtop(obj);
  2092.     w=_mwidth(obj);
  2093.     h=_mheight(obj);
  2094.     rp=_rp(obj);
  2095.     if(dat->bm) {
  2096.     if(msg->flags&MADF_DRAWOBJECT) {
  2097.         display_page(dat);
  2098.         if(w>dat->width+2 || h>dat->height+2) {
  2099.         int h1=(h-dat->height-2)/2;
  2100.         int h2=h-dat->height-h1;
  2101.         int w1=(w-dat->width-2)/2;
  2102.         int w2=w-dat->width-w1;
  2103.         h-=h1+h2;
  2104.         if(h1)
  2105.             DoMethod(obj,MUIM_DrawBackground,x,y,w,h1,0);
  2106.         if(h2)
  2107.             DoMethod(obj,MUIM_DrawBackground,x,y+h1+h,w,h2,0);
  2108.         w-=w1+w2;
  2109.         y+=h1;
  2110.         if(w1)
  2111.             DoMethod(obj,MUIM_DrawBackground,x,y,w1,h,0);
  2112.         if(w2)
  2113.             DoMethod(obj,MUIM_DrawBackground,x+w1+w,y,w2,h,0);
  2114.         x+=w1;
  2115.         }
  2116.         if(w && h) {
  2117.         SetAPen(rp,_dri(obj)->dri_Pens[SHINEPEN]);
  2118.         Move(rp,x,y+h-1);
  2119.         Draw(rp,x,y);
  2120.         Draw(rp,x+w-1,y);
  2121.         if(w>1 && h>1) {
  2122.             SetAPen(rp,_dri(obj)->dri_Pens[SHADOWPEN]);
  2123.             Move(rp,x+w-1,y+1);
  2124.             Draw(rp,x+w-1,y+h-1);
  2125.             Draw(rp,x+1,y+h-1);
  2126.             if(w>2 && h>2)
  2127.             BltBitMapRastPort(dat->bm,0,0,rp,x+1,y+1,w-2,h-2,0xc0);
  2128.         }
  2129.         }
  2130.     } else if(msg->flags&MADF_DRAWUPDATE) {
  2131.         x+=(w-dat->width-2)/2;
  2132.         w=dat->width-2;
  2133.         y+=(h-dat->height-2)/2;
  2134.         h=dat->height-2;
  2135.         if(dat->select_displayed) {
  2136.         int x1=dat->old_selection.MinX;
  2137.         int y1=dat->old_selection.MinY;
  2138.         int x2=dat->old_selection.MaxX;
  2139.         int y2=dat->old_selection.MaxY;
  2140.         if(x1>x2) {
  2141.             int t=x2;
  2142.             x2=x1;
  2143.             x1=t;
  2144.         }
  2145.         if(y1>y2) {
  2146.             int t=y2;
  2147.             y2=y1;
  2148.             y1=t;
  2149.         }
  2150.         if(x1>=0 && x1<w && y2>=0 && y1<h) {
  2151.             int y3=y1<0?0:y1;
  2152.             int y4=y2>=h?h-1:y2;
  2153.             BltBitMapRastPort(dat->bm,x1,y3,rp,x+1+x1,y+1+y3,1,y4-y3+1,0xc0);
  2154.             if(x1<0)
  2155.             x1=0;
  2156.         }
  2157.         if(x2>=0 && x2<w && y2>=0 && y1<h) {
  2158.             int y3=y1<0?0:y1;
  2159.             int y4=y2>=h?h-1:y2;
  2160.             BltBitMapRastPort(dat->bm,x2,y3,rp,x+1+x2,y+1+y3,1,y4-y3+1,0xc0);
  2161.             if(x2>=w)
  2162.             x2=w-1;
  2163.         }
  2164.         if(y1>=0 && y1<h)
  2165.             BltBitMapRastPort(dat->bm,x1,y1,rp,x+1+x1,y+1+y1,x2-x1+1,1,0xc0);
  2166.         if(y2>=0 && y2<h)
  2167.             BltBitMapRastPort(dat->bm,x1,y2,rp,x+1+x1,y+1+y2,x2-x1+1,1,0xc0);
  2168.         }
  2169.     }
  2170.     if(msg->flags&(MADF_DRAWOBJECT|MADF_DRAWUPDATE)) {
  2171.         dat->select_displayed=dat->selected || dat->selecting;
  2172.         if(dat->select_displayed) {
  2173.         SetAPen(rp,_dri(obj)->dri_Pens[FILLPEN]);
  2174.         Move(rp,x+dat->selection.MinX+bleft,y+dat->selection.MinY+btop);
  2175.         Draw(rp,x+dat->selection.MinX+bleft,y+dat->selection.MaxY+btop);
  2176.         Draw(rp,x+dat->selection.MaxX+bleft,y+dat->selection.MaxY+btop);
  2177.         Draw(rp,x+dat->selection.MaxX+bleft,y+dat->selection.MinY+btop);
  2178.         Draw(rp,x+dat->selection.MinX+bleft,y+dat->selection.MinY+btop);
  2179.         dat->old_selection=dat->selection;
  2180.         }
  2181.     }
  2182.     } else if(w && h) {
  2183.     EraseRect(_rp(obj),x,y,x+w-1,y+h-1);
  2184.     }
  2185.     return 0;
  2186. }
  2187.  
  2188. static void upkey(void) {
  2189.     LONG top,height,totheight,t;
  2190.     get(vgroup,MUIA_Virtgroup_Height,&totheight);
  2191.     get(vgroup,MUIA_Virtgroup_Top,&top);
  2192.     get(vgroup,MUIA_Height,&height);
  2193.     get(vgroup,MUIA_InnerBottom,&t);
  2194.     height-=t;
  2195.     get(vgroup,MUIA_InnerTop,&t);
  2196.     height-=t;
  2197.     if(top>0)
  2198.     set(vgroup,MUIA_Virtgroup_Top,top-height+10);
  2199.     else {
  2200.     DoMethod(pageobj,MUIM_Numeric_Decrease,1);
  2201.     set(vgroup,MUIA_Virtgroup_Top,totheight-height);
  2202.     }
  2203. }
  2204.  
  2205. static void downkey(void) {
  2206.     LONG top,height,totheight,t;
  2207.     get(vgroup,MUIA_Virtgroup_Height,&totheight);
  2208.     get(vgroup,MUIA_Virtgroup_Top,&top);
  2209.     get(vgroup,MUIA_Height,&height);
  2210.     get(vgroup,MUIA_InnerBottom,&t);
  2211.     height-=t;
  2212.     get(vgroup,MUIA_InnerTop,&t);
  2213.     height-=t;
  2214.     if(top<totheight-height)
  2215.     set(vgroup,MUIA_Virtgroup_Top,top+height-10);
  2216.     else {
  2217.     DoMethod(pageobj,MUIM_Numeric_Increase,1);
  2218.     set(vgroup,MUIA_Virtgroup_Top,0);
  2219.     }
  2220. }
  2221.  
  2222. static ULONG mHandleInput(struct IClass *cl,Object *obj,struct MUIP_HandleInput *msg) {
  2223.     DocData* dat=INST_DATA(cl,obj);
  2224.     int x=_mleft(obj);
  2225.     int y=_mtop(obj);
  2226.     int w=_mwidth(obj);
  2227.     int h=_mheight(obj);
  2228.     x+=(w-dat->width-bleft-bright)/2+bleft;
  2229.     w=dat->width-bleft-bright;
  2230.     y+=(h-dat->height-btop-bbottom)/2+btop;
  2231.     h=dat->height-btop-bbottom;
  2232.  
  2233.     #define _between(a,x,b) ((x)>=(a) && (x)<(b))
  2234.     #define _isinobject(u,v) (_between(x,(u),x+w) && _between(y,(v),y+h))
  2235.  
  2236.     if(msg->imsg) {
  2237.     switch(msg->imsg->Class) {
  2238.       case IDCMP_MOUSEBUTTONS:
  2239.         if(msg->imsg->Code==SELECTDOWN) {
  2240.         if(_isinobject(msg->imsg->MouseX,msg->imsg->MouseY)) {
  2241.             dat->selection.MinX=msg->imsg->MouseX-x;
  2242.             dat->selection.MinY=msg->imsg->MouseY-y;
  2243.             dat->selection.MaxX=dat->selection.MinX;
  2244.             dat->selection.MaxY=dat->selection.MinY;
  2245.             if(!do_link(dat->selection.MinX,dat->selection.MinY)) {
  2246.             dat->selecting=TRUE;
  2247.             dat->selected=TRUE;
  2248.             MUI_Redraw(obj,MADF_DRAWUPDATE);
  2249.             }
  2250.         } else {
  2251.             dat->selected=FALSE;
  2252.             dat->selecting=FALSE;
  2253.         }
  2254.         } else if(msg->imsg->Code==SELECTUP) {
  2255.         if(dat->selecting) {
  2256.             dat->selection.MaxX=msg->imsg->MouseX-x;
  2257.             if(dat->selection.MaxX<0)
  2258.             dat->selection.MaxX=0;
  2259.             else if(dat->selection.MaxX>=w)
  2260.             dat->selection.MaxX=w-1;
  2261.             dat->selection.MaxY=msg->imsg->MouseY-y;
  2262.             if(dat->selection.MaxY<0)
  2263.             dat->selection.MaxY=0;
  2264.             else if(dat->selection.MaxY>=h)
  2265.             dat->selection.MaxY=h-1;
  2266.             dat->selected=TRUE;
  2267.             dat->selecting=FALSE;
  2268.             MUI_Redraw(obj,MADF_DRAWUPDATE);
  2269.         }
  2270.         }
  2271.         break;
  2272.       case IDCMP_MOUSEMOVE:
  2273.         if(dat->selecting) {
  2274.         dat->selection.MaxX=msg->imsg->MouseX-x;
  2275.         if(dat->selection.MaxX<0)
  2276.             dat->selection.MaxX=0;
  2277.         else if(dat->selection.MaxX>=w)
  2278.             dat->selection.MaxX=w-1;
  2279.         dat->selection.MaxY=msg->imsg->MouseY-y;
  2280.         if(dat->selection.MaxY<0)
  2281.             dat->selection.MaxY=0;
  2282.         else if(dat->selection.MaxY>=h)
  2283.             dat->selection.MaxY=h-1;
  2284.         MUI_Redraw(obj,MADF_DRAWUPDATE);
  2285.         } else if(_isinobject(msg->imsg->MouseX,msg->imsg->MouseY))
  2286.         check_link(msg->imsg->MouseX-x,msg->imsg->MouseY-y);
  2287.         break;
  2288.       /*case IDCMP_RAWKEY:
  2289.         switch(msg->imsg->Code) {
  2290.           case :
  2291.         break;
  2292.         }
  2293.         break; */
  2294.       case IDCMP_VANILLAKEY:
  2295.         switch(msg->imsg->Code) {
  2296.           case 8:  /* BS */
  2297.         upkey();
  2298.         break;
  2299.           case 'o':
  2300.         DoMethod(App,MUIM_Application_ReturnID,ID_OPEN);
  2301.         break;
  2302.           case 'f':
  2303.         set(win,MUIA_Window_ActiveObject,(ULONG)searchobj);
  2304.         break;
  2305.           case ' ':
  2306.         downkey();
  2307.         break;
  2308.           case 'q':
  2309.         DoMethod(App,MUIM_Application_ReturnID,MUIV_Application_ReturnID_Quit);
  2310.         break;
  2311.           case '+':
  2312.         DoMethod(zoomobj,MUIM_Numeric_Increase,1);
  2313.         break;
  2314.           case '-':
  2315.         DoMethod(zoomobj,MUIM_Numeric_Decrease,1);
  2316.         break;
  2317.         }
  2318.         break;
  2319.     }
  2320.     }
  2321.     switch(msg->muikey) {
  2322.       case MUIKEY_UP:
  2323.     upkey();
  2324.     break;
  2325.       case MUIKEY_DOWN:
  2326.     downkey();
  2327.     break;
  2328.       case MUIKEY_PAGEUP:
  2329.     DoMethod(pageobj,MUIM_Numeric_Decrease,1);
  2330.     break;
  2331.       case MUIKEY_PAGEDOWN:
  2332.     DoMethod(pageobj,MUIM_Numeric_Increase,1);
  2333.     break;
  2334.       case MUIKEY_TOP:
  2335.     set(pageobj,MUIA_Numeric_Value,1);
  2336.     break;
  2337.       case MUIKEY_BOTTOM: {
  2338.     LONG t;
  2339.     get(pageobj,MUIA_Numeric_Max,&t);
  2340.     set(pageobj,MUIA_Numeric_Value,t);
  2341.     break;
  2342.       }
  2343.     }
  2344.     return DoSuperMethodA(cl,obj,(Msg)msg);
  2345.     #undef _between
  2346.     #undef _isinobject
  2347. }
  2348.  
  2349. SAVEDS ASM ULONG dispatcher(REG(a0,struct IClass *cl),REG(a2,Object *obj),REG(a1, Msg msg)) {
  2350.     switch(msg->MethodID) {
  2351.       case OM_NEW          : return mNew        (cl,obj,(APTR)msg);
  2352.       case OM_DISPOSE      : return mDispose    (cl,obj,(APTR)msg);
  2353.       case OM_SET          : return mSet        (cl,obj,(APTR)msg);
  2354.       case OM_GET          : return mGet        (cl,obj,(APTR)msg);
  2355.       case MUIM_Setup      : return mSetup      (cl,obj,(APTR)msg);
  2356.       case MUIM_Cleanup    : return mCleanup    (cl,obj,(APTR)msg);
  2357.       case MUIM_AskMinMax  : return mAskMinMax  (cl,obj,(APTR)msg);
  2358.       case MUIM_Draw       : return mDraw       (cl,obj,(APTR)msg);
  2359.       case MUIM_HandleInput: return mHandleInput(cl,obj,(APTR)msg);
  2360.       case MYM_Reset       : return mReset      (cl,obj,(APTR)msg);
  2361.     }
  2362.     return DoSuperMethodA(cl,obj,msg);
  2363. }
  2364.  
  2365.  
  2366. /*
  2367.  * Custom slider class: maintains MYATTR_Value, that
  2368.  * is similar to MUIA_Numeric_Value, except that it is
  2369.  * updated only when the slider is released.
  2370.  */
  2371.  
  2372. struct SliderData {
  2373.     LONG value;
  2374.     BOOL pressed;
  2375.     BOOL lock;
  2376. };
  2377. typedef struct SliderData SliderData;
  2378.  
  2379. #define MySliderObject NewObject(slider_mcc->mcc_Class,NULL
  2380.  
  2381. static ULONG msNew(struct IClass *cl,Object *obj,Msg msg) {
  2382.     SliderData* dat;
  2383.  
  2384.     if(obj=(Object *)DoSuperMethodA(cl,obj,msg)) {
  2385.     dat=INST_DATA(cl,obj);
  2386.     dat->pressed=FALSE;
  2387.     dat->lock=FALSE;
  2388.     }
  2389.     return (ULONG)obj;
  2390. }
  2391.  
  2392. static ULONG msSet(struct IClass *cl,Object *obj,struct opSet *msg) {
  2393.     SliderData *dat=INST_DATA(cl,obj);
  2394.     struct TagItem *tags=msg->ops_AttrList;
  2395.     struct TagItem *tag;
  2396.     while(tag=NextTagItem(&tags)) {
  2397.     switch(tag->ti_Tag) {
  2398.       case MYATTR_Value:
  2399.         if(!dat->lock) {
  2400.         dat->lock=TRUE;
  2401.         set(obj,MUIA_Numeric_Value,tag->ti_Data);
  2402.         dat->lock=FALSE;
  2403.         }
  2404.         get(obj,MUIA_Numeric_Value,&dat->value);
  2405.         break;
  2406.       case MUIA_Numeric_Value: {
  2407.         LONG r=DoSuperMethodA(cl,obj,(Msg)msg);
  2408.         if(!dat->pressed && !dat->lock) {
  2409.         dat->lock=TRUE;
  2410.         set(obj,MYATTR_Value,tag->ti_Data);
  2411.         dat->lock=FALSE;
  2412.         }
  2413.         return (ULONG)r;
  2414.       }
  2415.     }
  2416.     }
  2417.     return DoSuperMethodA(cl,obj,(Msg)msg);
  2418. }
  2419.  
  2420. static ULONG msGet(struct IClass *cl,Object *obj,struct opGet *msg) {
  2421.     switch(msg->opg_AttrID) {
  2422.       case MYATTR_Value: {
  2423.     SliderData* dat=INST_DATA(cl,obj);
  2424.     *msg->opg_Storage=dat->value;
  2425.     return TRUE;
  2426.       }
  2427.     }
  2428.     return DoSuperMethodA(cl,obj,(Msg)msg);
  2429. }
  2430.  
  2431. static ULONG msSetup(struct IClass *cl,Object *obj,Msg msg) {
  2432.     if(DoSuperMethodA(cl,obj,msg)) {
  2433.     MUI_RequestIDCMP(obj,IDCMP_MOUSEBUTTONS);
  2434.     return TRUE;
  2435.     } else
  2436.     return FALSE;
  2437. }
  2438.  
  2439.  
  2440. static ULONG msCleanup(struct IClass *cl,Object *obj,Msg msg) {
  2441.     MUI_RejectIDCMP(obj,IDCMP_MOUSEBUTTONS);
  2442.     return DoSuperMethodA(cl,obj,msg);
  2443. }
  2444.  
  2445.  
  2446. static ULONG msHandleInput(struct IClass *cl,Object *obj,struct MUIP_HandleInput *msg) {
  2447.     #define _between(a,x,b) ((x)>=(a) && (x)<=(b))
  2448.     #define _isinobject(x,y) (_between(_mleft(obj),(x),_mright(obj)) && _between(_mtop(obj),(y),_mbottom(obj)))
  2449.     SliderData* dat=INST_DATA(cl,obj);
  2450.  
  2451.     if(msg->imsg) {
  2452.     switch(msg->imsg->Class) {
  2453.       case IDCMP_MOUSEBUTTONS:
  2454.         if(msg->imsg->Code==SELECTDOWN) {
  2455.         if(_isinobject(msg->imsg->MouseX,msg->imsg->MouseY))
  2456.             dat->pressed=TRUE;
  2457.         } else if(msg->imsg->Code==SELECTUP) {
  2458.         ULONG r=DoSuperMethodA(cl,obj,(Msg)msg);
  2459.         LONG x;
  2460.         dat->pressed=FALSE;
  2461.         get(obj,MUIA_Numeric_Value,&x);
  2462.         set(obj,MYATTR_Value,x);
  2463.         return r;
  2464.         }
  2465.         break;
  2466.     }
  2467.     }
  2468.     return DoSuperMethodA(cl,obj,(Msg)msg);
  2469.     #undef _between
  2470.     #undef _isinobject
  2471. }
  2472.  
  2473. SAVEDS ASM ULONG mysliderdispatcher(REG(a0,struct IClass *cl),REG(a2,Object *obj),REG(a1,Msg msg)) {
  2474.     switch(msg->MethodID) {
  2475.       case OM_NEW          : return msNew        (cl,obj,(APTR)msg);
  2476.       case OM_SET          : return msSet        (cl,obj,(APTR)msg);
  2477.       case OM_GET          : return msGet        (cl,obj,(APTR)msg);
  2478.       case MUIM_Setup      : return msSetup      (cl,obj,(APTR)msg);
  2479.       case MUIM_Cleanup    : return msCleanup    (cl,obj,(APTR)msg);
  2480.       case MUIM_HandleInput: return msHandleInput(cl,obj,(APTR)msg);
  2481.     }
  2482.     return DoSuperMethodA(cl,obj,msg);
  2483. }
  2484.  
  2485.  
  2486. /*
  2487.  * Custom rotate slider class: displays multiples of 90°
  2488.  */
  2489.  
  2490. struct RotateSliderData {
  2491.     char buf[5];
  2492. };
  2493. typedef struct RotateSliderData RotateSliderData;
  2494.  
  2495. #define MyRotateSliderObject NewObject(rotate_slider_mcc->mcc_Class,NULL
  2496.  
  2497.  
  2498. SAVEDS ASM ULONG myrotatesliderdispatcher(REG(a0,struct IClass *cl),REG(a2,Object *obj),REG(a1,Msg msg)) {
  2499.     if(msg->MethodID==MUIM_Numeric_Stringify) {
  2500.     RotateSliderData *dat=INST_DATA(cl,obj);
  2501.     struct MUIP_Numeric_Stringify *m=(APTR)msg;
  2502.     sprintf(dat->buf,"%ld°",m->value*90);
  2503.     return (ULONG)dat->buf;
  2504.     } else
  2505.     return DoSuperMethodA(cl,obj,msg);
  2506. }
  2507.  
  2508.  
  2509. /*
  2510.  * Custom list class: allows drag and drop
  2511.  */
  2512.  
  2513. struct ListData {
  2514.     LONG id;
  2515. };
  2516. typedef struct ListData ListData;
  2517.  
  2518. #define MyListObject NewObject(list_mcc->mcc_Class,NULL
  2519.  
  2520. static ULONG mlNew(struct IClass *cl,Object *obj,struct opSet *msg) {
  2521.     ListData* dat;
  2522.  
  2523.     if(obj=(Object *)DoSuperMethodA(cl,obj,(Msg)msg)) {
  2524.     dat=INST_DATA(cl,obj);
  2525.     dat->id=GetTagData(MYATTR_ListID,0,msg->ops_AttrList);
  2526.     }
  2527.     return (ULONG)obj;
  2528. }
  2529.  
  2530. static ULONG mlGet(struct IClass *cl,Object *obj,struct opGet *msg) {
  2531.     switch(msg->opg_AttrID) {
  2532.       case MYATTR_ListID: {
  2533.     ListData* dat=INST_DATA(cl,obj);
  2534.     *msg->opg_Storage=dat->id;
  2535.     return TRUE;
  2536.       }
  2537.     }
  2538.     return DoSuperMethodA(cl,obj,(Msg)msg);
  2539. }
  2540.  
  2541. static ULONG mlDragQuery(struct IClass *cl,Object *obj,struct MUIP_DragDrop *msg) {
  2542.     ListData *dat=INST_DATA(cl,obj);
  2543.     LONG x;
  2544.     if(msg->obj==obj)
  2545.     return DoSuperMethodA(cl,obj,(Msg)msg);
  2546.     else if(get(msg->obj,MYATTR_ListID,&x) && x==dat->id)
  2547.     return MUIV_DragQuery_Accept;
  2548.     else
  2549.     return MUIV_DragQuery_Refuse;
  2550. }
  2551.  
  2552.  
  2553. static ULONG mlDragDrop(struct IClass *cl,Object *obj,struct MUIP_DragDrop *msg) {
  2554.     if(msg->obj==obj)
  2555.     return DoSuperMethodA(cl,obj,(Msg)msg);
  2556.     else {
  2557.     LONG dropmark;
  2558.     LONG id=MUIV_List_NextSelected_Start;
  2559.     get(obj,MUIA_List_DropMark,&dropmark);
  2560.     while(1) {
  2561.         APTR entry;
  2562.         DoMethod(msg->obj,MUIM_List_NextSelected,&id);
  2563.         if(id==MUIV_List_NextSelected_End)
  2564.         break;
  2565.         DoMethod(msg->obj,MUIM_List_GetEntry,id,&entry);
  2566.         DoMethod(obj,MUIM_List_InsertSingle,entry,dropmark);
  2567.     }
  2568.     DoMethod(msg->obj,MUIM_List_Remove,MUIV_List_Remove_Selected);
  2569.     get(obj,MUIA_List_InsertPosition,&dropmark);
  2570.     set(obj,MUIA_List_Active,dropmark);
  2571.     set(msg->obj,MUIA_List_Active,MUIV_List_Active_Off);
  2572.     return 0;
  2573.     }
  2574. }
  2575.  
  2576.  
  2577. SAVEDS ASM ULONG mylistdispatcher(REG(a0,struct IClass *cl),REG(a2,Object *obj),REG(a1,Msg msg)) {
  2578.     switch(msg->MethodID) {
  2579.       case OM_NEW:         return mlNew      (cl,obj,(APTR)msg);
  2580.       case OM_GET:         return mlGet      (cl,obj,(APTR)msg);
  2581.       case MUIM_DragQuery: return mlDragQuery(cl,obj,(APTR)msg);
  2582.       case MUIM_DragDrop : return mlDragDrop (cl,obj,(APTR)msg);
  2583.     }
  2584.     return DoSuperMethodA(cl,obj,msg);
  2585. }
  2586.  
  2587.  
  2588.  
  2589. void cleanup(void) {
  2590.  
  2591.  
  2592.     if(MUIMasterBase) {
  2593.     MUI_FreeAslRequest(req);
  2594.     MUI_DisposeObject(App);
  2595.     if(list_mcc)
  2596.         MUI_DeleteCustomClass(list_mcc);
  2597.     if(rotate_slider_mcc)
  2598.         MUI_DeleteCustomClass(rotate_slider_mcc);
  2599.     if(slider_mcc)
  2600.         MUI_DeleteCustomClass(slider_mcc);
  2601.     if(mcc)
  2602.         MUI_DeleteCustomClass(mcc);
  2603.     CloseLibrary(MUIMasterBase);
  2604.     }
  2605.  
  2606. #ifdef POWERUP
  2607.  
  2608.     while(!ppc_quitted) {
  2609.     quit();
  2610.     PPCWaitPort(reply_port);
  2611.     if(PPCGetMessage(reply_port)==startupmsg)
  2612.         ppc_quitted=TRUE;
  2613.     }
  2614.  
  2615.     if(startup_data)
  2616.     PPCFreeVec(startup_data);
  2617.  
  2618.     if(startupmsg)
  2619.     PPCDeleteMessage(startupmsg);
  2620.  
  2621.     if(quitmsg)
  2622.     PPCDeleteMessage(quitmsg);
  2623.  
  2624.     if(cmdmsg)
  2625.     PPCDeleteMessage(cmdmsg);
  2626.  
  2627.     if(cmddata)
  2628.     PPCFreeVec(cmddata);
  2629.  
  2630.     if(portlist)
  2631.     PPCDeletePortList(portlist);
  2632.  
  2633.     if(port)
  2634.     PPCDeletePort(port);
  2635.  
  2636.     if(reply_port)
  2637.     PPCDeletePort(reply_port);
  2638.  
  2639.     if(elfobject)
  2640.     PPCUnLoadObject(elfobject);
  2641.  
  2642.     CloseLibrary(PPCLibBase);
  2643. #endif
  2644.  
  2645.     if(diskobj)
  2646.     FreeDiskObject(diskobj);
  2647.  
  2648.     CloseLibrary(CyberGfxBase);
  2649.     CloseLibrary(IFFParseBase);
  2650.     CloseLibrary(DiskfontBase);
  2651.     CloseLibrary(IconBase);
  2652.     CloseLibrary((struct Library*)UtilityBase);
  2653.     CloseLibrary(LayersBase);
  2654.     CloseLibrary((struct Library*)GfxBase);
  2655.     CloseLibrary((struct Library*)IntuitionBase);
  2656.  
  2657.     FreeArgs(rda);
  2658.     CurrentDir(olddir);
  2659.     UnLock(docdir);
  2660.     free(progname);
  2661.     free(docname);
  2662.     free(gzipcmd_arg);
  2663.     free(urlcmd_arg);
  2664.     free(deficon_arg);
  2665.     free(diskobj_arg);
  2666.  
  2667.     if(input) {
  2668.     SelectInput(oldinput);
  2669.     Close(input);
  2670.     }
  2671. }
  2672.  
  2673. /*
  2674.  *  MUI data and hooks.
  2675.  */
  2676. static struct NewMenu menudata[]={
  2677.     {NM_TITLE,"Project"     ,0,0,0,NULL},
  2678.     {NM_ITEM , "About..."   ,"?",0,0,(APTR)ID_ABOUT},
  2679.     {NM_ITEM , "About MUI...",0,0,0,(APTR)ID_ABOUTMUI},
  2680.     {NM_ITEM , NM_BARLABEL  ,0,0,0,NULL},
  2681.     {NM_ITEM , "Open..."    ,"O",0,0,(APTR)ID_OPEN},
  2682.     {NM_ITEM , "Save as..." ,"A",0,0,(APTR)ID_SAVEAS},
  2683.     {NM_ITEM , "Print..."   ,"P",0,0,(APTR)ID_PRINT},
  2684.     {NM_ITEM , NM_BARLABEL  ,0,0,0,NULL},
  2685.     {NM_ITEM , "Hide"       ,"H",0,0,(APTR)ID_HIDE},
  2686.     {NM_ITEM , "Quit"       ,"Q",0,0,(APTR)MUIV_Application_ReturnID_Quit},
  2687.     {NM_TITLE,"Edit"        ,0,0,0,NULL},
  2688.     {NM_ITEM , "Copy"       ,"C",0,0,(APTR)ID_COPY},
  2689.     {NM_TITLE,"Settings"    ,0,0,0,NULL},
  2690.     {NM_ITEM , "Default font mapping..."   ,0,0,0,(APTR)ID_DEFFONTS},
  2691.     {NM_ITEM , "Document font mapping..."   ,0,0,0,(APTR)ID_DOCFONTS},
  2692.     {NM_ITEM , "MUI..."     ,0,0,0,(APTR)ID_MUIPREFS},
  2693.     {NM_END  ,NULL          ,0,0,0,NULL}
  2694. };
  2695.  
  2696.  
  2697. static const char* save_types[]={
  2698.     "Postscript (level 2)","Postscript (level 1)","Text","PBM/PPM Images","PBM/PPM/JPEG Images",NULL
  2699. };
  2700.  
  2701.  
  2702. static ULONG SAVEDS ASM setnum_func(REG(a2,Object* obj),REG(a1,Object** p)) {
  2703.     int n=1;
  2704.     get(*p,MUIA_String_Integer,&n);
  2705.     set(obj,MUIA_Numeric_Value,n);
  2706.     return 0;
  2707. }
  2708. static struct Hook setnum_hook={{NULL,NULL},setnum_func};
  2709.  
  2710.  
  2711. struct fontmapentry {
  2712.     char pdffont[128];
  2713.     char afont[128];
  2714.     int mwidth;
  2715.     int encoding;
  2716.     BOOL bold;
  2717.     BOOL italic;
  2718. };
  2719.  
  2720. static const char* encodings[]={
  2721.     "Latin 1","Latin 2","Symbols","Dingbats",NULL
  2722. };
  2723.  
  2724. static APTR SAVEDS ASM fontmapctor_func(REG(a2,APTR pool),REG(a1,struct fontmapentry* p)) {
  2725.     struct fontmapentry* q=AllocPooled(pool,sizeof(*q));
  2726.     if(q)
  2727.     *q=*p;
  2728.     return q;
  2729. }
  2730. static struct Hook fontmapctor_hook={{NULL,NULL},(ULONG(*)())fontmapctor_func};
  2731.  
  2732. static void SAVEDS ASM fontmapdtor_func(REG(a2,APTR pool),REG(a1,struct fontmapentry* p)) {
  2733.     FreePooled(pool,p,sizeof(*p));
  2734. }
  2735. static struct Hook fontmapdtor_hook={{NULL,NULL},(ULONG(*)())fontmapdtor_func};
  2736.  
  2737. static APTR SAVEDS ASM fontmapdisp_func(REG(a2,const char** array),REG(a1,struct fontmapentry* p)) {
  2738.     if(p) {
  2739.     static char buf[4];
  2740.     sprintf(buf,"%3d",p->mwidth);
  2741.     *array++=p->pdffont;
  2742.     *array++=p->afont;
  2743.     *array++=buf;
  2744.     *array++=p->bold?"×":" ";
  2745.     *array++=p->italic?"×":" ";
  2746.     *array++=encodings[p->encoding];
  2747.     } else {
  2748.     *array++="\33u\33bPDF font";
  2749.     *array++="\33u\33bAmiga font";
  2750.     *array++="\33u\33bScale";
  2751.     *array++="\33u\33bBold";
  2752.     *array++="\33u\33bItalic";
  2753.     *array++="\33u\33bEncoding";
  2754.     }
  2755.     return 0;
  2756. }
  2757. static struct Hook fontmapdisp_hook={{NULL,NULL},(ULONG(*)())fontmapdisp_func};
  2758.  
  2759. static void SAVEDS ASM fontreq_func(REG(a2,Object* obj),REG(a1,struct FontRequester* p)) {
  2760.     set(obj,MUIA_String_Contents,p->fo_Attr.ta_Name);
  2761. }
  2762. static struct Hook fontreq_hook={{NULL,NULL},(ULONG(*)())fontreq_func};
  2763.  
  2764. static void setfontmap(Object* o) {
  2765.     LONG entries;
  2766.     int k;
  2767.     get(o,MUIA_List_Entries,&entries);
  2768.     for(k=0;k<entries;++k) {
  2769.     struct fontmapentry* e;
  2770.     DoMethod(o,MUIM_List_GetEntry,k,&e);
  2771.     add_fontmap(e->pdffont,e->afont,e->mwidth,(e->bold?FSF_BOLD:0)|(e->italic?FSF_ITALIC:0),e->encoding);
  2772.     }
  2773.     /*set_fontmap();*/
  2774. }
  2775.  
  2776. static void parse_fontmap_entry(Object* obj,const char* q) {
  2777.     struct fontmapentry e;
  2778.     const char *p=q;
  2779.     while(*p && *p!='/')
  2780.     ++p;
  2781.     if(*p=='/' && p!=q && p-q<sizeof(e.pdffont)) {
  2782.     memcpy(e.pdffont,q,p-q);
  2783.     e.pdffont[p-q]='\0';
  2784.     e.mwidth=100;
  2785.     e.bold=FALSE;
  2786.     e.italic=FALSE;
  2787.     e.encoding=0;
  2788.     if(*++p=='[') {
  2789.         while(*++p && *p!=']') {
  2790.         switch(*p) {
  2791.           case '1':
  2792.             e.encoding=0;
  2793.             break;
  2794.           case '2':
  2795.             e.encoding=1;
  2796.             break;
  2797.           case 's':
  2798.             e.encoding=2;
  2799.             break;
  2800.           case 'z':
  2801.             e.encoding=3;
  2802.             break;
  2803.           case 'B':
  2804.             e.bold=TRUE;
  2805.             break;
  2806.           case 'I':
  2807.             e.italic=TRUE;
  2808.             break;
  2809.           case '%': {
  2810.             e.mwidth=0;
  2811.             while(p[1]>='0' && p[1]<='9') {
  2812.             e.mwidth*=10;
  2813.             e.mwidth+=*++p-'0';
  2814.             }
  2815.             if(e.mwidth>999)
  2816.             e.mwidth=999;
  2817.             else if(e.mwidth<1)
  2818.             e.mwidth=1;
  2819.             break;
  2820.           }
  2821.         }
  2822.         }
  2823.         if(*p!=']') {
  2824.         printf("Invalid fontmap entry: \"%s\".\n",q);
  2825.         return;
  2826.         }
  2827.         ++p;
  2828.     }
  2829.     strncpy(e.afont,p,sizeof(e.afont)-1);
  2830.     e.afont[sizeof(e.afont)-1]='\0';
  2831.     DoMethod(obj,MUIM_List_InsertSingle,&e,MUIV_List_Insert_Bottom);
  2832.     } else
  2833.     printf("Invalid fontmap entry: \"%s\".\n",q);
  2834. }
  2835.  
  2836. static void parse_fontmap(Object* o,const char** args) {
  2837.     while(*args) {
  2838.     parse_fontmap_entry(o,*args);
  2839.     ++args;
  2840.     }
  2841. }
  2842.  
  2843. static void parse_fontmap_tooltypes(Object* o,BPTR lock,const char* name) {
  2844.     struct DiskObject *dob;
  2845.     BPTR olddir=CurrentDir(lock);
  2846.     if(dob=GetDiskObject((char*)name)) {
  2847.     char** p=(char**)dob->do_ToolTypes;
  2848.     if(p) {
  2849.         while(*p) {
  2850.         if(!Strnicmp(*p,"FONTMAP=",8))
  2851.             parse_fontmap_entry(o,*p+8);
  2852.         ++p;
  2853.         }
  2854.     }
  2855.     FreeDiskObject(dob);
  2856.     }
  2857.     CurrentDir(olddir);
  2858. }
  2859.  
  2860. static BOOL save_fontmap(Object* o,BPTR lock,const char* name) {
  2861.     struct DiskObject* dob;
  2862.     BOOL ret=FALSE;
  2863.     BPTR olddir=CurrentDir(lock);
  2864.     if((dob=GetDiskObject((char*)name)) ||
  2865.        (dob=GetDiskObject((char*)DEFICON)) ||
  2866.        (dob=GetDiskObjectNew((char*)name))) {
  2867.     char** oldtt=dob->do_ToolTypes;
  2868.     LONG entries;
  2869.     LONG numoldtt=0;
  2870.     char** p;
  2871.     char** newtt;
  2872.  
  2873.     get(o,MUIA_List_Entries,&entries);
  2874.  
  2875.     if(oldtt)
  2876.         for(p=oldtt;*p;++p)
  2877.         if(Strnicmp(*p,"FONTMAP",7))
  2878.             ++numoldtt;
  2879.  
  2880.     if(newtt=malloc(sizeof(*newtt)*(numoldtt+entries+1))) {
  2881.         char** q=newtt;
  2882.         int k;
  2883.         BOOL err=FALSE;
  2884.  
  2885.         if(oldtt)
  2886.         for(p=oldtt;*p;++p)
  2887.             if(Strnicmp(*p,"FONTMAP",7))
  2888.             *q++=*p;
  2889.  
  2890.         for(k=0;k<entries;++k) {
  2891.         struct fontmapentry* e;
  2892.         size_t l1,l2;
  2893.         char* s;
  2894.  
  2895.         DoMethod(o,MUIM_List_GetEntry,k,&e);
  2896.         l1=strlen(e->pdffont);
  2897.         l2=strlen(e->afont);
  2898.         if(s=malloc(l1+l2+32)) {
  2899.             *q++=s;
  2900.             memcpy(s,"FONTMAP=",8);
  2901.             s+=8;
  2902.             memcpy(s,e->pdffont,l1);
  2903.             s+=l1;
  2904.             *s++='/';
  2905.             *s++='[';
  2906.             *s++="12sz"[e->encoding];
  2907.             if(e->bold)
  2908.             *s++='B';
  2909.             if(e->italic)
  2910.             *s++='I';
  2911.             if(e->mwidth!=100) {
  2912.             int m=e->mwidth;
  2913.             *s++='%';
  2914.             *s++='0'+m/100;
  2915.             m%=100;
  2916.             *s++='0'+m/10;
  2917.             m%=10;
  2918.             *s++='0'+m;
  2919.             }
  2920.             *s++=']';
  2921.             memcpy(s,e->afont,l2+1);
  2922.         } else
  2923.             err=TRUE;
  2924.         }
  2925.         *q=NULL;
  2926.  
  2927.         dob->do_ToolTypes=newtt;
  2928.         if(PutDiskObject((char*)name,dob) && !err)
  2929.         ret=TRUE;
  2930.  
  2931.         p=newtt+numoldtt;
  2932.         while(*p)
  2933.         free(*p++);
  2934.         free(newtt);
  2935.  
  2936.     }
  2937.     dob->do_ToolTypes=oldtt;
  2938.     FreeDiskObject(dob);
  2939.     }
  2940.     CurrentDir(olddir);
  2941.     if(!ret)
  2942.     printf("Can't save fonts map.\n");
  2943.     return ret;
  2944. }
  2945.  
  2946. /*
  2947.  *  fontmap windows.
  2948.  */
  2949.  
  2950. struct fontmap_window {
  2951.     Object *win;
  2952.     Object *fontmapobj;
  2953.     BPTR* dir;
  2954.     char** filename;
  2955.  
  2956.     Object *pdffontobj;
  2957.     Object *afontobj;
  2958.     Object *popobj;
  2959.     Object *scaleobj;
  2960.     Object *boldobj;
  2961.     Object *italicobj;
  2962.     Object *encodingobj;
  2963.     Object *remfontobj;
  2964. };
  2965.  
  2966. static int changed_disabled; // kludge...
  2967.  
  2968. static void SAVEDS ASM activefonts_func(REG(a2,Object* obj),REG(a1,struct fontmap_window** p)) {
  2969.     struct fontmap_window* fmw=*p;
  2970.     LONG x;
  2971.     get(obj,MUIA_List_Active,&x);
  2972.     DoMethod(obj,MUIM_MultiSet,MUIA_Disabled,x==MUIV_List_Active_Off,
  2973.          fmw->pdffontobj,fmw->popobj,fmw->scaleobj,fmw->boldobj,
  2974.          fmw->italicobj,fmw->encodingobj,fmw->remfontobj,NULL);
  2975.     if(x!=MUIV_List_Active_Off) {
  2976.     struct fontmapentry* e;
  2977.     ++changed_disabled;
  2978.     DoMethod(obj,MUIM_List_GetEntry,x,&e);
  2979.     if(e) {
  2980.         nnset(fmw->pdffontobj,MUIA_String_Contents,e->pdffont);
  2981.         nnset(fmw->afontobj,MUIA_String_Contents,e->afont);
  2982.         nnset(fmw->encodingobj,MUIA_Cycle_Active,e->encoding);
  2983.         nnset(fmw->scaleobj,MUIA_String_Integer,e->mwidth);
  2984.         nnset(fmw->boldobj,MUIA_Selected,e->bold);
  2985.         nnset(fmw->italicobj,MUIA_Selected,e->italic);
  2986.         --changed_disabled;
  2987.     }
  2988.     }
  2989. }
  2990. static struct Hook activefonts_hook={{NULL,NULL},(ULONG(*)())activefonts_func};
  2991.  
  2992. static void SAVEDS ASM fontmapchanged_func(REG(a2,Object* obj),REG(a1,struct fontmap_window** q)) {
  2993.     struct fontmap_window* fmw=*q;
  2994.     LONG x;
  2995.     if(changed_disabled)
  2996.     return;
  2997.     get(obj,MUIA_List_Active,&x);
  2998.     if(x!=MUIV_List_Active_Off) {
  2999.     struct fontmapentry* e;
  3000.     const char* p;
  3001.     DoMethod(obj,MUIM_List_GetEntry,x,&e);
  3002.     if(e) {
  3003.         get(fmw->pdffontobj,MUIA_String_Contents,&p);
  3004.         strcpy(e->pdffont,p);
  3005.         get(fmw->afontobj,MUIA_String_Contents,&p);
  3006.         strcpy(e->afont,p);
  3007.         get(fmw->encodingobj,MUIA_Cycle_Active,&e->encoding);
  3008.         get(fmw->scaleobj,MUIA_String_Integer,&e->mwidth);
  3009.         if(e->mwidth<1)
  3010.         e->mwidth=1;
  3011.         else if(e->mwidth>999)
  3012.         e->mwidth=999;
  3013.         get(fmw->boldobj,MUIA_Selected,&x);
  3014.         e->bold=x;
  3015.         get(fmw->italicobj,MUIA_Selected,&x);
  3016.         e->italic=x;
  3017.         DoMethod(obj,MUIM_List_Redraw,MUIV_List_Redraw_Active);
  3018.     }
  3019.     }
  3020. }
  3021. static struct Hook fontmapchanged_hook={{NULL,NULL},(ULONG(*)())fontmapchanged_func};
  3022.  
  3023. static void SAVEDS ASM addfont_func(REG(a2,Object* obj),REG(a1,struct fontmap_window** q)) {
  3024.     struct fontmap_window* fmw=*q;
  3025.     struct fontmapentry e;
  3026.     e.pdffont[0]='\0';
  3027.     e.afont[0]='\0';
  3028.     e.mwidth=100;
  3029.     e.encoding=0;
  3030.     e.bold=FALSE;
  3031.     e.italic=FALSE;
  3032.     DoMethod(obj,MUIM_List_InsertSingle,&e,MUIV_List_Insert_Bottom);
  3033.     set(obj,MUIA_List_Active,MUIV_List_Active_Bottom);
  3034.     set(fmw->win,MUIA_Window_ActiveObject,fmw->pdffontobj);
  3035. }
  3036. static struct Hook addfont_hook={{NULL,NULL},(ULONG(*)())addfont_func};
  3037.  
  3038. static void SAVEDS ASM savefontmap_func(REG(a2,Object* obj),REG(a1,struct fontmap_window** q)) {
  3039.     struct fontmap_window* fmw=*q;
  3040.     save_fontmap(fmw->fontmapobj,*fmw->dir,*fmw->filename);
  3041. }
  3042. static struct Hook savefontmap_hook={{NULL,NULL},(ULONG(*)())savefontmap_func};
  3043.  
  3044.  
  3045. static void make_fontmap_win(struct fontmap_window* fmw,const char* title,
  3046.               BPTR* dir,char** filename,unsigned long id,
  3047.               Object* scanfontsobj) {
  3048.     Object *applyfontmapobj,*saveobj;
  3049.     Object *addfontobj,*win,*fontmapobj;
  3050.  
  3051.     fmw->dir=dir;
  3052.     fmw->filename=filename;
  3053.  
  3054.     fontmapobj=fmw->fontmapobj=ListviewObject,
  3055.     MUIA_Listview_Input,TRUE,
  3056.     MUIA_Listview_DragType,MUIV_Listview_DragType_Immediate,
  3057.     MUIA_Listview_MultiSelect,MUIV_Listview_MultiSelect_Default,
  3058.     MUIA_Listview_List,MyListObject,
  3059.         InputListFrame,
  3060.         MUIA_List_Title,TRUE,
  3061.         MUIA_List_Format,"BAR,BAR,P=\33l BAR,P=\33c BAR,P=\33c BAR,",
  3062.         MUIA_List_ConstructHook,&fontmapctor_hook,
  3063.         MUIA_List_DestructHook,&fontmapdtor_hook,
  3064.         MUIA_List_DisplayHook,&fontmapdisp_hook,
  3065.         MUIA_List_DragSortable,TRUE,
  3066.         MUIA_List_ShowDropMarks,TRUE,
  3067.         MYATTR_ListID,1,
  3068.         End,
  3069.     End;
  3070.  
  3071.     win=fmw->win=WindowObject,
  3072.     MUIA_Window_Title,title,
  3073.     MUIA_Window_ID,id,
  3074.     MUIA_Window_DefaultObject,fontmapobj,
  3075.     WindowContents,VGroup,
  3076.         Child,fontmapobj,
  3077.         Child,HGroup,
  3078.         Child,addfontobj=SimpleButton("_Add"),
  3079.         Child,fmw->remfontobj=SimpleButton("_Remove"),
  3080.         End,
  3081.         Child,ColGroup(2),
  3082.         Child,Label2("PDF Font"),
  3083.         Child,fmw->pdffontobj=StringObject,
  3084.             StringFrame,
  3085.             MUIA_String_AdvanceOnCR,TRUE,
  3086.             MUIA_String_MaxLen,sizeof(((struct fontmapentry*)NULL)->pdffont),
  3087.             MUIA_String_AttachedList,fontmapobj,
  3088.             MUIA_CycleChain,TRUE,
  3089.             MUIA_Disabled,TRUE,
  3090.             End,
  3091.         Child,Label2("Amiga Font"),
  3092.         Child,fmw->popobj=PopaslObject,
  3093.             MUIA_Popasl_Type,ASL_FontRequest,
  3094.             MUIA_Popasl_StopHook,&fontreq_hook,
  3095.             MUIA_Popstring_String,fmw->afontobj=StringObject,
  3096.             StringFrame,
  3097.             MUIA_String_MaxLen,sizeof(((struct fontmapentry*)NULL)->afont)-5,
  3098.             MUIA_String_AdvanceOnCR,TRUE,
  3099.             MUIA_String_AttachedList,fontmapobj,
  3100.             MUIA_CycleChain,TRUE,
  3101.             MUIA_Disabled,TRUE,
  3102.             End,
  3103.             MUIA_Popstring_Button,PopButton(MUII_PopUp),
  3104.             ASLFO_TitleText,"Select a font...",
  3105.             End,
  3106.         End,
  3107.         Child,HGroup,
  3108.         Child,Label1("_Scale"),
  3109.         Child,fmw->scaleobj=StringObject,
  3110.             StringFrame,
  3111.             MUIA_String_Accept,"0123456789",
  3112.             MUIA_String_Integer,100,
  3113.             MUIA_String_MaxLen,4,
  3114.             MUIA_String_AdvanceOnCR,TRUE,
  3115.             MUIA_String_AttachedList,fontmapobj,
  3116.             MUIA_CycleChain,TRUE,
  3117.             End,
  3118.         Child,Label1("_Bold"),
  3119.         Child,fmw->boldobj=MUI_MakeObject(MUIO_Checkmark,"_Bold"),
  3120.         Child,Label1("_Italic"),
  3121.         Child,fmw->italicobj=MUI_MakeObject(MUIO_Checkmark,"_Italic"),
  3122.         Child,Label1("_Encoding"),
  3123.         Child,fmw->encodingobj=MUI_MakeObject(MUIO_Cycle,"_Encoding",encodings),
  3124.         End,
  3125.         Child,HGroup,
  3126.         Child,RectangleObject,
  3127.             End,
  3128.         Child,saveobj=SimpleButton("Sa_ve"),
  3129.         Child,applyfontmapobj=SimpleButton("Appl_y"),
  3130.         Child,scanfontsobj,
  3131.         Child,RectangleObject,
  3132.             End,
  3133.         End,
  3134.         End,
  3135.     End;
  3136.  
  3137.     if(win) {
  3138.     DoMethod(App,OM_ADDMEMBER,win);
  3139.  
  3140.     DoMethod(win,MUIM_MultiSet,MUIA_Disabled,TRUE,
  3141.          fmw->remfontobj,fmw->pdffontobj,fmw->popobj,fmw->encodingobj,
  3142.          fmw->boldobj,fmw->italicobj,fmw->scaleobj,NULL);
  3143.     DoMethod(win,MUIM_Notify,MUIA_Window_CloseRequest,TRUE,
  3144.          win,3,MUIM_Set,MUIA_Window_Open,FALSE);
  3145.     DoMethod(fontmapobj,MUIM_Notify,MUIA_List_Active,MUIV_EveryTime,
  3146.          fontmapobj,3,MUIM_CallHook,&activefonts_hook,fmw);
  3147.     DoMethod(fmw->pdffontobj,MUIM_Notify,MUIA_String_Acknowledge,MUIV_EveryTime,
  3148.          fontmapobj,3,MUIM_CallHook,&fontmapchanged_hook,fmw);
  3149.     DoMethod(fmw->pdffontobj,MUIM_Notify,MUIA_String_Contents,MUIV_EveryTime,
  3150.          fontmapobj,3,MUIM_CallHook,&fontmapchanged_hook,fmw);
  3151.     DoMethod(fmw->afontobj,MUIM_Notify,MUIA_String_Acknowledge,MUIV_EveryTime,
  3152.          fontmapobj,3,MUIM_CallHook,&fontmapchanged_hook,fmw);
  3153.     DoMethod(fmw->afontobj,MUIM_Notify,MUIA_String_Contents,MUIV_EveryTime,
  3154.          fontmapobj,3,MUIM_CallHook,&fontmapchanged_hook,fmw);
  3155.     DoMethod(fmw->scaleobj,MUIM_Notify,MUIA_String_Acknowledge,MUIV_EveryTime,
  3156.          fontmapobj,3,MUIM_CallHook,&fontmapchanged_hook,fmw);
  3157.     DoMethod(fmw->scaleobj,MUIM_Notify,MUIA_String_Contents,MUIV_EveryTime,
  3158.          fontmapobj,3,MUIM_CallHook,&fontmapchanged_hook,fmw);
  3159.     DoMethod(fmw->boldobj,MUIM_Notify,MUIA_Selected,MUIV_EveryTime,
  3160.          fontmapobj,3,MUIM_CallHook,&fontmapchanged_hook,fmw);
  3161.     DoMethod(fmw->italicobj,MUIM_Notify,MUIA_Selected,MUIV_EveryTime,
  3162.          fontmapobj,3,MUIM_CallHook,&fontmapchanged_hook,fmw);
  3163.     DoMethod(fmw->encodingobj,MUIM_Notify,MUIA_Cycle_Active,MUIV_EveryTime,
  3164.          fontmapobj,3,MUIM_CallHook,&fontmapchanged_hook,fmw);
  3165.     DoMethod(addfontobj,MUIM_Notify,MUIA_Pressed,FALSE,
  3166.          fontmapobj,3,MUIM_CallHook,&addfont_hook,fmw);
  3167.     DoMethod(fmw->remfontobj,MUIM_Notify,MUIA_Pressed,FALSE,
  3168.          fontmapobj,2,MUIM_List_Remove,MUIV_List_Remove_Selected);
  3169.     DoMethod(applyfontmapobj,MUIM_Notify,MUIA_Pressed,FALSE,
  3170.          App,2,MUIM_Application_ReturnID,ID_APPLYFONTMAP);
  3171.     DoMethod(saveobj,MUIM_Notify,MUIA_Pressed,FALSE,
  3172.          fontmapobj,3,MUIM_CallHook,&savefontmap_hook,fmw);
  3173.     }
  3174. }
  3175.  
  3176. static void do_scan_fonts(struct fontmap_window* fmw,int n) {
  3177.     if(n) {
  3178.     int k;
  3179.     set(fmw->fontmapobj,MUIA_List_Quiet,TRUE);
  3180.     for(k=0;k<n;++k) {
  3181.         struct fontmapentry e;
  3182.         int style;
  3183.         if(get_font(k,e.pdffont,sizeof(e.pdffont),e.afont,sizeof(e.afont),&e.mwidth,&style,&e.encoding)) {
  3184.         int entries;
  3185.         int k;
  3186.         e.bold=(style&FSF_BOLD)!=0;
  3187.         e.italic=(style&FSF_ITALIC)!=0;
  3188.  
  3189.         get(fmw->fontmapobj,MUIA_List_Entries,&entries);
  3190.         for(k=0;k<entries;++k) {
  3191.             struct fontmapentry *e2;
  3192.             DoMethod(fmw->fontmapobj,MUIM_List_GetEntry,k,&e2);
  3193.             if(!strcmp(e.pdffont,e2->pdffont) &&
  3194.                !strcmp(e.afont,e2->afont) &&
  3195.                e.mwidth==e2->mwidth &&
  3196.                e.bold==e2->bold &&
  3197.                e.italic==e2->italic &&
  3198.                e.encoding==e2->encoding)
  3199.             break;
  3200.         }
  3201.         if(k==entries)
  3202.             DoMethod(fmw->fontmapobj,MUIM_List_InsertSingle,&e,MUIV_List_Insert_Bottom);
  3203.         }
  3204.     }
  3205.     end_scan_fonts();
  3206.     set(fmw->fontmapobj,MUIA_List_Quiet,FALSE);
  3207.     set(fmw->win,MUIA_Window_ActiveObject,fmw->pdffontobj);
  3208.     }
  3209. }
  3210.  
  3211. static struct fontmap_window def_fmw;
  3212. static struct fontmap_window doc_fmw;
  3213.  
  3214. static void open_file(BPTR lock,const char* name) {
  3215.     sleep(TRUE);
  3216.     set(win,MUIA_Window_Title,"Loading...");
  3217.     if(create_doc(lock,name,CACHESZ,BLOCSZ)) {
  3218.     BPTR lock2=DupLock(lock);
  3219.     CurrentDir(lock2);
  3220.     UnLock(docdir);
  3221.     docdir=lock2;
  3222.     copystr(&docname,name);
  3223.     DoMethod(doc_fmw.fontmapobj,MUIM_List_Clear);
  3224.     parse_fontmap_tooltypes(doc_fmw.fontmapobj,docdir,docname);
  3225.     get_page_info();
  3226.     }
  3227.     set(win,MUIA_Window_Title,docname);
  3228.     sleep(FALSE);
  3229. }
  3230.  
  3231. static ULONG SAVEDS ASM appwin_func(REG(a2,Object* obj),REG(a1,struct AppMessage** p)) {
  3232.     struct AppMessage *msg=*p;
  3233.     if(msg->am_Version>=AM_VERSION && msg->am_NumArgs>=1)
  3234.     open_file(msg->am_ArgList->wa_Lock,msg->am_ArgList->wa_Name);
  3235.     return 0;
  3236. }
  3237. static struct Hook appwin_hook={{NULL,NULL},appwin_func};
  3238.  
  3239. static int open_req(void) {
  3240.     struct Screen *scr=NULL;
  3241.     if(win) /* NULL for the initial requester */
  3242.     get(win,MUIA_Window_Screen,&scr);
  3243.     if((req ||
  3244.     (req=MUI_AllocAslRequestTags(ASL_FileRequest,
  3245.                      ASLFR_TitleText,"Open...",
  3246.                      ASLFR_PositiveText,"Open",
  3247.                      ASLFR_NegativeText,"Cancel",
  3248.                      ASLFR_RejectIcons,TRUE,
  3249.                      ASLFR_DoPatterns,TRUE,
  3250.                      ASLFR_InitialPattern,"#?.pdf",
  3251.                      TAG_END))) &&
  3252.     MUI_AslRequestTags(req,
  3253.                scr?ASLFR_Screen:TAG_IGNORE,scr,
  3254.                TAG_END))
  3255.     return 1;
  3256.     return 0;
  3257. }
  3258.  
  3259. static void open_req_file(void) {
  3260.     if(req) {
  3261.     BPTR lock=Lock(req->fr_Drawer,ACCESS_READ);
  3262.     open_file(lock,req->fr_File);
  3263.     UnLock(lock);
  3264.     }
  3265. }
  3266.  
  3267. int main() {
  3268.  
  3269.     Object *nxtsrchobj,*strobj,*menu;
  3270.     Object *pssaveobj,*pscancelobj,*psrotateobj,*pszoomobj;
  3271.     Object *psstartstrobj,*psstopstrobj,*pstypeobj;
  3272.     Object *pspopobj,*pswin,*psfilenameobj;
  3273.     Object *scanstartstrobj,*scanstopstrobj,*scanwin,*scanobj;
  3274.     Object *defaultfontsobj,*scanfontsobj;
  3275.  
  3276.     ULONG sigs;
  3277.     struct Process* proc=(struct Process*)FindTask(NULL);
  3278.  
  3279.     /* This test is probably useless. If run on 68000 or */
  3280.     /* 68010, we have probably already crashed at this point. */
  3281.     if(!(SysBase->AttnFlags&AFF_68020)) {
  3282.     printf("This version requires at least a 68020.\n");
  3283.     exit(EXIT_FAILURE);
  3284.     }
  3285.  
  3286. #ifndef POWERUP
  3287. #   if defined(__HAVE_68881__)
  3288.     if(!(SysBase->AttnFlags&AFF_68881)) {
  3289.     printf("This version requires a FPU.\n");
  3290.     exit(EXIT_FAILURE);
  3291.     }
  3292. #   endif
  3293.  
  3294. #   if defined(__mc68060__) /* should work on 68040 too */
  3295.     if(!(SysBase->AttnFlags&(AFF_68060|AFF_68040))) {
  3296.     printf("This version requires a 68060.\n");
  3297.     exit(EXIT_FAILURE);
  3298.     }
  3299. #   elif defined(__mc68040__) /* should work on 68060 too */
  3300.     if(!(SysBase->AttnFlags&(AFF_68060|AFF_68040))) {
  3301.     printf("This version requires a 68040.\n");
  3302.     exit(EXIT_FAILURE);
  3303.     }
  3304. #   endif
  3305. #endif
  3306.  
  3307.     olddir=CurrentDir(0);
  3308.     CurrentDir(olddir);
  3309.  
  3310.     atexit(&cleanup);
  3311.  
  3312.     IntuitionBase=(struct IntuitionBase*)OpenLibrary("intuition.library",39);
  3313.     GfxBase=(struct GfxBase*)OpenLibrary("graphics.library",39);
  3314.     LayersBase=OpenLibrary("layers.library",39);
  3315.     UtilityBase=(struct UtilityBase*)OpenLibrary("utility.library",39);
  3316.     IconBase=OpenLibrary("icon.library",39);
  3317.     DiskfontBase=OpenLibrary("diskfont.library",39);
  3318.     IFFParseBase=OpenLibrary("iffparse.library",39);
  3319.     if(!IntuitionBase || !GfxBase || !LayersBase || !UtilityBase ||
  3320.        !IconBase || !DiskfontBase || !IFFParseBase) {
  3321.     printf("Requires AmigaOS 3.0+\n");
  3322.     exit(EXIT_FAILURE);
  3323.     }
  3324.  
  3325.     if(proc->pr_CLI) {
  3326.     size_t l=16;
  3327.     char* path;
  3328.     const char* endpath;
  3329.     while(1) {
  3330.         progname=malloc(l);
  3331.         if(!progname)
  3332.         break;
  3333.         if(GetProgramName(progname,l))
  3334.         break;
  3335.         free(progname);
  3336.         l+=16;
  3337.     }
  3338.     if(!(rda=ReadArgs(TEMPLATE,args,NULL))) {
  3339.         PrintFault(IoErr(),"Error: ");
  3340.         exit(EXIT_FAILURE);
  3341.     }
  3342.     if(PDFFILE) {
  3343.         endpath=PathPart((char*)PDFFILE);
  3344.         path=malloc(endpath-PDFFILE+1);
  3345.         if(path) {
  3346.         memcpy(path,PDFFILE,endpath-PDFFILE);
  3347.         path[endpath-PDFFILE]='\0';
  3348.         docdir=Lock(path,ACCESS_READ);
  3349.         free(path);
  3350.         copystr(&docname,FilePart((char*)PDFFILE));
  3351.         }
  3352.     }
  3353.     } else {
  3354. #if defined(__SASC) || defined(__libnix__)
  3355.     size_t l;
  3356.     if(_WBenchMsg && _WBenchMsg->sm_NumArgs>=1) {
  3357.         copystr(&progname,_WBenchMsg->sm_ArgList[0].wa_Name);
  3358.         if(_WBenchMsg->sm_NumArgs>=2) {
  3359.         docdir=DupLock(_WBenchMsg->sm_ArgList[1].wa_Lock);
  3360.         copystr(&docname,_WBenchMsg->sm_ArgList[1].wa_Name);
  3361.         }
  3362.     } else {
  3363.         printf("I don't understand the startup method !?\n");
  3364.         exit(EXIT_FAILURE);
  3365.     }
  3366. #else
  3367.     /* adapt for other compilers/libraries */
  3368.     exit(EXIT_FAILURE);
  3369. #endif
  3370.     }
  3371.  
  3372.     progdir=GetProgramDir();
  3373.  
  3374.     /* gzip sometimes tries to open "*" for input, */
  3375.     /* which opens and locks the stdiowin. */
  3376.     /* Let's prevent that: */
  3377.     if(input=Open("nil:",MODE_OLDFILE))
  3378.     oldinput=SelectInput(input);
  3379.  
  3380.     MUIMasterBase=OpenLibrary(MUIMASTER_NAME,MUIMASTER_VMIN);
  3381.     if(!MUIMasterBase) {
  3382.     printf("Can't open \"muimaster.library\".\n");
  3383.     exit(EXIT_FAILURE);
  3384.     }
  3385.  
  3386.     if(!docname && open_req()) {
  3387.     UnLock(docdir); /* there is a slight chance that docdir is locked... */
  3388.     docdir=Lock(req->fr_Drawer,ACCESS_READ);
  3389.     copystr(&docname,req->fr_File);
  3390.     }
  3391.     if(!progname || !docname)
  3392.     exit(EXIT_FAILURE);
  3393.  
  3394.     parse_tooltypes(progdir,progname);
  3395.     parse_tooltypes(docdir,docname);
  3396.  
  3397.     {
  3398.     BPTR olddir=CurrentDir(progdir);
  3399.     if(DISKOBJ)
  3400.         diskobj=GetDiskObject((char*)DISKOBJ);
  3401.     else
  3402.         diskobj=GetDiskObject(progname);
  3403.     CurrentDir(olddir);
  3404.     }
  3405.  
  3406.     CyberGfxBase=OpenLibrary("cybergraphics.library",41); /* may fail */
  3407.  
  3408. #ifdef POWERUP
  3409.     PPCLibBase=OpenLibrary("ppc.library",46);
  3410.     if(!PPCLibBase) {
  3411.     printf("Can't open \"ppc.library\".\n");
  3412.     exit(EXIT_FAILURE);
  3413.     }
  3414.  
  3415.     elfobject=PPCLoadObject("PROGDIR:apdf.elf");
  3416.     if(!elfobject) {
  3417.     printf("Can't load \"apdf.elf\".\n");
  3418.     exit(EXIT_FAILURE);
  3419.     }
  3420.  
  3421.     port=PPCCreatePort(NULL);
  3422.     reply_port=PPCCreatePort(NULL);
  3423.     if(!port || !reply_port) {
  3424.     printf("Can't create port.\n");
  3425.     exit(EXIT_FAILURE);
  3426.     }
  3427.  
  3428.     ports[0]=port;
  3429.     ports[1]=reply_port;
  3430.     ports[2]=NULL;
  3431.     portlist=PPCCreatePortList(ports,0);
  3432.     if(!portlist) {
  3433.     printf("Can't create port list.\n");
  3434.     exit(EXIT_FAILURE);
  3435.     }
  3436. #endif
  3437.  
  3438.     mcc=MUI_CreateCustomClass(NULL,MUIC_Area,NULL,sizeof(DocData),dispatcher);
  3439.     slider_mcc=MUI_CreateCustomClass(NULL,MUIC_Slider,NULL,sizeof(SliderData),mysliderdispatcher);
  3440.     rotate_slider_mcc=MUI_CreateCustomClass(NULL,MUIC_Slider,NULL,sizeof(RotateSliderData),myrotatesliderdispatcher);
  3441.     list_mcc=MUI_CreateCustomClass(NULL,MUIC_List,NULL,sizeof(ListData),mylistdispatcher);
  3442.     if(!mcc || !slider_mcc || !rotate_slider_mcc || !list_mcc) {
  3443.     printf("Can't create custom class.\n");
  3444.     exit(EXIT_FAILURE);
  3445.     }
  3446.  
  3447.     App=ApplicationObject,
  3448.     MUIA_Application_Title,         "Apdf",
  3449.     MUIA_Application_Version,       "$VER: " apdfVerString,
  3450.     MUIA_Application_Copyright,     xpdfCopyright,
  3451.     MUIA_Application_Author,        "Derek B. Noonburg, Emmanuel Lesueur",
  3452.     MUIA_Application_Description,   "PDF documents viewer",
  3453.     MUIA_Application_Base,          "Apdf",
  3454.     MUIA_Application_DiskObject,    diskobj,
  3455.     /*
  3456.      *  Main window
  3457.      */
  3458.     SubWindow,win=WindowObject,
  3459.         MUIA_Window_Title,docname,
  3460.         MUIA_Window_ID,MAKE_ID('A','P','D','F'),
  3461.         MUIA_Window_Menustrip,menu=MUI_MakeObject(MUIO_MenustripNM,menudata,0),
  3462.         MUIA_Window_AppWindow,TRUE,
  3463.         WindowContents,VGroup,
  3464.         Child,ScrollgroupObject,
  3465.             MUIA_Scrollgroup_Contents,vgroup=VirtgroupObject,
  3466.             VirtualFrame,
  3467.             Child,bitmapobj=DocObject,
  3468.                 MUIA_CycleChain,TRUE,
  3469.                 End,
  3470.             End,
  3471.             End,
  3472.         Child,HGroup,
  3473.             Child,Label2("Page"),
  3474.             Child,pageobj=MySliderObject,
  3475.             SliderFrame,
  3476.             MUIA_Background,MUII_SliderBack,
  3477.             MUIA_Slider_Horiz,TRUE,
  3478.             MUIA_Numeric_Min,1,
  3479.             MUIA_Numeric_Max,1,
  3480.             MYATTR_Value,1,
  3481.             End,
  3482.             Child,BalanceObject,
  3483.             End,
  3484.             Child,strobj=StringObject,
  3485.             StringFrame,
  3486.             MUIA_String_Accept,"0123456789",
  3487.             MUIA_String_Contents,"1",
  3488.             MUIA_String_MaxLen,10,
  3489.             MUIA_Weight,10,
  3490.             MUIA_CycleChain,TRUE,
  3491.             End,
  3492.             End,
  3493.         Child,HGroup,
  3494.             Child,Label2("Zoom"),
  3495.             Child,zoomobj=MySliderObject,
  3496.             SliderFrame,
  3497.             MUIA_Background,MUII_SliderBack,
  3498.             MUIA_Slider_Horiz,TRUE,
  3499.             MUIA_Numeric_Min,minZoom,
  3500.             MUIA_Numeric_Max,maxZoom,
  3501.             MUIA_Numeric_Value,defZoom,
  3502.             MUIA_CycleChain,TRUE,
  3503.             End,
  3504.             Child,BalanceObject,
  3505.             End,
  3506.             Child,Label2("Search"),
  3507.             Child,searchobj=StringObject,
  3508.             StringFrame,
  3509.             MUIA_String_MaxLen,99,
  3510.             MUIA_Weight,200,
  3511.             MUIA_CycleChain,TRUE,
  3512.             End,
  3513.             Child,nxtsrchobj=SimpleButton("_Next"),
  3514.             Child,BalanceObject,
  3515.             End,
  3516.             Child,linkobj=TextObject,
  3517.             TextFrame,
  3518.             MUIA_Background,MUII_TextBack,
  3519.             End,
  3520.             End,
  3521.         End,
  3522.         End,
  3523.  
  3524.     /*
  3525.      *  Gauge window
  3526.      */
  3527.     SubWindow,gaugewin=WindowObject,
  3528.         MUIA_Window_ID,MAKE_ID('P','R','G','S'),
  3529.         MUIA_Window_CloseGadget,FALSE,
  3530.         WindowContents,VGroup,
  3531.         Child,gaugeobj=GaugeObject,
  3532.             GaugeFrame,
  3533.             MUIA_Gauge_Horiz,TRUE,
  3534.             End,
  3535.         Child,HGroup,
  3536.             Child,RectangleObject,
  3537.             End,
  3538.             Child,abortobj=SimpleButton("_Abort"),
  3539.             Child,RectangleObject,
  3540.             End,
  3541.             End,
  3542.         End,
  3543.         End,
  3544.  
  3545.     /*
  3546.      *  Save window
  3547.      */
  3548.     SubWindow,pswin=WindowObject,
  3549.         MUIA_Window_Title,"Save as...",
  3550.         MUIA_Window_ID,MAKE_ID('S','A','V','E'),
  3551.         WindowContents,VGroup,
  3552.         Child,ColGroup(2),
  3553.             Child,Label2("File"),
  3554.             Child,pspopobj=PopaslObject,
  3555.             MUIA_Popasl_Type,ASL_FileRequest,
  3556.             MUIA_Popstring_String,psfilenameobj=StringObject,
  3557.                 StringFrame,
  3558.                 MUIA_String_MaxLen,255,
  3559.                 MUIA_String_AdvanceOnCR,TRUE,
  3560.                 MUIA_CycleChain,TRUE,
  3561.                 End,
  3562.             MUIA_Popstring_Button,PopButton(MUII_PopFile),
  3563.             ASLFR_TitleText,"Select a file name...",
  3564.             End,
  3565.             Child,Label2("Mode"),
  3566.             Child,pstypeobj=CycleObject,
  3567.             MUIA_Cycle_Entries,save_types,
  3568.             MUIA_CycleChain,TRUE,
  3569.             End,
  3570.             Child,Label2("First page"),
  3571.             Child,HGroup,
  3572.             Child,psstartobj=SliderObject,
  3573.                 SliderFrame,
  3574.                 MUIA_Background,MUII_SliderBack,
  3575.                 MUIA_Slider_Horiz,TRUE,
  3576.                 MUIA_Numeric_Min,1,
  3577.                 MUIA_Numeric_Max,1,
  3578.                 End,
  3579.             Child,BalanceObject,
  3580.                 End,
  3581.             Child,psstartstrobj=StringObject,
  3582.                 StringFrame,
  3583.                 MUIA_String_Accept,"0123456789",
  3584.                 MUIA_String_Contents,"1",
  3585.                 MUIA_String_MaxLen,10,
  3586.                 MUIA_String_AdvanceOnCR,TRUE,
  3587.                 MUIA_Weight,10,
  3588.                 MUIA_CycleChain,TRUE,
  3589.                 End,
  3590.             End,
  3591.             Child,Label2("Last page"),
  3592.             Child,HGroup,
  3593.             Child,psstopobj=SliderObject,
  3594.                 SliderFrame,
  3595.                 MUIA_Background,MUII_SliderBack,
  3596.                 MUIA_Slider_Horiz,TRUE,
  3597.                 MUIA_Numeric_Min,1,
  3598.                 MUIA_Numeric_Max,1,
  3599.                 End,
  3600.             Child,BalanceObject,
  3601.                 End,
  3602.             Child,psstopstrobj=StringObject,
  3603.                 StringFrame,
  3604.                 MUIA_String_Accept,"0123456789",
  3605.                 MUIA_String_Contents,"1",
  3606.                 MUIA_String_MaxLen,10,
  3607.                 MUIA_String_AdvanceOnCR,TRUE,
  3608.                 MUIA_Weight,10,
  3609.                 MUIA_CycleChain,TRUE,
  3610.                 End,
  3611.             End,
  3612.             Child,Label2("Zoom"),
  3613.             Child,pszoomobj=SliderObject,
  3614.             SliderFrame,
  3615.             MUIA_Background,MUII_SliderBack,
  3616.             MUIA_Slider_Horiz,TRUE,
  3617.             MUIA_Numeric_Min,minZoom,
  3618.             MUIA_Numeric_Max,maxZoom,
  3619.             MUIA_Numeric_Value,0,
  3620.             MUIA_CycleChain,TRUE,
  3621.             End,
  3622.             Child,Label2("Rotate"),
  3623.             Child,psrotateobj=MyRotateSliderObject,
  3624.             SliderFrame,
  3625.             MUIA_Background,MUII_SliderBack,
  3626.             MUIA_Slider_Horiz,TRUE,
  3627.             MUIA_Numeric_Min,0,
  3628.             MUIA_Numeric_Max,3,
  3629.             MUIA_Numeric_Value,0,
  3630.             MUIA_CycleChain,TRUE,
  3631.             End,
  3632.             End,
  3633.         Child,HGroup,
  3634.             Child,pssaveobj=SimpleButton("_Save"),
  3635.             Child,pscancelobj=SimpleButton("_Cancel"),
  3636.             End,
  3637.         End,
  3638.         End,
  3639.  
  3640.     SubWindow,scanwin=WindowObject,
  3641.         MUIA_Window_Title,"Scan...",
  3642.         MUIA_Window_ID,MAKE_ID('S','C','A','N'),
  3643.         WindowContents,VGroup,
  3644.         Child,HGroup,
  3645.             Child,VGroup,
  3646.             Child,Label2("First page"),
  3647.             Child,Label2("Last page"),
  3648.             End,
  3649.             Child,VGroup,
  3650.             Child,scanstartobj=SliderObject,
  3651.                 SliderFrame,
  3652.                 MUIA_Background,MUII_SliderBack,
  3653.                 MUIA_Slider_Horiz,TRUE,
  3654.                 MUIA_Numeric_Min,1,
  3655.                 MUIA_Numeric_Max,1,
  3656.                 End,
  3657.             Child,scanstopobj=SliderObject,
  3658.                 SliderFrame,
  3659.                 MUIA_Background,MUII_SliderBack,
  3660.                 MUIA_Slider_Horiz,TRUE,
  3661.                 MUIA_Numeric_Min,1,
  3662.                 MUIA_Numeric_Max,1,
  3663.                 End,
  3664.             End,
  3665.             Child,BalanceObject,
  3666.             End,
  3667.             Child,VGroup,
  3668.             MUIA_Weight,10,
  3669.             Child,scanstartstrobj=StringObject,
  3670.                 StringFrame,
  3671.                 MUIA_String_Accept,"0123456789",
  3672.                 MUIA_String_Contents,"1",
  3673.                 MUIA_String_MaxLen,10,
  3674.                 MUIA_String_AdvanceOnCR,TRUE,
  3675.                 MUIA_CycleChain,TRUE,
  3676.                 End,
  3677.             Child,scanstopstrobj=StringObject,
  3678.                 StringFrame,
  3679.                 MUIA_String_Accept,"0123456789",
  3680.                 MUIA_String_Contents,"1",
  3681.                 MUIA_String_MaxLen,10,
  3682.                 MUIA_String_AdvanceOnCR,TRUE,
  3683.                 MUIA_CycleChain,TRUE,
  3684.                 End,
  3685.             End,
  3686.             End,
  3687.         Child,HGroup,
  3688.             Child,RectangleObject,
  3689.             End,
  3690.             Child,scanobj=SimpleButton("_Scan"),
  3691.             Child,RectangleObject,
  3692.             End,
  3693.             End,
  3694.         End,
  3695.         End,
  3696.     MUIA_Application_DropObject,win,
  3697.     End;
  3698.  
  3699.     if(!App) {
  3700.     printf("Can't create MUI application.\n");
  3701.     exit(EXIT_FAILURE);
  3702.     }
  3703.  
  3704.     make_fontmap_win(&def_fmw,"Default font mapping",
  3705.              &progdir,&progname,MAKE_ID('F','N','T','1'),
  3706.              defaultfontsobj=SimpleButton("_Scan"));
  3707.     make_fontmap_win(&doc_fmw,"Document font mapping",
  3708.              &docdir,&docname,MAKE_ID('F','N','T','2'),
  3709.              scanfontsobj=SimpleButton("_Scan..."));
  3710.  
  3711.     set(win,MUIA_Window_DefaultObject,bitmapobj);
  3712.     DoMethod(win,MUIM_Notify,MUIA_Window_CloseRequest,TRUE,
  3713.          App,2,MUIM_Application_ReturnID,MUIV_Application_ReturnID_Quit);
  3714.     DoMethod(win,MUIM_Notify,MUIA_AppMessage,MUIV_EveryTime,
  3715.          win,3,MUIM_CallHook,&appwin_hook,MUIV_TriggerValue);
  3716.     DoMethod(pageobj,MUIM_Notify,MYATTR_Value,MUIV_EveryTime,
  3717.          strobj,3,MUIM_Set,MUIA_String_Integer,MUIV_TriggerValue);
  3718.     DoMethod(strobj,MUIM_Notify,MUIA_String_Acknowledge,MUIV_EveryTime,
  3719.          pageobj,3,MUIM_CallHook,&setnum_hook,strobj);
  3720.     DoMethod(pageobj,MUIM_Notify,MYATTR_Value,MUIV_EveryTime,
  3721.          bitmapobj,3,MUIM_Set,MYATTR_Page,MUIV_TriggerValue);
  3722.     DoMethod(zoomobj,MUIM_Notify,MYATTR_Value,MUIV_EveryTime,
  3723.          bitmapobj,3,MUIM_Set,MYATTR_Zoom,MUIV_TriggerValue);
  3724.     DoMethod(searchobj,MUIM_Notify,MUIA_String_Acknowledge,MUIV_EveryTime,
  3725.          App,2,MUIM_Application_ReturnID,ID_SEARCH);
  3726.     DoMethod(nxtsrchobj,MUIM_Notify,MUIA_Selected,FALSE,
  3727.          App,2,MUIM_Application_ReturnID,ID_SEARCH);
  3728.  
  3729.     DoMethod(pswin,MUIM_Notify,MUIA_Window_CloseRequest,TRUE,
  3730.          pswin,3,MUIM_Set,MUIA_Window_Open,FALSE);
  3731.     DoMethod(psstartobj,MUIM_Notify,MUIA_Numeric_Value,MUIV_EveryTime,
  3732.          psstartstrobj,3,MUIM_Set,MUIA_String_Integer,MUIV_TriggerValue);
  3733.     DoMethod(psstopobj,MUIM_Notify,MUIA_Numeric_Value,MUIV_EveryTime,
  3734.          psstopstrobj,3,MUIM_Set,MUIA_String_Integer,MUIV_TriggerValue);
  3735.     DoMethod(psstartstrobj,MUIM_Notify,MUIA_String_Acknowledge,MUIV_EveryTime,
  3736.          psstartobj,3,MUIM_CallHook,&setnum_hook,psstartstrobj);
  3737.     DoMethod(psstopstrobj,MUIM_Notify,MUIA_String_Acknowledge,MUIV_EveryTime,
  3738.          psstopobj,3,MUIM_CallHook,&setnum_hook,psstopstrobj);
  3739.     DoMethod(pscancelobj,MUIM_Notify,MUIA_Pressed,FALSE,
  3740.          pswin,3,MUIM_Set,MUIA_Window_Open,FALSE);
  3741.     DoMethod(pssaveobj,MUIM_Notify,MUIA_Pressed,FALSE,
  3742.          App,2,MUIM_Application_ReturnID,ID_WRITE);
  3743.  
  3744.     DoMethod(defaultfontsobj,MUIM_Notify,MUIA_Pressed,FALSE,
  3745.          App,2,MUIM_Application_ReturnID,ID_DEFAULTFONTS);
  3746.     DoMethod(scanfontsobj,MUIM_Notify,MUIA_Pressed,FALSE,
  3747.          App,2,MUIM_Application_ReturnID,ID_OPENSCANFONTS);
  3748.  
  3749.     DoMethod(scanwin,MUIM_Notify,MUIA_Window_CloseRequest,TRUE,
  3750.          scanwin,3,MUIM_Set,MUIA_Window_Open,FALSE);
  3751.     DoMethod(scanstartobj,MUIM_Notify,MUIA_Numeric_Value,MUIV_EveryTime,
  3752.          scanstartstrobj,3,MUIM_Set,MUIA_String_Integer,MUIV_TriggerValue);
  3753.     DoMethod(scanstopobj,MUIM_Notify,MUIA_Numeric_Value,MUIV_EveryTime,
  3754.          scanstopstrobj,3,MUIM_Set,MUIA_String_Integer,MUIV_TriggerValue);
  3755.     DoMethod(scanstartstrobj,MUIM_Notify,MUIA_String_Acknowledge,MUIV_EveryTime,
  3756.          scanstartobj,3,MUIM_CallHook,&setnum_hook,scanstartstrobj);
  3757.     DoMethod(scanstopstrobj,MUIM_Notify,MUIA_String_Acknowledge,MUIV_EveryTime,
  3758.          scanstopobj,3,MUIM_CallHook,&setnum_hook,scanstopstrobj);
  3759.     DoMethod(scanobj,MUIM_Notify,MUIA_Pressed,FALSE,
  3760.          App,2,MUIM_Application_ReturnID,ID_SCANFONTS);
  3761.  
  3762.     DoMethod(abortobj,MUIM_Notify,MUIA_Selected,FALSE,
  3763.          App,2,MUIM_Application_ReturnID,ID_ABORT);
  3764.  
  3765. #ifdef POWERUP
  3766.     {
  3767.     size_t l=strlen(GZIPCMD);
  3768.     startup_length=sizeof(struct StartupData)+1+l;
  3769.     startup_data=PPCAllocVec(startup_length,MEMF_ANY);
  3770.     startup_data->port=port;
  3771.     startup_data->in=Input();
  3772.     startup_data->out=Output();
  3773.         /* libnix startup code does not initialize pr_CES */
  3774.         /* when started from Workbench. Use Output() instead. */
  3775.     startup_data->err=proc->pr_CLI?proc->pr_CES:Output();
  3776.     startup_data->status=0;
  3777.     startup_data->flags=0;
  3778.     startup_data->colors=COLORS;
  3779.     startup_data->id=VMAGIC;
  3780.     memcpy(startup_data->gzipcmd,GZIPCMD,l+1);
  3781.     }
  3782.  
  3783.     quitmsg=PPCCreateMessage(reply_port,0);
  3784.     cmdmsg=PPCCreateMessage(reply_port,sizeof(union msg_max));
  3785.     startupmsg=PPCCreateMessage(reply_port,startup_length);
  3786.     cmddata=PPCAllocVec(sizeof(union msg_max),MEMF_ANY);
  3787.     if(!startupmsg || !quitmsg || !cmdmsg || !cmddata) {
  3788.     printf("Can't create message.\n");
  3789.     exit(EXIT_FAILURE);
  3790.     }
  3791.  
  3792.     ppctask=PPCCreateTaskTags(elfobject,
  3793.     PPCTASKTAG_NAME,"PDF decoder",
  3794.     PPCTASKTAG_STACKSIZE,50000,
  3795.     //PPCTASKTAG_PRIORITY,0,
  3796.     PPCTASKTAG_STARTUP_MSG,startupmsg,
  3797.     PPCTASKTAG_STARTUP_MSGDATA,startup_data,
  3798.     PPCTASKTAG_STARTUP_MSGLENGTH,startup_length,
  3799.     PPCTASKTAG_MSGPORT,TRUE,
  3800.     NP_Input,startup_data->in,
  3801.     NP_CloseInput,FALSE,
  3802.     NP_Output,startup_data->out,
  3803.     NP_CloseOutput,FALSE,
  3804.     NP_Error,startup_data->err,
  3805.     NP_CloseError,FALSE,
  3806.     TAG_END);
  3807.     if(!ppctask) {
  3808.     printf("Can't create PPC task.\n");
  3809.     exit(EXIT_FAILURE);
  3810.     }
  3811.     ppcport=(void*)PPCGetTaskAttrsTags(ppctask,PPCTASKINFOTAG_MSGPORT,NULL,TAG_END);
  3812.  
  3813.     while(1) {
  3814.     void* msg;
  3815.     PPCWaitPortList(portlist);
  3816.     if(msg=PPCGetMessage(port)) {
  3817.         /* syncmsg */
  3818.         BOOL ok=VMAGIC==(int)PPCGetMessageAttr(msg,PPCMSGTAG_DATA);
  3819.         PPCReplyMessage(msg);
  3820.         if(!ok) {
  3821.         printf("Wrong version of the PPC module.\n");
  3822.         quit();
  3823.         exit(EXIT_FAILURE);
  3824.         }
  3825.         break;
  3826.     } else if(PPCGetMessage(reply_port)) {
  3827.         /* startupmsg */
  3828.         printf("PPC task initialization failed.\n");
  3829.         exit(EXIT_FAILURE);
  3830.     }
  3831.     }
  3832.     ppc_quitted=FALSE;
  3833. #else
  3834.     if(!init(COLORS,GZIPCMD))
  3835.     exit(EXIT_FAILURE);
  3836. #endif
  3837.  
  3838. #ifdef POWERUP
  3839.     if(quitting)
  3840.     ;
  3841.     else
  3842. #endif
  3843.      if(!create_doc(docdir,docname,CACHESZ,BLOCSZ))
  3844.     quit();
  3845.     else {
  3846.     CurrentDir(docdir);
  3847.     get_page_info();
  3848.  
  3849.     parse_fontmap_tooltypes(def_fmw.fontmapobj,progdir,progname);
  3850.     setfontmap(def_fmw.fontmapobj);
  3851.     do_scan_fonts(&def_fmw,scan_default_fonts());
  3852.     parse_fontmap_tooltypes(doc_fmw.fontmapobj,docdir,docname);
  3853.     if(FONTMAP) {
  3854.         parse_fontmap(def_fmw.fontmapobj,FONTMAP);
  3855.         setfontmap(def_fmw.fontmapobj);
  3856.     }
  3857.     setfontmap(doc_fmw.fontmapobj);
  3858.  
  3859.     set(pageobj,MUIA_Numeric_Value,PAGE);
  3860.     set(zoomobj,MUIA_Numeric_Value,ZOOM);
  3861.  
  3862.     set(win,MUIA_Window_Open,TRUE);
  3863.     {
  3864.         LONG x;
  3865.         get(win,MUIA_Window_Open,&x);
  3866.         if(!x)
  3867.         quit();
  3868.     }
  3869.     }
  3870.  
  3871.     sigs=0;
  3872.     while(
  3873. #ifdef POWERUP
  3874.       !ppc_quitted
  3875. #else
  3876.       1
  3877. #endif
  3878.        ) {
  3879.     void* msg;
  3880.     if(App) {
  3881.         do {
  3882.         LONG id=DoMethod(App,MUIM_Application_NewInput,&sigs);
  3883.         switch(id) {
  3884.           case MUIV_Application_ReturnID_Quit:
  3885.             set(win,MUIA_Window_Open,FALSE);
  3886.             quit();
  3887.             break;
  3888.  
  3889.           case ID_ABOUT:
  3890.             MUI_Request(App,win,0,"Apdf "apdfVersion,"OK",
  3891.                 MUIX_C
  3892.                 "Apdf "apdfVersion"\n"
  3893. #ifdef POWERUP
  3894.                 "PowerUp"
  3895. #else
  3896. #   if defined(__mc68060__)
  3897.                 "68060"
  3898. #   elif defined(__mc68040__)
  3899.                 "68040"
  3900. #   elif defined(__mc68030__)
  3901.                 "68030"
  3902. #   elif defined(__mc68020__)
  3903.                 "68020"
  3904. #   endif
  3905.                 " "
  3906. #   if defined(__HAVE_68881__)
  3907.                 "FPU"
  3908. #   else
  3909.                 "no FPU"
  3910. #   endif
  3911. #endif
  3912.                 " version.\n\n"
  3913.                 "Based on xpdf "xpdfVersion"\n"
  3914.                 xpdfCopyright"\n"
  3915.                 "derekn@foolabs.com\n\n"
  3916.                 "Supports PDF version "pdfVersion"\n"
  3917.                 "The PDF data structures, operators, and specification\n"
  3918.                 "are copyright 1995 Adobe Systems Inc.\n\n"
  3919.                 "http://www.foolabs.com/xpdf/\n\n"
  3920.                 "Amiga port by Emmanuel Lesueur\n"
  3921.                 "lesueur@club-internet.fr\n");
  3922.             break;
  3923.  
  3924.           case ID_ABOUTMUI:
  3925.             DoMethod(App,MUIM_Application_AboutMUI,win);
  3926.             break;
  3927.  
  3928.           case ID_OPEN:
  3929.             if(open_req())
  3930.             open_req_file();
  3931.             break;
  3932.  
  3933.           case ID_SEARCH: {
  3934.             const char* str;
  3935.             get(searchobj,MUIA_String_Contents,&str);
  3936.             search(str);
  3937.             break;
  3938.           }
  3939.           case ID_PRINT:
  3940.             set(psfilenameobj,MUIA_String_Contents,"PRT:");
  3941.             set(pstypeobj,MUIA_Cycle_Active,0);
  3942.             /* Fall through */
  3943.           case ID_SAVEAS: {
  3944.             LONG x;
  3945.             get(pageobj,MUIA_Numeric_Value,&x);
  3946.             set(psstartobj,MUIA_Numeric_Value,x);
  3947.             set(psstopobj,MUIA_Numeric_Value,x);
  3948.             set(psrotateobj,MUIA_Numeric_Value,0);
  3949.             set(pswin,MUIA_Window_Open,TRUE);
  3950.             break;
  3951.           }
  3952.           case ID_WRITE: {
  3953.             int first_page;
  3954.             int last_page;
  3955.             int zoom;
  3956.             int rotate;
  3957.             int type;
  3958.             const char* filename;
  3959.             LONG active;
  3960.             get(psfilenameobj,MUIA_String_Contents,&filename);
  3961.             get(psstartobj,MUIA_Numeric_Value,&first_page);
  3962.             get(psstopobj,MUIA_Numeric_Value,&last_page);
  3963.             get(pszoomobj,MUIA_Numeric_Value,&zoom);
  3964.             get(psrotateobj,MUIA_Numeric_Value,&rotate);
  3965.             get(pspopobj,MUIA_Popasl_Active,&active);
  3966.             get(pstypeobj,MUIA_Cycle_Active,&type);
  3967.             zoom=zoomDPI[zoom-minZoom];
  3968.             rotate*=90;
  3969.             if(!active && filename && last_page>=first_page) {
  3970.             SetAttrs(pswin,
  3971.                  MUIA_Window_Open,FALSE,
  3972.                  MUIA_Window_ActiveObject,psfilenameobj,
  3973.                  TAG_END);
  3974.             save(filename,first_page,last_page,zoom,rotate,type);
  3975.             } else
  3976.             DisplayBeep(NULL);
  3977.             break;
  3978.           }
  3979.           case ID_COPY: {
  3980.             LONG selected;
  3981.             get(bitmapobj,MYATTR_Selected,&selected);
  3982.             if(selected) {
  3983.             struct Rectangle rect;
  3984.             get(bitmapobj,MYATTR_Selection,&rect);
  3985.             toclip(rect.MinX,rect.MinY,rect.MaxX,rect.MaxY);
  3986.             }
  3987.             break;
  3988.           }
  3989.  
  3990.           case ID_MUIPREFS:
  3991.             DoMethod(App,MUIM_Application_OpenConfigWindow,0);
  3992.             break;
  3993.  
  3994.           case ID_DEFFONTS:
  3995.             set(def_fmw.win,MUIA_Window_Open,TRUE);
  3996.             break;
  3997.  
  3998.           case ID_DOCFONTS:
  3999.             set(doc_fmw.win,MUIA_Window_Open,TRUE);
  4000.             break;
  4001.  
  4002.           case ID_APPLYFONTMAP:
  4003.             clear_fontmap();
  4004.             setfontmap(def_fmw.fontmapobj);
  4005.             setfontmap(doc_fmw.fontmapobj);
  4006.             DoMethod(bitmapobj,MYM_Reset);
  4007.             break;
  4008.  
  4009.           case ID_OPENSCANFONTS: {
  4010.             LONG x;
  4011.             get(pageobj,MUIA_Numeric_Value,&x);
  4012.             set(scanstartobj,MUIA_Numeric_Value,x);
  4013.             set(scanstopobj,MUIA_Numeric_Value,x);
  4014.             set(scanwin,MUIA_Window_Open,TRUE);
  4015.             break;
  4016.           }
  4017.           case ID_SCANFONTS: {
  4018.             int first_page;
  4019.             int last_page;
  4020.             get(scanstartobj,MUIA_Numeric_Value,&first_page);
  4021.             get(scanstopobj,MUIA_Numeric_Value,&last_page);
  4022.             if(last_page>=first_page) {
  4023.             do_scan_fonts(&doc_fmw,scan_doc_fonts(first_page,last_page));
  4024.             set(scanwin,MUIA_Window_Open,FALSE);
  4025.             } else
  4026.             DisplayBeep(NULL);
  4027.             break;
  4028.           }
  4029.  
  4030.           case ID_DEFAULTFONTS:
  4031.             do_scan_fonts(&def_fmw,scan_default_fonts());
  4032.             break;
  4033.  
  4034.           case ID_HIDE:
  4035.             set(App,MUIA_Application_Iconified,TRUE);
  4036.             break;
  4037.         }
  4038.         } while(sigs==0);
  4039.     }
  4040.  
  4041. #ifdef POWERUP
  4042.     PPCSetPortListAttr(portlist,PPCPORTLISTTAG_EXTENDEDSIGNALS,sigs|SIGBREAKF_CTRL_C);
  4043.     PPCWaitPortList(portlist);
  4044.  
  4045.     if(msg=PPCGetMessage(reply_port)) {
  4046.         MYASSERT(msg==startupmsg);
  4047.         ppc_quitted=TRUE;
  4048.         exit(EXIT_SUCCESS);
  4049.     }
  4050.     if(PPCGetMessage(port)) {
  4051.         MYASSERT(FALSE);
  4052.     }
  4053.  
  4054.     sigs=PPCGetPortListAttr(portlist,PPCPORTLISTTAG_RECEIVEDSIGNALS);
  4055. #else
  4056.     sigs=Wait(sigs|SIGBREAKF_CTRL_C);
  4057. #endif
  4058.     if(sigs&SIGBREAKF_CTRL_C) {
  4059.         set(win,MUIA_Window_Open,FALSE);
  4060.         quit();
  4061.     }
  4062.     }
  4063.  
  4064.     return EXIT_SUCCESS;
  4065. }
  4066.  
  4067.  
  4068.