home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / wps / graphic / fractint / sources / pmfract.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-25  |  32.8 KB  |  901 lines

  1. /*---------------------------------------------------
  2.    PMFRACT.C -- FRACTINT for PM
  3.           Main Module
  4.  
  5. Copyright (C) 1991 The Stone Soup Group.  FRACTINT for
  6. Presentation Manager may be freely copied and distributed,
  7. but may not be sold.
  8.  
  9.     We are, of course, copyrighting the code we wrote to implement
  10.     Fractint-for-PM, and not the routines we lifted directly
  11.     or indirectly from Microsoft's OS/2 Presentation Manager Toolkit.
  12.  
  13. GIF and "Graphics Interchange Format" are trademarks of Compuserve
  14. Incorporated, an H&R Block Company.
  15.  
  16.    05/25/91      Code by Donald P. Egen (with help)
  17.  ---------------------------------------------------*/
  18.  
  19. #define INCL_WIN
  20. #define INCL_GPI
  21. #define INCL_DOS
  22. #include <os2.h>
  23. #include <process.h>
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <malloc.h>
  28. #include <smplhelp.h>
  29.  
  30. #include "fractint.h"
  31. #include "fractype.h"
  32. /* generate global variables in this module only */
  33. #define EXTERN
  34. #include "pmfract.h"
  35.  
  36. /*
  37.    **** WARNING **** WARNING **** WARNING ****
  38.  
  39.    The following is used to disable stack overflow
  40.    checking in the runtime library routines called by
  41.    the subthread.
  42.  
  43. */
  44.  
  45. extern unsigned int _pascal STKHQQ;
  46.  
  47. /*--------------------------------------------------
  48.    Main routine.
  49.  
  50.    This is strictly Presentation Manager standard
  51.    except for initializing and terminating
  52.    SMPLHELP.
  53.  ---------------------------------------------------*/
  54. void main (int argc, char *argv[])
  55.      {
  56.      static ULONG flFrameFlags = FCF_TITLEBAR      | FCF_SYSMENU  |
  57.                                  FCF_SIZEBORDER    | FCF_MINMAX   |
  58.                                  FCF_SHELLPOSITION |
  59.                                  FCF_MENU          | FCF_ICON     |
  60.                                  FCF_ACCELTABLE ;
  61.      HMQ          hmq ;
  62.      HWND         hwndFrame, hwndClient ;
  63.      QMSG         qmsg ;
  64.  
  65. /*
  66.    **** WARNING **** WARNING **** WARNING ****
  67.  
  68.    The following is used to disable stack overflow
  69.    checking in the runtime library routines called by
  70.    the subthread.
  71.  
  72. */
  73.  
  74.      STKHQQ = 0;
  75.  
  76.      /* stash the original parameters for analysis later */
  77.      MainArgc = argc;
  78.      MainArgv = argv;
  79.  
  80.      hab = WinInitialize (0) ;
  81.      hmq = WinCreateMsgQueue (hab, 0) ;
  82.  
  83.      /*
  84.           Master initialization.
  85.      */
  86.  
  87.      PMfrGlobalInit();
  88.  
  89.      WinRegisterClass (hab, szClientClass, ClientWndProc, CS_SIZEREDRAW, 0) ;
  90.  
  91.      /* Note:
  92.         Subthread is attached during window create.
  93.      */
  94.  
  95.      hwndFrame = WinCreateStdWindow (HWND_DESKTOP, 0,
  96.                                      &flFrameFlags, szClientClass,
  97.                                      szTitleBar ,
  98.                                      0L, (HMODULE) 0,
  99.                                      ID_RESOURCE, &hwndClient) ;
  100.  
  101.      if (hwndFrame != (HWND) NULL)
  102.         {
  103.         /* now put the window up */
  104.         WinShowWindow(hwndFrame, TRUE);
  105.  
  106.         SimpleHelpInit (hab) ;
  107.  
  108.         SetSwitchEntry (hwndClient, szTitleBar, "");
  109.  
  110.         /* now go into the message loop */
  111.  
  112.         while (WinGetMsg (hab, &qmsg, (HWND) NULL, 0, 0))
  113.                WinDispatchMsg (hab, &qmsg) ;
  114.  
  115.         SimpleHelpExit();
  116.  
  117.         WinDestroyWindow (hwndFrame) ;
  118.         }
  119.      else
  120.         {
  121.         WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
  122.                       szInitFatal, szClientClass, ID_EMESSAGEBOX,
  123.                       MB_OK | MB_ICONHAND | MB_APPLMODAL);
  124.         }
  125.  
  126.      WinDestroyMsgQueue (hmq) ;
  127.      WinTerminate (hab) ;
  128.      DosExit(EXIT_PROCESS, 0) ;
  129.      }
  130.  
  131. /*--------------------------------------------------
  132.    Main Window Procedure.
  133.  
  134.    This is strictly Presentation Manager standard.
  135.    Each message will be detailed.
  136.  ---------------------------------------------------*/
  137. MRESULT EXPENTRY ClientWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  138.      {
  139.  
  140.      SHORT  cxNew, cyNew;
  141.      LONG errorcode;
  142.  
  143.      switch (msg)
  144.           {
  145.           case WM_CREATE:
  146.                /*
  147.                 *  Call subroutine to do initialization.
  148.                 */
  149.  
  150.                return ((MRESULT) (PMfrWindowInit(hwnd, mp2) ? 0 : 1));
  151.  
  152.  
  153.           case WM_INITMENU:
  154.                /*
  155.                 *  Call subroutine to do update menu enable/disable.
  156.                 */
  157.                if (UpdateMenuStatus ( hwnd, SHORT1FROMMP(mp1) ) )
  158.  
  159.                   return 0;
  160.  
  161.                break;
  162.  
  163.           case WM_TIMER:
  164.                /*
  165.                 *  A timer pop says the subthread is calculating
  166.                 *  and the screen should be refreshed by a WM_PAINT
  167.                 *  Request a WM_PAINT.
  168.                 */
  169.                if (sStatus == STATUS_WORKING)
  170.                   {
  171.  
  172.                   if ( 0 == DosSemRequest((HSEM) &cp.ulSemMemPS, 100L) )
  173.                      {   /* note: if failure at 100 ms,
  174.                            just wait for the next opportunity */
  175.                          /* refresh the memory bitmap from the pixel array */
  176.                       cp.pbmiMemory->cx = cp.cx;
  177.                       cp.pbmiMemory->cy = cp.cy;
  178.                       cp.pbmiMemory->cPlanes = cp.cPlanes;
  179.                       cp.pbmiMemory->cBitCount = cp.cBitCount;
  180.                       errorcode = GpiSetBitmapBits(cp.hpsMemory, 0L, (LONG) cp.cy,
  181.                                        cp.pixels, cp.pbmiMemory);
  182.                       DosSemClear((HSEM) &cp. ulSemMemPS);
  183.                       }
  184.                   else
  185.                       {
  186.                       /* maybe we can get the bitmap later */
  187.                       cp.fNewBits = TRUE;
  188.                       }
  189.  
  190.                   WinInvalidateRect (hwnd, NULL, FALSE);
  191.                   }
  192.                else /* renegade timer? */
  193.                   {
  194.                   WinStopTimer (hab, hwnd, ID_TIMER);
  195.                   cp.fNewBits = TRUE;   /* better safe than sorry */
  196.                   }
  197.                return 0 ;
  198.  
  199.           case WM_HELP:
  200.                /* just a press of F1 gets the basic operations help */
  201.                SimpleHelp(hab, hwnd, szTitleBar,
  202.                        (HMODULE) 0, IDT_TEXT, IDT_HELP_OPERATE);
  203.                return 0;
  204.  
  205.           case WM_SIZE:
  206.                /*
  207.                   if we are getting minimized, then the new window
  208.                   sizes will both be zeros.
  209.                   If so, ignore the message.
  210.                   If the "New" values are the same as the old values,
  211.                   also ignore the message.
  212.                */
  213.                cxNew = SHORT1FROMMP (mp2) ;
  214.                cyNew = SHORT2FROMMP (mp2) ;
  215.  
  216.                if ( (cxNew == 0) && (cyNew == 0) )
  217.                    /* being minimized */
  218.                    {
  219.  
  220.                    flAmIcon = TRUE;
  221.  
  222.                    /* if being minimized and the calc thread is running,
  223.                       turn off the timer interrupts.  No need in triggering
  224.                       repaints if we are an icon. */
  225.  
  226.                    if ((sStatus == STATUS_WORKING) &&
  227.                        (cp.sSubAction == SUB_ACT_CALC))
  228.                       WinStopTimer(hab, hwnd, ID_TIMER);
  229.  
  230.                    return 0;
  231.                    }
  232.  
  233.                if (flAmIcon)
  234.                   {
  235.                   /* if restoring, restart what was turned off,
  236.                      if still appropriate. */
  237.                   flAmIcon = FALSE;
  238.  
  239.                   if ((sStatus == STATUS_WORKING) &&
  240.                       (cp.sSubAction == SUB_ACT_CALC))
  241.                      {
  242.                      WinStartTimer(hab, hwnd, ID_TIMER, TIMER_REPAINT);
  243.                      cp.fNewBits = TRUE;    /* force immediate update */
  244.                      }
  245.                   }
  246.  
  247.                cxClient = cxNew ;
  248.                cyClient = cyNew ;
  249.  
  250.                return 0 ;
  251.  
  252.           case WM_COMMAND:
  253.                /* commands handled out of line */
  254.  
  255.                return  ( PMfrCommands(hwnd, msg, mp1, mp2) ) ;
  256.  
  257.           case WM_SETFOCUS:
  258.                /*
  259.                 * On losing focus, make sure we aren't in
  260.                 * Window or Pan mode.
  261.                 */
  262.                if ( ! ( (BOOL) SHORT1FROMMP (mp2) ) )  /* if loosing focus */
  263.                   {
  264.                   CancelZoomOrPan(hwnd);   /* cancel zoom or pan if going on */
  265.                   fActive = FALSE;
  266.                   return 0;
  267.                   }
  268.                else
  269.                  {
  270.                  fActive = TRUE;
  271.                  }
  272.  
  273.                break;
  274.  
  275.           case WM_CHAR:
  276.                 /*
  277.                  * Keyboard interface is incomplete
  278.                  */
  279.  
  280.                 if (CHARMSG(&msg)->fs & KC_KEYUP)
  281.                    break;
  282.  
  283.                 if (CHARMSG(&msg)->fs & KC_VIRTUALKEY)
  284.                     {
  285.                     if (CHARMSG(&msg)->fs & KC_CTRL)
  286.                         {
  287.                         switch(CHARMSG(&msg)->vkey)
  288.                         {
  289.                           /* case VK_HOME:
  290.                                  return WinSendMsg (hWnd, WM_VSCROLL,
  291.                                         MPFROMSHORT(1), MPFROM2SHORT(0, SB_SLIDERPOSITION));
  292.                              case VK_END:
  293.                                  return WinSendMsg (hWnd, WM_VSCROLL,
  294.                                         MPFROMSHORT(1), MPFROM2SHORT(iMaxVert, SB_SLIDERPOSITION));
  295.                              case VK_PAGEUP:
  296.                                  return WinSendMsg (hWnd, WM_HSCROLL,
  297.                                         MPFROMSHORT(1), MPFROM2SHORT(0, SB_PAGELEFT));
  298.                              case VK_PAGEDOWN:
  299.                                  return WinSendMsg (hWnd, WM_HSCROLL,
  300.                                         MPFROMSHORT(1), MPFROM2SHORT(0, SB_PAGERIGHT));
  301.                          */
  302.                          }
  303.                          break;
  304.                          }
  305.  
  306.                     switch (CHARMSG(&msg)->vkey)
  307.                          {
  308.                      /*   case VK_HOME:
  309.                              return WinSendMsg (hWnd, WM_HSCROLL,
  310.                                     MPFROMSHORT(1), MPFROM2SHORT(0, SB_SLIDERPOSITION));
  311.                         case VK_END:
  312.                                  return WinSendMsg (hWnd, WM_HSCROLL,
  313.                                         MPFROMSHORT(1), MPFROM2SHORT(iMaxHorz, SB_SLIDERPOSITION));
  314.                         case VK_LEFT:
  315.                         case VK_RIGHT:
  316.                              return WinSendMsg (hWndHorzSB, msg, mp1, mp2) ;
  317.                         case VK_UP:
  318.                         case VK_DOWN:
  319.                         case VK_PAGEUP:
  320.                         case VK_PAGEDOWN:
  321.                              return WinSendMsg (hWndVertSB, msg, mp1, mp2) ;
  322.                      */
  323.                         case VK_ESC:
  324.                             CancelZoomOrPan(hwnd);
  325.                             return 0;
  326.                         }
  327.                     }
  328.                 break ;
  329.  
  330.           case WM_MOUSEMOVE:
  331.                /*
  332.                 * Mouse movements count if panning or window zooming.
  333.                 */
  334.                if (fActive)
  335.                   {
  336.                   POINTL ptlHere;
  337.  
  338.                   ptlHere.x = SHORT1FROMMP(mp1);
  339.                   ptlHere.y = SHORT2FROMMP(mp1);
  340.  
  341.                   if (fPan)   /* Panning */
  342.                      {
  343.                      if ((cxMouseTol >= labs(ptlHere.x-ptlCrossHairs.x) ) &&
  344.                          (cyMouseTol >= labs(ptlHere.y-ptlCrossHairs.y) ) )
  345.                         {
  346.  
  347.                         /* ignore if within tolerance */
  348.                         return 0;
  349.  
  350.                         }
  351.                      else
  352.                         {   /* moved too far, switch to zooming */
  353.                             /* lock down first point */
  354.                         InitZoomBox((SHORT) ptlCrossHairs.x, (SHORT) ptlCrossHairs.y);
  355.                         fGoodPan = FALSE;
  356.                         fPan = FALSE;
  357.                         fZoomWin = TRUE;
  358.                         EraseCrossHairs(hwnd);
  359.                         MoveZoomBox(hwnd, mp1);
  360.                         return 0;
  361.                         }
  362.                      }
  363.  
  364.                   if (fZoomWin)   /* Maybe Zooming? */
  365.                      {
  366.                      MoveZoomBox (hwnd, mp1);
  367.                      return 0;
  368.                      }
  369.                   }
  370.  
  371.                 break;
  372.  
  373.           case WM_BUTTON1DOWN:
  374.                /*
  375.                 * Button 1 is Pan and Zoom Window.
  376.                 */
  377.  
  378.                /* 1st click on inactive window is ignored */
  379.                if (!fActive)
  380.                   break;
  381.  
  382.                /* prepare for mouseing */
  383.                if (fGoodZoom)
  384.                   EraseZoomBox(hwnd);
  385.                WinSetCapture (HWND_DESKTOP, hwnd);
  386.                WinShowPointer (HWND_DESKTOP, FALSE);
  387.                InitCrossHairs();
  388.                MoveCrossHairs(hwnd, mp1);
  389.                /* assume panning until we can tell otherwise */
  390.                fPan = TRUE;
  391.                fZoomWin = FALSE;
  392.                fGoodZoom = FALSE;
  393.                return 0;
  394.  
  395.                break;
  396.  
  397.           case WM_BUTTON1UP:
  398.                /* This is the "While Mouseing" end signal */
  399.  
  400.                if (fPan)
  401.                {  /* panning, keep the point */
  402.                   EraseCrossHairs(hwnd);
  403.                   fGoodPan = TRUE;
  404.                   fGoodZoom = FALSE;
  405.                   fPan = FALSE;
  406.                   fZoomWin = FALSE;
  407.                   /* release the mouse */
  408.                   WinSetCapture (HWND_DESKTOP, (HWND) NULL);
  409.                   WinShowPointer (HWND_DESKTOP, TRUE);
  410.                   return 0;
  411.                }
  412.  
  413.                if (fZoomWin)
  414.                {  /* zooming, keep the zoom box */
  415.                   fGoodZoom = TRUE;
  416.                   fGoodPan = FALSE;
  417.                   fZoomWin = FALSE;
  418.                   fPan = FALSE;
  419.                   /* release the mouse */
  420.                   WinSetCapture (HWND_DESKTOP, (HWND) NULL);
  421.                   WinShowPointer (HWND_DESKTOP, TRUE);
  422.                   return 0;
  423.                }
  424.  
  425.                break;
  426.  
  427.           case WM_THRD_POST:
  428.                /* analyze an event from the background task */
  429.                {
  430.                SHORT subrc = SHORT1FROMMP (mp1);
  431.  
  432.                switch (subrc)
  433.                   {
  434.                   case SUB_STAT_START_TIMER:
  435.                        /* this is normal Calculation start-up */
  436.                        /* clear the screen */
  437.                        cp.fNewBits = TRUE;
  438.                        cp.fSuppressPaint = FALSE;
  439.                        WinInvalidateRect (hwnd, NULL, FALSE);
  440.                        /* and start the refresh timer */
  441.                        WinStartTimer (hab, hwnd, ID_TIMER, TIMER_REPAINT);
  442.                        return 0;
  443.  
  444.                   case SUB_STAT_OK:
  445.                        /* this is normal termination */
  446.                        {
  447.                        if (sStatus == STATUS_NEWPARMS)
  448.                           {
  449.                           /* We may have aborted because of new parms, but */
  450.                           /* due to a race condition we ended at DONE. */
  451.                           /* in any case,                              */
  452.                           /* fake the GO! button to restart */
  453.                           sStatus = STATUS_READY;
  454.                           WinPostMsg (hwnd, WM_COMMAND,
  455.                                  MPFROMSHORT ( IDM_GO ),
  456.                                  MPFROM2SHORT ( CMDSRC_OTHER , 0) ) ;
  457.                           }
  458.                        else
  459.                           {
  460.                           /* schedule final clean-up at WM_PAINT time */
  461.                           sStatus = STATUS_DONE ;
  462.                           cp.fSuppressPaint = FALSE;
  463.                           WinInvalidateRect (hwnd, NULL, FALSE) ;
  464.                           UpdateMenuText (hwnd, IDM_FREEZE_HALT, szFreeze);
  465.                           EnableMenuItem (hwnd, IDM_GO, FALSE) ;
  466.                           EnableMenuItem (hwnd, IDM_FREEZE_HALT, FALSE) ;
  467.                           if (! flAmIcon)
  468.                              WinStopTimer (hab, hwnd, ID_TIMER);
  469.                           }
  470.  
  471.                        /* if this was a LOAD, update the title bar */
  472.                        if (cp.sSubAction == SUB_ACT_LOAD)
  473.                               SetSwitchEntry (hwnd, szTitleBar,
  474.                                        GetFractalName(cp.iFractType) );
  475.  
  476.                        return 0 ;
  477.                        }
  478.                        break;
  479.  
  480.                   case SUB_INIT_DONE:
  481.                        {
  482.                        /* move us to working state */
  483.                        sStatus = STATUS_WORKING;
  484.                        EnableMenuItem(hwnd, IDM_GO, FALSE);
  485.                        UpdateMenuText(hwnd, IDM_FREEZE_HALT, szHalt);
  486.                        EnableMenuItem(hwnd, IDM_FREEZE_HALT, TRUE);
  487.  
  488.                        SetSwitchEntry (hwnd, szTitleBar,
  489.                                        GetFractalName(cp.iFractType) );
  490.  
  491.                        cp.fSuppressPaint = FALSE;
  492.  
  493.                        return 0;
  494.                        }
  495.                        break;
  496.  
  497.                   case SUB_STAT_ABORT:
  498.                        {
  499.                        /* aborted by command from the user interface */
  500.                        if (sStatus == STATUS_NEWPARMS)
  501.                           {
  502.                           /* if we aborted because of new parms, */
  503.                           /* fake the GO! button to restart */
  504.                           sStatus = STATUS_READY;
  505.                           WinPostMsg (hwnd, WM_COMMAND,
  506.                                  MPFROMSHORT ( IDM_GO ),
  507.                                  MPFROM2SHORT ( CMDSRC_OTHER , 0) ) ;
  508.                           }
  509.                        else
  510.                           {
  511.                           sStatus = STATUS_DONE ;
  512.                           cp.fSuppressPaint = FALSE;
  513.                           WinInvalidateRect (hwnd, NULL, FALSE) ;
  514.                           UpdateMenuText (hwnd, IDM_FREEZE_HALT, szFreeze);
  515.                           EnableMenuItem (hwnd, IDM_GO, FALSE) ;
  516.                           EnableMenuItem (hwnd, IDM_FREEZE_HALT, FALSE);
  517.                           if (! flAmIcon)
  518.                               WinStopTimer (hab, hwnd, ID_TIMER);
  519.                           }
  520.  
  521.                        /* if this was a LOAD, update the title bar */
  522.                        if (cp.sSubAction == SUB_ACT_LOAD)
  523.                               SetSwitchEntry (hwnd, szTitleBar,
  524.                                        GetFractalName(cp.iFractType) );
  525.  
  526.                        return 0 ;
  527.                        }
  528.                        break;
  529.  
  530.                   case SUB_STAT_FATAL:
  531.                        {
  532.                        /*  the subtask has given up, probably insufficient
  533.                            memory.  we say so then go bye-bye.    */
  534.                        WinMessageBox (HWND_DESKTOP, hwnd,
  535.                             (PSZ) szSubtaskFatal, (PSZ) szClientClass,
  536.                             ID_EMESSAGEBOX,
  537.                             MB_OK | MB_ICONHAND | MB_APPLMODAL);
  538.                        /* schedule final clean-up at WM_DESTROY time */
  539.                        sStatus = STATUS_DONE ;
  540.                        cp.fSuppressPaint = TRUE;
  541.                        UpdateMenuText (hwnd, IDM_FREEZE_HALT, szFreeze);
  542.                        EnableMenuItem (hwnd, IDM_GO, FALSE) ;
  543.                        EnableMenuItem (hwnd, IDM_FREEZE_HALT, FALSE) ;
  544.                        WinPostMsg(hwnd, WM_QUIT, MPFROMP(NULL), MPFROMP(NULL) );
  545.                        return 0;
  546.                        }
  547.                        break;
  548.  
  549.                   default:
  550.                        {
  551.                        char szErrorMessage[50];
  552.                        char tszMissingSub[35];
  553.  
  554.                        _fstrcpy(tszMissingSub, szMissingSub);
  555.                        /*  in this case the return code is a code identifying
  556.                            a loose end in the calculation process */
  557.                        if (! flAmIcon)
  558.                           WinStopTimer (hab, hwnd, ID_TIMER);
  559.                        sprintf(szErrorMessage, tszMissingSub, subrc);
  560.                        WinMessageBox (HWND_DESKTOP, hwnd,
  561.                             (PSZ) szErrorMessage, (PSZ) szClientClass,
  562.                             ID_EMESSAGEBOX,
  563.                             MB_OK | MB_ICONASTERISK | MB_APPLMODAL);
  564.                        /* schedule final clean-up at WM_PAINT time */
  565.                        sStatus = STATUS_DONE ;
  566.                        cp.fSuppressPaint = TRUE;
  567.                        WinInvalidateRect (hwnd, NULL, FALSE) ;
  568.                        UpdateMenuText (hwnd, IDM_FREEZE_HALT, szFreeze);
  569.                        EnableMenuItem (hwnd, IDM_GO, FALSE) ;
  570.                        EnableMenuItem (hwnd, IDM_FREEZE_HALT, FALSE) ;
  571.                        return 0;
  572.                        }
  573.                        break;
  574.                   }
  575.                }
  576.                break;
  577.  
  578.           case WM_SYNC_MSG:
  579.                /* the subthread needs to issue a message and wait for
  580.                   a response.  */
  581.                {
  582.                PSZ szSyncMsg = (PSZ) PVOIDFROMMP(mp1);
  583.                int flags = (int) SHORT1FROMMP(mp2);
  584.                int result;
  585.  
  586.                if (! (flags & 4)) WinAlarm(HWND_DESKTOP, WA_WARNING);
  587.  
  588.                result = MBID_OK;
  589.  
  590.                if (!(flags & 2))
  591.                   result = WinMessageBox (
  592.                            HWND_DESKTOP, hwnd,
  593.                            szSyncMsg,
  594.                            szTitleBar, ID_SYNCMSGBOX,
  595.                            MB_ICONASTERISK | MB_OK | MB_APPLMODAL);
  596.                else
  597.                   result = WinMessageBox (
  598.                            HWND_DESKTOP, hwnd,
  599.                            szSyncMsg,
  600.                            szTitleBar, ID_SYNCMSGBOX,
  601.                            MB_ICONQUESTION | MB_OKCANCEL | MB_APPLMODAL);
  602.  
  603.                if (result == 0 || result == MBID_OK || result == MBID_YES)
  604.                       cp.SyncMsgAnswer = 0;
  605.                else
  606.                       cp.SyncMsgAnswer = -1;
  607.  
  608.                /* post out the subtask */
  609.                DosSemClear((HSEM) &cp.ulSemSyncMsgDone);
  610.  
  611.                /* we done */
  612.                return 0;
  613.  
  614.                }
  615.                break;
  616.  
  617.           case WM_PAINT:
  618.                /* what we do is determined by our status */
  619.                switch (sStatus)
  620.                   {
  621.                   case STATUS_DONE:
  622.                      {  /* on a good run, wait till last minute to fix menu */
  623.                      EnableMenuItem (hwnd, IDM_GO, TRUE) ;
  624.                      EnableMenuItem (hwnd, IDM_FREEZE_HALT, TRUE) ;
  625.                      sStatus = STATUS_READY;
  626.                      cp.fNewBits = TRUE;
  627.                      break;
  628.                      }
  629.                   }
  630.  
  631.                PMfrRepaint (hwnd);
  632.  
  633.                return 0 ;
  634.  
  635.           case WM_DESTROY:
  636.                /*
  637.                 * Do clean up.
  638.                 * Ask the subtask to gracefully shutdown.
  639.                 */
  640.                cp.fContinueCalc = FALSE;
  641.                cp.sSubAction = SUB_ACT_TERM;
  642.                DosSemClear ((HSEM) &cp.ulSemTrigger);
  643.                DosSemWait ((HSEM) &cp.ulSemSubEnded, SEM_INDEFINITE_WAIT);
  644.  
  645.                /* recover subthread resources if it did not */
  646.                if (cp.hpsMemory != (HPS) 0)
  647.                   {  /* protection from a failed WM_CREATE or IDM_GO */
  648.                   GpiSetBitmap(cp.hpsMemory, (HBITMAP) NULL);
  649.                   GpiDestroyPS(cp.hpsMemory);
  650.                   GpiDeleteBitmap (cp.hbmMemory);
  651.                   }
  652.                if ( cp.pixels != NULL)
  653.                     hfree(cp.pixels);
  654.  
  655.                if (cp.hdcMemory != (HDC) 0)
  656.                   DevCloseDC (cp.hdcMemory);
  657.  
  658.                GpiDestroyPS(cp.hpsScreen);
  659.  
  660.                return 0 ;
  661.           }
  662.      return WinDefWindowProc (hwnd, msg, mp1, mp2) ;
  663.      }
  664.  
  665. VOID PMfrRepaint (HWND hwnd)
  666.      {
  667.      HPS    hps;
  668.      POINTL aptl[4];
  669.      RECTL  rctl;
  670.      LONG   errorcode;
  671.  
  672.      static BOOL fLastSuppressPaint = FALSE;
  673.  
  674.      /* zap from memory bitmap to screen */
  675.      aptl[0].x = 0;     aptl[0].y = 0;
  676.      /* aptl[1].x = cp.cx; aptl[1].y = cp.cy;  */
  677.      aptl[1].x = cxClient; aptl[1].y = cyClient;
  678.      aptl[2].x = 0;     aptl[2].y = 0;
  679.      aptl[3].x = cp.cx; aptl[3].y = cp.cy;
  680.  
  681.      /* If the cp.fSuppressPaint toggle has changed, we
  682.         must change the appearance of the entire window.
  683.         Therefore, invalidate the entire window on a change.
  684.      */
  685.      if (fLastSuppressPaint != cp.fSuppressPaint)
  686.         {
  687.         fLastSuppressPaint = cp.fSuppressPaint;
  688.         WinInvalidateRect(hwnd, NULL, FALSE);
  689.         }
  690.  
  691.      hps = WinBeginPaint(hwnd, cp.hpsScreen, &rctl) ;
  692.  
  693.      if (! cp.fSuppressPaint)
  694.         {
  695.         /* if cross hairs or zoom window are displayed, flash
  696.            them off temporarily while blitting */
  697.         if (fPan)
  698.            DrawCrossHairsInner (hwnd);
  699.         if (fZoomWin || fGoodZoom)
  700.            DrawZoomBoxInner (hwnd);
  701.  
  702.         /* serialize with the subthread */
  703.         if ( 0 == DosSemRequest((HSEM) &cp.ulSemMemPS, 100L) )
  704.            {   /* note: if failure at 100 ms, just wait for the next PAINT */
  705.  
  706.            /* refresh the memory bitmap from the pixel array if needed */
  707.            if (cp.fNewBits)
  708.               {
  709.               cp.pbmiMemory->cx = cp.cx;
  710.               cp.pbmiMemory->cy = cp.cy;
  711.               cp.pbmiMemory->cPlanes = cp.cPlanes;
  712.               cp.pbmiMemory->cBitCount = cp.cBitCount;
  713.               errorcode = GpiSetBitmapBits(cp.hpsMemory, 0L, (LONG) cp.cy,
  714.                                     cp.pixels, cp.pbmiMemory);
  715.               cp.fNewBits = FALSE;
  716.               }
  717.  
  718.            GpiErase (hps);           /* black out screen first */
  719.            /* refresh screen */
  720.            GpiBitBlt (hps, cp.hpsMemory, 4L, aptl, ROP_SRCCOPY, BBO_IGNORE);
  721.            errorcode = WinGetLastError(hab);
  722.  
  723.            DosSemClear((HSEM) &cp.ulSemMemPS);
  724.  
  725.            }
  726.  
  727.         if (fPan)
  728.            DrawCrossHairsInner (hwnd);
  729.         if (fZoomWin || fGoodZoom)
  730.            DrawZoomBoxInner (hwnd);
  731.         }
  732.      else
  733.         {
  734.         WinQueryWindowRect(hwnd, &rctl);
  735.         WinFillRect(hps, &rctl,
  736.               GpiQueryColorIndex(hps, LCOLOPT_REALIZED, 0x00000000L)) ;
  737.         WinDrawText(hps, 0xFFFF, szWorking, &rctl,
  738.               GpiQueryColorIndex(hps, LCOLOPT_REALIZED, 0x00FFFFFFL) ,
  739.               GpiQueryColorIndex(hps, LCOLOPT_REALIZED, 0x00000000L) ,
  740.               DT_CENTER | DT_VCENTER);
  741.         }
  742.  
  743.      WinEndPaint(hps);
  744.  
  745.      }
  746.  
  747. /*---------------------------------------------
  748.    Subroutines to manage the Calcparm and Newparms structures.
  749.  ---------------------------------------------*/
  750. VOID InitNewParms(PNEWPARAM npTempParms)
  751.      {
  752.      /* if we are frozen, we already copied once at entry to Frozen state. */
  753.      /* since we want to play repeatedly with that copy, we will not */
  754.      /* copy again. */
  755.      /* if we are in pending state (STATUS_NEWPARMS), we don't want */
  756.      /* to copy parms either, because we will overlay what is scheduled. */
  757.      /* However, let the user see what is scheduled anyhow, for now. */
  758.  
  759.      if (! ((sStatus == STATUS_FROZEN) || (sStatus == STATUS_NEWPARMS)) )
  760.         CopyParmsToNew();
  761.  
  762.      /* if we had a temp parms structure passed to us, update it */
  763.      /* from the npNewParms structure */
  764.  
  765.      if (npTempParms != NULL)
  766.         *npTempParms = npNewParms;
  767.  
  768.      }
  769.  
  770. VOID    ScheduleNewParms(HWND hwnd)
  771.      {
  772.      /* if we are frozen, we don't want to come out until an explicit GO! */
  773.      /* we don't have anything to do at this time */
  774.      if (sStatus == STATUS_FROZEN)
  775.          return;
  776.  
  777.      /* if we are currently running, we enter a Change Pending state, */
  778.      /* and signal the subthread to find a stopping place. */
  779.      /* we will actually restart with the new parms after the subthread */
  780.      /* has signalled it is ready to restart (at SUB_STAT_ABORT processing). */
  781.      /* this is also true if we are already in Change Pending state. */
  782.  
  783.      if ( (sStatus == STATUS_WORKING) || (sStatus == STATUS_NEWPARMS) )
  784.         {
  785.         cp.fContinueCalc = FALSE;
  786.         EnableMenuItem (hwnd, IDM_FREEZE_HALT, FALSE);
  787.         sStatus = STATUS_NEWPARMS;
  788.         return;
  789.         }
  790.  
  791.      /* otherwize, we want to start up with these new parms. */
  792.      /* simulate hitting the GO! menu button */
  793.      WinPostMsg (hwnd, WM_COMMAND,
  794.                  MPFROMSHORT ( IDM_GO ),
  795.                  MPFROM2SHORT ( CMDSRC_OTHER , 0) ) ;
  796.  
  797.      }
  798.  
  799. VOID CopyParmsToNew(VOID)
  800.      {
  801.      /* refresh the npNewParms from the cp base fields */
  802.      npNewParms.fNewParms = FALSE;
  803.      npNewParms.iFractType = cp.iFractType;
  804.      npNewParms.cFloatflag = cp.cFloatflag;
  805.      npNewParms.cx = cp.cx;
  806.      npNewParms.cy = cp.cy;
  807.      npNewParms.XL = cp.XL; npNewParms.XR = cp.XR;
  808.      npNewParms.YT = cp.YT; npNewParms.YB = cp.YB;
  809.      npNewParms.param[0] = cp.param[0];
  810.      npNewParms.param[1] = cp.param[1];
  811.      npNewParms.param[2] = cp.param[2];
  812.      npNewParms.param[3] = cp.param[3];
  813.      npNewParms.trigndx[0] = cp.trigndx[0];
  814.      npNewParms.trigndx[1] = cp.trigndx[1];
  815.      npNewParms.trigndx[2] = cp.trigndx[2];
  816.      npNewParms.trigndx[3] = cp.trigndx[3];
  817.      _fstrcpy(npNewParms.szFileName, cp.szFileName);
  818.      _fstrcpy(npNewParms.szIfsFileName, cp.szIfsFileName);
  819.      _fstrcpy(npNewParms.szIfs3dFileName, cp.szIfs3dFileName);
  820.      _fstrcpy(npNewParms.szFormFileName, cp.szFormFileName);
  821.      _fstrcpy(npNewParms.szFormName, cp.szFormName);
  822.      _fstrcpy(npNewParms.szLSysFileName, cp.szLSysFileName);
  823.      _fstrcpy(npNewParms.szLSysName, cp.szLSysName);
  824.      _fstrcpy(npNewParms.szPrintName, cp.szPrintName);
  825.      npNewParms.colors = cp.colors;
  826.      npNewParms.maxiter = cp.maxiter;
  827.      npNewParms.stdCalcMode = cp.stdCalcMode;
  828.      npNewParms.distest = cp.distest;
  829.      npNewParms.periodicitycheck = cp.periodicitycheck;
  830.      npNewParms.biomorph = cp.biomorph;
  831.      npNewParms.decomp[0] = cp.decomp[0]; npNewParms.decomp[1] = cp.decomp[1];
  832.      npNewParms.inside = cp.inside;
  833.      npNewParms.outside = cp.outside;
  834.  
  835.      /* always recalculate a valid center point */
  836.      npNewParms.XCenter = (npNewParms.XL + npNewParms.XR)/2.0;
  837.      npNewParms.YCenter = (npNewParms.YT + npNewParms.YB)/2.0;
  838.  
  839.      /* obtain the max extents from the engine table for
  840.         reference of the selection dialogs.      */
  841.      npNewParms.mxXL = fractalspecific[npNewParms.iFractType].xmin;
  842.      npNewParms.mxXR = fractalspecific[npNewParms.iFractType].xmax;
  843.      npNewParms.mxYT = fractalspecific[npNewParms.iFractType].ymax;
  844.      npNewParms.mxYB = fractalspecific[npNewParms.iFractType].ymin;
  845.      }
  846.  
  847. VOID CopyParmsToBase(VOID)
  848.      {
  849.      /* copy npNewParms to the cp base fields */
  850.      cp.fNewParms  = npNewParms.fNewParms;
  851.      cp.iFractType = npNewParms.iFractType;
  852.      cp.cFloatflag = npNewParms.cFloatflag;
  853.      cp.cx         = npNewParms.cx;
  854.      cp.cy         = npNewParms.cy;
  855.      cp.XL = npNewParms.XL; cp.XR = npNewParms.XR;
  856.      cp.YT = npNewParms.YT; cp.YB = npNewParms.YB;
  857.      cp.param[0] = npNewParms.param[0];
  858.      cp.param[1] = npNewParms.param[1];
  859.      cp.param[2] = npNewParms.param[2];
  860.      cp.param[3] = npNewParms.param[3];
  861.      cp.trigndx[0] = npNewParms.trigndx[0];
  862.      cp.trigndx[1] = npNewParms.trigndx[1];
  863.      cp.trigndx[2] = npNewParms.trigndx[2];
  864.      cp.trigndx[3] = npNewParms.trigndx[3];
  865.      _fstrcpy(cp.szFileName, npNewParms.szFileName);
  866.      _fstrcpy(cp.szIfsFileName, npNewParms.szIfsFileName);
  867.      _fstrcpy(cp.szIfs3dFileName, npNewParms.szIfs3dFileName);
  868.      _fstrcpy(cp.szFormFileName, npNewParms.szFormFileName);
  869.      _fstrcpy(cp.szFormName, npNewParms.szFormName);
  870.      _fstrcpy(cp.szLSysFileName, npNewParms.szLSysFileName);
  871.      _fstrcpy(cp.szLSysName, npNewParms.szLSysName);
  872.      _fstrcpy(cp.szPrintName, npNewParms.szPrintName);
  873.      cp.colors = npNewParms.colors;
  874.      cp.maxiter = npNewParms.maxiter;
  875.      cp.stdCalcMode = npNewParms.stdCalcMode;
  876.      cp.distest = npNewParms.distest;
  877.      cp.periodicitycheck = npNewParms.periodicitycheck;
  878.      cp.biomorph = npNewParms.biomorph;
  879.      cp.decomp[0] = npNewParms.decomp[0]; cp.decomp[1] = npNewParms.decomp[1];
  880.      cp.inside = npNewParms.inside;
  881.      cp.outside = npNewParms.outside;
  882.      }
  883.  
  884. /*---------------------------------------------
  885.    General use subroutines.
  886.  ---------------------------------------------*/
  887.  
  888. /* Given a fractalspecific index, return (pointer to the)
  889.        appropriate fractal name.
  890. */
  891.  
  892. PSZ GetFractalName(int iFractType)
  893.     {
  894.  
  895.     return ((PSZ)
  896.              (('*' == *fractalspecific[iFractType].name)
  897.                ? fractalspecific[iFractType].name + 1
  898.                : fractalspecific[iFractType].name )
  899.             );
  900.     }
  901.