home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / apps / dtp / ghost / gs301src / atari / gp_atar3.c < prev    next >
C/C++ Source or Header  |  1994-09-17  |  62KB  |  2,716 lines

  1. /* Copyright (C) 1989, 1992, 1993 Aladdin Enterprises.  All rights reserved.
  2.  
  3. This file is part of Ghostscript.
  4.  
  5. Ghostscript is distributed in the hope that it will be useful, but
  6. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  7. to anyone for the consequences of using it or for whether it serves any
  8. particular purpose or works at all, unless he says so in writing.  Refer
  9. to the Ghostscript General Public License for full details.
  10.  
  11. Everyone is granted permission to copy, modify and redistribute
  12. Ghostscript, but only under the conditions described in the Ghostscript
  13. General Public License.  A copy of this license is supposed to have been
  14. given to you along with Ghostscript so you can know your rights and
  15. responsibilities.  It should be in a file named COPYING.  Among other
  16. things, the copyright notice and this notice must be preserved on all
  17. copies.  */
  18.  
  19. /* gp_atar3.c */
  20.  
  21. /*
  22.  * This file contains general utility routines for the Atari platform.
  23.  */
  24.  
  25. #include "gp_atar3.h"
  26.  
  27. extern WINLIST *WList;                    /* gp_atar2.c */
  28. extern WINDOW conswin;                    /* gp_atar2.c */
  29. extern WINDOW imagwin, aboutwin, reswin;        /* gp_atar2.c */
  30. extern WINDOW devwin, sizwin, iconwin, printwin;    /* gp_atar2.c */
  31.  
  32. extern OBJECT menuobj[], aboutobj[], resobj[], devobj[];
  33. extern OBJECT sizobj[], iconobj[], printobj[], savemsg[];
  34.  
  35. extern GRAPHIC Graphic;
  36.  
  37. extern char saveline[MAXLEN];                /* gp_atar1.h */
  38. extern char devices[DEVICES][DNAMELEN];            /* gp_atar1.h */
  39. extern char sizes[DEVICES][DNAMELEN];            /* gp_atar1.h */
  40.  
  41. extern VWRK VWork;                    /* gp_atar1.h */
  42. extern PSTATE State;                    /* gp_atar1.h */
  43.  
  44. WINDOW  *WinFindH(), *WinAlloc();
  45. WINLIST *WinListAdd(), *WinListDelete();
  46. WINTEXT *WinTextAlloc();
  47. char    (*TextBuffRealloc())[COLUMNS+1];
  48. GRAPHIC *GraphicAlloc();
  49.  
  50. void *ObjFindH();
  51.  
  52. void
  53. GetPalette(int *Palette, VWRK *vw)
  54. {
  55.     int ColorIndex;
  56.     int ColorEntry[3];
  57.     unsigned int DefinedColors = vw->PaletteSize/3;
  58.  
  59.     for (ColorIndex = 0; ColorIndex < DefinedColors; ColorIndex++) {
  60.  
  61.     vq_color(vw->VdiHandle, ColorIndex, DEFINED_INTENSITY, ColorEntry);
  62.  
  63.     Palette[3*ColorIndex]   = ColorEntry[0];
  64.     Palette[3*ColorIndex+1] = ColorEntry[1];
  65.     Palette[3*ColorIndex+2] = ColorEntry[2];
  66.       
  67.     }
  68. }
  69.  
  70. void
  71. SetPalette(int *Palette, VWRK *vw)
  72.   
  73.     int ColorIndex;
  74.     int ColorEntry[3];
  75.     unsigned int DefinedColors = vw->PaletteSize/3;
  76.  
  77.     for (ColorIndex = 0; ColorIndex < DefinedColors; ColorIndex++) {
  78.  
  79.     ColorEntry[0] = Palette[3*ColorIndex];
  80.     ColorEntry[1] = Palette[3*ColorIndex+1];
  81.     ColorEntry[2] = Palette[3*ColorIndex+2];
  82.   
  83.     vs_color(vw->VdiHandle, ColorIndex, ColorEntry);
  84.     }
  85. }
  86.  
  87. /* Set the position of an object window. */
  88.  
  89. int
  90. SetWinPosition(WINDOW *win, VWRK *vw, PSTATE *st, float x, float y)
  91. {
  92.  
  93.   GRECT itemp;
  94.   OBJECT *object = win->obj;
  95.  
  96.   itemp.g_x = nint(x * vw->full.g_w);
  97.   itemp.g_y = nint(y * vw->full.g_h);
  98.  
  99.   EnforceLimits(&itemp, vw);
  100.  
  101.   if (win->opened) {
  102.  
  103.     st->Event->SendMsg[0] = WM_MOVED;
  104.     st->Event->SendMsg[3] = win->handle;
  105.     st->Event->SendMsg[4] = itemp.g_x;
  106.     st->Event->SendMsg[5] = itemp.g_y;
  107.     st->Event->SendMsg[6] = win->frame.g_w;
  108.     st->Event->SendMsg[7] = win->frame.g_h;
  109.     appl_write(st->ApId, 16, st->Event->SendMsg);
  110.  
  111.   }
  112.   else {
  113.  
  114.     int ChangeX = itemp.g_x - win->frame.g_x;
  115.     int ChangeY = itemp.g_y - win->frame.g_y;
  116.  
  117.     win->frame.g_x = itemp.g_x;
  118.     win->frame.g_y = itemp.g_y;
  119.  
  120.     win->canvas.g_x += ChangeX;
  121.     win->canvas.g_y += ChangeY;
  122.  
  123.     object[0].ob_x += ChangeX;
  124.     object[0].ob_y += ChangeY;
  125.  
  126.   }
  127. }
  128.  
  129. /* Set the window frame size. */
  130.  
  131. int
  132. SetWinFrame(WINDOW *win, VWRK *vw, PSTATE *st,
  133.         float x, float y, float w, float h)
  134. {
  135.   GRECT itemp;
  136.  
  137.   if (win->opened) {
  138.  
  139.     itemp.g_x = nint(x * vw->full.g_w);
  140.     itemp.g_y = nint(y * vw->full.g_h);
  141.     itemp.g_w = nint(w * vw->full.g_w);
  142.     itemp.g_h = nint(h * vw->full.g_h);
  143.  
  144.     EnforceLimits(&itemp, vw);
  145.  
  146.     st->Event->SendMsg[0] = WM_SIZED;
  147.     st->Event->SendMsg[3] = win->handle;
  148.     st->Event->SendMsg[4] = itemp.g_x;
  149.     st->Event->SendMsg[5] = itemp.g_y;
  150.     st->Event->SendMsg[6] = itemp.g_w;
  151.     st->Event->SendMsg[7] = itemp.g_h;
  152.     appl_write(st->ApId, 16, st->Event->SendMsg);
  153.  
  154.   }
  155.   else {
  156.  
  157.     win->frame.g_x = nint(x * vw->full.g_w);
  158.     win->frame.g_y = nint(y * vw->full.g_h);
  159.     win->frame.g_w = nint(w * vw->full.g_w);
  160.     win->frame.g_h = nint(h * vw->full.g_h);
  161.  
  162.     EnforceLimits(&win->frame, vw);
  163.     
  164.   }
  165.  
  166. }
  167.  
  168. /* Load the configuration file. */
  169.  
  170. int
  171. LoadConfig(VWRK *vw, PSTATE *st)
  172. {
  173.  
  174.     FILE *config;
  175.     char *PathFind(), *sptr;
  176.     char line[MAXLEN], envvar[MAXLEN], value[MAXLEN];
  177.  
  178.     static short DevCount=1, SizCount=0;
  179.     int itemp, ret;
  180.  
  181.     float tempx, tempy, tempw, temph;
  182.  
  183.     /* Look for the configuration file in the current and HOME directories. */
  184.  
  185.     if ((sptr = PathFind("HOME", CONFIGFILE, ",")) != NULL) {
  186.     strcpy(line, sptr);
  187.     }
  188.     else {    
  189.     return -1;
  190.     }
  191.  
  192.     if ((config = fopen(line, "r")) == NULL) {
  193.     sprintf(line, "[1][Could not open %s!][OK]", CONFIGFILE);
  194.     form_alert(1, line);
  195.     return -1;
  196.     }
  197.  
  198.     /* Process the information in the config file. */
  199.  
  200.     while (fgets(line, MAXLEN-1, config) != NULL) {
  201.  
  202.     line[strlen(line)-1] = '\0';
  203.  
  204.     if (!strncmp(line, "consolewin ", 11)) {
  205.         sscanf(line+11, "%f %f %f %f", &tempx, &tempy, &tempw, &temph);
  206.         SetWinFrame(&conswin, vw, st, tempx, tempy, tempw, temph);
  207.     }
  208.     else if (!strncmp(line, "imagewin ", 9)) {
  209.         sscanf(line+9, "%f %f %f %f", &tempx, &tempy, &tempw, &temph);
  210.         SetWinFrame(&imagwin, vw, st, tempx, tempy, tempw, temph);
  211.     }
  212.     else if (!strncmp(line, "aboutwin ", 9)) {
  213.         sscanf(line+9, "%f %f", &tempx, &tempy);
  214.         SetWinPosition(&aboutwin, vw, st, tempx, tempy);
  215.     }
  216.     else if (!strncmp(line, "reswin ", 7)) {
  217.         sscanf(line+7, "%f %f", &tempx, &tempy);
  218.         SetWinPosition(&reswin, vw, st, tempx, tempy);
  219.     }
  220.     else if (!strncmp(line, "devwin ", 7)) {
  221.         sscanf(line+7, "%f %f", &tempx, &tempy);
  222.         SetWinPosition(&devwin, vw, st, tempx, tempy);
  223.     }
  224.     else if (!strncmp(line, "sizwin ", 7)) {
  225.         sscanf(line+7, "%f %f", &tempx, &tempy);
  226.         SetWinPosition(&sizwin, vw, st, tempx, tempy);
  227.     }
  228.     else if (!strncmp(line, "iconwin ", 8)) {
  229.         sscanf(line+8, "%f %f", &tempx, &tempy);
  230.         SetWinPosition(&iconwin, vw, st, tempx, tempy);
  231.     }
  232.     else if (!strncmp(line, "printwin ", 9)) {
  233.         sscanf(line+9, "%f %f", &tempx, &tempy);
  234.         SetWinPosition(&printwin, vw, st, tempx, tempy);
  235.     }
  236.     else if (!strncmp(line, "device ", 7)) {
  237.         if (DevCount < DEVICES) {
  238.         sscanf(line+7, "%s", devices[DevCount]);
  239.         ++DevCount;
  240.         }
  241.     }
  242.     else if (!strncmp(line, "pagesize ", 9)) {
  243.         if (SizCount < SIZES) {
  244.         sscanf(line+9, "%s", sizes[SizCount]);
  245.         ++SizCount;
  246.         }
  247.     }
  248.     else if (!strncmp(line, "pshelp ", 7)) {
  249.         sscanf(line+7, "%d", &itemp);
  250.         st->PSHelp = itemp;
  251.         menu_icheck(menuobj, PSHELP, st->PSHelp);
  252.     }
  253.     else if (!strncmp(line, "setenv ", 7)) {
  254.         sscanf(line+7, "%s", envvar);
  255.         putenv(envvar);
  256.     }
  257.  
  258.     }
  259.  
  260.     fclose(config);
  261. }
  262.  
  263. /* Save the configuration file. */
  264.  
  265. int
  266. SaveConfig(VWRK *vw, PSTATE *st)
  267. {
  268.  
  269.     FILE *config, *backup;
  270.  
  271.     char *PathFind(), *sptr;
  272.     char line[MAXLEN], configfile[MAXLEN], backupfile[MAXLEN];
  273.  
  274.     short i, back=0;
  275.     int fx, fy, fw, fh;
  276.  
  277.     float hnorm, vnorm;
  278.  
  279.     if ((vw->full.g_w == 0) || (vw->full.g_h == 0)) {
  280.     form_alert(1, "[1][Could not save!|Internal Error.][OK]");
  281.     return -1;
  282.     }
  283.  
  284.     /* Look for the configuration file in the current and HOME directories. */
  285.  
  286.     if ((sptr = PathFind("HOME", CONFIGFILE, ",")) != NULL) {
  287.     strcpy(configfile, sptr);
  288.     strcpy(backupfile, sptr);
  289.  
  290.     if ((sptr = strrchr(backupfile, '\\')) != NULL) {
  291.         strcpy(sptr+1, CONFIGBAK);
  292.     }
  293.     else {
  294.         strcpy(backupfile, CONFIGBAK);
  295.     }
  296.  
  297.     back = 1;
  298.  
  299.     }
  300.  
  301.     if (!strlen(configfile)) {
  302.     if ((sptr = getenv("HOME")) != NULL) {
  303.         strcpy(configfile, sptr);
  304.         strcat(configfile, CONFIGFILE);
  305.     }
  306.     else {
  307.         strcat(configfile, CONFIGFILE);
  308.     }
  309.     }
  310.  
  311.     sprintf(saveline, " Saving Configuration to %s ... ", configfile);
  312.     savemsg[0].ob_width = strlen(saveline) * vw->Wchar;
  313.     savemsg[1].ob_width = strlen(saveline) * vw->Wchar;
  314.  
  315.     form_center(savemsg, &fx, &fy, &fw, &fh);
  316.     form_dial(FMD_START, 0, 0, vw->Wchar, vw->Hchar, fx, fy, fw, fh);
  317.     objc_draw(savemsg, 0, 2, fx, fy, fw, fh);
  318.  
  319.     /* Back up the config file. */
  320.  
  321.     if (back) {
  322.  
  323.       if ((config = fopen(configfile, "r")) == NULL) {
  324.     sprintf(line, "[1][Could not open %s!][OK]", configfile);
  325.     form_dial(FMD_FINISH, 0, 0, vw->Wchar, vw->Hchar, fx, fy, fw, fh);
  326.     form_alert(1, line);
  327.     return -1;
  328.       }
  329.  
  330.       if ((backup = fopen(backupfile, "w")) == NULL) {
  331.     sprintf(line, "[1][Could not open %s!][OK]", backupfile);
  332.     form_dial(FMD_FINISH, 0, 0, vw->Wchar, vw->Hchar, fx, fy, fw, fh);
  333.     form_alert(1, line);
  334.     return -1;
  335.       }
  336.  
  337.       while (fgets(line, MAXLEN-1, config) != NULL) {
  338.     fputs(line, backup);
  339.       }
  340.  
  341.       fclose(backup);
  342.       fclose(config);
  343.  
  344.     }
  345.  
  346.     if ((config = fopen(configfile, "w")) == NULL) {
  347.     sprintf(line, "[1][Could not open %s!][OK]", configfile);
  348.     form_dial(FMD_FINISH, 0, 0, vw->Wchar, vw->Hchar, fx, fy, fw, fh);
  349.     form_alert(1, line);
  350.     return -1;
  351.     }
  352.  
  353.     hnorm = 1.0 / ((float)vw->full.g_w);
  354.     vnorm = 1.0 / ((float)vw->full.g_h);
  355.  
  356.     /* Write information to the config file. */
  357.  
  358.     fputs("# Configuration file for Atari ST Ghostscript.\n", config);
  359.     fputs("# Window x, y, w, and h are specified as fractions\n", config);
  360.     fputs("# of the screen size.\n\n", config);
  361.  
  362.     fprintf(config, "consolewin %f %f %f %f\n",
  363.     conswin.frame.g_x * hnorm,
  364.     conswin.frame.g_y * vnorm,
  365.     conswin.frame.g_w * hnorm,
  366.     conswin.frame.g_h * vnorm);
  367.  
  368.     fprintf(config, "imagewin %f %f %f %f\n",
  369.     imagwin.frame.g_x * hnorm,
  370.     imagwin.frame.g_y * vnorm,
  371.     imagwin.frame.g_w * hnorm,
  372.     imagwin.frame.g_h * vnorm);
  373.  
  374.     fputs("\n# Only x and y for the following windows.\n\n", config);
  375.  
  376.     fprintf(config, "aboutwin %f %f\n",
  377.     aboutwin.frame.g_x * hnorm,
  378.     aboutwin.frame.g_y * vnorm);
  379.  
  380.     fprintf(config, "reswin %f %f\n",
  381.     reswin.frame.g_x * hnorm,
  382.     reswin.frame.g_y * vnorm);
  383.  
  384.     fprintf(config, "devwin %f %f\n",
  385.     devwin.frame.g_x * hnorm,
  386.     devwin.frame.g_y * vnorm);
  387.  
  388.     fprintf(config, "sizwin %f %f\n",
  389.     sizwin.frame.g_x * hnorm,
  390.     sizwin.frame.g_y * vnorm);
  391.  
  392.     fprintf(config, "iconwin %f %f\n",
  393.     iconwin.frame.g_x * hnorm,
  394.     iconwin.frame.g_y * vnorm);
  395.  
  396.     fprintf(config, "printwin %f %f\n",
  397.     printwin.frame.g_x * hnorm,
  398.     printwin.frame.g_y * vnorm);
  399.  
  400.     fputs("\n# Devices available from the device dialog.\n\n", config);
  401.  
  402.     for (i=1; i<DEVICES; ++i) {
  403.     fprintf(config, "device %s\n", devices[i]);
  404.     }
  405.  
  406.     fputs("\n# Page sizes available from the size dialog.\n\n", config);
  407.  
  408.     for (i=0; i<SIZES; ++i) {
  409.     fprintf(config, "pagesize %s\n", sizes[i]);
  410.     }
  411.  
  412.     fputs("\n# Options: 1 = selected, 0 = unselected.\n\n", config);
  413.     fprintf(config, "pshelp %d\n", st->PSHelp);
  414.  
  415.     /* Copy any environment variables from the backup file. */
  416.  
  417. #if 0
  418.     if (back) {
  419.  
  420.       fputs("\n# Ghostscript Environment Variables.\n\n", config);
  421.  
  422.       if ((backup = fopen(backupfile, "r")) == NULL) {
  423.     sprintf(line, "[1][Could not open %s!][OK]", backupfile);
  424.     form_dial(FMD_FINISH, 0, 0, vw->Wchar, vw->Hchar, fx, fy, fw, fh);
  425.     form_alert(1, line);
  426.     return -1;
  427.       }
  428.  
  429.       while (fgets(line, MAXLEN-1, backup) != NULL) {
  430.     if (!strncmp(line, "setenv ", 7)) {
  431.       fputs(line, config);
  432.     }
  433.       }
  434.  
  435.       fclose(backup);
  436.     }
  437. #endif
  438.  
  439.     fclose(config);
  440.  
  441.     form_dial(FMD_FINISH, 0, 0, vw->Wchar, vw->Hchar, fx, fy, fw, fh);
  442.  
  443. }
  444.  
  445. int
  446. DevObjUpdate(PSTATE *st)
  447. {
  448.   int i;
  449.  
  450.   /* Ensure that the button for the current device is selected. */
  451.  
  452.   for (i=FIRSTDEV; !(devobj[i].ob_state & SELECTED) && (i<=LASTDEV); ++i);
  453.  
  454.   if ((i <= LASTDEV) && (i != st->Device)) {
  455.  
  456.     objc_change(devobj, i, 0,
  457.         devwin.canvas.g_x, devwin.canvas.g_y,
  458.         devwin.canvas.g_w, devwin.canvas.g_h,
  459.         (devobj[i].ob_state ^ SELECTED), devwin.opened);
  460.  
  461.     objc_change(devobj, st->Device, 0,
  462.         devwin.canvas.g_x, devwin.canvas.g_y,
  463.         devwin.canvas.g_w, devwin.canvas.g_h,
  464.         (devobj[st->Device].ob_state ^ SELECTED), devwin.opened);
  465.  
  466.     st->LastDevice = st->Device;
  467.  
  468.   }
  469. }
  470.  
  471. int
  472. CopyImage(GRAPHIC *sgr, VWRK *vw, PSTATE *st)
  473. {
  474.     WINDOW *bwin;
  475.     GRAPHIC *gr;        /* new graphic structure */
  476.  
  477.     WINLIST *wl = WList;
  478.  
  479.     byte *buff;
  480.  
  481.     ulong buff_size = sgr->image.fd_w * sgr->image.fd_h;
  482.  
  483.     if ((bwin = WinAlloc()) == NULL) {
  484.     form_alert(1, "[1][Ghostscript Error!|No More Memory.][Continue]");
  485.     return (-1);
  486.     }
  487.  
  488.     if ((gr = GraphicAlloc()) == NULL) {
  489.     form_alert(1, "[1][Ghostscript Error!|No More Memory.][Continue]");
  490.     WinFree(bwin);
  491.     return (-1);
  492.     }
  493.  
  494.     if ((buff = (byte *)gs_malloc((uint)buff_size, 1, "bitbuffer")) == NULL) {
  495.     form_alert(1, "[1][Ghostscript Error!|No More Memory.][Continue]");
  496.     WinFree(bwin);
  497.     GraphicFree(gr);
  498.     return (-1);
  499.     }
  500.  
  501.     BitWinInit(bwin, gr, C_GADGETS, C_TITL);
  502.  
  503.     gr->image.fd_addr = (unsigned long) buff;
  504.  
  505.     memcpy((void *)gr->image.fd_addr, (void *)sgr->image.fd_addr, buff_size);
  506.  
  507.     WinListAdd(wl, bwin);
  508.     BitWinOpen(bwin, vw, st);
  509.  
  510. }
  511.  
  512. int
  513. BitWinOpen(WINDOW *bwin, VWRK *vw, PSTATE *st)
  514. {
  515.     GRAPHIC *gr = bwin->obj;
  516.  
  517.     /* Open a window for a bitmap image. */
  518.  
  519.     if (bwin->iconified) {
  520.     wind_open(bwin->handle,
  521.         bwin->frame.g_x, bwin->frame.g_y,
  522.         MIN(bwin->frame.g_w, bwin->mframe.g_w),
  523.         MIN(bwin->frame.g_h, bwin->mframe.g_h));
  524.  
  525.     bwin->opened = 1;
  526.     bwin->iconified = 0;
  527.     }
  528.     else if (!bwin->opened) {
  529.  
  530.     wind_calc(0, bwin->gadgets,
  531.         vw->full.g_x, vw->full.g_y,
  532.         gr->Width, gr->Height,
  533.         &bwin->mframe.g_x, &bwin->mframe.g_y,
  534.         &bwin->mframe.g_w, &bwin->mframe.g_h);
  535.  
  536.     if ((bwin->frame.g_w + bwin->frame.g_h) == 0) {
  537.         bwin->frame.g_x = bwin->mframe.g_x;
  538.         bwin->frame.g_y = bwin->mframe.g_y;
  539.         bwin->frame.g_w = bwin->mframe.g_w;
  540.         bwin->frame.g_h = bwin->mframe.g_h;
  541.     }
  542.  
  543.     bwin->handle = wind_create(
  544.         bwin->gadgets + (st->MultiTOS ? SMALLER : 0),
  545.         bwin->mframe.g_x, bwin->mframe.g_y,
  546.         bwin->mframe.g_w, bwin->mframe.g_h);
  547.  
  548.     if (bwin->handle < 0) {
  549.         form_alert(1, "[1][Ghostscript Error!|No More Windows.][Continue]");
  550.         WinListDelete(WList, bwin);
  551.         return (-1);
  552.     }
  553.  
  554.     wind_set(bwin->handle, WF_NAME, bwin->title, bwin->title, 0, 0);
  555.  
  556.     wind_open(bwin->handle,
  557.         bwin->frame.g_x, bwin->frame.g_y,
  558.         MIN(bwin->frame.g_w, bwin->mframe.g_w),
  559.         MIN(bwin->frame.g_h, bwin->mframe.g_h));
  560.  
  561.     wind_get(bwin->handle, WF_CURRXYWH,
  562.         &bwin->frame.g_x, &bwin->frame.g_y,
  563.         &bwin->frame.g_w, &bwin->frame.g_h);
  564.  
  565.     wind_get(bwin->handle, WF_CURRXYWH,
  566.         &bwin->oframe.g_x, &bwin->oframe.g_y,
  567.         &bwin->oframe.g_w, &bwin->oframe.g_h);
  568.  
  569.     wind_get(bwin->handle, WF_WORKXYWH,
  570.         &bwin->canvas.g_x, &bwin->canvas.g_y,
  571.         &bwin->canvas.g_w, &bwin->canvas.g_h);
  572.  
  573.     gr->StepX = .9 * bwin->canvas.g_w;
  574.     gr->StepY = .9 * bwin->canvas.g_h;
  575.  
  576.     bwin->opened = 1;
  577.     update_scroll(bwin->handle);
  578.     }
  579.  
  580.     return 0;
  581. }
  582.  
  583. int
  584. HelpWinOpen(VWRK *vw, PSTATE *st, char *HelpFile)
  585. {
  586.     FILE *helpf, *lib_fopen();
  587.     WINDOW *hwin;
  588.     WINTEXT *text;
  589.     WINLIST *wl=WList;
  590.  
  591.     char line[MAXLEN], helpfile[MAXLEN];
  592.     int count, twincount=0, length, longest=0;
  593.  
  594.     if ((hwin = WinAlloc()) == NULL) {
  595.     form_alert(1, "[1][Ghostscript Error!|No More Memory.][Continue]");
  596.     return (-1);
  597.     }
  598.  
  599.     if ((text = WinTextAlloc(LINES)) == NULL) {
  600.     form_alert(1, "[1][Ghostscript Error!|No More Memory.][Continue]");
  601.     WinFree(hwin);
  602.     return (-1);
  603.     }
  604.  
  605.     TextWinInit(hwin, text, H_GADGETS, H_TITL);
  606.  
  607.     /* Read help file into the text buffer. */
  608.  
  609.     strcpy(helpfile, HelpFile);
  610.  
  611.     if ((helpf = lib_fopen(helpfile)) == NULL) {
  612.     sprintf(line, "[1][Could not open %s!][OK]", helpfile);
  613.     form_alert(1, line);
  614.     return -1;
  615.     }
  616.  
  617.     for (count=0; (fgets(line, MAXLEN-1, helpf) != NULL); ++count) {
  618.  
  619.     length = strlen(line);
  620.     line[length-2] = '\0';
  621.  
  622.     if (length-2 > longest) longest = length-2;
  623.  
  624.     if (count >= text->bsize - 1) {
  625.         int NewSize = text->bsize + LINES;
  626.         if (TextBuffRealloc(text, NewSize) == NULL) {
  627.         form_alert(1, "[1][There is only enough ram to|\
  628.             load a portion of this file.][Continue]");
  629.         break;
  630.         }
  631.     }
  632.  
  633.     strcpy(text->buff[count], line);
  634.  
  635.     }
  636.  
  637.     fclose(helpf);
  638.  
  639.     if (hwin->frame.g_w + hwin->frame.g_h == 0) {
  640.     wind_calc(0, hwin->gadgets, vw->full.g_x, vw->full.g_y,
  641.         (longest + 4)*vw->Wchar, (count + 1)*vw->Hchar,
  642.         &hwin->frame.g_x, &hwin->frame.g_y,
  643.         &hwin->frame.g_w, &hwin->frame.g_h);
  644.  
  645.     /* Count the number of open text windows. */
  646.  
  647.     do {
  648.         if (wl->Win->type == TEXT){
  649.         ++twincount;
  650.         }
  651.         wl = wl->Next;
  652.     }
  653.     while (wl != WList);
  654.  
  655.     /* Place the window according to how many text windows are open. */
  656.  
  657.     hwin->frame.g_x = 2 * twincount * vw->Wchar;
  658.     hwin->frame.g_y = vw->full.g_y + twincount * vw->Hchar;
  659.     hwin->frame.g_w = MIN(hwin->frame.g_w, vw->full.g_w - hwin->frame.g_x);
  660.     hwin->frame.g_h = MIN(hwin->frame.g_h,
  661.         vw->full.g_h - twincount * vw->Hchar);
  662.     }
  663.  
  664.     text->bw = longest;
  665.     text->bh = count;
  666.  
  667.     WinListAdd(WList, hwin);
  668.     TextWinOpen(hwin, vw, st);
  669.  
  670.     text->ln = count-1;
  671. }
  672.  
  673. int
  674. TextWinOpen(WINDOW *twin, VWRK *vw, PSTATE *st)
  675. {
  676.  
  677.     WINTEXT *text = twin->obj;
  678.  
  679.     /* Create, open, and initialize a text window. */
  680.  
  681.     if (twin->iconified) {
  682.     wind_open(twin->handle,
  683.         twin->frame.g_x, twin->frame.g_y,
  684.         MIN(twin->frame.g_w, twin->mframe.g_w),
  685.         MIN(twin->frame.g_h, twin->mframe.g_h));
  686.  
  687.     twin->opened = 1;
  688.     twin->iconified = 0;
  689.     }
  690.     else if (!twin->opened) {
  691.  
  692.     int dummy;
  693.  
  694.     text->wc = vw->Wchar;
  695.     text->hc = vw->Hchar;
  696.  
  697.     wind_calc(0, twin->gadgets, vw->full.g_x, vw->full.g_y,
  698.         (text->bw + 4)*text->wc, (text->bh + 1)*text->hc,
  699.         &twin->mframe.g_x, &twin->mframe.g_y,
  700.         &twin->mframe.g_w, &twin->mframe.g_h);
  701.  
  702.     twin->mframe.g_x = MAX(twin->mframe.g_x, vw->full.g_x);
  703.     twin->mframe.g_y = MAX(twin->mframe.g_y, vw->full.g_y);
  704.     twin->mframe.g_w = MIN(twin->mframe.g_w, vw->full.g_w);
  705.     twin->mframe.g_h = MIN(twin->mframe.g_h, vw->full.g_h);
  706.  
  707.     twin->handle = wind_create(
  708.         twin->gadgets + (st->MultiTOS ? SMALLER : 0),
  709.         twin->mframe.g_x, twin->mframe.g_y,
  710.         twin->mframe.g_w, twin->mframe.g_h);
  711.  
  712.     if (twin->handle < 0) {
  713.         form_alert(1, "[1][Ghostscript Error!|No More Windows.][Continue]");
  714.         WinListDelete(WList, twin);
  715.         return (-1);
  716.     }
  717.  
  718.     wind_set(twin->handle, WF_NAME,
  719.         twin->title, twin->title, 0, 0);
  720.  
  721.     if ((twin->frame.g_w + twin->frame.g_h) == 0) {
  722.  
  723.         wind_calc(0, twin->gadgets + (st->MultiTOS ? SMALLER : 0),
  724.         vw->full.g_x, vw->full.g_y,
  725.         (text->bw + 2)*text->wc, (text->bh + 1)*text->hc,
  726.         &twin->frame.g_x, &twin->frame.g_y,
  727.         &twin->frame.g_w, &twin->frame.g_h);
  728.  
  729.         twin->frame.g_x = vw->full.g_x;
  730.         twin->frame.g_y = vw->full.g_y;
  731.         twin->frame.g_w = MIN(twin->frame.g_w, vw->full.g_w);
  732.         twin->frame.g_h = MIN(twin->frame.g_h, vw->full.g_h);
  733.  
  734.     }
  735.  
  736.     wind_open(twin->handle,
  737.         twin->frame.g_x, twin->frame.g_y,
  738.         twin->frame.g_w, twin->frame.g_h);
  739.  
  740.     wind_get(twin->handle, WF_CURRXYWH,
  741.         &twin->oframe.g_x, &twin->oframe.g_y,
  742.         &twin->oframe.g_w, &twin->oframe.g_h);
  743.  
  744.     wind_get(twin->handle, WF_WORKXYWH,
  745.         &twin->canvas.g_x, &twin->canvas.g_y,
  746.         &twin->canvas.g_w, &twin->canvas.g_h);
  747.  
  748.     twin->opened = 1;
  749.  
  750.     text->edge = twin->canvas.g_x;
  751.     text->top = twin->canvas.g_y;
  752.  
  753.     text->xoff = text->wc/2;
  754.     text->yoff = text->hc/2;
  755.  
  756.     text->lins = visible_lines(twin);
  757.     text->cols = visible_cols(twin);
  758.     text->ll   = text->bh - 1;
  759.     text->ldl  = text->fdl + text->lins - 1;
  760.  
  761.     text->cx = align(text->edge + text->xoff);
  762.     text->cy = text->top + text->yoff;
  763.  
  764.     vst_alignment(vw->VdiHandle, 0, 5, &dummy, &dummy);
  765.  
  766.     clear_win(&twin->canvas);
  767.     update_scroll(twin->handle);
  768.  
  769.     }
  770.  
  771.     return 0;
  772. }
  773.  
  774. int
  775. ObjWinOpen(OBJECT obj[], WINDOW *owin, VWRK *vw, PSTATE *st)
  776. {
  777.  
  778.     /* Create and open a window for a GEM object. */
  779.  
  780.     if (owin->iconified) {
  781.  
  782.     obj[0].ob_flags ^= HIDETREE;     /* Make the object tree visible. */
  783.  
  784.     wind_open(owin->handle,
  785.         owin->frame.g_x, owin->frame.g_y,
  786.         owin->frame.g_w, owin->frame.g_h);
  787.  
  788.     owin->opened = 1;
  789.     owin->iconified = 0;
  790.  
  791.     }
  792.     else if (!owin->opened) {
  793.  
  794.     owin->handle = wind_create(owin->gadgets,
  795.         vw->full.g_x, vw->full.g_y,
  796.         vw->full.g_w, vw->full.g_h);
  797.  
  798.     if (owin->handle < 0) {
  799.         form_alert(1,
  800.         "[1][Ghostscript Error!|No More Windows.][Continue]");
  801.         WinListDelete(WList, owin);
  802.         return (-1);
  803.         }
  804.  
  805.     wind_set(owin->handle, WF_NAME, owin->title, owin->title, 0, 0);
  806.  
  807.     /* Make the object tree visible. */
  808.  
  809.     obj[0].ob_flags ^= HIDETREE;
  810.  
  811.     /* If the window has never been opened, width and height will
  812.      * be zero. In this case, center the object before opening
  813.      * the window.
  814.      */
  815.  
  816.     if ((owin->frame.g_w + owin->frame.g_h) == 0) {
  817.         int tempx, tempy;
  818.  
  819.         form_center(obj,
  820.         &owin->canvas.g_x, &owin->canvas.g_y,
  821.         &owin->canvas.g_w, &owin->canvas.g_h);
  822.  
  823.         wind_calc(0, owin->gadgets,
  824.         owin->canvas.g_x, owin->canvas.g_y,
  825.         owin->canvas.g_w, owin->canvas.g_h,
  826.         &tempx, &tempy,
  827.         &owin->frame.g_w, &owin->frame.g_h);
  828.  
  829.         if (owin->frame.g_x + owin->frame.g_y) {
  830.         owin->canvas.g_x += owin->frame.g_x - tempx;
  831.         owin->canvas.g_y += owin->frame.g_y - tempy;
  832.         obj[0].ob_x += owin->frame.g_x - tempx;
  833.         obj[0].ob_y += owin->frame.g_y - tempy;
  834.         }
  835.         else {
  836.         owin->frame.g_x = tempx;
  837.         owin->frame.g_y = tempy;
  838.         }
  839.  
  840.     }
  841.  
  842.     /* The object is drawn by the redraw message which is
  843.      * automatically sent when the window is opened.
  844.      */
  845.  
  846.     wind_open(owin->handle,
  847.         owin->frame.g_x, owin->frame.g_y,
  848.         owin->frame.g_w, owin->frame.g_h);
  849.  
  850.     owin->opened = 1;
  851.  
  852.     }
  853.     else {
  854.     wind_set(owin->handle, WF_TOP, 0, 0, 0, 0);
  855.     }
  856.  
  857.     return 0;
  858.  
  859. }
  860.  
  861. int
  862. WinClose(WINDOW *win)
  863. {
  864.  
  865.     /* Close and delete the window; hide the object. */
  866.     
  867.     if (win->iconified) {
  868.  
  869.     wind_delete(win->handle);
  870.  
  871.     win->handle = -1;
  872.     win->iconified = 0;
  873.  
  874.     }
  875.     else if (win->opened) {
  876.  
  877.     wind_get(win->handle, WF_CURRXYWH,
  878.         &win->frame.g_x, &win->frame.g_y,
  879.         &win->frame.g_w, &win->frame.g_h);
  880.  
  881.     wind_get(win->handle, WF_CURRXYWH,
  882.         &win->oframe.g_x, &win->oframe.g_y,
  883.         &win->oframe.g_w, &win->oframe.g_h);
  884.  
  885.     wind_close(win->handle);
  886.     wind_delete(win->handle);
  887.  
  888.     if (win->type == OBJ) {
  889.         OBJECT *obj = win->obj;
  890.         obj[0].ob_flags ^= HIDETREE;
  891.     }
  892.  
  893.     win->handle = -1;
  894.     win->opened = 0;
  895.     }
  896.  
  897.     return 0;
  898. }
  899.  
  900. int
  901. bitw_arrow(PSTATE *st)
  902. {
  903.     int ChangeX, ChangeY;
  904.  
  905.     WINDOW *bwin = WinFindH(st->Event->Message[3]);
  906.     GRAPHIC *gr = bwin->obj;
  907.     VWRK *vw = &VWork;
  908.  
  909.     switch (st->Event->Message[4]) {
  910.  
  911.     case WA_UPLINE:    /* up line or top of page */
  912.     if (st->Event->KeyState)
  913.         gr->PlotY = 0;
  914.     else
  915.         gr->PlotY = MAX(gr->PlotY - vw->Hchar, 0);
  916.     break;
  917.  
  918.     case WA_DNLINE:    /* down line or bottom of page */
  919.     if (st->Event->KeyState)
  920.         gr->PlotY = gr->Height - bwin->canvas.g_h;
  921.     else
  922.         gr->PlotY = MIN(gr->PlotY + vw->Hchar,
  923.         gr->Height - bwin->canvas.g_h);
  924.     break;
  925.  
  926.     case WA_LFLINE:    /* left line or left page edge */
  927.     if (st->Event->KeyState)
  928.         gr->PlotX = 0;
  929.     else
  930.         gr->PlotX = MAX(gr->PlotX - vw->Wchar, 0);
  931.     break;
  932.  
  933.     case WA_RTLINE:    /* right page edge */
  934.     if (st->Event->KeyState)
  935.         gr->PlotX = gr->Width - bwin->canvas.g_w;
  936.     else
  937.         gr->PlotX = MIN(gr->PlotX + vw->Wchar, 
  938.         gr->Width - bwin->canvas.g_w);
  939.     break;
  940.  
  941.     case WA_UPPAGE:    /* up page */
  942.     gr->PlotY = MAX(gr->PlotY - gr->StepY, 0);
  943.     break;
  944.  
  945.     case WA_DNPAGE:    /* down page */
  946.     gr->PlotY = MIN(gr->PlotY + gr->StepY,
  947.         gr->Height - bwin->canvas.g_h);
  948.     break;
  949.  
  950.     case WA_LFPAGE:    /* left page */
  951.     gr->PlotX = MAX(gr->PlotX - gr->StepX, 0);
  952.     break;
  953.  
  954.     case WA_RTPAGE:    /* right page */
  955.     gr->PlotX = MIN(gr->PlotX + gr->StepX,
  956.         gr->Width - bwin->canvas.g_w);
  957.     break;
  958.  
  959.     }
  960.  
  961.     update_scroll(st->Event->Message[3]);
  962.     cursor(OFF);
  963.     HandleRedraw(FULL_WIN, &State);
  964.     cursor(ON);
  965.  
  966. }
  967.  
  968. int
  969. txtw_hslide(PSTATE *st)
  970. {
  971.     int ChangeX, ChangeY;
  972.     int handle = st->Event->Message[3];
  973.  
  974.     WINDOW  *twin = WinFindH(handle);
  975.     WINTEXT *text = twin->obj;
  976.  
  977.     text->fdc = (text->bw + 2 - text->cols) * st->Event->Message[4]/1000;
  978.     text->ldc = text->fdc + text->cols - 1;
  979.  
  980.     ChangeX = twin->canvas.g_x - text->fdc * text->wc - text->edge;
  981.  
  982.     text->edge += ChangeX;
  983.     text->cx   += ChangeX;
  984.  
  985.     update_scroll(handle);
  986.     cursor(OFF);
  987.     HandleRedraw(FULL_WIN, st);
  988.     cursor(ON);
  989. }
  990.  
  991. int
  992. bitw_hslide(PSTATE *st)
  993. {
  994.     WINDOW *bwin = WinFindH(st->Event->Message[3]); 
  995.     GRAPHIC *gr = bwin->obj;
  996.  
  997.     gr->PlotX = (gr->Width - bwin->canvas.g_w) * st->Event->Message[4]/1000;
  998.  
  999.     update_scroll(st->Event->Message[3]);
  1000.     HandleRedraw(FULL_WIN, st);
  1001. }
  1002.  
  1003. int
  1004. txtw_vslide(PSTATE *st)
  1005. {
  1006.     int ChangeX, ChangeY;
  1007.     WINTEXT *text = ObjFindH(st->Event->Message[3]);
  1008.  
  1009.     int OldOffset = text->fdl - text->fl;
  1010.     int NewOffset = (text->bh - text->lins) * st->Event->Message[4]/1000;
  1011.  
  1012.     if (OldOffset < 0) OldOffset += text->bh;
  1013.  
  1014.     text->fdl = text->fl + NewOffset;
  1015.     if (text->fdl >= text->bh) text->fdl -= text->bh;
  1016.  
  1017.     text->ldl = text->fdl + text->lins - 1;
  1018.     if (text->ldl >= text->bh) text->ldl -= text->bh;
  1019.  
  1020.     ChangeY = (OldOffset - NewOffset) * text->hc;
  1021.     text->top += ChangeY;
  1022.     text->cy  += ChangeY;
  1023. }
  1024.  
  1025. int
  1026. bitw_vslide(PSTATE *st)
  1027. {
  1028.     WINDOW *bwin = WinFindH(st->Event->Message[3]);
  1029.     GRAPHIC *gr = bwin->obj;
  1030.  
  1031.     gr->PlotY = (gr->Height - bwin->canvas.g_h) * st->Event->Message[4]/1000;
  1032. }
  1033.  
  1034. int
  1035. objw_move(PSTATE *st)
  1036. {
  1037.     int ChangeX, ChangeY;
  1038.  
  1039.     WINDOW *owin = WinFindH(st->Event->Message[3]);
  1040.     OBJECT *obj = owin->obj;
  1041.  
  1042.     wind_set(owin->handle, WF_CURRXYWH,
  1043.     st->Event->Message[4], st->Event->Message[5],
  1044.     st->Event->Message[6], st->Event->Message[7]);
  1045.  
  1046.     ChangeX = st->Event->Message[4] - owin->frame.g_x;
  1047.     ChangeY = st->Event->Message[5] - owin->frame.g_y;
  1048.  
  1049.     obj[0].ob_x += ChangeX;
  1050.     obj[0].ob_y += ChangeY;
  1051.  
  1052.     wind_get(owin->handle, WF_CURRXYWH,
  1053.     &owin->frame.g_x, &owin->frame.g_y,
  1054.     &owin->frame.g_w, &owin->frame.g_h);
  1055.  
  1056.     wind_get(owin->handle, WF_WORKXYWH,
  1057.     &owin->canvas.g_x, &owin->canvas.g_y,
  1058.     &owin->canvas.g_w, &owin->canvas.g_h);
  1059.  
  1060. }
  1061.  
  1062. int
  1063. bitw_move(PSTATE *st)
  1064. {
  1065.  
  1066.     WINDOW *bwin = WinFindH(st->Event->Message[3]);
  1067.  
  1068.     wind_set(bwin->handle, WF_CURRXYWH,
  1069.     st->Event->Message[4], st->Event->Message[5],
  1070.     MIN(bwin->mframe.g_w, st->Event->Message[6]),
  1071.     MIN(bwin->mframe.g_h, st->Event->Message[7]));
  1072.  
  1073.     wind_get(bwin->handle, WF_CURRXYWH,
  1074.     &bwin->frame.g_x, &bwin->frame.g_y,
  1075.     &bwin->frame.g_w, &bwin->frame.g_h);
  1076.  
  1077.     wind_get(bwin->handle, WF_WORKXYWH,
  1078.     &bwin->canvas.g_x, &bwin->canvas.g_y,
  1079.     &bwin->canvas.g_w, &bwin->canvas.g_h);
  1080. }
  1081.  
  1082. int
  1083. txtw_move(PSTATE *st)
  1084. {
  1085.     int ChangeX, ChangeY;
  1086.  
  1087.     WINDOW *twin = WinFindH(st->Event->Message[3]);
  1088.     WINTEXT *text = twin->obj;
  1089.  
  1090.     int oldcanvas_x = twin->canvas.g_x;
  1091.     int oldcanvas_y = twin->canvas.g_y;
  1092.  
  1093.     wind_set(twin->handle, WF_CURRXYWH,
  1094.     align(st->Event->Message[4]), st->Event->Message[5],
  1095.     MIN(twin->mframe.g_w, st->Event->Message[6]),
  1096.     MIN(twin->mframe.g_w, st->Event->Message[7]));
  1097.  
  1098.     wind_get(twin->handle, WF_CURRXYWH,
  1099.     &twin->frame.g_x, &twin->frame.g_y,
  1100.     &twin->frame.g_w, &twin->frame.g_h);
  1101.  
  1102.     wind_get(twin->handle, WF_WORKXYWH,
  1103.     &twin->canvas.g_x, &twin->canvas.g_y,
  1104.     &twin->canvas.g_w, &twin->canvas.g_h);
  1105.  
  1106.     ChangeX = twin->canvas.g_x - oldcanvas_x;
  1107.     ChangeY = twin->canvas.g_y - oldcanvas_y;
  1108.  
  1109.     text->edge += ChangeX;
  1110.     text->top  += ChangeY;
  1111.  
  1112.     text->cx += ChangeX;
  1113.     text->cy += ChangeY;
  1114. }
  1115.  
  1116. int
  1117. txtw_arrow(PSTATE *st)
  1118. {
  1119.     int ChangeX, ChangeY;
  1120.     int handle = st->Event->Message[3];
  1121.  
  1122.     WINDOW *twin  = WinFindH(handle);
  1123.     WINTEXT *text = twin->obj;
  1124.  
  1125.     switch (st->Event->Message[4]) {
  1126.  
  1127.     case WA_UPLINE:    /* top line or up line */
  1128.     if (st->Event->KeyState) {
  1129.         ChangeY = twin->canvas.g_y - text->top;
  1130.         text->top += ChangeY;
  1131.         text->cy  += ChangeY;
  1132.         text->fdl = text->fl;
  1133.         text->ldl = text->fl + text->lins - 1;
  1134.         if (text->ldl >= text->bh) text->ldl -= text->bh;
  1135.     }
  1136.     else {
  1137.         if (text->fdl != text->fl) {
  1138.         text->top += text->hc;
  1139.         text->cy += text->hc;
  1140.         if (--text->fdl < 0) text->fdl += text->bh;
  1141.         if (--text->ldl < 0) text->fdl += text->bh;
  1142.         }
  1143.     }
  1144.     break;
  1145.  
  1146.     case WA_DNLINE:    /* bottom line or down line */
  1147.     if (st->Event->KeyState) {
  1148.         ChangeY = twin->canvas.g_y
  1149.             - (text->bh - text->lins) * text->hc - text->top;
  1150.         text->top += ChangeY;
  1151.         text->cy  += ChangeY;
  1152.         text->fdl = text->ll - text->lins + 1;
  1153.         text->ldl = text->ll;
  1154.         if (text->fdl < 0) text->fdl += text->bh;
  1155.     }
  1156.     else {
  1157.         if (text->ldl != text->ll) {
  1158.         text->top -= text->hc;
  1159.         text->cy  -= text->hc;
  1160.         if (++text->fdl >= text->bh) text->fdl = 0;
  1161.         if (++text->ldl >= text->bh) text->ldl = 0;
  1162.         }
  1163.     }
  1164.     break;
  1165.  
  1166.     case WA_LFLINE:    /* left line */
  1167.     if (st->Event->KeyState) {
  1168.         ChangeX = twin->canvas.g_x - text->edge;
  1169.         text->edge += ChangeX;
  1170.         text->cx   += ChangeX;
  1171.         text->fdc = 0;
  1172.         text->ldc = text->cols - 1;
  1173.     }
  1174.     else {
  1175.         if (text->fdc > 0) {
  1176.         text->edge += text->wc;
  1177.         text->cx  += text->wc;
  1178.         text->fdc--;
  1179.         text->ldc--;
  1180.         }
  1181.     }
  1182.     break;
  1183.  
  1184.     case WA_RTLINE:    /* right line */
  1185.     if (st->Event->KeyState) {
  1186.         ChangeX = twin->canvas.g_x
  1187.             - (text->bw + 2 - text->cols) * text->wc - text->edge;
  1188.         text->edge += ChangeX;
  1189.         text->cx   += ChangeX;
  1190.         text->fdc = (text->bw + 2 - text->cols);
  1191.         text->ldc = text->fdc + text->cols - 1;
  1192.     }
  1193.     else {
  1194.         if ((text->fdc + text->cols) < (text->bw + 2)) {
  1195.         text->edge -= text->wc;
  1196.         text->cx  -= text->wc;
  1197.         text->fdc++;
  1198.         text->ldc++;
  1199.         }
  1200.     }
  1201.     break;
  1202.  
  1203.     case WA_UPPAGE:    /* up page */
  1204.       {
  1205.     int to_top = text->fdl - text->fl;
  1206.     to_top = (to_top >= 0) ? to_top : to_top + text->bh;
  1207.  
  1208.     if (to_top >= (text->lins - 1)) {
  1209.         text->top += (text->lins - 1) * text->hc;
  1210.         text->cy  += (text->lins - 1) * text->hc;
  1211.         text->fdl -= (text->lins - 1);
  1212.         text->ldl  -= (text->lins - 1);
  1213.         if (text->fdl < 0) text->fdl += text->bh;
  1214.         if (text->ldl < 0) text->ldl += text->bh;
  1215.     }
  1216.     else {
  1217.         ChangeY = twin->canvas.g_y - text->top;
  1218.         text->top += ChangeY;
  1219.         text->cy  += ChangeY;
  1220.         text->fdl = text->fl;
  1221.         text->ldl = text->fl + text->lins - 1;
  1222.         if (text->ldl >= text->bh) text->ldl -= text->bh;
  1223.     }
  1224.     break;
  1225.       }
  1226.  
  1227.     case WA_DNPAGE:    /* down page */
  1228.       {
  1229.     int to_bot = text->ll - text->ldl;
  1230.     to_bot = (to_bot >= 0) ? to_bot : to_bot + text->bh;
  1231.  
  1232.     if (to_bot >= (text->lins - 1)) {
  1233.         text->top -= (text->lins - 1) * text->hc;
  1234.         text->cy  -= (text->lins - 1) * text->hc;
  1235.         text->fdl += (text->lins - 1);
  1236.         text->ldl += (text->lins - 1);
  1237.         if (text->fdl >= text->bh) text->fdl -= text->bh;
  1238.         if (text->ldl >= text->bh) text->ldl -= text->bh;
  1239.     }
  1240.     else {
  1241.         ChangeY = twin->canvas.g_y
  1242.             - (text->bh - text->lins) * text->hc - text->top;
  1243.         text->top += ChangeY;
  1244.         text->cy  += ChangeY;
  1245.         text->fdl = text->ll - text->lins + 1;
  1246.         text->ldl = text->ll;
  1247.         if (text->fdl < 0) text->fdl += text->bh;
  1248.     }
  1249.     break;
  1250.       }
  1251.  
  1252.     case WA_LFPAGE:    /* left page */
  1253.     if (text->fdc  >= (text->cols - 1)) {
  1254.         text->edge += (text->cols - 1) * text->wc;
  1255.         text->cx   += (text->cols - 1) * text->wc;
  1256.         text->fdc  -= (text->cols - 1);
  1257.         text->ldc = text->fdc + text->cols - 1;
  1258.     }
  1259.     else {
  1260.         ChangeX = twin->canvas.g_x - text->edge;
  1261.         text->edge += ChangeX;
  1262.         text->cx   += ChangeX;
  1263.         text->fdc = 0;
  1264.         text->ldc = text->cols - 1;
  1265.     }
  1266.     break;
  1267.  
  1268.     case WA_RTPAGE:    /* right page */
  1269.     if (text->fdc <= (text->bw - 2*text->cols + 3)) {
  1270.         text->edge -= (text->cols - 1) * text->wc;
  1271.         text->cx  -= (text->cols - 1) * text->wc;
  1272.         text->fdc += (text->cols - 1);
  1273.         text->ldc += (text->cols - 1);
  1274.     }
  1275.     else {
  1276.         ChangeX = twin->canvas.g_x
  1277.             - (text->bw + 2 - text->cols) * text->wc - text->edge;
  1278.         text->edge += ChangeX;
  1279.         text->cx   += ChangeX;
  1280.         text->fdc = (text->bw + 2 - text->cols);
  1281.         text->ldc = text->fdc + text->cols - 1;
  1282.     }
  1283.     break;
  1284.  
  1285.     }
  1286.  
  1287.     update_scroll(st->Event->Message[3]);
  1288.     cursor(OFF);
  1289.     HandleRedraw(FULL_WIN, &State);
  1290.     cursor(ON);
  1291.  
  1292. }
  1293.  
  1294. int
  1295. txtw_size(PSTATE *st)
  1296. {
  1297.  
  1298.     int handle = st->Event->Message[3];
  1299.  
  1300.     WINDOW *twin = WinFindH(handle);
  1301.     WINTEXT *text = twin->obj;
  1302.  
  1303.     int offset, diff, ChangeX;
  1304.  
  1305.     int old_x = twin->canvas.g_x;
  1306.     int old_y = twin->canvas.g_y;
  1307.     int old_w = twin->canvas.g_w;
  1308.     int old_h = twin->canvas.g_h;
  1309.  
  1310.     wind_set(twin->handle, WF_CURRXYWH,
  1311.     st->Event->Message[4], st->Event->Message[5],
  1312.     MIN(twin->mframe.g_w, st->Event->Message[6]),
  1313.     MIN(twin->mframe.g_h, st->Event->Message[7]));
  1314.  
  1315.     wind_get(twin->handle, WF_CURRXYWH,
  1316.     &twin->frame.g_x, &twin->frame.g_y,
  1317.     &twin->frame.g_w, &twin->frame.g_h);
  1318.  
  1319.     wind_get(twin->handle, WF_WORKXYWH,
  1320.     &twin->canvas.g_x, &twin->canvas.g_y,
  1321.     &twin->canvas.g_w, &twin->canvas.g_h);
  1322.  
  1323.     text->lins = visible_lines(twin);
  1324.     text->cols = visible_cols(twin);
  1325.  
  1326.     /* For the console window, put the current line at the bottom
  1327.      * of the window and adjust the first and last lines accordingly.
  1328.      * For other text windows, leave the first line unchanged if
  1329.      * possible.
  1330.      */
  1331.  
  1332.     if (twin->handle == conswin.handle) {
  1333.     text->fdl = text->ln - text->lins + 1;
  1334.  
  1335.     if (text->fdl > text->bh) {
  1336.         text->fdl -= text->bh;
  1337.     }
  1338.     else if (text->fdl < 0 && !text->scrolled) {
  1339.         text->fdl = 0;
  1340.     }
  1341.     else if (text->fdl < 0 && text->scrolled) {
  1342.         text->fdl += text->bh;
  1343.     }
  1344.     }
  1345.  
  1346.     text->ldl = text->fdl + text->lins - 1;
  1347.  
  1348.     if (text->ldl >= text->bh) {
  1349.     if (text->scrolled) {
  1350.         text->ldl -= text->bh;
  1351.     }
  1352.     else {        /* First displayed line must be changed. */
  1353.         text->ldl = text->bh - 1;
  1354.         text->fdl = text->ldl - text->lins + 1;
  1355.     }
  1356.     }
  1357.  
  1358.     /* Keep the first column the same, if possible, and adjust the
  1359.      * last column appropriately.
  1360.      */
  1361.  
  1362.     text->ldc = text->fdc + text->cols - 1;
  1363.     ChangeX = twin->canvas.g_x - old_x;
  1364.  
  1365.     if ((diff = text->ldc - text->bw - 1) > 0) {  /* Change first column. */
  1366.     ChangeX += diff * text->wc;
  1367.     text->ldc = text->bw + 1;
  1368.     text->fdc = text->ldc - text->cols + 1;
  1369.     }
  1370.  
  1371.     /* Adjust the cursor position. */
  1372.  
  1373.     text->cx += ChangeX;
  1374.  
  1375.     offset = text->ln - text->fdl;
  1376.     if (offset < 0) offset += text->bh;
  1377.     if (offset >= text->bh) offset -= text->bh;
  1378.     text->cy = twin->canvas.g_y + text->yoff + offset * text->hc;
  1379.  
  1380.     /* Adjust the left edge and top of the page. */
  1381.  
  1382.     text->edge += ChangeX;
  1383.  
  1384.     offset = text->fdl - text->fl;
  1385.     if (offset < 0) offset += text->bh;
  1386.     if (offset >= text->bh) offset -= text->bh;
  1387.     text->top = twin->canvas.g_y - offset * text->hc;
  1388.  
  1389.     /* Redraw the window if the OS won't. */
  1390.  
  1391.     if (old_x <= twin->canvas.g_x &&
  1392.     old_y <= twin->canvas.g_y &&
  1393.     old_w >= twin->canvas.g_w &&
  1394.     old_h >= twin->canvas.g_h) {
  1395.  
  1396.     cursor(OFF);
  1397.     HandleRedraw(FULL_WIN, st);
  1398.     cursor(ON);
  1399.     }
  1400.  
  1401.     update_scroll(handle);
  1402. }
  1403.  
  1404. int
  1405. bitw_size(PSTATE *st)
  1406. {
  1407.  
  1408.     WINDOW *bwin = WinFindH(st->Event->Message[3]);
  1409.     GRAPHIC *gr = bwin->obj;
  1410.  
  1411.     wind_set(bwin->handle, WF_CURRXYWH,
  1412.     st->Event->Message[4], st->Event->Message[5],
  1413.     MIN(bwin->mframe.g_w, st->Event->Message[6]),
  1414.     MIN(bwin->mframe.g_h, st->Event->Message[7]));
  1415.  
  1416.     wind_get(bwin->handle, WF_CURRXYWH,
  1417.     &bwin->frame.g_x, &bwin->frame.g_y,
  1418.     &bwin->frame.g_w, &bwin->frame.g_h);
  1419.  
  1420.     wind_get(bwin->handle, WF_WORKXYWH,
  1421.     &bwin->canvas.g_x, &bwin->canvas.g_y,
  1422.     &bwin->canvas.g_w, &bwin->canvas.g_h);
  1423.  
  1424.     gr->StepX = .9 * bwin->canvas.g_w;
  1425.     gr->StepY = .9 * bwin->canvas.g_h;
  1426.  
  1427.     update_scroll(st->Event->Message[3]);
  1428. }
  1429.  
  1430.  
  1431. int
  1432. txtw_redraw(int full_win, PSTATE *st)
  1433. {
  1434.     int handle = st->Event->Message[3];
  1435.  
  1436.     WINDOW *twin = WinFindH(handle);
  1437.     WINTEXT *text = twin->obj;
  1438.  
  1439.     int i, cnt;
  1440.     int x = align(twin->canvas.g_x + text->xoff);
  1441.     int fcol = text->fdc;
  1442.     int y, TopLineY, ln;
  1443.  
  1444.     GRECT dirty, rect;
  1445.  
  1446.     if (full_win) {
  1447.     dirty.g_x = twin->canvas.g_x;
  1448.     dirty.g_y = twin->canvas.g_y;
  1449.     dirty.g_w = twin->canvas.g_w;
  1450.     dirty.g_h = twin->canvas.g_h;
  1451.     }
  1452.     else {
  1453.     dirty.g_x = st->Event->Message[4];
  1454.     dirty.g_y = st->Event->Message[5];
  1455.     dirty.g_w = st->Event->Message[6];
  1456.     dirty.g_h = st->Event->Message[7];
  1457.     }
  1458.  
  1459.     TopLineY = twin->canvas.g_y + text->yoff;
  1460.  
  1461.     cnt = text->ln - text->fdl + 1;
  1462.     cnt = (cnt > 0) ? cnt : cnt + text->bh;
  1463.     cnt = MIN(cnt, text->lins);
  1464.  
  1465.     wind_get(twin->handle, WF_FIRSTXYWH,
  1466.     &rect.g_x, &rect.g_y,
  1467.     &rect.g_w, &rect.g_h);
  1468.  
  1469.     graf_mouse(M_OFF, 0L);
  1470.  
  1471.     while (rect.g_w && rect.g_h) {
  1472.  
  1473.     if (rc_intersect(&dirty, &rect)) {
  1474.         if (rc_intersect(&twin->canvas, &rect)) {
  1475.         
  1476.         y = TopLineY;
  1477.  
  1478.         grect_to_array(&rect, st->pxy);
  1479.         vs_clip(VWork.VdiHandle, 1, st->pxy);
  1480.         
  1481.         clear_win(&rect);
  1482.  
  1483.         for (ln=text->fdl, i=cnt; i; i--, ln++, y+=text->hc) {
  1484.             if (ln >= text->bh) ln -= text->bh;
  1485.             if (strlen(text->buff[ln]) > fcol)
  1486.             v_gtext(VWork.VdiHandle, x, y, text->buff[ln]+fcol);
  1487.         }
  1488.  
  1489.         vs_clip(VWork.VdiHandle, 0, st->pxy);
  1490.         }
  1491.     }
  1492.  
  1493.     wind_get(twin->handle, WF_NEXTXYWH,
  1494.         &rect.g_x, &rect.g_y,
  1495.         &rect.g_w, &rect.g_h);
  1496.     }
  1497.  
  1498.     graf_mouse(M_ON, 0L);
  1499.  
  1500. }
  1501.  
  1502. int
  1503. objw_redraw(int full_win, PSTATE *st)
  1504. {
  1505.  
  1506.     int handle = st->Event->Message[3];
  1507.  
  1508.     WINDOW *owin = WinFindH(handle);
  1509.     OBJECT *obj = owin->obj;
  1510.  
  1511.     GRECT dirty, rect;
  1512.  
  1513.     if (full_win) {
  1514.     dirty.g_x = owin->canvas.g_x;
  1515.     dirty.g_y = owin->canvas.g_y;
  1516.     dirty.g_w = owin->canvas.g_w;
  1517.     dirty.g_h = owin->canvas.g_h;
  1518.     }
  1519.     else {
  1520.     dirty.g_x = st->Event->Message[4];
  1521.     dirty.g_y = st->Event->Message[5];
  1522.     dirty.g_w = st->Event->Message[6];
  1523.     dirty.g_h = st->Event->Message[7];
  1524.     }
  1525.  
  1526.     wind_get(handle, WF_FIRSTXYWH,
  1527.     &rect.g_x, &rect.g_y,
  1528.     &rect.g_w, &rect.g_h);
  1529.  
  1530.     graf_mouse(M_OFF, 0L);
  1531.  
  1532.     while (rect.g_w && rect.g_h) {
  1533.  
  1534.     if (rc_intersect(&dirty, &rect)) {
  1535.         if (rc_intersect(&owin->canvas, &rect)) {
  1536.         objc_draw(obj, 0, 3,
  1537.             rect.g_x, rect.g_y,
  1538.             rect.g_w, rect.g_h);
  1539.         }
  1540.     }
  1541.  
  1542.     wind_get(handle, WF_NEXTXYWH,
  1543.         &rect.g_x, &rect.g_y,
  1544.         &rect.g_w, &rect.g_h);
  1545.  
  1546.     }
  1547.  
  1548.     graf_mouse(M_ON, 0L);
  1549.  
  1550. }
  1551.  
  1552. int
  1553. bitw_redraw(int full_win, PSTATE *st)
  1554. {
  1555.  
  1556.     WINDOW *bwin = WinFindH(st->Event->Message[3]);
  1557.     GRAPHIC *gr  = bwin->obj;
  1558.  
  1559.     GRECT dirty, rect;
  1560.  
  1561.     if (full_win) {
  1562.     dirty.g_x = bwin->canvas.g_x;
  1563.     dirty.g_y = bwin->canvas.g_y;
  1564.     dirty.g_w = bwin->canvas.g_w;
  1565.     dirty.g_h = bwin->canvas.g_h;
  1566.     }
  1567.     else {
  1568.     dirty.g_x = st->Event->Message[4];
  1569.     dirty.g_y = st->Event->Message[5];
  1570.     dirty.g_w = st->Event->Message[6];
  1571.     dirty.g_h = st->Event->Message[7];
  1572.     }
  1573.  
  1574.     gr->PlotX = MIN(gr->PlotX, gr->Width - bwin->canvas.g_w);
  1575.     gr->PlotY = MIN(gr->PlotY, gr->Height - bwin->canvas.g_h);
  1576.  
  1577.     wind_get(bwin->handle, WF_FIRSTXYWH,
  1578.     &rect.g_x, &rect.g_y,
  1579.     &rect.g_w, &rect.g_h);
  1580.  
  1581.     graf_mouse(M_OFF, 0L);
  1582.  
  1583.     while (rect.g_w && rect.g_h) {
  1584.     if (rc_intersect(&dirty, &rect)) {
  1585.         if (rc_intersect(&bwin->canvas, &rect)) {
  1586.         
  1587.         st->pxy[0] = gr->PlotX + (rect.g_x - bwin->canvas.g_x);
  1588.         st->pxy[1] = gr->PlotY + (rect.g_y - bwin->canvas.g_y);
  1589.         st->pxy[2] = st->pxy[0] + rect.g_w - 1;
  1590.         st->pxy[3] = st->pxy[1] + rect.g_h - 1;
  1591.  
  1592.         grect_to_array(&rect, &st->pxy[4]);
  1593.  
  1594.         vs_clip(VWork.VdiHandle, 1, &st->pxy[4]);
  1595.         vro_cpyfm(VWork.VdiHandle, 3, st->pxy,
  1596.             &gr->image, &gr->screen);
  1597.         vs_clip(VWork.VdiHandle, 0, &st->pxy[4]);
  1598.  
  1599.         }
  1600.     }
  1601.  
  1602.     wind_get(bwin->handle, WF_NEXTXYWH,
  1603.         &rect.g_x, &rect.g_y,
  1604.         &rect.g_w, &rect.g_h);
  1605.     }
  1606.  
  1607.     graf_mouse(M_ON, 0L);
  1608.  
  1609. }
  1610.  
  1611. int
  1612. update_scroll(int handle)
  1613. {
  1614.     int hslide_pos, hslide_siz, vslide_pos, vslide_siz;
  1615.  
  1616.     WINDOW *win = WinFindH(handle);
  1617.  
  1618.     switch (win->type) {
  1619.  
  1620.     case BIT:
  1621.       {
  1622.     GRAPHIC *gr = win->obj;
  1623.  
  1624.     if (gr->Width != win->canvas.g_w) {
  1625.         hslide_pos = 1000 * gr->PlotX/(gr->Width - win->canvas.g_w);
  1626.     }
  1627.     else {
  1628.         hslide_pos = 0;
  1629.     }
  1630.  
  1631.     if (gr->Height != win->canvas.g_h) {
  1632.         vslide_pos = 1000 * gr->PlotY
  1633.                / (gr->Height - win->canvas.g_h);
  1634.     }
  1635.     else {
  1636.         vslide_pos = 0;
  1637.     }
  1638.  
  1639.     hslide_siz = 1000 * win->canvas.g_w/gr->Width;
  1640.     vslide_siz = 1000 * win->canvas.g_h/gr->Height;
  1641.  
  1642.       }
  1643.     break;
  1644.  
  1645.     case TEXT:
  1646.       {
  1647.     WINTEXT *text = win->obj;
  1648.  
  1649.     int offset = text->fdl - text->fl;
  1650.  
  1651.     if (offset < 0) offset += text->bh;
  1652.  
  1653.     if (text->cols != text->bw + 2) {
  1654.         hslide_pos = 1000 * text->fdc/(text->bw + 2 - text->cols);
  1655.     }
  1656.     else {
  1657.         hslide_pos = 0;
  1658.     }
  1659.  
  1660.     if (text->lins < text->bh) {
  1661.         vslide_pos = 1000 * offset/(text->bh - text->lins);
  1662.     }
  1663.     else {
  1664.         vslide_pos = 0;
  1665.     }
  1666.  
  1667.     hslide_siz = 1000 * text->cols/(text->bw + 2);
  1668.     vslide_siz = 1000 * text->lins/text->bh;
  1669.  
  1670.       }
  1671.     break;
  1672.  
  1673.     }
  1674.  
  1675.     wind_set(handle, WF_HSLIDE,  hslide_pos);
  1676.     wind_set(handle, WF_VSLIDE,  vslide_pos);
  1677.     wind_set(handle, WF_HSLSIZE, hslide_siz);
  1678.     wind_set(handle, WF_VSLSIZE, vslide_siz);
  1679.  
  1680.     return 0;
  1681. }
  1682.  
  1683. int
  1684. TextWinInit(WINDOW *twin, WINTEXT *text, int gadgets, char *title)
  1685. {
  1686.     twin->handle = -1;
  1687.     twin->type = TEXT;
  1688.     twin->obj = (void *)text;
  1689.     twin->gadgets = gadgets;
  1690.     twin->title = title;
  1691.     twin->opened = 0;
  1692.     twin->iconified = 0;
  1693.  
  1694.     twin->canvas.g_x = 0; twin->canvas.g_y = 0;
  1695.     twin->canvas.g_w = 0; twin->canvas.g_h = 0;
  1696.  
  1697.     twin->frame.g_x = 0; twin->frame.g_y = 0;
  1698.     twin->frame.g_w = 0; twin->frame.g_h = 0;
  1699.  
  1700.     twin->oframe.g_x = 0; twin->oframe.g_y = 0;
  1701.     twin->oframe.g_w = 0; twin->oframe.g_h = 0;
  1702.  
  1703.     twin->mframe.g_x = 0; twin->mframe.g_y = 0;
  1704.     twin->mframe.g_w = 0; twin->mframe.g_h = 0;
  1705.  
  1706.     twin->redraw = txtw_redraw;
  1707.     twin->move   = txtw_move;
  1708.     twin->size   = txtw_size;
  1709.     twin->arrow  = txtw_arrow;
  1710.     twin->hslide = txtw_hslide;
  1711.     twin->vslide = txtw_vslide;
  1712.  
  1713.     text->bw   = COLUMNS;
  1714.     text->bh   = LINES;
  1715.     text->top  = text->edge = 0;
  1716.     text->xoff = text->yoff = 0;
  1717.     text->cx   = text->cy   = 0;
  1718.     text->cstate = 0;
  1719.     text->wc   = text->hc   = 0;
  1720.     text->lins = text->cols = 0;
  1721.     text->ln   = text->cn   = 0;
  1722.     text->fl   = 0;
  1723.     text->ll   = LINES-1;
  1724.     text->fdl  = 0;
  1725.     text->ldl  = LINES-1;
  1726.     text->fdc  = text->ldc  = 0;
  1727.     text->scrolled = 0;
  1728. }
  1729.  
  1730. int
  1731. BitWinInit(WINDOW *bwin, GRAPHIC *gr, int gadgets, char *title)
  1732. {
  1733.     bwin->handle = -1;
  1734.     bwin->type = BIT;
  1735.     bwin->obj = (void *)gr;
  1736.     bwin->gadgets = gadgets;
  1737.     bwin->title = title;
  1738.     bwin->opened = 0;
  1739.     bwin->iconified = 0;
  1740.  
  1741.     bwin->redraw = bitw_redraw;
  1742.     bwin->move   = bitw_move;
  1743.     bwin->size   = bitw_size;
  1744.     bwin->arrow  = bitw_arrow;
  1745.     bwin->hslide = bitw_hslide;
  1746.     bwin->vslide = bitw_vslide;
  1747.  
  1748.     bwin->frame.g_x = imagwin.frame.g_x + 2 * VWork.Wchar;
  1749.     bwin->frame.g_y = imagwin.frame.g_x + VWork.Hchar;
  1750.     bwin->frame.g_w = imagwin.frame.g_w;
  1751.     bwin->frame.g_h = imagwin.frame.g_h;
  1752.  
  1753.     memcpy(gr, imagwin.obj, sizeof(GRAPHIC));
  1754.  
  1755. }
  1756.  
  1757. int
  1758. ObjWinInit(WINDOW *owin, OBJECT *object, int gadgets, char *title)
  1759. {
  1760.     owin->handle = -1;
  1761.     owin->type = OBJ;
  1762.     owin->obj = (void *)object;
  1763.     owin->gadgets = gadgets;
  1764.     owin->title = title;
  1765.     owin->opened = 0;
  1766.     owin->iconified = 0;
  1767.  
  1768.     owin->canvas.g_x = 0; owin->canvas.g_y = 0;
  1769.     owin->canvas.g_w = 0; owin->canvas.g_h = 0;
  1770.  
  1771.     owin->frame.g_x = 0; owin->frame.g_y = 0;
  1772.     owin->frame.g_w = 0; owin->frame.g_h = 0;
  1773.  
  1774.     owin->oframe.g_x = 0; owin->oframe.g_y = 0;
  1775.     owin->oframe.g_w = 0; owin->oframe.g_h = 0;
  1776.  
  1777.     owin->mframe.g_x = 0; owin->mframe.g_y = 0;
  1778.     owin->mframe.g_w = 0; owin->mframe.g_h = 0;
  1779.  
  1780.     owin->redraw = objw_redraw;
  1781.     owin->move   = objw_move;
  1782.     owin->size   = NULL;
  1783.     owin->arrow  = NULL;
  1784.     owin->hslide = NULL;
  1785.     owin->vslide = NULL;
  1786. }
  1787.  
  1788. /* WinAlloc allocates memory for a new window. */
  1789.  
  1790. WINDOW *
  1791. WinAlloc(void)
  1792. {
  1793.     return (WINDOW *) gs_malloc((uint)sizeof(WINDOW), 1, "window");
  1794. }
  1795.  
  1796. /* Free the memory allocated for a window. */
  1797.  
  1798. int
  1799. WinFree(WINDOW *win)
  1800. {
  1801.     gs_free((char *)win, 1, sizeof(WINDOW), "window");
  1802. }
  1803.  
  1804. /* WinTextAlloc allocates memory for a window text structure. */
  1805.  
  1806. WINTEXT *
  1807. WinTextAlloc(int Lines)
  1808. {
  1809.     WINTEXT *text;
  1810.  
  1811.     /* Allocate the WINTEXT structure. */
  1812.  
  1813.     if ((text = (WINTEXT *) gs_malloc((uint)sizeof(WINTEXT), 1, "wintext")) == NULL) {
  1814.     return text;
  1815.     }
  1816.  
  1817.     /* Allocate the character buffer. */
  1818.  
  1819.     if ((text->buff = (char (*)[COLUMNS+1])gs_malloc((uint)(COLUMNS+1), Lines, "charbuff")) == NULL) {
  1820.     gs_free((char *)text, 1, sizeof(WINTEXT), "wintext");
  1821.     return (WINTEXT *)NULL;
  1822.     }
  1823.  
  1824.     text->bsize = Lines;
  1825.  
  1826.     return text;
  1827. }
  1828.  
  1829. char
  1830. (*TextBuffRealloc(WINTEXT *text, int NewSize))[COLUMNS+1]
  1831. {
  1832.     char (*temp)[COLUMNS+1];
  1833.  
  1834.     /* Allocate another character buffer of the new size. */
  1835.  
  1836.     if ((temp = (char (*)[COLUMNS+1])gs_malloc((uint)(COLUMNS+1), NewSize, "charbuff")) == NULL) {
  1837.     return temp;
  1838.     }
  1839.  
  1840.     if (text->buff != 0) {
  1841.  
  1842.     /* Copy the old buffer to the new one. */
  1843.     memcpy(temp, text->buff, (MIN(text->bsize, NewSize))*(COLUMNS+1));
  1844.  
  1845.     /* Free the old character buffer. */
  1846.     gs_free((char *)text->buff, text->bsize, (COLUMNS+1), "charbuff");
  1847.  
  1848.     }
  1849.  
  1850.     text->bsize = NewSize;
  1851.     text->buff = temp;
  1852.     return temp;
  1853. }
  1854.  
  1855. /* Free the memory allocated for a window text structure. */
  1856.  
  1857. int
  1858. WinTextFree(WINTEXT *text)
  1859. {
  1860.     gs_free((char *)text->buff, text->bsize, (COLUMNS+1), "charbuff");
  1861.     gs_free((char *)text, 1, sizeof(WINTEXT), "wintext");
  1862. }
  1863.  
  1864. /* GraphicAlloc allocates memory for a graphic structure. */
  1865.  
  1866. GRAPHIC *
  1867. GraphicAlloc(void)
  1868. {
  1869.     return (GRAPHIC *) gs_malloc((uint)sizeof(GRAPHIC), 1, "graphic");
  1870. }
  1871.  
  1872. /* Free the memory allocated for a graphic structure. */
  1873.  
  1874. int
  1875. GraphicFree(GRAPHIC *gr)
  1876. {
  1877.     gs_free((char *)gr, 1, sizeof(GRAPHIC), "graphic");
  1878. }
  1879.  
  1880. /* Free the memory allocated for a bitmap buffer. */
  1881.  
  1882. int
  1883. BitBufferFree(GRAPHIC *gr)
  1884. {
  1885.     char *buff = (char *)gr->image.fd_addr;
  1886.     ulong buff_size = gr->image.fd_w * gr->image.fd_h;
  1887.  
  1888.     gs_free((char *)buff, buff_size, 1, "bitbuffer");
  1889. }
  1890.  
  1891. /* ListAlloc allocates memory for a new element of the window list. */
  1892.  
  1893. WINLIST *
  1894. WinListAlloc(void)
  1895. {
  1896.     return (WINLIST *) gs_malloc((uint)sizeof(WINLIST), 1, "winlist");
  1897. }
  1898.  
  1899. /* Free the memory for the winlist structure */
  1900.  
  1901. int
  1902. WinListFree(WINLIST *wl)
  1903. {
  1904.     gs_free((char *)wl, 1, sizeof(WINLIST), "winlist");
  1905. }
  1906.  
  1907. /* WinListAdd adds a new window to the window list. */
  1908.  
  1909. WINLIST *
  1910. WinListAdd(WINLIST *wlist, WINDOW *win)
  1911. {
  1912.     WINLIST *wl = WinListAlloc();
  1913.  
  1914.     if (win->opened || win->iconified) return wlist;
  1915.  
  1916.     if (wlist == NULL) {    /* Begin a new list. */
  1917.  
  1918.     wl->Prev = wl;
  1919.     wl->Next = wl;
  1920.  
  1921.     }
  1922.     else {            /* Add a new list element. */
  1923.  
  1924.     wl->Prev = wlist->Prev;
  1925.     wl->Next = wlist;
  1926.  
  1927.     wlist->Prev->Next = wl;
  1928.     wlist->Prev = wl;
  1929.  
  1930.     }
  1931.  
  1932.     wl->Win = win;        /* Put the window in the list. */
  1933.     return wl;
  1934. }
  1935.  
  1936.  
  1937. /* Delete a window from the window list and free its associated memory. */
  1938.  
  1939. WINLIST *
  1940. WinListDelete(WINLIST *wlist, WINDOW *win)
  1941. {
  1942.     WINLIST *ret, *wl = wlist;
  1943.  
  1944.     /*
  1945.      * Return the new head of the window list. If the head was not
  1946.      * deleted, it remains the head. If the head is deleted, make
  1947.      * the next list element the head. If deleting the head leaves
  1948.      * the list empty, then return NULL.
  1949.      */
  1950.  
  1951.     ret = (win == wlist->Win) ?
  1952.     ((wlist->Next == wlist) ? NULL : wlist->Next) : wlist;
  1953.  
  1954.     /* Delete the specified list element. */
  1955.  
  1956.     do {
  1957.     if (win == wl->Win) {
  1958.         wl->Prev->Next = wl->Next;
  1959.         wl->Next->Prev = wl->Prev;
  1960.         break;
  1961.     }
  1962.     wl = wl->Next;
  1963.     }
  1964.     while (wl != wlist);
  1965.  
  1966.     /* Free the memory for the window structure. */
  1967.     if ((win->type == TEXT) && (win != &conswin)) {
  1968.     WinTextFree(win->obj);
  1969.     WinFree(win);
  1970.     }
  1971.     else if ((win->type == BIT) && (win != &imagwin)) {
  1972.     GRAPHIC *gr = win->obj;
  1973.         BitBufferFree(gr);
  1974.     GraphicFree(gr);
  1975.     WinFree(win);
  1976.     }
  1977.  
  1978.     /* Free the memory used for the window list. */
  1979.     WinListFree(wl);
  1980.  
  1981.     return ret;
  1982. }
  1983.  
  1984. /* Open all the windows in the window list, leaving the list intact. */
  1985.  
  1986. int
  1987. WinListOpen(WINLIST *wlist)
  1988. {
  1989.     WINLIST *wl = wlist;
  1990.  
  1991.     do {
  1992.     if (wl->Win->iconified) {
  1993.         wind_open(wl->Win->handle,
  1994.         wl->Win->frame.g_x, wl->Win->frame.g_y,
  1995.         wl->Win->frame.g_w, wl->Win->frame.g_h);
  1996.  
  1997.         wl->Win->opened = 1;
  1998.         wl->Win->iconified = 0;
  1999.  
  2000.         if (wl->Win->type == OBJ) {
  2001.         OBJECT *obj = wl->Win->obj;
  2002.         obj[0].ob_flags ^= HIDETREE;
  2003.         }
  2004.     }
  2005.  
  2006.     wl = wl->Next;
  2007.     }
  2008.     while (wl != wlist);
  2009. }
  2010.  
  2011. /* Close all the windows in the window list, leaving the list intact. */
  2012.  
  2013. int
  2014. WinListClose(WINLIST *wlist)
  2015. {
  2016.     WINLIST *wl = wlist;
  2017.  
  2018.     do {
  2019.     if (wl->Win->opened) {
  2020.  
  2021.         wind_get(wl->Win->handle, WF_CURRXYWH,
  2022.         &wl->Win->oframe.g_x, &wl->Win->oframe.g_y,
  2023.         &wl->Win->oframe.g_w, &wl->Win->oframe.g_h);
  2024.  
  2025.         wind_get(wl->Win->handle, WF_CURRXYWH,
  2026.         &wl->Win->frame.g_x, &wl->Win->frame.g_y,
  2027.         &wl->Win->frame.g_w, &wl->Win->frame.g_h);
  2028.  
  2029.         wind_close(wl->Win->handle);
  2030.         wl->Win->opened = 0;
  2031.         wl->Win->iconified = 1;
  2032.  
  2033.         if (wl->Win->type == OBJ) {
  2034.         OBJECT *obj = wl->Win->obj;
  2035.         obj[0].ob_flags ^= HIDETREE;
  2036.         }
  2037.  
  2038.     }
  2039.  
  2040.     wl = wl->Next;
  2041.     }
  2042.     while (wl != wlist);
  2043. }
  2044.  
  2045. /* Redraw all windows in the list. */
  2046.  
  2047. int
  2048. WinListRedraw(WINLIST *wlist, PSTATE *st)
  2049. {
  2050.     WINLIST *wl = wlist;
  2051.  
  2052.     do {
  2053.     if (wl->Win->opened) {
  2054.         st->Event->Message[3] = wl->Win->handle;
  2055.         HandleRedraw(FULL_WIN, st);
  2056.     }
  2057.  
  2058.     wl = wl->Next;
  2059.     }
  2060.     while (wl != wlist);
  2061. }
  2062.  
  2063. /*
  2064.  * Pathfind(path, file, sep) searches for 'file' in the path given
  2065.  * by the envionment variable named in 'env'. Sep specifies the
  2066.  * path separator. It returns a pointer to the filename if it is
  2067.  * found, and a NULL if not.
  2068.  */
  2069.  
  2070. char *
  2071. PathFind(char *env, char *file, char *sep)
  2072. {
  2073.     FILE *fp;
  2074.  
  2075.     char path[2*MAXLEN];
  2076.     static char name[MAXLEN];
  2077.  
  2078.     char *ptr;
  2079.     char *presub();
  2080.  
  2081.     if ((fp = fopen(file, "r")) == NULL) {
  2082.  
  2083.     if ((ptr = getenv(env)) != NULL) {
  2084.         strcpy(path, ptr);
  2085.     }
  2086.     else {
  2087.         return NULL;
  2088.     }
  2089.  
  2090.     if ((ptr = presub(path, sep)) == NULL) {
  2091.         return NULL;
  2092.     }
  2093.  
  2094.     do {
  2095.         strcpy(name, ptr);
  2096.  
  2097.         if (name[strlen(name)-1] != '\\' ||
  2098.         name[strlen(name)-1] != '/') strcat(name, "\\");
  2099.  
  2100.         strcat(name, file);
  2101.  
  2102.         if ((fp = fopen(name, "r")) != NULL) {
  2103.         fclose(fp);
  2104.         return name;
  2105.         }
  2106.  
  2107.     } while ((ptr = presub(NULL, sep)) != NULL);
  2108.  
  2109.     }
  2110.     else {
  2111.     fclose(fp);
  2112.     return file;
  2113.     }
  2114. }
  2115.  
  2116. /* Presub(s, subs) searches the string s for the substring subs. Presub
  2117.  * returns a pointer to the NULL terminated substring which immediately
  2118.  * preceeds subs. If presub is called again with a NULL pointer for s, 
  2119.  * it returns a pointer to the substring between the previous subs and
  2120.  * the current subs. If subs is a null character, presub returns a pointer
  2121.  * to the portion of s between the previous subs and the end of s.
  2122.  */
  2123.  
  2124. char *presub(s, subs)
  2125. char *s, *subs;
  2126. {
  2127.     int sublen;
  2128.     char *mptr;
  2129.     static int count;
  2130.     static char match[MAXLEN], *ptr;
  2131.  
  2132.     if (s != NULL) {
  2133.         ptr = s;
  2134.         count = 0;
  2135.     }
  2136.  
  2137.     mptr = match + count;
  2138.     if ((sublen = strlen(subs)) == 0) {
  2139.         strcpy(mptr, ptr);
  2140.         return (mptr);
  2141.     }
  2142.  
  2143.     while (*ptr != '\0') {
  2144.         if (strncmp(ptr, subs, sublen) == 0) {
  2145.             match[count] = '\0';
  2146.             ptr += sublen;
  2147.             ++count;
  2148.             return (mptr);
  2149.         }
  2150.         match[count] = *ptr;
  2151.         ++ptr;
  2152.         ++count;
  2153.         
  2154.     }
  2155.  
  2156.     if ((match + count) > mptr) {
  2157.         match[count] = *ptr;
  2158.         ++count;
  2159.         return (mptr);
  2160.  
  2161.     }
  2162.  
  2163.     return (NULL);
  2164.  
  2165. }
  2166.  
  2167. /* Ensure that the size of a window is within the limits of
  2168.  * the hardware.
  2169.  */
  2170.  
  2171. int EnforceLimits(GRECT *rect, VWRK *vw)
  2172. {
  2173.  
  2174.     if ((rect->g_x < vw->full.g_x) || (rect->g_x >= vw->full.g_w)) {
  2175.     rect->g_x = vw->full.g_x;
  2176.     }
  2177.  
  2178.     if ((rect->g_y < vw->full.g_y) || (rect->g_y >= vw->full.g_h)) {
  2179.     rect->g_y = vw->full.g_y;
  2180.     }
  2181.  
  2182.     if (rect->g_w < 0) {
  2183.     rect->g_w = vw->full.g_w - rect->g_x;
  2184.     }
  2185.  
  2186.     if (rect->g_h < 0) {
  2187.     rect->g_h = vw->full.g_h - rect->g_y + vw->full.g_y;
  2188.     }
  2189. }
  2190.  
  2191. /* Routine itoa(num, s) converts an integer, num, to an ascii string 
  2192.  * representation of the integer, pointed to by s. The integer 100 is 
  2193.  *  converted to the string "100", etc.
  2194.  */
  2195.  
  2196. char *itoa(int number, char *s)
  2197. {
  2198.  
  2199. /* Local variables:
  2200.  *    i:        loop counter,
  2201.  *    j:        number of loops needed to transpose the string in s,
  2202.  *    body:        integer part of num/10,
  2203.  *    remain:        remainder of num/10,
  2204.  *    sign:        sign of the integer,
  2205.  *    count:        number of times num is divisible by 10,
  2206.  *    temp:        temporary character storage.
  2207.  */
  2208.  
  2209.     int i, j, num, body, remain, sign, count;
  2210.     char temp;
  2211.  
  2212.     count = 0;
  2213.     num = number;
  2214.     sign = 1;
  2215.  
  2216.     if (num == 0) {
  2217.         s[count] = '0';
  2218.         ++count;
  2219.     } else {
  2220.  
  2221.         if (num < 0) {
  2222.             sign = -1;
  2223.             num = -num;
  2224.         }
  2225.  
  2226.         while (num > 0) {        /* Divide by 10, convert */
  2227.             body = (num/10);    /* remainder to ascii    */
  2228.             remain = num - body*10;
  2229.             s[count] = remain + '0';
  2230.             num = body;
  2231.             ++count;
  2232.         }
  2233.  
  2234.         if (sign < 0) {
  2235.             s[count] = '-';
  2236.             ++count;
  2237.         }
  2238.  
  2239.         /* Ascii representation is transposed in s, so put it in 
  2240.          * the right order. */
  2241.  
  2242.         j = count/2;    
  2243.  
  2244.         for (i = 0; i < j; ++i) {
  2245.             temp = s[i];
  2246.             s[i] = s[count-(i+1)];
  2247.             s[count-(i+1)] = temp;
  2248.         }
  2249.  
  2250.     }
  2251.  
  2252.     s[count] = '\0';
  2253.     return(s);
  2254.  
  2255. }
  2256.  
  2257. /* Round to nearest integer. */
  2258.  
  2259. int
  2260. nint(double Num)
  2261. {
  2262.  
  2263.     int Floor = floor(Num);
  2264.     int Ceil  = ceil(Num);
  2265.  
  2266.     return (fabs(Num - Floor) > fabs(Num - Ceil)) ? Ceil : Floor;
  2267.  
  2268. }
  2269.  
  2270. int align(int x)
  2271. {
  2272.     return ((x & 0xfffffff0) + ((x & 0xf) ? 0x10 : 0));
  2273. /*    return ((x & 0xfffffff8) + ((x & 0x07) ? 0x08 : 0)); */
  2274. }
  2275.  
  2276.  
  2277. /*
  2278.  * The remainder of this file contains printer output routines, most of
  2279.  * which were contributed by Chris Strunk (some of them were written by me).
  2280.  * I made some modifications to the following code (with permission), and
  2281.  * may have introduced errors not in the original code.
  2282.  * Tim Gallivan, 3/92.
  2283.  */
  2284.  
  2285. /*
  2286.  * This file is Copyright (C) 1990 Christoph Strunk.
  2287.  *
  2288.  * You are not allowed to copy or modify it.
  2289.  */
  2290.  
  2291. #define ATARI_TOS    (1)
  2292. #define MAKE_VOID    (void *)
  2293.  
  2294. void con_flush();
  2295. int OutputIsAscii = 0, RTX_Found = 0;
  2296. long *old_ssp = NULL;
  2297. FILE *OutFile = NULL;
  2298.  
  2299. #if PC_DOS || ATARI_TOS
  2300. #  define DIRECT    1    /* 1 = Direct Centronics port programming */
  2301. #endif
  2302.  
  2303. #if ATARI_TOS || ( PC_DOS && DIRECT )
  2304. static short prn_out ( int );
  2305. #endif
  2306.  
  2307. #if ATARI_TOS && LATTICE
  2308. #include <dos.h>
  2309. #endif
  2310.  
  2311. #ifdef __GNUC__
  2312. #include <osbind.h>
  2313. #endif
  2314.  
  2315. #if PC_DOS && DIRECT
  2316. #include <bios.h>
  2317. #endif
  2318.  
  2319. /* output one character */
  2320.  
  2321. static int fatal_output_error = 0;
  2322.  
  2323. void
  2324. lputc(c)
  2325. int c;
  2326. {
  2327.     static short rc;
  2328.     static unsigned char global_count = 0; /* other processes every 256 chars */
  2329.     void l_stop(), fatal();
  2330.  
  2331.     if ( fatal_output_error ) return;
  2332.  
  2333.     global_count += 1;
  2334.  
  2335.     c &= 255;            /* New in 2.9.44: avoid signed char problems */
  2336.  
  2337. #if ATARI_TOS || PC_DOS
  2338.     if ( ( c == '\n' ) && OutputIsAscii ) {
  2339.       lputc ( '\r' );    /* recursion */
  2340.     }
  2341. #endif
  2342.  
  2343.     if ( OutFile ) {
  2344.        rc = ( fputc ( c, OutFile ) == EOF );
  2345.     } else {
  2346. #if ATARI_TOS || ( PC_DOS && DIRECT )
  2347.                    rc = prn_out ( c );
  2348. #else
  2349.                    rc = -1;
  2350. #endif
  2351.     }
  2352.  
  2353.     if ( rc ) {
  2354.         if ( OutFile ) {
  2355.             perror ( "\nlputc" );
  2356.             fprintf ( stderr, "\nOutput error -- %s ?\n",
  2357.                       "Disk full or printer not ready" );
  2358.             fclose ( OutFile );
  2359.             OutFile = NULL;
  2360.         } else {
  2361.             fprintf ( stderr, "\nOutput error -- Printer not ready ?\n" );
  2362.         }
  2363.         l_stop();
  2364.         fatal_output_error = 1;
  2365.         fatal ( "Output error" );
  2366.     }
  2367.  
  2368. #if ATARI_TOS
  2369.     if ( RTX_Found && ! global_count ) call_yield(); /* allow other processes */
  2370. #endif
  2371. }
  2372.  
  2373. /* output a string */
  2374.  
  2375. void
  2376. lputs ( s )
  2377. char *s;
  2378. {
  2379.     while ( *s ) lputc ( *s++ );
  2380. }
  2381.  
  2382. void
  2383. lflush()
  2384. {
  2385.    if ( OutFile ) fflush ( OutFile );
  2386. }
  2387.  
  2388. /* start/stop lputc device */
  2389.  
  2390. void
  2391. l_start()
  2392. {
  2393.   void l_stop(), fatal();
  2394.  
  2395. #if ATARI_TOS && DIRECT
  2396.   volatile char *gpip = (char *) 0xFFFFFA01L;
  2397.   int cnt;
  2398.  
  2399.   if ( OutFile == NULL && old_ssp == NULL ) {
  2400.     old_ssp = (void *) call_super ( NULL );
  2401.     cnt = 0;
  2402. /*    for ( cnt=0; ( *gpip & 1 ) && ( ++cnt <= 10 ); ) {
  2403.      printf("cnt = %d\n", cnt); */
  2404.      Ongibit(0x20);                                        /* set strobe bit */
  2405. /*    } */
  2406.     if ( cnt > 10 ) {
  2407.       l_stop();
  2408.       dputs ( "\n" );
  2409.       fatal_output_error = 1;
  2410.       fatal ( "Printer not ready" );
  2411.     }
  2412.   }
  2413. #endif
  2414. #if ATARI_TOS && ! DIRECT
  2415.   int cnt;
  2416.  
  2417.   if ( OutFile == NULL && old_ssp == NULL ) {
  2418.     old_ssp = (void *) call_super ( NULL );
  2419.  
  2420.     for ( cnt=0; ( ! prt_ready(0) ) && ( ++cnt <= 10 ); ) {
  2421.      Ongibit(0x20);                                        /* set strobe bit */
  2422.     }
  2423.     if ( cnt > 10 ) {
  2424.       l_stop();
  2425.       dputs ( "\n" );
  2426.       fatal_output_error = 1;
  2427.       fatal ( "Printer not ready" );
  2428.     }
  2429.   }
  2430. #endif
  2431. #if PC_DOS && DIRECT
  2432.   if ( OutFile == NULL && ( biosprint ( 2, 0, BiosChannel ) & 0x29 ) ) {
  2433.     l_stop();
  2434.     dputs ( "\n" );
  2435.     fatal_output_error = 1;
  2436.     fatal ( "Printer not ready" );
  2437.   }
  2438. #endif
  2439. }
  2440.  
  2441. void l_stop()
  2442. {
  2443.     lflush();
  2444. #if ATARI_TOS
  2445.     if ( old_ssp != NULL ) {
  2446.         MAKE_VOID call_super ( old_ssp );
  2447.         old_ssp = NULL;
  2448.     }
  2449. #endif
  2450. }
  2451.  
  2452. #if ATARI_TOS && DIRECT
  2453.  
  2454. extern void int_off __PROTO( ( void ) );
  2455.  
  2456. /* int_off:  ori.w  #$0700,sr
  2457.  *           ret
  2458.  */
  2459.  
  2460. extern void int_on __PROTO( ( void ) );
  2461.  
  2462. /* int_on:   andi.w #$F8FF,sr
  2463.  *           ret
  2464.  */
  2465.  
  2466. static short prn_out ( c )
  2467. int c;
  2468. {
  2469.   volatile unsigned long *hz_200;
  2470.   register unsigned long end_time;
  2471.   volatile char *gpip = (char *) 0xFFFFFA01L;
  2472.   register char g;
  2473.  
  2474. #if OLD
  2475.   unsigned char loop_count = 0;
  2476. #endif
  2477.  
  2478.   if ( old_ssp == NULL ) l_start();
  2479.  
  2480.   hz_200 = (unsigned long *) 0x04BAL;
  2481. #if OLD
  2482.   end_time = *hz_200 + 200;        /* check once per second */
  2483. #else
  2484.   end_time = *hz_200 + 2;          /* check 100 times per second */
  2485. #endif
  2486.  
  2487.   while ( *gpip & 1 ) {  /* wait */
  2488. #if OLD
  2489.     /* Printer 1 sec. or more not ready ? */
  2490.     if ( ( end_time < *hz_200 ) ||
  2491.          ( ( ( ++loop_count & 7 ) == 0 ) && ( BatchMode || RTX_Found ) ) ) {
  2492.         con_flush();         /* allow Control_C, other Processes etc. */
  2493.         end_time = *hz_200 + 2;          /* check 100 times per second */
  2494.     }
  2495. #else
  2496.     if ( end_time <= *hz_200 ) {
  2497.         con_flush();               /* allow Control_C, other Processes etc. */
  2498.         end_time = *hz_200 + 1;              /* check 200 times per second */
  2499.     }
  2500. #endif
  2501.   }
  2502.  
  2503.   int_off();                   /* disable interrupts */
  2504.  
  2505.   gpip = (char *) 0xFFFF8800L; /* load sound chip adress now */
  2506.  
  2507.   /* This next section of code was added by Tim Gallivan on 7/11/94
  2508.    * to fix a problem of this routine not working on some hardware.
  2509.    */
  2510.  
  2511.   *gpip = 7;               /* select enable register */
  2512.   g = *gpip;                   /* get old value */
  2513.   g |= 0x80;                   /* set port B output bit */
  2514.   gpip[2] = g;
  2515.  
  2516.   /* End fix. */
  2517.  
  2518.   *gpip = 15;                  /* select port B */
  2519.   gpip[2] = (char) c;          /* write out char */
  2520.   *gpip = 14;                  /* select port A */
  2521.   g = *gpip;                   /* get old value */
  2522. #if OLD
  2523.   g &= 0xDF;                   /* clear strobe bit */
  2524. #else
  2525.   g &= ~0x20;                  /* clear strobe bit */
  2526. #endif
  2527.   gpip[2] = g;
  2528.   g |= 0x20;                   /* set strobe bit */
  2529.   g |= 0x20;                   /* short delay */
  2530.   gpip[2] = g;
  2531.  
  2532.   int_on();                    /* enable interrupts */
  2533.  
  2534.   return 0;
  2535. }
  2536. #endif
  2537.  
  2538. #if ATARI_TOS && ! DIRECT
  2539. static short prn_out ( c )
  2540. int c;
  2541. {
  2542.   volatile unsigned long *hz_200 = (unsigned long *) 0x04BAL;
  2543.   register unsigned long end_time;
  2544.  
  2545.   if ( old_ssp == NULL ) l_start();
  2546.  
  2547.   end_time = *hz_200 + 2;          /* check 200 times per second */
  2548.  
  2549.   while ( ! prt_ready(0) ) {  /* wait */
  2550.     if ( end_time <= *hz_200 ) {
  2551.         con_flush();               /* allow Control_C, other Processes etc. */
  2552.         end_time = *hz_200 + 1;              /* check 200 times per second */
  2553.     }
  2554.   }
  2555.  
  2556.   prt_out ( 0, c );
  2557.  
  2558.   return 0;
  2559. }
  2560. #endif
  2561.  
  2562. #if PC_DOS && DIRECT
  2563.  
  2564. static short prn_out ( c )
  2565. int c;
  2566. {
  2567.   while ( biosprint ( 0, c, BiosChannel ) & 0x29 ) {
  2568.     /* wait until Ok or Control-C pressed */
  2569.     con_flush();
  2570.   }
  2571.  
  2572.   return 0;
  2573. }
  2574.  
  2575. #endif
  2576.  
  2577. void
  2578. con_flush()
  2579. {
  2580.     int chin;
  2581.     void fatal();
  2582.  
  2583.     chin = Crawio(0xFF);
  2584.     if ((chin & 0xFF) == 3) fatal("Keyboard Interrupt");
  2585. }
  2586.  
  2587. void
  2588. fatal(char *message)
  2589. {
  2590.     fprintf(stderr, "%s\n", message);
  2591.     l_stop();
  2592.     exit(-1);
  2593. }
  2594.  
  2595. /* Restore the usual desktop background. */
  2596.  
  2597. #undef puts
  2598.  
  2599. int RestoreBG(VWRK *vw)
  2600. {
  2601.     puts("\033f");
  2602.     v_hide_c(vw->VdiHandle);
  2603.     form_dial(FMD_FINISH, 0, 0, 8, 16, 0, 0, vw->XRes, vw->YRes);
  2604.     v_show_c(vw->VdiHandle, 0);
  2605. }
  2606.  
  2607. /*
  2608. #-----------------------------------------------------------------------------#
  2609. #:    Simple support routines for LATTICE C 5.04.01 and other C compilers
  2610. #
  2611. #:    Lattice C Assembler
  2612. #
  2613. #:    The parameter comes on the stack for functions starting with '_'.
  2614. #
  2615. #:    void *call_super ( void * );  supervisor mode on/off
  2616. #
  2617. #:    Original code by Chris Strunk. Modified for use with gcc in
  2618. #:    Ghostscript by Tim Gallivan, 3/92.
  2619. #-----------------------------------------------------------------------------#
  2620. */
  2621.     asm("\
  2622.  
  2623.     .text 0
  2624.  
  2625.     .globl _int_off
  2626.     .globl _int_on
  2627.     .globl _call_super
  2628.     .globl _call_yield
  2629.     .globl _call_nice
  2630.     .globl _user_trace
  2631.     .globl _prt_ready
  2632.     .globl _prt_out
  2633.  
  2634. _get_la:
  2635.     moveml   d2/a2,sp@- 
  2636.     .byte    0xA0,0x00            | Adresse Line-A-Var nach A0 & D0
  2637.     moveml   sp@+,d2/a2
  2638.     rts
  2639.  
  2640. _int_off:
  2641.     oriw     #0x0700,sr
  2642.     rts
  2643.  
  2644. _int_on:
  2645.     andiw    #0xF8FF,sr
  2646.     rts
  2647.  
  2648. _call_super:
  2649.     movel    a7@(4),a0
  2650.     moveml   d2/a2-a3,sp@-
  2651.     movel    a0,sp@-
  2652.     movew    #0x20,sp@-
  2653.     movel    a7,a3     | save current stack pointer
  2654.     trap      #1
  2655.     movel    a3,a7     | make bad stack pointer good again !!!!!!!
  2656.     addql    #6,sp
  2657.     movel    d0,a0     | return value in both: d0 and a0
  2658.     moveml   sp@+,d2/a2-a3
  2659.     rts
  2660.  
  2661. _call_yield:
  2662.     moveml   d2/a2,sp@-
  2663.     movew    #0x00ff,sp@-   | MiNT Syield()  --  TOS illegal (rc -32)
  2664.     trap      #1
  2665.     addql    #2,sp
  2666.     moveml   sp@+,d2/a2
  2667.     rts
  2668.  
  2669. _call_nice:
  2670.     movel    a7@(4),d0
  2671.     moveml   d2/a2,sp@-
  2672.     movew    d0,sp@-
  2673.     movew    #0x10A,sp@-
  2674.     trap      #1
  2675.     addql    #4,sp
  2676.     moveml   sp@+,d2/a2
  2677.     rts
  2678.  
  2679. _user_trace:
  2680.     moveml   d1-d7/a0-a6,sp@-
  2681.     moveql   #0,d0
  2682.     movel    0x3F0,a1     | TEMPLMON user trace vector
  2683.     cmpal    #0,a1       | not installed ?
  2684.     beqs     end_trace
  2685.     jsr      a1@        | execute it !
  2686.     extl     d0
  2687.  
  2688. end_trace:
  2689.     moveml   sp@+,d1-d7/a0-a6
  2690.     rts
  2691.  
  2692. _prt_ready:
  2693.     moveml    d3/a3/a5,a7@-
  2694.     subl    a5,a5
  2695.     movew    d0,a7@-
  2696.     movel    0x506,a0
  2697.     jsr    a0@
  2698.     addql    #2,a7
  2699.     moveml    a7@+,d3/a3/a5
  2700.     rts
  2701.  
  2702. _prt_out:
  2703.     moveml    d3/a3/a5,a7@-
  2704.     subl    a5,a5
  2705.     movew    d1,a7@-
  2706.     movew    d0,a7@-
  2707.     movel    0x50A,a0
  2708.     jsr    a0@
  2709.     addql    #4,a7
  2710.     moveml    a7@+,d3/a3/a5
  2711.     rts
  2712.  
  2713.     ");
  2714.  
  2715.