home *** CD-ROM | disk | FTP | other *** search
/ The Developer Connection…ice Driver Kit for OS/2 3 / DEV3-D1.ISO / source / bitmapsr / bitmap32.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-08  |  78.8 KB  |  2,092 lines

  1. /*****************************************************************************/
  2. /*                             VERSION 04/17/90                              */
  3. /*                                                                           */
  4. /*  The base code for reading in the bitmap (i.e. the LoadBitmapFile()       */
  5. /*  routine) is a combination of my code and Rick Chapman's, John Clegg's,   */
  6. /*  Ralph Yozzo's, and Richard Redpath's.  The rest of the code is my own.   */
  7. /*                                                                           */
  8. /*  I have tried to keep this stuff fairly bug-free, but this program was    */
  9. /*  written in my spare time, mainly to demonstrate some things that can be  */
  10. /*  done, so therefore certain error checking and other "product level"      */
  11. /*  coding styles may not be fully adhered to.                               */
  12. /*                                                                           */
  13. /*                       -  Keith Bernstein                                  */
  14. /*                                                                           */
  15. /*                                                                           */
  16. /*****************************************************************************/
  17. #define INCL_PM
  18. #define INCL_GPIBITMAPS
  19. #define INCL_DOSFILEMGR
  20. #define INCL_DOSINFOSEG
  21. #define INCL_DOSMEMMGR
  22. #define INCL_DOSMISC
  23. #define INCL_DOSPROCESS
  24. #define INCL_DOSSEMAPHORES
  25.  
  26. #include <os2.h>                        /* PM header file               */
  27. #include <stdlib.h>                     /* "max()" definition.          */
  28. #include <stdio.h>                      /* "fopen()" definition.        */
  29. #include <string.h>                     /* C/2 string functions         */
  30. #include <process.h>                    /* _beginthread prototype.      */
  31. #include <ctype.h>                      /* toupper prototype            */
  32. #include <fcntl.h>
  33. #include <io.h>
  34. #include <sys\stat.h>
  35. #include "standard.h"                   /* Standard definitions for GBM     */
  36. #include "gbm.h"                        /* For GBM interfaces               */
  37. #include "bitmap.h"                     /* Contants, typedefs, & prototypes */
  38. #include "bitmaprc.h"                   /* Resource symbolic identifiers    */
  39.  
  40. #define FRAME_LIST (FCF_TITLEBAR | FCF_SYSMENU | FCF_MINMAX | FCF_MENU)
  41.  
  42. CHAR szString [STRINGLENGTH];
  43. CHAR *szTitleBar = "Bitmap File Displayer";
  44. CHAR *pOptions="errok";
  45. UCHAR PathBuf[160];
  46. UCHAR SlideBuf[160];
  47. UCHAR ErrorBuf[MAXPATH + 100];
  48. BOOL bScaleWhileDrawing = FALSE;
  49. BOOL bStopSlide;
  50. BOOL bPaletteManager = TRUE;
  51. BOOL bPaletteSupport;
  52. BOOL bIgnoreErrors = FALSE;
  53. BOOL bNewPalette = FALSE;
  54. BOOL bBW;
  55. BOOL bKeepProportion = TRUE;
  56. BOOL bFrameEmpty = FALSE;
  57. ULONG backcolor;
  58. ULONG forecolor;
  59. HWND hClient;
  60. HWND hFrame;
  61. HWND hClient;
  62. HWND hwndTitleBar;
  63. HWND hwndSysMenu;
  64. HWND hwndMinMax;
  65. HWND hwndAppMenu;
  66. QMSG qmsg;
  67. HDC hdcMem;
  68. HDC hdcScreen;
  69. HPS hpsWindow;
  70. HPS hpsMem;                                  \
  71. HPAL hsyspal = 0;
  72. USHORT GlobalBitCount;
  73. ULONG  Globalx;
  74. ULONG  Globaly;
  75. HBITMAP hbmMem;
  76. UCHAR *pFname;
  77. BOOL bNewImage;
  78. HMTX hUpdateSem;
  79. HEV  hStopWaitSem;
  80. HEV  hPauseSem;
  81. ULONG posts;
  82. BOOL Paused = FALSE;
  83. PFNWP pFrameWndProc;
  84. USHORT Direction;
  85. HPS    hpsCurrent;          /* Used for "in-memory" transformations*/
  86. HDC    hdcCurrent;          /* Used for "in-memory" transformations*/
  87. HBITMAP hbmCurrent;         /* Used for "in-memory" transformations*/
  88. PSZ dcdatablk[9] = {0,
  89.                     "MEMORY", /* display driver      */
  90.                     0,
  91.                     0,
  92.                     0,
  93.                     0,
  94.                     0,
  95.                     0,
  96.                     0
  97.                    };
  98.  
  99.  
  100. /*****************************************************************************/
  101. /*  Abstract for function: SlideThread()                                       */
  102. /*    This function will keep on reading in the .BMP files listed in the     */
  103. /*    .SLD file until bStopSlide is TRUE.                                      */
  104. /*****************************************************************************/
  105. void SlideThread(PVOID pFile)
  106. {
  107.    HAB hAB = WinInitialize(0);
  108.    HMQ hmq = WinCreateMsgQueue(hAB, 0);    /* Create a message queue       */
  109.    UCHAR *pTime;
  110.    UCHAR *pErrorString;
  111.    LONG TimeOutAmount;
  112.    LONG DefaultDelay = SEM_INDEFINITE_WAIT;
  113.    FILE *hSlideFile;
  114.    PLINKNODE pHeadNode;
  115.    PLINKNODE pCurrNode;
  116.    HWND hMenu;
  117.    HWND hUpdateWnd;
  118.    ULONG CurrChecked;
  119.    ULONG TempShort;
  120.    SHORT ErrorCode = 0;
  121.    PSZ   pFileName = &SlideBuf[0];
  122.  
  123.    if (!(hSlideFile = fopen(SlideBuf, "r"))) {
  124.       ErrorCode = LBF_COULDNT_OPEN_FILE_RC;
  125.       strcpy((PSZ)ErrorBuf, "Error loading file:  <");
  126.       strcat((PSZ)ErrorBuf, pFileName);
  127.       strcat((PSZ)ErrorBuf, ">");
  128.       pErrorString = ErrorBuf;
  129.    } else if (pHeadNode = PutFileInLList(hSlideFile)) {
  130.       pCurrNode = pHeadNode;
  131.       fclose(hSlideFile);
  132.       Direction = FORWARD;
  133.       /* Enable menu items which may now be used, and disable ones which */
  134.       /* are now invalid... */
  135.       hMenu = FixupMenus(hFrame, TRUE);
  136.       /* Check the "Forward" choice... */
  137.       WinSendMsg(hMenu, MM_SETITEMATTR, MPFROM2SHORT(ID_FORWARD, TRUE),
  138.                  MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED));
  139.       CurrChecked = ID_FORWARD;
  140.       while (!bStopSlide) {
  141.          strcpy(PathBuf, pCurrNode->pString);
  142.          /* See if they want to terminate or change defaults... */
  143.          if (PathBuf[0] == '/') {
  144.             if (!PathBuf[1]) {
  145.                /* Then terminate... */
  146.                bStopSlide = TRUE;
  147.            } else {
  148.               if ( (PathBuf[1] == 'I') || (PathBuf[1] == 'i') ) {
  149.                  DefaultDelay = SEM_INDEFINITE_WAIT;
  150.               } else {
  151.                  DefaultDelay = atol(&PathBuf[1]) * 1000;
  152.               }
  153.            }
  154.          } else {
  155.             /* Now see if they've specified a display time parameter... */
  156.             pTime = strrchr(PathBuf, '/');
  157.             if (pTime) {
  158.                if ( (pTime[1] == 'I') || (pTime[1] == 'i') ) {
  159.                   TimeOutAmount = SEM_INDEFINITE_WAIT;
  160.                } else {
  161.                   TimeOutAmount = atol(pTime + 1) * 1000;
  162.                }
  163.                /* Now remove this from filename string... */
  164.                *pTime = '\0';
  165.             } else {
  166.                TimeOutAmount = DefaultDelay;
  167.             }
  168.             /* Remove white space or open may fail! */
  169.             RemoveWhiteSpace(PathBuf);
  170.  
  171.             /* Wait 'till we're done drawing the old one before loading a */
  172.             /* new one!! */
  173.             DosRequestMutexSem(hUpdateSem, SEM_INDEFINITE_WAIT);
  174.             TempShort = LoadBitmapFile(PathBuf, (PHAB)&hAB,
  175.                                        (PHDC)&hdcMem, (PHPS)&hpsMem,
  176.                                        (PHBITMAP)&hbmMem, FALSE);
  177.             if (!TempShort) {
  178.                /* Let main thread do this so we for WinXXX and "C" calls! */
  179.                bNewImage = TRUE;
  180.                /* Now get window to update, see if we are iconic or not... */
  181.                if (WinQueryWindowULong(hFrame, QWL_STYLE) & WS_MINIMIZED) {
  182.                   hUpdateWnd = hFrame;
  183.                } else {
  184.                   hUpdateWnd = hClient;
  185.                }
  186.                WinInvalidateRect (hUpdateWnd, (PRECTL) NULL, FALSE);
  187.                DosReleaseMutexSem(hUpdateSem);
  188.                WinUpdateWindow(hUpdateWnd);
  189.                /* Don't display the title until the window is up!! */
  190.                DosRequestMutexSem(hUpdateSem, SEM_INDEFINITE_WAIT);
  191.                DosReleaseMutexSem(hUpdateSem);
  192.                ResetWindowText(hFrame, PathBuf, GlobalBitCount, Globalx, Globaly);
  193.                /* Let's show the picture for the length of time they've */
  194.                /* specified, *unless* this semaphore gets cleared by a key */
  195.                /* or button press, in which case we'll stop waiting. */
  196.                DosResetEventSem(hStopWaitSem, &posts);
  197.                DosWaitEventSem(hStopWaitSem, TimeOutAmount);
  198.                DosResetEventSem(hStopWaitSem, &posts);
  199.                /* Now let's see if they've paused it!! */
  200.                DosWaitEventSem(hPauseSem, SEM_INDEFINITE_WAIT);
  201.                /* Do this in two steps to make sure hStopWaitSem is still */
  202.                /* currently set (since FORWARD, etc. get out of pause and */
  203.                /* reset it!). */
  204.                if (Paused) {
  205.                   Paused = FALSE;
  206.                   /* Uncheck the option... */
  207.                   WinSendMsg(hMenu, MM_SETITEMATTR, MPFROM2SHORT(ID_PAUSE, TRUE),
  208.                              MPFROM2SHORT(MIA_CHECKED, NULL));
  209.                }
  210.             } else {
  211.                DosReleaseMutexSem(hUpdateSem);
  212.                ErrorCode = TempShort;
  213.                if (TempShort == LBF_COULDNT_OPEN_FILE_RC) {
  214.                   strcpy(ErrorBuf, "Error loading file:  <");
  215.                   strupr(PathBuf);
  216.                   strcat(ErrorBuf, PathBuf);
  217.                   strcat(ErrorBuf, ">");
  218.                   pErrorString = ErrorBuf;
  219.                } else {
  220.                   pErrorString = (UCHAR *)NULL;
  221.                }
  222.             }
  223.          }
  224.          switch (Direction) {
  225.             case FORWARD:
  226.                pCurrNode = pCurrNode->pNext;
  227.                if (CurrChecked == ID_REVERSE) {
  228.                   CurrChecked = ID_FORWARD;
  229.                   WinSendMsg(hMenu, MM_SETITEMATTR,
  230.                              MPFROM2SHORT(ID_FORWARD, TRUE),
  231.                              MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED));
  232.                   WinSendMsg(hMenu, MM_SETITEMATTR,
  233.                              MPFROM2SHORT(ID_REVERSE, TRUE),
  234.                              MPFROM2SHORT(MIA_CHECKED, NULL));
  235.                }
  236.                break;
  237.             case REVERSE:
  238.                pCurrNode = pCurrNode->pPrev;
  239.                if (CurrChecked == ID_FORWARD) {
  240.                   CurrChecked = ID_REVERSE;
  241.                   WinSendMsg(hMenu, MM_SETITEMATTR,
  242.                              MPFROM2SHORT(ID_REVERSE, TRUE),
  243.                              MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED));
  244.                   WinSendMsg(hMenu, MM_SETITEMATTR,
  245.                              MPFROM2SHORT(ID_FORWARD, TRUE),
  246.                              MPFROM2SHORT(MIA_CHECKED, NULL));
  247.                }
  248.                break;
  249.             case RESTART:
  250.                pCurrNode = pHeadNode;
  251.                Direction = FORWARD;
  252.                break;
  253.          }
  254.       }
  255.       WinSendMsg(hMenu, MM_SETITEMATTR, MPFROM2SHORT(CurrChecked, TRUE),
  256.                  MPFROM2SHORT(MIA_CHECKED, NULL));
  257.       FixupMenus(hFrame, FALSE);
  258.       FreeLList(pHeadNode);
  259.    }
  260.    if (ErrorCode) {
  261.       ShowErrors(ErrorCode, pErrorString);
  262.    }
  263.    bStopSlide = TRUE;
  264.    WinCancelShutdown(hmq, 0);
  265.    WinDestroyMsgQueue(hmq);
  266.    WinPostMsg(hClient, WM_COMMAND, MPFROMSHORT(ID_CLEAR_BITMAP), (MPARAM)NULL);
  267. }
  268.  
  269.  
  270.  
  271. HAB  hAB;
  272. HMQ  hmq;
  273.  
  274. int main(int argc, char *argv[])
  275. {
  276.    SHORT TempShort;
  277.    ULONG ParamBits;
  278.    RECTL InitialSize;
  279.    ULONG flCreate;                       /* Window creation control flags*/
  280.  
  281.    hAB = WinInitialize( 0 );             /* Initialize PM                */
  282.    hmq = WinCreateMsgQueue( hAB, 0 );    /* Create a message queue       */
  283.  
  284.    WinRegisterClass(                     /* Register window class        */
  285.       hAB,                               /* Anchor block handle          */
  286.       "MyWindow",                        /* Window class name            */
  287.       (PFNWP)MyWindowProc,               /* Address of window procedure  */
  288.       CS_SIZEREDRAW,                     /* Class Style                  */
  289.       0                                  /* No extra window words        */
  290.       );
  291.  
  292.    flCreate = FCF_STANDARD & (~FCF_TASKLIST);
  293.  
  294.  
  295.    hFrame = WinCreateStdWindow(
  296.                HWND_DESKTOP,            /* Desktop window is parent     */
  297.                0,                       /* Set frame styles to standard */
  298.                (PVOID)&flCreate,        /* Frame control flag           */
  299.                "MyWindow",              /* Client window class name     */
  300.                szTitleBar,              /* Fill in after creation for TM*/
  301.                0L,                      /* No special class style       */
  302.                (HMODULE)NULL,           /* Resource is in .EXE file     */
  303.                ID_WINDOW,               /* Frame window identifier      */
  304.                &hClient                 /* Client window handle         */
  305.                );
  306.  
  307.    /* This subclassing is necessary so we can get paint messages when iconic. */
  308. /*   pFrameWndProc = WinSubclassWindow(hFrame, FilterProc); */
  309.  
  310.    /* This is sort of a PM oddity, but if we don't set the style to */
  311.    /* WS_VISIBLE, then PM won't give us our default coords., HOWEVER, if we */
  312.    /* don't specify WS_VISIBLE, and make it iconic, PM *will* set our  */
  313.    /* restore coordinates to SHELLPOSITION!! So Let's initially show the  */
  314.    /* window as iconic, but with NOREDRAW so it doesn't actually get */
  315.    /* shown (if we don't make it iconic, the client area gets shown!), then */
  316.    /* we will have valid restore coords, in case the user doesn't specify */
  317.    /* all coords on the command line, then we'll show the window!! */
  318.    WinSetWindowPos(hFrame, (HWND)NULL, 0, 0, 0, 0,
  319.                    SWP_MINIMIZE | SWP_SHOW | SWP_NOREDRAW | SWP_DEACTIVATE);
  320.    WinSetWindowPos(hFrame, (HWND)NULL, 0, 0, 0, 0,
  321.                    SWP_HIDE);
  322.    WinSetWindowPos(hFrame, (HWND)NULL, 0, 0, 0, 0,
  323.                    SWP_RESTORE);
  324.    /* Now we are where we want to be, an invisible window at FCF_SHELLPOSITION!*/
  325.  
  326.    InitialSize.xLeft = WinQueryWindowUShort(hFrame, QWS_XRESTORE);
  327.    InitialSize.xRight = WinQueryWindowUShort(hFrame, QWS_CXRESTORE);
  328.    InitialSize.yBottom = WinQueryWindowUShort(hFrame, QWS_YRESTORE);
  329.    InitialSize.yTop = WinQueryWindowUShort(hFrame, QWS_CYRESTORE);
  330.  
  331.    ParamBits =  ParseArgs(argc, argv, &pFname, &InitialSize);
  332.  
  333.    DosCreateMutexSem(NULL,&hUpdateSem,0,0);
  334.    DosCreateEventSem(NULL,&hPauseSem,0,0);
  335.    DosPostEventSem(hPauseSem);
  336.    DosCreateEventSem(NULL,&hStopWaitSem,0,1);
  337.  
  338.    /* We do this explicitly rather than in our style bits so that the title */
  339.    /* will ALWAYS be szTitleBar, and not what someone may have started */
  340.    /* us with! */
  341.    AddToSwitchList(hFrame, (HWND)NULL, szTitleBar);
  342.    gbm_init();
  343.  
  344.    if (ParamBits & BITMAP_FILE) {
  345.       TempShort = LoadBitmapFile(pFname, (PHAB)&hAB, (PHDC)&hdcMem,
  346.                                  (PHPS)&hpsMem, (PHBITMAP)&hbmMem, TRUE);
  347.       if (!TempShort) {
  348.          bNewImage = TRUE;
  349.          /* Remember, we haven't assigned the value of 'hFrame' yet!! */
  350.          /* so use the client handle to get the frame's handle... */
  351.          ResetWindowText(hFrame, pFname, GlobalBitCount, Globalx, Globaly);
  352.       } else if (TempShort == LBF_COULDNT_OPEN_FILE_RC) {
  353.          strcpy(ErrorBuf, "Error loading file:  <");
  354.          strcat(ErrorBuf, pFname);
  355.          strcat(ErrorBuf, ">");
  356.          ShowErrors(TempShort, ErrorBuf);
  357.       } else {
  358.          ShowErrors(TempShort, NULL);
  359.       }
  360.    } else if (ParamBits & SLIDE_FILE) {
  361.       bStopSlide = FALSE;
  362.       strcpy(SlideBuf,pFname);
  363.       if (_beginthread(SlideThread, NULL, THREAD_STACKSIZE, (PVOID)pFname)
  364.                        == -1) {
  365.          ShowErrors(NO_SLIDE_THREAD_RC, NULL);
  366.       }
  367.    }
  368.  
  369.    /* Make sure we have the focus when we come up!! */
  370.    TempShort = (SWP_SHOW | SWP_ACTIVATE);
  371.    if (ParamBits & SWP_SIZE) {
  372.       TempShort |= (SWP_MOVE | SWP_SIZE);
  373.    }
  374.  
  375.    if (ParamBits & SWP_MINIMIZE) {
  376.       /* This must be done before any possible moves!! */
  377.       WinSetWindowPos(hFrame, (HWND)NULL, 0, 0, 0, 0, SWP_MINIMIZE);
  378.       TempShort &= (~(SWP_SIZE));
  379.    } else if (ParamBits & SWP_MAXIMIZE) {
  380.       TempShort &= (~(SWP_SIZE));
  381.       WinSetWindowPos(hFrame, (HWND)NULL, 0, 0, 0, 0, SWP_MAXIMIZE);
  382.    }
  383.  
  384.    WinSetWindowPos(hFrame, (HWND)NULL, (SHORT)InitialSize.xLeft,
  385.                    (SHORT)InitialSize.yBottom, (SHORT)InitialSize.xRight,
  386.                    (SHORT)InitialSize.yTop, TempShort);
  387.  
  388.    WinSendMsg(WinWindowFromID(hFrame, FID_MENU), MM_SETITEMATTR,
  389.               MPFROM2SHORT(ID_SCALE_WHILE_DRAW, TRUE),
  390.               MPFROM2SHORT(MIA_CHECKED, bScaleWhileDrawing ? 0 : MIA_CHECKED));
  391.    WinSendMsg(WinWindowFromID(hFrame, FID_MENU), MM_SETITEMATTR,
  392.               MPFROM2SHORT(ID_PALETTE_MANAGEMENT, TRUE),
  393.               MPFROM2SHORT(MIA_CHECKED, bPaletteManager ? MIA_CHECKED : 0));
  394.    WinSendMsg(WinWindowFromID(hFrame, FID_MENU), MM_SETITEMATTR,
  395.               MPFROM2SHORT(ID_KEEP_PROPORTION, TRUE),
  396.               MPFROM2SHORT(MIA_CHECKED, bKeepProportion ? MIA_CHECKED : 0));
  397.  
  398.  
  399.    hwndTitleBar =  WinWindowFromID( hFrame, (USHORT)FID_TITLEBAR);
  400.    hwndSysMenu  =  WinWindowFromID( hFrame, (USHORT)FID_SYSMENU );
  401.    hwndMinMax   =  WinWindowFromID( hFrame, (USHORT)FID_MINMAX  );
  402.    hwndAppMenu  =  WinWindowFromID( hFrame, (USHORT)FID_MENU    );
  403.    if (bFrameEmpty) {
  404.       bFrameEmpty = !bFrameEmpty;
  405.       WinSendMsg(hClient, WM_COMMAND, MPFROMSHORT(ID_FRAME_EMPTY), NULL);
  406.    } /* endif */
  407.  
  408.    while( WinGetMsg( hAB, (PQMSG)&qmsg, (HWND)NULL, 0, 0 ) ) {
  409.            WinDispatchMsg( hAB, (PQMSG)&qmsg );
  410.    }
  411.  
  412.    /* Our resources should get freed automatically, but let's just be sure! */
  413.    RemoveBitmapFromMem((PHDC)&hdcMem, (PHPS)&hpsMem, (PHBITMAP)&hbmMem);
  414.    RemoveBitmapFromMem((PHDC)&hdcCurrent, (PHPS)&hpsCurrent,
  415.                        (PHBITMAP)&hbmCurrent);
  416.    WinDestroyWindow(hFrame);           /* Tidy up...                   */
  417.    WinDestroyMsgQueue(hmq);            /* and                          */
  418.    return(WinTerminate(hAB));          /* terminate the application    */
  419. }
  420.  
  421. /*#if 0*/
  422. PVOID MakeRLEBitmap(HBITMAP hbmMem, HPS hpsMem, HAB hab)
  423. {
  424.    BITMAPINFOHEADER2 bmih;
  425.    PBITMAPINFO2 pbmih = NULL;
  426.    ULONG scansize, tsize;
  427.    LONG bmisize;
  428.    PVOID  data;
  429.    LONG   scans;
  430.  
  431.    bmih.cbFix = sizeof(bmih);
  432.    GpiQueryBitmapInfoHeader(hbmMem, &bmih);
  433.    scansize = ((bmih.cBitCount*bmih.cx+31)/32)*bmih.cPlanes*4;
  434.    bmisize = (bmih.cbFix+(sizeof(RGB2))*
  435.                  (bmih.cclrUsed ? bmih.cclrUsed :
  436.                                   2<<(bmih.cBitCount*bmih.cPlanes) ) );
  437.    tsize = bmisize+scansize*bmih.cy;
  438.    if ( DosAllocMem((PVOID)&pbmih, tsize, PAG_COMMIT+OBJ_TILE+PAG_WRITE)) {
  439.        return FALSE;
  440.    } /* endif */
  441.    data = (PVOID)pbmih;
  442.    memcpy(data, (PVOID)&bmih, bmih.cbFix);
  443.    pbmih->cBitCount = bmih.cBitCount*bmih.cPlanes;
  444.    pbmih->cPlanes = 1;
  445.    pbmih->cbImage = scansize*bmih.cy;
  446.    pbmih->ulCompression = (pbmih->cBitCount == 4 ? BCA_RLE4 :
  447.                            pbmih->cBitCount == 8 ? BCA_RLE8 : BCA_UNCOMP);
  448.    scans = GpiQueryBitmapBits(hpsMem, 0, bmih.cy, ((PSZ)data)+bmisize, pbmih);
  449.    if (GPI_ALTERROR == scans) {
  450.       data = NULL;
  451.       tsize = pbmih->cbImage*3/2;
  452.       while (  tsize < 2*scansize*bmih.cy) {
  453.          DosFreeMem(pbmih);
  454.          if ( DosAllocMem((PVOID)&pbmih, tsize+bmisize,
  455.                           PAG_COMMIT+OBJ_TILE+PAG_WRITE)) {
  456.              return FALSE;
  457.          } /* endif */
  458.          memcpy((PVOID)pbmih, (PVOID)&bmih, bmih.cbFix);
  459.          pbmih->cBitCount = bmih.cBitCount*bmih.cPlanes;
  460.          pbmih->cPlanes = 1;
  461.          pbmih->cbImage = tsize;
  462.          pbmih->ulCompression = (pbmih->cBitCount == 4 ? BCA_RLE4 :
  463.                                  pbmih->cBitCount == 8 ? BCA_RLE8 : BCA_UNCOMP);
  464.          scans = GpiQueryBitmapBits(hpsMem, 0, bmih.cy, ((PSZ)pbmih)+bmisize, pbmih);
  465.          if (GPI_ALTERROR != scans) {
  466.             data = (PVOID)pbmih;
  467.             break;
  468.          } /* endif */
  469.       } /* endwhile */
  470.    } /* endif */
  471.    return data;
  472. }
  473.  
  474. ULONG WriteBitmap(PVOID bm, PSZ filename, USHORT type, USHORT xhot, USHORT yhot)
  475. {
  476.    PBITMAPINFO2 pbmih = (PBITMAPINFO2)bm;
  477.    PBITMAPFILEHEADER2 pbmfh = NULL;
  478.    ULONG  bmihsize, bmisize, bmfhsize, ctabsize;
  479.    PVOID   bits;
  480.    PSZ     tptr;
  481.    ULONG   result = FALSE;
  482.    HFILE   hfile;
  483.    ULONG   action, written;
  484.  
  485.    bmisize = (pbmih->cbFix+(sizeof(RGB2))*
  486.                (pbmih->cclrUsed ? pbmih->cclrUsed :
  487.                                   2<<(pbmih->cBitCount*pbmih->cPlanes) ) );
  488.    bits = (PVOID)((PSZ)pbmih + bmisize);
  489.    if (pbmih->ulIdentifier) {
  490.       bmihsize = sizeof(*pbmih);
  491.    } else if (pbmih->ulColorEncoding) {
  492.       bmihsize = FIELDOFFSET(BITMAPINFOHEADER2, ulIdentifier);
  493.    } else if (pbmih->cSize2) {
  494.       bmihsize = FIELDOFFSET(BITMAPINFOHEADER2, ulColorEncoding);
  495.    } else if (pbmih->cSize1) {
  496.       bmihsize = FIELDOFFSET(BITMAPINFOHEADER2, cSize2);
  497.    } else if (pbmih->usRendering) {
  498.       bmihsize = FIELDOFFSET(BITMAPINFOHEADER2, cSize1);
  499.    } else if (pbmih->usRecording) {
  500.       bmihsize = FIELDOFFSET(BITMAPINFOHEADER2, usRendering);
  501.    } else if (pbmih->usUnits) {
  502.       bmihsize = FIELDOFFSET(BITMAPINFOHEADER2, usRecording);
  503.    } else if (pbmih->cclrImportant) {
  504.       bmihsize = FIELDOFFSET(BITMAPINFOHEADER2, usUnits);
  505.    } else {
  506.       bmihsize = FIELDOFFSET(BITMAPINFOHEADER2, cclrImportant);
  507.    } /* endif */
  508.    ctabsize = ((sizeof(RGB2))* (pbmih->cclrUsed ? pbmih->cclrUsed :
  509.                                1<<(pbmih->cBitCount*pbmih->cPlanes) ) );
  510.    bmfhsize = FIELDOFFSET(BITMAPFILEHEADER2, bmp2) + bmihsize + ctabsize;
  511.    if (DosAllocMem((PVOID)&pbmfh, bmfhsize, PAG_COMMIT+OBJ_TILE+PAG_WRITE)) {
  512.       return FALSE;
  513.    } /* endif */
  514.    pbmfh->usType   = (USHORT)(type ? type : BFT_BMAP);
  515. /*   pbmfh->cbSize   = bmfhsize+pbmfh->bmp2.cbImage;*/
  516.    pbmfh->cbSize   = FIELDOFFSET(BITMAPFILEHEADER2, bmp2) + bmihsize;
  517.    pbmfh->xHotspot = xhot;
  518.    pbmfh->yHotspot = yhot;
  519.    pbmfh->offBits  = bmfhsize;
  520.    tptr = (PSZ)&(pbmfh->bmp2);
  521.    memcpy(tptr, (PVOID)bm, bmihsize);
  522.    (pbmfh->bmp2).cbFix = bmihsize;
  523.    tptr += bmihsize;
  524.    memcpy(tptr, (PVOID)&(pbmih->argbColor), ctabsize);
  525.    if (!DosOpen(filename, &hfile, &action, bmfhsize+pbmfh->bmp2.cbImage,
  526.                FILE_NORMAL, FILE_TRUNCATE | FILE_CREATE,
  527.                OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE |
  528.                  OPEN_FLAGS_NOINHERIT,
  529.                0 )) {
  530.       if (DosWrite(hfile, pbmfh, bmfhsize, &written) ||
  531.                  written != bmfhsize) {
  532.          DosClose(hfile);
  533.          DosDelete(filename);
  534.       } else if (DosWrite(hfile, bits, pbmfh->bmp2.cbImage, &written) ||
  535.                  written != pbmfh->bmp2.cbImage) {
  536.          DosClose(hfile);
  537.          DosDelete(filename);
  538.       } else {
  539.          result = TRUE;
  540.          DosClose(hfile);
  541.       } /* endif */
  542.    } /* endif */
  543.    DosFreeMem(pbmfh);
  544.    return result;
  545. }
  546. /*#endif*/
  547.  
  548. PSZ Editname(PSZ source)
  549. {
  550. static ULONG maxfile;
  551.    PSZ       tptr, outfile = NULL;
  552.    ULONG     rc;
  553.  
  554.    if (!maxfile) {
  555.       if (rc = DosQuerySysInfo(QSV_MAX_PATH_LENGTH, QSV_MAX_PATH_LENGTH,
  556.                                        &maxfile, sizeof(maxfile)) ) {
  557.          exit(rc);
  558.       } /* endif */
  559.    } /* endif */
  560.    if (!outfile && !(outfile = malloc(maxfile))) {
  561.       exit(25);
  562.    } /* endif */
  563.    strcpy(outfile, source);
  564.    tptr = outfile + strlen(outfile) - 1;
  565.    while (tptr>outfile) {
  566.       if (*tptr == '\\' || *tptr == ':' ) {
  567.          break;
  568.       } /* endif */
  569.       tptr--;
  570.    } /* endwhile */
  571.    ++tptr;
  572.    if (rc = DosEditName(1, source+(tptr-outfile), "*.RLE",
  573.                                 tptr, maxfile-(tptr-outfile)) ) {
  574.       exit(rc);
  575.    } /* endif */
  576.    if (':' == *(outfile+1)) {
  577.       DosSetDefaultDisk(toupper(*(outfile+1))-'A');
  578.       if (tptr>outfile+2) {
  579.          *--tptr = '\0';
  580.          DosSetCurrentDir(outfile+2);
  581.          *tptr = '\\';
  582.       } /* endif */
  583.    } else {
  584.       if (tptr>outfile) {
  585.          *--tptr = '\0';
  586.          DosSetCurrentDir(outfile);
  587.          *tptr = '\\';
  588.       } /* endif */
  589.    } /* endif */
  590.  
  591.    return (PSZ)strdup(outfile);
  592. }
  593.  
  594. PSZ copyext(PSZ exts)      /* Copy an extension from a blank separated list   */
  595. {
  596.    UCHAR temp[30];
  597.    int   i = 0;
  598.  
  599.    while (exts[i] && exts[i] != ' ') {
  600.       temp[i] = exts[i];
  601.       i++;
  602.    } /* endwhile */
  603.    temp[i] = 0;
  604.    return strdup(temp);
  605. }
  606.  
  607.  
  608. /* This is the file filter to allow only files with the supported bitmap/image   */
  609. /*    extensions into the file dialog.                                           */
  610. MRESULT EXPENTRY FileDlgFilter(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  611. {
  612. static PSZ types[100];                 /* Keep the supported extensions here.    */
  613. static BOOL firsttime = TRUE;          /* We only want to obtain the extension   */
  614.                                        /*    list one time.                      */
  615. static ULONG typecount = 0;            /* Number of extensions we support.       */
  616.    ULONG i;
  617.    int count;
  618.    PSZ tptr;
  619.  
  620.    if (firsttime) {                    /* First time through we query GBM for    */
  621.       firsttime = FALSE;               /*    supported file types and build up   */
  622.       for (i=0; i<100; i++) {          /*    our table.                          */
  623.          types[i] = NULL;
  624.       } /* endfor */
  625.       if (!gbm_query_n_filetypes(&count)) {
  626.          for (i=0; i<count; i++) {
  627.             GBMFT gbmft;
  628.  
  629.             if (!gbm_query_filetype(i, &gbmft)) {
  630.                PSZ ptr = gbmft.extensions;
  631.  
  632.                while (ptr && *ptr && *ptr != ' ') {
  633.                   types[typecount++] = copyext(ptr);
  634.                   while (*ptr && *ptr != ' ')ptr++;
  635.                   if (*ptr) ptr++;
  636.                } /* endwhile */
  637.             } /* endif */
  638.          } /* endfor */
  639.       } /* endif */
  640.    } /* endif */
  641.  
  642.    if (FDM_FILTER == msg) {            /* Process the FDM_FILTER message to      */
  643.       tptr = (PSZ)mp1;                 /*    filter out the unwanted file types. */
  644.       tptr += strlen(tptr) - 1;
  645.       while (tptr>(PSZ)mp1 && *tptr != '.') {     /* Locate an extension! Reject if   */
  646.                                              /*    can't find one.               */
  647.          if (*tptr == '\\' || *tptr == ':') return (MRESULT)FALSE;
  648.          tptr--;
  649.       } /* endwhile */
  650.       if (*tptr != '.') {
  651.          return (MRESULT)FALSE;
  652.       } /* endif */
  653.       tptr++;
  654.       for (i=0; i<typecount; i++) {          /* Now compare the extension to our */
  655.          if (!stricmp(tptr,types[i])) {      /*    supported extension list.     */
  656.             return (MRESULT)TRUE;            /* Return TRUE if it is supported!  */
  657.          } /* endif */
  658.       } /* endfor */
  659.       return (MRESULT)FALSE;
  660.    } else {
  661.       return WinDefFileDlgProc(hwnd, msg, mp1, mp2);
  662.    } /* endif */
  663. }
  664.  
  665. typedef struct {
  666.    HWND         hwnd;
  667.    PSZ          name;
  668.    BOOL         bRLE;
  669. } BITINFO;
  670. typedef BITINFO * PBITINFO;
  671.  
  672. void LoadBitmapThread(PVOID pData)
  673. {
  674.    HAB          hABt = WinInitialize(0);
  675.    HMQ          hmqt = WinCreateMsgQueue(hABt, 0);    /* Create a message queue       */
  676.    PBITINFO     pb = (PBITINFO)pData;
  677.    SHORT        TempShort;
  678.  
  679.    /* Wait 'till we're done drawing the old one before loading a */
  680.    /* new one!! */
  681.    DosRequestMutexSem(hUpdateSem, SEM_INDEFINITE_WAIT);
  682.    TempShort = LoadBitmapFile(pb->name, (PHAB)&hABt,
  683.                               (PHDC)&hdcMem, (PHPS)&hpsMem,
  684.                               (PHBITMAP)&hbmMem, TRUE);
  685.    DosReleaseMutexSem(hUpdateSem);
  686.    if (!TempShort) {
  687.      bNewImage = TRUE;
  688.      /* Now get window to update... */
  689.      WinInvalidateRect (pb->hwnd, (PRECTL) NULL, FALSE);
  690.      WinUpdateWindow(pb->hwnd);
  691.      ResetWindowText(hFrame, pb->name, GlobalBitCount, Globalx, Globaly);
  692.    } else if (TempShort == LBF_COULDNT_OPEN_FILE_RC) {
  693.      strcpy(ErrorBuf, "Error loading file:  <");
  694.      strcat(ErrorBuf, pb->name);
  695.      strcat(ErrorBuf, ">");
  696.      ShowErrors(TempShort, ErrorBuf);
  697.    } else {
  698.      ShowErrors(TempShort, NULL);
  699.    }
  700.    free(pb->name);
  701.    free(pb);
  702.    WinDestroyMsgQueue(hmqt);
  703.    WinTerminate(hABt);
  704. }
  705.  
  706.  
  707. ULONG SaveBitmapFile(PSZ lpFileName, PHAB phAB, PHDC phdcMem,
  708.                       PHPS phpsMem, PHBITMAP phbmMem,
  709.                       BOOL bShowWaitPointer)
  710. {
  711.   ULONG             ReturnVal   = 0  ;
  712.   BITMAPINFOHEADER  bih              ;
  713.   int               ft               ;
  714.   int               fd               ;
  715.   GBM               gbm              ;
  716.   GBMFT             gbmft            ;
  717.   GBMRGB            gbmrgb [0x100]   ;
  718.   BYTE             *pbData = NULL    ;
  719.   PSZ               opts             ;
  720.   struct {
  721.      BITMAPINFOHEADER2 bmp2;
  722.      RGB2              rgb[0x100];
  723.   } bm;
  724.  
  725. #define GBM_WRITE (GBM_FT_W1 || GBM_FT_W4 || GBM_FT_W8 || GBM_FT_W24)
  726.  
  727. static ULONG errtab[9] = {
  728.    0, SBF_NO_MEMORY, SBF_ERROR_WRITE_FORMAT, SBF_ERROR_WRITE_FORMAT,
  729.    SBF_ERROR_WRITE_FORMAT, SBF_ERROR_WRITE_FORMAT, SBF_ERROR_WRITE_FORMAT,
  730.    SBF_ERROR_WRITE_FORMAT, SBF_ERROR_WRITE_FORMAT
  731. };
  732.  
  733.  
  734.   if ((opts = strchr(lpFileName, ',')) != NULL ) {
  735.      *opts++ = '\0';
  736.   } else {
  737.      opts = "";
  738.   } /* endif */
  739.   if (bShowWaitPointer) {
  740.     WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP,
  741.                                                    SPTR_WAIT, FALSE));
  742.   }
  743.  
  744.   /* First remove all leading and trailing white space, or this call */
  745.   /* will fail!! */
  746.   RemoveWhiteSpace(lpFileName);
  747.   bih.cbFix = sizeof(bih);
  748.   /* Now check the filetype! */
  749.   if (gbm_guess_filetype(lpFileName,&ft) || gbm_query_filetype(ft, &gbmft) ) {
  750.      ReturnVal = SBF_UNKNOWN_FORMAT_RC;
  751.   } else {
  752.      bm.bmp2.cbFix = sizeof(BITMAPINFOHEADER2);
  753.      if (!(gbmft.flags && GBM_WRITE)) {
  754.         ReturnVal = SBF_FORMAT_NO_WRITE;
  755.      } else if (!GpiQueryBitmapParameters(*phbmMem, &bih)) {
  756.         ReturnVal = SBF_ERROR_GETTING_BITMAP_INFO;
  757.      } else {
  758. #ifdef DEBUG
  759.         printf("Checking for bits - %u.\n",bih.cPlanes*bih.cBitCount);
  760. #endif
  761.         switch (bih.cPlanes * bih.cBitCount) {
  762.         case 1:
  763.            ReturnVal = !(gbmft.flags & GBM_FT_W1);
  764.            break;
  765.         case 4:
  766.            ReturnVal = !(gbmft.flags & GBM_FT_W4);
  767.            break;
  768.         case 8:
  769.            ReturnVal = !(gbmft.flags & GBM_FT_W8);
  770.            break;
  771.         case 24:
  772.            ReturnVal = !(gbmft.flags & GBM_FT_W24);
  773.            break;
  774.         default:
  775.            ReturnVal = TRUE;
  776.           break;
  777.         } /* endswitch */
  778.         if (ReturnVal) {
  779.            ReturnVal = SBF_FORMAT_MISMATCH;
  780.         } else if (!GpiQueryBitmapInfoHeader(*phbmMem, (PBITMAPINFOHEADER2)&bm)) {
  781.            ReturnVal = SBF_ERROR_GETTING_BITMAP_INFO;
  782.         } else {
  783.            bm.bmp2.ulCompression   = 0;
  784.            bm.bmp2.usReserved      = 0;
  785.            bm.bmp2.usRecording     = 0;
  786.            bm.bmp2.usRendering     = 0;
  787.            bm.bmp2.ulColorEncoding = 0;
  788.            if (bm.bmp2.cBitCount == 1 && bm.bmp2.cPlanes == 4) {
  789.               bm.bmp2.cBitCount = 4;
  790.               bm.bmp2.cPlanes   = 1;
  791.            } /* endif */
  792.            gbm.w = bm.bmp2.cx;
  793.            gbm.h = bm.bmp2.cy;
  794.            gbm.bpp = bm.bmp2.cBitCount;
  795. #ifdef DEBUG
  796.            printf("Bitcount = %u.\n",bm.bmp2.cBitCount);
  797. #endif
  798.            if (!(pbData = malloc(((bm.bmp2.cBitCount*gbm.w+31)/32)*4))  ) {
  799.               ReturnVal = SBF_NO_MEMORY;
  800.            } else if (!GpiQueryBitmapBits(*phpsMem, 0, 1, pbData, (PBITMAPINFO2)&bm) ) {
  801.               ReturnVal = SBF_NO_COLOR_TABLE;
  802.            } else if ((free(pbData), (pbData = malloc(((bm.bmp2.cBitCount*gbm.w+31)/32)*4*gbm.h))) ) {
  803.               if (bm.bmp2.cBitCount != 24) {
  804.                  int ulCol;
  805.  
  806.                  for (ulCol=0; ulCol<(1<<gbm.bpp); ulCol++) {
  807.                     gbmrgb [ulCol].r = bm.rgb[ulCol].bRed  ;
  808.                     gbmrgb [ulCol].g = bm.rgb[ulCol].bGreen;
  809.                     gbmrgb [ulCol].b = bm.rgb[ulCol].bBlue ;
  810.                  } /* endfor */
  811.               } /* endif */
  812.               if (GpiQueryBitmapBits(*phpsMem, 0, gbm.h, pbData, (PBITMAPINFO2)&bm) ) {
  813.                  if (-1 == (fd = open( lpFileName, O_CREAT | O_TRUNC | O_RDWR | O_BINARY
  814.                                      , S_IREAD | S_IWRITE)) ) {
  815.                     ReturnVal = SBF_ERROR_OPEN_FILE;
  816.                  } else {
  817.                     ReturnVal = errtab[gbm_write( lpFileName, fd, ft, &gbm, (GBMRGB *)gbmrgb
  818.                                                 , pbData, opts)];
  819.                  } /* endif */
  820.                  close(fd);
  821.               } else {
  822.                  ReturnVal = SBF_ERROR_GETBITS;
  823.               } /* endif */
  824.            } else {
  825.               ReturnVal = SBF_NO_MEMORY;
  826.            } /* endif */
  827.            if (pbData) {
  828.               free(pbData);
  829.            } /* endif */
  830.         } /* endif */
  831.      } /* endif */
  832.   } /* endif */
  833.  
  834.   return(ReturnVal);
  835. }
  836.  
  837.  
  838. void SaveBitmapThread(PVOID pData)
  839. {
  840.    HAB          hABt = WinInitialize(0);
  841.    HMQ          hmqt = WinCreateMsgQueue(hABt, 0);    /* Create a message queue       */
  842.    PBITINFO     pb = (PBITINFO)pData;
  843.    SHORT        TempShort;
  844.  
  845.    /* Wait 'till we're done drawing the old one before loading a */
  846.    /* new one!! */
  847.    DosRequestMutexSem(hUpdateSem, SEM_INDEFINITE_WAIT);
  848.    TempShort = SaveBitmapFile(pb->name, (PHAB)&hABt,
  849.                               (PHDC)&hdcMem, (PHPS)&hpsMem,
  850.                               (PHBITMAP)&hbmMem, TRUE);
  851.    DosReleaseMutexSem(hUpdateSem);
  852.    if (TempShort == LBF_COULDNT_OPEN_FILE_RC) {
  853.      strcpy(ErrorBuf, "Error saving bitmap file:  <");
  854.      strcat(ErrorBuf, pb->name);
  855.      strcat(ErrorBuf, ">");
  856.      ShowErrors(TempShort, ErrorBuf);
  857.    } else if (TempShort) {
  858.      ShowErrors(TempShort, NULL);
  859.    }
  860.    free(pb->name);
  861.    free(pb);
  862.    WinDestroyMsgQueue(hmqt);
  863.    WinTerminate(hABt);
  864. }
  865.  
  866. /*****************************************************************************/
  867. /*  Abstract for function: MyWindowProc()                                    */
  868. /*    This function is the main window function.                             */
  869. /*****************************************************************************/
  870. MRESULT EXPENTRY MyWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  871. {
  872.   USHORT           command;             /* WM_COMMAND command value     */
  873.   HPS              hps;                 /* Presentation Space handle    */
  874.   RECTL            rc;                  /* Rectangle coordinates.       */
  875.   POINTL           PointStruct;         /* For GpiCharStringAt().       */
  876.   FONTMETRICS      FontBuf;             /* For GpiCharStringAt().       */
  877.   USHORT           CharHeight;          /* For GpiCharStringAt().       */
  878.   HPS              hpsForDrawing;       /* For final BitBlt.            */
  879.   SHORT            TempShort;
  880.   BOOL             bError = FALSE;
  881.   UCHAR            MsgBuf[100];
  882.   POINTL           bmarray [5];
  883.   BITMAPINFOHEADER bmapinfo;
  884.   BOOL             bReturnVal = FALSE;
  885.   FILEDLG          filedlg;
  886.   HWND             hwndDest;
  887.   PVOID            prlebm;
  888.  
  889.   /* Make this static, so we can check if we really have to do any */
  890.   /* transformations. */
  891.   static SIZEL  NewImageSize;
  892.   /* Make this static since we can only do this once per window invocation. */
  893.   PSZ outfile;
  894.   ULONG cclr;
  895.   SIZEL empty = {0,0};
  896.  
  897.   switch(msg) {
  898.     case WM_CREATE:
  899.       hClient = hwnd;
  900.       bReturnVal = FALSE;
  901.       hdcScreen = WinOpenWindowDC(hwnd);
  902.       DevQueryCaps(hdcScreen, CAPS_ADDITIONAL_GRAPHICS, 1, (PLONG)&cclr);
  903.       bPaletteSupport = (cclr&CAPS_PALETTE_MANAGER) == CAPS_PALETTE_MANAGER;
  904.       hpsWindow = GpiCreatePS(hAB, hdcScreen, &empty, PU_PELS | GPIT_MICRO | GPIA_ASSOC );
  905.       GpiAssociate(hpsWindow, hdcScreen);
  906.       break;
  907.  
  908.     case WM_BUTTON1DBLCLK:
  909.       Direction = REVERSE;
  910.       DosPostEventSem(hStopWaitSem);
  911.       DosPostEventSem(hPauseSem);
  912.       break;
  913.  
  914.     case WM_BUTTON2DBLCLK:
  915.       Direction = FORWARD;
  916.       DosPostEventSem(hStopWaitSem);
  917.       DosPostEventSem(hPauseSem);
  918.       break;
  919.  
  920.     case WM_BUTTON1DOWN:
  921.     case WM_BUTTON2DOWN:
  922.       if (bFrameEmpty) {
  923.          if (   (WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000)
  924.             && (WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000) ) {
  925.             WinPostMsg(hwnd, WM_COMMAND, MPFROMSHORT(ID_FRAME_EMPTY), NULL);
  926.          } /* endif */
  927.       } /* endif */
  928.       break;
  929.  
  930.     case WM_COMMAND:
  931.       command = SHORT1FROMMP(mp1);      /* Extract the command value    */
  932.       switch (command) {
  933.         case ID_LOADFILE:
  934.          memset(&filedlg, 0, sizeof(filedlg));
  935.          filedlg.cbSize          = sizeof(filedlg);
  936.          filedlg.fl              = FDS_CENTER |FDS_OPEN_DIALOG;
  937.          filedlg.pszTitle        = "Source Bitmap Selection";
  938.          filedlg.pfnDlgProc      = FileDlgFilter;
  939.          strcpy(filedlg.szFullFile,"*");
  940.          if (WinFileDlg(HWND_DESKTOP, hwnd, &filedlg) && filedlg.lReturn == DID_OK) {
  941.             PBITINFO pbitinfo = malloc(sizeof(BITINFO));
  942.             /* So we have a filespec... */
  943.             strcpy(PathBuf, filedlg.szFullFile);
  944.             pbitinfo->hwnd = hwnd;
  945.             pbitinfo->name = strdup(PathBuf);
  946.             _beginthread(LoadBitmapThread, NULL
  947.                         , THREAD_STACKSIZE, (PVOID)pbitinfo);
  948.           }
  949.           /* else they cancelled out, so do nothing!! */
  950.           bReturnVal = TRUE;
  951.           break;
  952.  
  953.        case ID_SAVEFILE:
  954.          memset(&filedlg, 0, sizeof(filedlg));
  955.          filedlg.cbSize          = sizeof(filedlg);
  956.          filedlg.fl              = FDS_CENTER |FDS_OPEN_DIALOG;
  957.          filedlg.pszTitle        = "Save Bitmap Selection";
  958.          filedlg.pfnDlgProc      = FileDlgFilter;
  959.          strcpy(filedlg.szFullFile,"*");
  960.          if (WinFileDlg(HWND_DESKTOP, hwnd, &filedlg) && filedlg.lReturn == DID_OK) {
  961.             PBITINFO pbitinfo = malloc(sizeof(BITINFO));
  962.             strcpy(PathBuf, filedlg.szFullFile);
  963.             pbitinfo->hwnd = hwnd;
  964.             pbitinfo->name = strdup(PathBuf);
  965.             pbitinfo->bRLE = FALSE;
  966.             _beginthread(SaveBitmapThread, NULL
  967.                         , THREAD_STACKSIZE, (PVOID)pbitinfo);
  968.           }
  969.           bReturnVal = TRUE;
  970.           break;
  971.  
  972.        case ID_SAVERLEFILE:
  973.           if (prlebm = MakeRLEBitmap(hbmMem, hpsMem, hAB)) {
  974.              outfile = Editname(PathBuf);
  975.              if (!(TempShort = WriteBitmap(prlebm, outfile, BFT_BMAP, 0, 0) )) {
  976.                 strcpy(ErrorBuf, "Error saving file:  <");
  977.                 strcat(ErrorBuf, outfile);
  978.                 strcat(ErrorBuf, ">");
  979.                 ShowErrors(TempShort, ErrorBuf);
  980.              }
  981.              DosFreeMem(prlebm);
  982.              free(outfile);
  983.           } else {
  984.              strcpy(ErrorBuf, "Error creating RLE format bitmap.");
  985.              ShowErrors(TempShort, ErrorBuf);
  986.           }
  987.           bReturnVal = TRUE;
  988.           break;
  989.  
  990.         case ID_LOADSLD:
  991.           /* List all .SLD files by default!! */
  992.           memset(&filedlg, 0, sizeof(filedlg));
  993.           filedlg.cbSize          = sizeof(filedlg);
  994.           filedlg.fl              = FDS_CENTER |FDS_OPEN_DIALOG;
  995.           filedlg.pszTitle        = "Load a .SLD (Slide) file for a slide show";
  996.           strcpy(filedlg.szFullFile,SLIDE_TEMPLATE);
  997.          if (WinFileDlg(HWND_DESKTOP, hwnd, &filedlg) && filedlg.lReturn == DID_OK) {
  998.             /* So we have a filespec... */
  999.             strcpy(SlideBuf, filedlg.szFullFile);
  1000.             bStopSlide = FALSE;
  1001.             DosReleaseMutexSem(hUpdateSem);
  1002.             DosPostEventSem(hPauseSem);
  1003.             DosPostEventSem(hStopWaitSem);
  1004.             if (_beginthread(SlideThread, NULL,
  1005.                              THREAD_STACKSIZE, (PVOID)SlideBuf)
  1006.                              == -1) {
  1007.               ShowErrors(NO_SLIDE_THREAD_RC, NULL);
  1008.             }
  1009.           }
  1010.           bReturnVal = TRUE;
  1011.           break;
  1012.  
  1013.         case ID_ABOUT:
  1014.           WinDlgBox(HWND_DESKTOP, hwnd, (PFNWP)StaticBox,
  1015.                     (HMODULE)NULL, ABOUTBOX, (PVOID)ABOUTBOX);
  1016.           bReturnVal = TRUE;
  1017.           break;
  1018.  
  1019.         case ID_FRAME_EMPTY:
  1020.           if (bFrameEmpty) {
  1021.              hwndDest = hFrame;
  1022.           } else {
  1023.              hwndDest = HWND_OBJECT;
  1024.           } /* endif */
  1025.           WinSetParent(hwndTitleBar, hwndDest, FALSE);
  1026.           WinSetParent(hwndSysMenu , hwndDest, FALSE);
  1027.           WinSetParent(hwndMinMax  , hwndDest, FALSE);
  1028.           WinSetParent(hwndAppMenu , hwndDest, FALSE);
  1029.           WinSendMsg(hFrame, WM_UPDATEFRAME, (MPARAM)FRAME_LIST, NULL);
  1030.           bFrameEmpty = !bFrameEmpty;
  1031.           bReturnVal = TRUE;
  1032.           break;
  1033.  
  1034.         case ID_SCALE_WHILE_DRAW:
  1035.           bScaleWhileDrawing = !(bScaleWhileDrawing);
  1036.           WinSendMsg(WinWindowFromID(hFrame, FID_MENU), MM_SETITEMATTR,
  1037.                      MPFROM2SHORT(ID_SCALE_WHILE_DRAW, TRUE),
  1038.                      MPFROM2SHORT(MIA_CHECKED, bScaleWhileDrawing ? 0 : MIA_CHECKED));
  1039.           /* Let's reflect this change... */
  1040.           /* First reset this so if we are sure we load the bitmap into */
  1041.           /* memory first if we are in that mode!! */
  1042.           bNewImage = TRUE;
  1043.           /* Now blank out the screen... */
  1044.           WinInvalidateRect(hFrame, (PRECTL)NULL, FALSE);
  1045.           /* Now invalidate the client area so we get a WM_PAINT message... */
  1046.           WinInvalidateRect(hwnd, (PRECTL)NULL, FALSE);
  1047.           bReturnVal = TRUE;
  1048.           break;
  1049.  
  1050.         case ID_PALETTE_MANAGEMENT:
  1051.           bPaletteManager = !(bPaletteManager);
  1052.           WinSendMsg(WinWindowFromID(hFrame, FID_MENU), MM_SETITEMATTR,
  1053.                      MPFROM2SHORT(ID_PALETTE_MANAGEMENT, TRUE),
  1054.                      MPFROM2SHORT(MIA_CHECKED, bPaletteManager ? MIA_CHECKED : 0));
  1055.           WinInvalidateRect(hwnd, (PRECTL)NULL, FALSE);
  1056.           GpiSelectPalette(hpsWindow, bPaletteManager ? hsyspal : 0);
  1057.           WinPostMsg( hClient, WM_REALIZEPALETTE, 0L, 0L );
  1058.           WinBroadcastMsg( HWND_DESKTOP, WM_REALIZEPALETTE, 0L, 0L, BMSG_POST | BMSG_DESCENDANTS);
  1059.           bReturnVal = TRUE;
  1060.           break;
  1061.  
  1062.         case ID_KEEP_PROPORTION:
  1063.           bKeepProportion = !(bKeepProportion);
  1064.           WinSendMsg(WinWindowFromID(hFrame, FID_MENU), MM_SETITEMATTR,
  1065.                      MPFROM2SHORT(ID_KEEP_PROPORTION, TRUE),
  1066.                      MPFROM2SHORT(MIA_CHECKED, bKeepProportion ? MIA_CHECKED : 0));
  1067.           WinInvalidateRect(hFrame, (PRECTL)NULL, FALSE);
  1068.           WinInvalidateRect(hwnd, (PRECTL)NULL, FALSE);
  1069.           bNewImage = TRUE;
  1070.           bReturnVal = TRUE;
  1071.           break;
  1072.  
  1073.  
  1074.         case ID_CLEAR_BITMAP:
  1075.           if (hsyspal) {
  1076.              GpiSelectPalette(hpsCurrent, 0);
  1077.              GpiSelectPalette(hpsMem, 0);
  1078.              GpiSelectPalette(hpsWindow, 0);
  1079.              GpiDeletePalette(hsyspal);
  1080.              WinRealizePalette(hClient, hpsWindow, &cclr);
  1081.              WinRealizePalette(hClient, hpsWindow, &cclr);
  1082.              WinRealizePalette(hClient, hpsWindow, &cclr);
  1083.           } /* endif */
  1084.           RemoveBitmapFromMem((PHDC)&hdcMem, (PHPS)&hpsMem, (PHBITMAP)&hbmMem);
  1085.           RemoveBitmapFromMem((PHDC)&hdcCurrent, (PHPS)&hpsCurrent,
  1086.                               (PHBITMAP)&hbmCurrent);
  1087.           /* Reset the window title text... */
  1088.           WinSetWindowText(hFrame, "Bitmap File Displayer");
  1089.           /* Clear window... */
  1090.           WinInvalidateRect(hFrame, (PRECTL)NULL, FALSE);
  1091.           bReturnVal = TRUE;
  1092.           break;
  1093.  
  1094.         case ID_RESTART:
  1095.           Direction = RESTART;
  1096.           DosPostEventSem(hStopWaitSem);
  1097.           DosPostEventSem(hPauseSem);
  1098.           break;
  1099.  
  1100.         case ID_PAUSE:
  1101.           if (Paused) {
  1102.             /* Stop pausing... */
  1103.             DosPostEventSem(hPauseSem);
  1104.           } else {
  1105.             /* Start pausing... */
  1106.             DosResetEventSem(hPauseSem,&posts);
  1107.             Paused = TRUE;
  1108.             /* Check the option... */
  1109.             WinSendMsg(WinWindowFromID(hFrame, FID_MENU),
  1110.                        MM_SETITEMATTR, MPFROM2SHORT(ID_PAUSE, TRUE),
  1111.                        MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED));
  1112.           }
  1113.           break;
  1114.  
  1115.         case ID_TERMINATE:
  1116.           if (bStopSlide == FALSE) {
  1117.             bStopSlide = TRUE;
  1118.             DosPostEventSem(hStopWaitSem);
  1119.             DosPostEventSem(hPauseSem);
  1120.           }
  1121.           break;
  1122.  
  1123.         case ID_REVERSE:
  1124.           Direction = REVERSE;
  1125.           DosPostEventSem(hStopWaitSem);
  1126.           DosPostEventSem(hPauseSem);
  1127.           break;
  1128.  
  1129.         case ID_FORWARD:
  1130.           Direction = FORWARD;
  1131.           DosPostEventSem(hStopWaitSem);
  1132.           DosPostEventSem(hPauseSem);
  1133.           break;
  1134.  
  1135.         case ID_EXIT:
  1136.           WinPostMsg( hwnd, WM_CLOSE, 0L, 0L );
  1137.           bReturnVal = TRUE;
  1138.           break;
  1139.  
  1140.         case ID_RESUME:
  1141.           bReturnVal = TRUE;
  1142.           break;
  1143.  
  1144.         case ID_HELP:
  1145.           WinDlgBox(HWND_DESKTOP, hwnd, (PFNWP)StaticBox,
  1146.                     (HMODULE)NULL, HELPBOX, (PVOID)HELPBOX);
  1147.           bReturnVal = TRUE;
  1148.           break;
  1149.  
  1150.         default:
  1151.           bReturnVal = FALSE;
  1152.           break;
  1153.       }
  1154.       break;
  1155.  
  1156.     case WM_HELP:
  1157.       WinDlgBox(HWND_DESKTOP, hwnd, (PFNWP)StaticBox,
  1158.                 (HMODULE)NULL, HELPBOX, (PVOID)HELPBOX);
  1159.       bReturnVal = TRUE;
  1160.       break;
  1161.  
  1162.     case WM_ERASEBACKGROUND:
  1163.       bReturnVal = TRUE;
  1164.       break;
  1165.  
  1166.     case WM_REALIZEPALETTE:
  1167.       if (bPaletteManager && hwnd == hClient && hsyspal) {
  1168.          if (WinRealizePalette(hwnd, hpsWindow, &cclr) > 0) {
  1169.               WinQueryWindowRect(hwnd, (PRECTL)&rc);
  1170.               WinInvalidateRect(hwnd, (PRECTL)&rc, 0);
  1171.          } /* endif */
  1172.          bReturnVal = TRUE;
  1173.       } else {
  1174.          bReturnVal = FALSE;
  1175.       } /* endif */
  1176.       break;
  1177.  
  1178.     case WM_PAINT:
  1179.       if (hbmMem) {
  1180.         DosRequestMutexSem(hUpdateSem, SEM_INDEFINITE_WAIT);
  1181.         WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP,
  1182.                                                        SPTR_WAIT, FALSE));
  1183.         /* Create a presentation space  */
  1184.         /* If we are iconic, the PS returned from BeginPaint is no good */
  1185.         /* so we will do this special processing... */
  1186.         if (WinQueryWindowULong(hFrame, QWL_STYLE) & WS_MINIMIZED) {
  1187.           bError = TRUE;
  1188.         } else {
  1189. /*          ULONG errorpos;
  1190. */
  1191.           hps = WinBeginPaint(hwnd, 0, &rc);
  1192.           WinQueryWindowRect(hwnd, (PRECTL)&rc);
  1193.           if (!GpiSetBackMix(hpsWindow, BM_OVERPAINT)
  1194.             || !GpiQueryBitmapParameters(hbmMem, (PBITMAPINFOHEADER)&bmapinfo)) {
  1195.             bError = TRUE;
  1196. #ifdef DEBUG
  1197.             printf("Error at GpiSetBackMix or GpiQueryBitmapParameters.\n");
  1198.             printf("Errorid = %x.\n",WinGetLastError(hAB));
  1199. #endif
  1200.           } else {
  1201.             /*******************************************************************/
  1202.             /* **** SOURCE **********                                          */
  1203.             /*******************************************************************/
  1204.             bmarray[2].x = 0;
  1205.             bmarray[2].y = 0;
  1206.             bmarray[3].x = bmapinfo.cx;
  1207.             bmarray[3].y = bmapinfo.cy;
  1208.  
  1209.             /*******************************************************************/
  1210.             /* **** TARGET **********                                          */
  1211.             /*******************************************************************/
  1212.  
  1213.             bmarray[0].x = rc.xLeft;
  1214.             bmarray[0].y = rc.yBottom;
  1215.             bmarray[1].x = rc.xRight;
  1216.             bmarray[1].y = rc.yTop;
  1217. #ifdef DEBUG
  1218.             printf("cx,cy=%d,%d.\n",bmapinfo.cx,bmapinfo.cy);
  1219.             printf("xLeft,xRight,yTop,yBottom=%d,%d,%d,%d.\n",rc.xLeft,rc.xRight,rc.yTop,rc.yBottom);
  1220. #endif
  1221.             if (bKeepProportion) {
  1222.                ULONG dx  = bmapinfo.cx;
  1223.                ULONG dy  = bmapinfo.cy;
  1224.                ULONG dxw = rc.xRight - rc.xLeft;
  1225.                ULONG dyw = rc.yTop - rc.yBottom;
  1226. #ifdef DEBUG
  1227.                printf("dx,dy,dxw,dyw=%d,%d,%d,%d.\n",dx,dy,dxw,dyw);
  1228. #endif
  1229.                if (dxw*dy>dx*dyw) {
  1230.                   ULONG deltax = (dxw) - (dx*dyw)/(dy);
  1231. #ifdef DEBUG
  1232.                   printf("deltax=%d.\n",deltax);
  1233. #endif
  1234.                   bmarray[0].x += deltax/2;
  1235.                   bmarray[1].x -= deltax/2;
  1236.                } else {
  1237.                   ULONG deltay = (dyw) - (dy*dxw)/(dx);
  1238. #ifdef DEBUG
  1239.                   printf("deltay=%d.\n",deltay);
  1240. #endif
  1241.                   bmarray[0].y += deltay/2;
  1242.                   bmarray[1].y -= deltay/2;
  1243.                } /* endif */
  1244.             } /* endif */
  1245.  
  1246.             if (bScaleWhileDrawing) {
  1247.               hpsForDrawing = hpsMem;
  1248.  
  1249.               /* Make sure we free any bitmaps we had in memory, in case */
  1250.               /* user just switched modes on us!!  Also, reset statics, so */
  1251.               /* if they switch modes back again, we'll be O.K.!! */
  1252.               if (hsyspal) {
  1253.                  GpiSelectPalette(hpsCurrent, 0);
  1254.               } /* endif */
  1255.               RemoveBitmapFromMem((PHDC)&hdcCurrent, (PHPS)&hpsCurrent,
  1256.                                   (PHBITMAP)&hbmCurrent);
  1257.               NewImageSize.cx = 0L;
  1258.               NewImageSize.cy = 0L;
  1259.             /* Let's adjust the bitmap's size in the memory PS, so user doesn't */
  1260.             /* see it get drawn... */
  1261.             } else if ( (NewImageSize.cx != rc.xRight)
  1262.                         || (NewImageSize.cy != rc.yTop)
  1263.                         || bNewImage ) {
  1264.               if (!bNewImage) {
  1265.                 strcpy(MsgBuf, "Re-scaling bitmap, one moment please...");
  1266.  
  1267.                 GpiQueryFontMetrics(hpsWindow, (LONG)sizeof(FONTMETRICS),
  1268.                                     (PFONTMETRICS)&FontBuf);
  1269.  
  1270.                 CharHeight = LOUSHORT(FontBuf.lMaxBaselineExt);
  1271.                 PointStruct.x = 0L;
  1272.                 PointStruct.y = rc.yTop - CharHeight;
  1273.                 GpiCharStringAt(hpsWindow, (PPOINTL)&PointStruct,
  1274.                                 (LONG)strlen(MsgBuf), (PCH)MsgBuf);
  1275.               }
  1276.               NewImageSize.cx = rc.xRight;
  1277.               NewImageSize.cy = rc.yTop;
  1278.  
  1279.               if (!hdcCurrent) {
  1280.                 hdcCurrent = DevOpenDC(hAB, OD_MEMORY, "*", 8L,
  1281.                                     (PDEVOPENDATA) dcdatablk, hdcScreen);
  1282.               }
  1283.  
  1284.               if (!hpsCurrent) {
  1285.                 hpsCurrent = GpiCreatePS(hAB, hdcCurrent, (PSIZEL)&NewImageSize,
  1286.                                       (LONG) PU_PELS | GPIT_NORMAL | GPIA_ASSOC);
  1287.               }
  1288.  
  1289.               bmapinfo.cx = (USHORT)NewImageSize.cx;
  1290.               bmapinfo.cy = (USHORT)NewImageSize.cy;
  1291.  
  1292.               if (!hdcCurrent || !hpsCurrent) {
  1293.                 bError = TRUE;
  1294. #ifdef DEBUG
  1295.                 printf("Error, hdcCurrent or hpsCurrent is NULL!.\n");
  1296. #endif
  1297.               } else {
  1298.                 if (hsyspal) {
  1299.                    GpiSelectPalette(hpsCurrent, hsyspal);
  1300.                 } /* endif */
  1301.                 /* Remove the old bitmap, so we can create a new one with the */
  1302.                 /* proper dimensions... */
  1303.                 /* NOTE:  Don't use our bitmap remover function, because we */
  1304.                 /*        want to keep the hps!! */
  1305.                 GpiSetBitmap (hpsCurrent, (HBITMAP)NULL);
  1306.                 GpiDeleteBitmap(hbmCurrent);
  1307.                 hbmCurrent = GpiCreateBitmap(hpsCurrent, (PBITMAPINFOHEADER2)&bmapinfo,
  1308.                                           (ULONG)0, (PBYTE)NULL, (PBITMAPINFO2)NULL);
  1309.                 if ( (GpiSetBitmap(hpsCurrent, hbmCurrent) == HBM_ERROR)
  1310.                      || (GpiBitBlt(hpsCurrent, hpsMem, 4L, (PPOINTL)bmarray,
  1311.                                    (LONG) ROP_SRCCOPY,
  1312.                                    (LONG) BBO_IGNORE) == GPI_ERROR) ) {
  1313.                   bError = TRUE;
  1314. #ifdef DEBUG
  1315.                   printf("Error from GpiSetBitmap or GpiBitBlt.\n");
  1316.                   printf("Errorid = %x.\n",WinGetLastError(hAB));
  1317. #endif
  1318.                 } else {
  1319.                   /* Now reset the array... */
  1320.                      bmarray[0].x = rc.xLeft;
  1321.                      bmarray[0].y = rc.yBottom;
  1322.                      bmarray[1].x = rc.xRight;
  1323.                      bmarray[1].y = rc.yTop;
  1324.                   bmarray[3].x = rc.xRight;
  1325.                   bmarray[3].y = rc.yTop;
  1326.  
  1327.                   hpsForDrawing = hpsCurrent;
  1328.                 }
  1329.               }
  1330.             } else {
  1331.               hpsForDrawing = hpsCurrent;
  1332.               /* Reset the array... */
  1333.                  bmarray[0].x = rc.xLeft;
  1334.                  bmarray[0].y = rc.yBottom;
  1335.                  bmarray[1].x = rc.xRight;
  1336.                  bmarray[1].y = rc.yTop;
  1337.               bmarray[3].x = rc.xRight;
  1338.               bmarray[3].y = rc.yTop;
  1339.             }
  1340.             if (bPaletteManager && bNewPalette) {
  1341.                WinPostMsg(hClient, WM_REALIZEPALETTE, 0, 0);
  1342.                WinBroadcastMsg( HWND_DESKTOP, WM_REALIZEPALETTE, 0L, 0L, BMSG_POST | BMSG_DESCENDANTS);
  1343.                WinRealizePalette(hClient, hpsWindow, &cclr);
  1344.                bNewPalette = FALSE;
  1345.             } /* endif */
  1346.  
  1347.             /* Now put it to screen... */
  1348.             if (bBW) {
  1349.                GpiSetBackColor(hpsWindow, 0);
  1350.                GpiSetColor(hpsWindow, 1);
  1351.             } /* endif */
  1352.             if (bKeepProportion && bScaleWhileDrawing) {
  1353.                if (!bPaletteManager) {
  1354.                   GpiCreateLogColorTable(hpsWindow, LCOL_RESET, LCOLF_RGB, 0, 0, NULL);
  1355.                } /* endif */
  1356.                WinFillRect(hpsWindow, &rc, bPaletteManager ? 0 : backcolor);
  1357.             } /* endif */
  1358.             if (GpiBitBlt(hpsWindow, hpsForDrawing, 4L, (PPOINTL)bmarray,
  1359.                           (LONG) ROP_SRCCOPY, (LONG) BBO_IGNORE) == GPI_ERROR) {
  1360.               bError = TRUE;
  1361. #ifdef DEBUG
  1362.               printf("Error from GpiBitBlt.\n");
  1363.               printf("Errorid = %x.\n",WinGetLastError(hAB));
  1364. #endif
  1365.             }
  1366.             if (bBW) {
  1367.                GpiSetColor(hpsWindow, CLR_BLACK);
  1368.                GpiSetBackColor(hpsWindow, CLR_WHITE);
  1369.             } /* endif */
  1370.  
  1371.             bNewImage = FALSE;
  1372.  
  1373.           }
  1374.           if (bError) {
  1375.             WinAlarm(HWND_DESKTOP, WA_WARNING);
  1376.  
  1377.             strcpy(MsgBuf, "An error occured while trying to draw bitmap (probably out of memory).");
  1378.             GpiQueryFontMetrics(hpsWindow, (LONG)sizeof(FONTMETRICS),
  1379.                                 (PFONTMETRICS)&FontBuf);
  1380.  
  1381.             CharHeight = LOUSHORT(FontBuf.lMaxBaselineExt);
  1382.             PointStruct.x = 0L;
  1383.             PointStruct.y = rc.yTop - CharHeight;
  1384.             GpiCharStringAt(hpsWindow, (PPOINTL)&PointStruct,
  1385.                             (LONG)strlen(MsgBuf), (PCH)MsgBuf);
  1386.             if (!bScaleWhileDrawing) {
  1387.               strcpy(MsgBuf, "Try not keeping the scaled image in memory (\"Drawing\" pulldown).");
  1388.               PointStruct.x = 0L;
  1389.               PointStruct.y = rc.yTop - (2 * CharHeight);
  1390.               GpiCharStringAt(hpsWindow, (PPOINTL)&PointStruct,
  1391.                               (LONG)strlen(MsgBuf), (PCH)MsgBuf);
  1392.             }
  1393.           }
  1394.           WinEndPaint(hps);                     /* Drawing is complete   */
  1395.           bReturnVal = TRUE;
  1396.         }
  1397.         DosReleaseMutexSem(hUpdateSem);
  1398.         /* Restore the pointer... */
  1399.         WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP,
  1400.                                                        SPTR_ARROW, FALSE));
  1401.       } else {
  1402.         bReturnVal = FALSE;
  1403.       }
  1404.       break;
  1405.  
  1406. case WM_CLOSE:
  1407.       if (bPaletteManager) {
  1408.           GpiSelectPalette(hpsWindow, 0);
  1409.           WinRealizePalette(hClient, hpsWindow, &cclr);
  1410.           WinRealizePalette(hClient, hpsWindow, &cclr);
  1411.           WinRealizePalette(hClient, hpsWindow, &cclr);
  1412.       } /* endif */
  1413.       WinPostMsg( hwnd, WM_QUIT, 0L, 0L );  /* Cause termination        */
  1414.       bReturnVal = TRUE;
  1415.       break;
  1416.  
  1417.     default:
  1418.       bReturnVal = FALSE;
  1419.   }
  1420.   if (bReturnVal) {
  1421.     return((MRESULT)bReturnVal);
  1422.   } else {
  1423.     return(WinDefWindowProc(hwnd, msg, mp1, mp2));
  1424.   }
  1425. }
  1426.  
  1427.  
  1428.  
  1429. #if 0
  1430. /*****************************************************************************/
  1431. /*  Abstract for function: FilterProc()                                      */
  1432. /*    This function is needed so we get PAINT messages when iconic so we     */
  1433. /*    can repaint ourselves properly when iconic.                            */
  1434. /*****************************************************************************/
  1435. MRESULT EXPENTRY FilterProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  1436. {
  1437.   if ( (msg == WM_PAINT)
  1438.        && (WinQueryWindowULong(hwnd, QWL_STYLE) & WS_MINIMIZED) ) {
  1439.     /* If we don't paint it, let the frame paint it! */
  1440.     if (WinSendMsg(hClient, WM_PAINT, (MPARAM)NULL, (MPARAM)NULL)) {
  1441.       /* If we don't return this, we go into an endless WM_PAINT loop!! */
  1442.       return(WinDefWindowProc(hwnd, msg, mp1, mp2));
  1443.     }
  1444.   }
  1445.   return (*pFrameWndProc)(hwnd, msg, mp1, mp2);
  1446. }
  1447. #endif
  1448.  
  1449.  
  1450. /* These flags are used for the "OpenMode" parameter of the DosOpen() call. */
  1451. #define OM_DASD              0x8000
  1452. #define OM_WRITETHROUGH      0x4000
  1453. #define OM_FAILERRORS        0x2000
  1454. #define OM_INHERITFLAG       0x0080
  1455. #define OM_SHARE_DENYRW      0x0010   /* Deny read/write access.             */
  1456. #define OM_SHARE_DENYWR      0x0020   /* Deny write access.                  */
  1457. #define OM_SHARE_DENYRD      0x0030   /* Deny read access.                   */
  1458. #define OM_SHARE_DENYNO      0x0040   /* Deny none.                          */
  1459. #define OM_ACCESS_RD         0x0000   /* Read only access.                   */
  1460. #define OM_ACCESS_WR         0x0001   /* Write only access.                  */
  1461. #define OM_ACCESS_RW         0x0002   /* Read/write access.                  */
  1462.  
  1463.  
  1464. /*...sLoadBitmap:0:*/
  1465. ULONG LoadBitmap(CHAR *szFn, CHAR *szOpt, GBM *pgbm, GBMRGB *pgbmrgb, BYTE **ppbData)
  1466. {
  1467.    GBM_ERR rc;
  1468.    int fd, ft;
  1469.    ULONG cb;
  1470.    USHORT usStride;
  1471.    PSZ pszFn = malloc(strlen(szFn)+10);
  1472.    PSZ pOpts;
  1473.  
  1474.    if (!pszFn) {
  1475.       return (ULONG)GBM_ERR_MEM;
  1476.    } /* endif */
  1477.    strcpy(pszFn, szFn);
  1478.    if (pOpts = strchr(pszFn, ',')) {
  1479.       *pOpts++ = '\0';
  1480.    } else {
  1481.       pOpts = pOptions;
  1482.    } /* endif */
  1483.    if ( (rc = gbm_guess_filetype(pszFn, &ft)) != GBM_ERR_OK ) {
  1484. #ifdef DEBUG
  1485.       printf("Error %u from gbm_guess_filetype. Filename is %s\n", rc, pszFn);
  1486. #endif
  1487.       rc = GBM_ERR_NOT_SUPP;
  1488.    } else if ( (fd = open(pszFn, O_RDONLY | O_BINARY)) == -1 ) {
  1489.       rc = GBM_ERR_NOT_FOUND;
  1490. #ifdef DEBUG
  1491.       printf("GBM_ERR_NOT_FOUND\n");
  1492. #endif
  1493.    } else {
  1494.       if ( (rc = gbm_read_header(pszFn, fd, ft, pgbm, pOpts)) != GBM_ERR_OK ) {
  1495. #ifdef DEBUG
  1496.          printf("Error %u from gbm_read_header.\n", rc);
  1497. #endif
  1498.          rc = GBM_ERR_READ;
  1499.       } else if ( (rc = gbm_read_palette(fd, ft, pgbm, pgbmrgb)) != GBM_ERR_OK ) {
  1500. #ifdef DEBUG
  1501.          printf("Error %u from gbm_read_palette.\n", rc);
  1502. #endif
  1503.          rc = GBM_ERR_READ;
  1504.       } else {
  1505.          usStride = ((pgbm -> w * pgbm -> bpp + 31)/32) * 4;
  1506.          cb = pgbm -> h * usStride;
  1507.          if ( (*ppbData = malloc((int) cb)) == NULL ) {
  1508.             rc = GBM_ERR_MEM;
  1509. #ifdef DEBUG
  1510.             printf("Error allocating memory, size = %u.\n", cb);
  1511. #endif
  1512.          } else if ( (rc = gbm_read_data(fd, ft, pgbm, *ppbData)) != GBM_ERR_OK ) {
  1513. #ifdef DEBUG
  1514.             printf("Error %u from gbm_read_data.\n", rc);
  1515. #endif
  1516.             free(*ppbData);
  1517.             rc = GBM_ERR_READ;
  1518.          } /* endif */
  1519.       } /* endif */
  1520.       close(fd);
  1521.    } /* endif */
  1522.    free(pszFn);
  1523.    return (ULONG)rc;
  1524. }
  1525.  
  1526.  
  1527.  
  1528. ULONG LoadBitmapFile(PSZ lpFileName, PHAB phAB, PHDC phdcMem,
  1529.                       PHPS phpsMem, PHBITMAP phbmMem,
  1530.                       BOOL bShowWaitPointer)
  1531. {
  1532.   SIZEL             ImageSize        ;
  1533.   ULONG             ReturnVal   = 0  ;
  1534.   HPAL              hpal             ;
  1535.   UCHAR             path[256]        ;
  1536.   PUCHAR            pdir             ;
  1537.   GBM gbm;
  1538.   GBMRGB gbmrgb [0x100];
  1539.   BYTE *pbData;
  1540.  
  1541. static ULONG errtab[9] = {
  1542.    0, LBF_ERROR_ALLOC_MEM_RC, LBF_ERROR_CREATING_BMP_RC, LBF_ERROR_CREATING_BMP_RC,
  1543.    LBF_COULDNT_OPEN_FILE_RC, LBF_ERROR_CREATING_BMP_RC, LBF_ERROR_CREATING_BMP_RC,
  1544.    LBF_ERROR_CREATING_BMP_RC, LBF_ERROR_CREATING_BMP_RC
  1545. };
  1546.  
  1547.   if (bShowWaitPointer) {
  1548.     WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP,
  1549.                                                    SPTR_WAIT, FALSE));
  1550.   }
  1551.  
  1552.   /* First remove all leading and trailing white space, or this call */
  1553.   /* will fail!! */
  1554.   RemoveWhiteSpace(lpFileName);
  1555.  
  1556.   if (!(ReturnVal = errtab[LoadBitmap(lpFileName, "", &gbm, gbmrgb, &pbData)])) {
  1557.      struct {
  1558.         BITMAPINFOHEADER2 bmp2;
  1559.         RGB2              rgb[0x100];
  1560.      } bm;
  1561.      ULONG cRGB;
  1562.      ULONG ulCol;
  1563.  
  1564.      memset(&bm, 0, sizeof(bm));
  1565.      bm.bmp2.cbFix     = sizeof(BITMAPINFOHEADER2);
  1566.      bm.bmp2.cx        = gbm.w;
  1567.      bm.bmp2.cy        = gbm.h;
  1568.      bm.bmp2.cBitCount = gbm.bpp;
  1569.      bm.bmp2.cPlanes   = 1;
  1570.      cRGB = ( (1 << gbm.bpp) & 0x1ff );
  1571.              /* 1 -> 2, 4 -> 16, 8 -> 256, 24 -> 0 */
  1572.  
  1573.      if (cRGB && cRGB<257) {
  1574.         for ( ulCol = 0; ulCol < cRGB; ulCol++ ) {
  1575.            bm.rgb[ulCol].bRed   = gbmrgb [ulCol].r;
  1576.            bm.rgb[ulCol].bGreen = gbmrgb [ulCol].g;
  1577.            bm.rgb[ulCol].bBlue  = gbmrgb [ulCol].b;
  1578.         } /* endfor */
  1579.         backcolor = *(PULONG)&bm.rgb[0];
  1580.         forecolor = *(PULONG)&bm.rgb[1];
  1581.      } else {
  1582.         backcolor = 0;
  1583.      } /* endif */
  1584.      bBW = (bm.bmp2.cBitCount == 1);
  1585.      if (bPaletteSupport && cRGB && cRGB<257) {
  1586.         hpal = GpiCreatePalette(hAB, 0, LCOLF_CONSECRGB, cRGB, (PULONG)&(bm.rgb));
  1587.      } else {
  1588.         hpal = 0;
  1589.      } /* endif */
  1590.      GpiSelectPalette(hpsCurrent, hpal);
  1591.      if (hsyspal) {
  1592.         GpiSelectPalette(*phpsMem, 0);
  1593.         GpiSelectPalette(hpsWindow, 0);
  1594.         GpiDeletePalette(hsyspal);
  1595.         hsyspal = 0;
  1596.      } /* endif */
  1597.      hsyspal = hpal;
  1598.      /* Make sure no old bitmaps are laying around!! */
  1599.      RemoveBitmapFromMem(phdcMem, phpsMem, phbmMem);
  1600.  
  1601.      *phdcMem  = DevOpenDC(*phAB, OD_MEMORY, "*", 8L,
  1602.                            (PDEVOPENDATA)dcdatablk, hdcScreen);
  1603. /*
  1604.      if (!*phdcMem) {
  1605.        ERRORID error = WinGetLastError(*phAB);
  1606.      }
  1607. */
  1608.      ImageSize.cx = 0;
  1609.      ImageSize.cy = 0;
  1610.      *phpsMem  = GpiCreatePS(*phAB, *phdcMem, (PSIZEL)&ImageSize,
  1611.                              (LONG) PU_PELS | GPIT_NORMAL | GPIA_ASSOC);
  1612.  
  1613.      if (hpal) {
  1614.         GpiSelectPalette(*phpsMem, hpal);
  1615.      } /* endif */
  1616.  
  1617.      *phbmMem  = GpiCreateBitmap(*phpsMem, (PBITMAPINFOHEADER2)&(bm.bmp2),
  1618.                                  (ULONG)CBM_INIT, (PSZ)pbData,
  1619.                                  (PBITMAPINFO2)&(bm.bmp2));
  1620.  
  1621.      if (!(*phdcMem && *phpsMem && *phbmMem)) {
  1622.        ReturnVal = LBF_ERROR_CREATING_BMP_RC;
  1623. #ifdef DEBUG
  1624.        printf("Error creating bitmap, hdc=%u, hps=%u, hbm=%u.\n",*phdcMem, *phpsMem, *phbmMem);
  1625. #endif
  1626.        RemoveBitmapFromMem(phdcMem, phpsMem, phbmMem);
  1627.      } else {
  1628.        BITMAPINFOHEADER2 bminfo;
  1629.  
  1630.        GpiSetBitmap(*phpsMem, *phbmMem);
  1631.        bminfo.cbFix = sizeof(bminfo);
  1632.        GpiQueryBitmapInfoHeader(*phbmMem, &bminfo);
  1633.        GlobalBitCount = bminfo.cBitCount;
  1634.        Globalx = bminfo.cx;
  1635.        Globaly = bminfo.cy;
  1636.      }
  1637.      GpiSelectPalette(hpsWindow, bPaletteManager ? hpal : 0);
  1638.      bNewPalette = TRUE;
  1639.  
  1640.      free(pbData);
  1641.   } /* endif */
  1642.  
  1643.   if (bShowWaitPointer) {
  1644.     WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP,
  1645.                                                    SPTR_ARROW, FALSE));
  1646.   }
  1647.   if (ReturnVal) {
  1648.      ShowErrors(ReturnVal,NULL);
  1649.   } else {
  1650.      if (lpFileName[1] == ':') {
  1651.         DosSetDefaultDisk(1+toupper(lpFileName[0])-'A');
  1652.         lpFileName += 2;
  1653.      } /* endif */
  1654.      strcpy(path,lpFileName);
  1655.      if (pdir = strrchr(path,'\\')) {
  1656.         *pdir = '\0';
  1657.         DosSetCurrentDir(path);
  1658.      } /* endif */
  1659.   } /* endif */
  1660.   return(ReturnVal);
  1661. }
  1662.  
  1663.  
  1664.  
  1665. /*****************************************************************************/
  1666. /*  Abstract for function: RemoveWhiteSpace()                                */
  1667. /*    This function will strip all leading and trailing whitespace from a    */
  1668. /*    string.  It uses no "C" routines so that it can be used without        */
  1669. /*    regard to memory model or multi-threaded/DLL problems.                 */
  1670. /*****************************************************************************/
  1671. VOID RemoveWhiteSpace(PSZ lpString)
  1672. {
  1673.   register ULONG i;
  1674.   register ULONG j;
  1675.   ULONG NumToShift;
  1676.  
  1677.   /* Don't use "C" routines in case someone wants to use this with small */
  1678.   /* or medium-model runtime libraries... */
  1679.   /* First remove trailing whitespace... */
  1680.   for (i = 0; lpString[i]; ) i++;
  1681.   for(;(i && (lpString[i - 1] == ' ')); i--) {
  1682.     lpString[i - 1] = '\0';
  1683.   }
  1684.  
  1685.   /* Now remove leading whitespace... */
  1686.   for (j = 0; lpString[j] && (lpString[j] == ' '); ) j++;
  1687.   /* Now just "shift" the string over by the appropriate amount... */
  1688.   if (NumToShift = i - j) {
  1689.     for (i = 0; i < NumToShift; i++, j++) {
  1690.       lpString[i] = lpString[j];
  1691.     }
  1692.     /* Now null-terminate */
  1693.     lpString[i] = '\0';
  1694.   }
  1695. }
  1696.  
  1697.  
  1698. /*****************************************************************************/
  1699. /*  Abstract: RemoveBitmapFromMem()                                          */
  1700. /*    This function totally frees the bitmap, presentation space, and        */
  1701. /*    device context, and then sets all of the pointers to these items to    */
  1702. /*    NULL.                                                                  */
  1703. /*****************************************************************************/
  1704. void RemoveBitmapFromMem(PHDC phdc, PHPS phps, PHBITMAP phbm)
  1705. {
  1706.   if (phbm) {
  1707.     if (phps && *phps) {
  1708.         /* Remove old bitmap... */
  1709.         GpiSetBitmap (*phps, (HBITMAP)NULL);
  1710.     }
  1711.     if (*phbm) {
  1712.       GpiDeleteBitmap(*phbm);
  1713.     }
  1714.  
  1715.     /* Free up the PS... */
  1716.     if (phps) {
  1717.       if (*phps) {
  1718.         GpiAssociate(*phps, (HDC)NULL);
  1719.         GpiDestroyPS(*phps);
  1720.       }
  1721.       *phps = (HPS)NULL;
  1722.     }
  1723.     *phbm = (HBITMAP)NULL;
  1724.   } else if (phps) {
  1725.     if (*phps) {
  1726.       /* Remove old bitmap... */
  1727.       GpiSetBitmap (*phps, (HBITMAP)NULL);
  1728.       /* Free up the PS... */
  1729.       GpiAssociate(*phps, (HDC)NULL);
  1730.       GpiDestroyPS(*phps);
  1731.     }
  1732.     *phps = (HPS)NULL;
  1733.   }
  1734.  
  1735.   if (phdc) {
  1736.     if (*phdc) {
  1737.       /* Remove old DC... */
  1738.       DevCloseDC(*phdc);
  1739.     }
  1740.     *phdc = (HDC)NULL;
  1741.   }
  1742. }
  1743.  
  1744.  
  1745. /*****************************************************************************/
  1746. /*  Abstract: AddToSwitchList()                                              */
  1747. /*    This function adds a program entry of text "pEntryText into the        */
  1748. /*    Task Manger's "switch list"                                            */
  1749. /*****************************************************************************/
  1750. HSWITCH AddToSwitchList(HWND hSomeWnd, HWND hIcon, UCHAR *pEntryText)
  1751. {
  1752.   SWCNTRL SwitchStruct;
  1753.   PID SomeWndPID;
  1754.   TID SomeWndTID;
  1755.  
  1756.   WinQueryWindowProcess(hSomeWnd, &SomeWndPID, &SomeWndTID);
  1757.  
  1758.   SwitchStruct.hwnd = hSomeWnd;
  1759.   SwitchStruct.hwndIcon = hIcon;
  1760.   SwitchStruct.hprog = (HPROGRAM)0L;
  1761.   SwitchStruct.idProcess = SomeWndPID;
  1762.   SwitchStruct.idSession = 0;
  1763.   SwitchStruct.uchVisibility = SWL_VISIBLE;
  1764.   SwitchStruct.fbJump = SWL_JUMPABLE;
  1765. /*  SwitchStruct.fReserved = 0;*/
  1766.   strncpy(SwitchStruct.szSwtitle, pEntryText,
  1767.          sizeof(SwitchStruct.szSwtitle) - 1);
  1768.   return(WinAddSwitchEntry((PSWCNTRL)&SwitchStruct));
  1769. }
  1770.  
  1771.  
  1772.       #define max(a,b) (((a) > (b)) ? (a) : (b))
  1773. /*****************************************************************************/
  1774. /*  Abstract: ResetWindowText()                                              */
  1775. /*    This function will extract the filename from the file/path spec,       */
  1776. /*    convert it to uppercase, and put it in hWnd's title bar.               */
  1777. /*****************************************************************************/
  1778. void ResetWindowText(HWND hWnd, UCHAR *pTextString, ULONG usNumberOfColors, ULONG x, ULONG y)
  1779. {
  1780.   UCHAR *pTemp;
  1781.   UCHAR TitleBuf[150];
  1782.  
  1783. #ifdef DEBUG
  1784.   printf("Entering ResetWindowText with hwnd=%x.\n", hWnd);
  1785. #endif
  1786.   pTemp = (PUCHAR)max(strrchr(pTextString, ':'), strrchr(pTextString, '\\'));
  1787.   if (pTemp) {
  1788.     pTemp++;
  1789.   } else {
  1790.     pTemp = pTextString;
  1791.   }
  1792.   strcpy(TitleBuf, pTemp);
  1793.   strupr(TitleBuf);
  1794.   strcat(TitleBuf, " - ");
  1795.   itoa(x, &TitleBuf[strlen(TitleBuf)], 10);
  1796.   strcat(TitleBuf, "x");
  1797.   itoa(y, &TitleBuf[strlen(TitleBuf)], 10);
  1798.   strcat(TitleBuf, "x");
  1799.   /* Convert number of bits to number of colors... */
  1800. /*  colors = 1 << usNumberOfColors;*/
  1801.   if (1 == usNumberOfColors) {
  1802.      strcat(TitleBuf,"2 colors");
  1803.   } else if (4 == usNumberOfColors) {
  1804.      strcat(TitleBuf,"16 colors");
  1805.   } else if (8 == usNumberOfColors) {
  1806.      strcat(TitleBuf,"256 colors");
  1807.   } else if (24 == usNumberOfColors) {
  1808.      strcat(TitleBuf," 24 bit color");
  1809.   } else {
  1810.      strcat(TitleBuf,"unknown colors");
  1811.   } /* endif */
  1812. /*  strcat(TitleBuf, " colors"); */
  1813. /*  itoa(colors, &TitleBuf[strlen(TitleBuf)], 10);*/
  1814.   WinSetWindowText(hWnd, TitleBuf);
  1815. }
  1816.  
  1817.  
  1818. void ShowErrors(ULONG ErrorCode, PSZ lpString)
  1819. {
  1820.   UCHAR MsgBuf[100];
  1821.   PSZ lpTemp;
  1822.  
  1823.   if (!lpString && !WinLoadMessage((HAB)NULL, (HMODULE)NULL, ErrorCode,
  1824.                                    sizeof(MsgBuf), MsgBuf)) {
  1825.     strcpy(MsgBuf, "Message not available.");
  1826.   } else if (lpString) {
  1827.     lpTemp = lpString;
  1828.   } else {
  1829.     lpTemp = MsgBuf;
  1830.   }
  1831.  
  1832.   WinAlarm(HWND_DESKTOP, WA_WARNING);
  1833.   if (!bIgnoreErrors && MBID_ERROR ==
  1834.            WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, lpTemp, "Bitmap Displayer Error!", 0,
  1835.                          MB_OK | MB_CUAWARNING | MB_MOVEABLE) ) {
  1836.      WinGetLastError(hAB);
  1837.   } /* endif */
  1838. }
  1839.  
  1840.  
  1841. /*****************************************************************************/
  1842. /*  Abstract: StaticBox()                                                    */
  1843. /*    This function is used to control DlgBoxes that only display static     */
  1844. /*    text and have just an "Ok" button.                                     */
  1845. /*                                                                           */
  1846. /*    Currently its associated DlgBoxes have the resource IDs of:            */
  1847. /*    ABOUTBOX and VALIDPARAMS.                                              */
  1848. /*****************************************************************************/
  1849. BOOL EXPENTRY StaticBox(HWND hDlg, ULONG Message, MPARAM mp1, MPARAM mp2)
  1850. {
  1851.   HWND hTempWnd;
  1852.  
  1853.   if (Message == WM_COMMAND) {
  1854.     WinDismissDlg(hDlg, TRUE);
  1855.     return(TRUE);
  1856.   } else if (Message == WM_CLOSE) {
  1857.     /* Tell ourselves to leave... */
  1858.     WinPostMsg(hDlg, WM_COMMAND, (MPARAM)DID_CANCEL, (MPARAM)0);
  1859.     return(TRUE);
  1860.   } else if (Message == WM_INITDLG) {
  1861.     if (mp2 == MPFROMSHORT(HELPBOX)) {
  1862.       /* Adjust the system pulldown to be more suitable for this DialogBox... */
  1863.       hTempWnd = WinWindowFromID(hDlg, FID_SYSMENU);
  1864.       WinSendMsg(hTempWnd, MM_REMOVEITEM, MPFROM2SHORT(SC_RESTORE, TRUE),
  1865.                  (MPARAM)NULL);
  1866.       WinSendMsg(hTempWnd, MM_REMOVEITEM, MPFROM2SHORT(SC_RESTORE, TRUE),
  1867.                  (MPARAM)NULL);
  1868.       WinSendMsg(hTempWnd, MM_REMOVEITEM, MPFROM2SHORT(SC_SIZE, TRUE),
  1869.                  (MPARAM)NULL);
  1870.       WinSendMsg(hTempWnd, MM_REMOVEITEM, MPFROM2SHORT(SC_MINIMIZE, TRUE),
  1871.                  (MPARAM)NULL);
  1872.       WinSendMsg(hTempWnd, MM_REMOVEITEM, MPFROM2SHORT(SC_MAXIMIZE, TRUE),
  1873.                  (MPARAM)NULL);
  1874.       /* Now change the "Close" item to be "Cancel"... */
  1875.       WinSendMsg(hTempWnd, MM_SETITEMTEXT, (MPARAM)SC_CLOSE,
  1876.                  MPFROMP("~Cancel\tAlt+F4"));
  1877.     }
  1878.     /* Make sure that the button we want starts off with the focus! */
  1879.     /* This isn't too bad, since under PM we have to give the dialogbox */
  1880.     /* the focus explicitly anyway, so just give the focus to control */
  1881.     /* instead! */
  1882.     WinSetFocus(HWND_DESKTOP, WinWindowFromID(hDlg, DID_OK));
  1883.     return(TRUE);
  1884.   } else {
  1885.     return((BOOL)SHORT1FROMMR(WinDefDlgProc(hDlg, Message, mp1, mp2)));
  1886.   }
  1887. }
  1888.  
  1889.  
  1890.  
  1891. /*****************************************************************************/
  1892. /*  Abstract for function: PutFileInLList()                                  */
  1893. /*    This function will put all *pertinent* lines from the .SLD (slide)     */
  1894. /*    file into a circularly linked list, and return a pointer to the        */
  1895. /*    head node of the list.  If there are no items or an error occurs,      */
  1896. /*    the return value will be NULL.                                         */
  1897. /*                                                                           */
  1898. /*    Use the FreeLList() function to delete the entire list.                */
  1899. /*****************************************************************************/
  1900. PLINKNODE PutFileInLList(FILE *hFile)
  1901. {
  1902.   register int TempShort;
  1903.   UCHAR LineBuf[260];
  1904.   PLINKNODE pHeadNode = (PLINKNODE)NULL;
  1905.   PLINKNODE pCurrNode;
  1906.  
  1907.   while (fgets(LineBuf, sizeof(LineBuf), hFile)) {
  1908.     if (LineBuf[0] != ';')  /* If comment line, skip it! */ {
  1909.       /* So we must have a valid path returned to us in */
  1910.       /* LineBuf!! */
  1911.       /* Remove trailing CR... */
  1912.       TempShort = strlen(LineBuf);
  1913.       if (TempShort) {
  1914.         if ( (LineBuf[TempShort - 1] == 0x0D)
  1915.           || (LineBuf[TempShort - 1] == 0x0A) ) {
  1916.           LineBuf[TempShort - 1] = '\0';
  1917.         }
  1918.       }
  1919.       /* Do this in case the line consists of all whitespace!! */
  1920.       RemoveWhiteSpace(LineBuf);
  1921.       if (LineBuf[0])  /* If blank line, skip it! */ {
  1922.         pCurrNode = calloc(1, sizeof(LINKNODE));
  1923.         pCurrNode->pString = malloc((strlen(LineBuf) + 1));
  1924.         strcpy(pCurrNode->pString, LineBuf);
  1925.         if (pHeadNode) {
  1926.           pCurrNode->pNext = pHeadNode;
  1927.           pCurrNode->pPrev = pHeadNode->pPrev;
  1928.           pCurrNode->pPrev->pNext = pCurrNode;
  1929.           pHeadNode->pPrev = pCurrNode;
  1930.           if (!pHeadNode->pNext) {
  1931.             pHeadNode->pNext = pCurrNode;
  1932.           }
  1933.         } else {
  1934.           pHeadNode = pCurrNode;
  1935.           pHeadNode->pPrev = pHeadNode;
  1936.         }
  1937.       }
  1938.     }
  1939.   }
  1940.   return(pHeadNode);
  1941. }
  1942.  
  1943.  
  1944. /*****************************************************************************/
  1945. /*  Abstract for function: FreeLList()                                       */
  1946. /*    This function will free the memory associated with this entire linked  */
  1947. /*    list structure.                                                        */
  1948. /*****************************************************************************/
  1949. VOID FreeLList(PLINKNODE pHeadNode)
  1950. {
  1951.   PLINKNODE pFreeNode;
  1952.  
  1953.   while (pHeadNode) {
  1954.     if (pHeadNode->pNext == pHeadNode) {
  1955.       free(pHeadNode->pString);
  1956.       free(pHeadNode);
  1957.       pHeadNode = (PLINKNODE)NULL;
  1958.     } else {
  1959.       pFreeNode = pHeadNode->pNext;  /* This is the one we'll be freeing.    */
  1960.       pHeadNode->pNext = pFreeNode->pNext;
  1961.       free(pFreeNode->pString);
  1962.       free(pFreeNode);
  1963.     }
  1964.   }
  1965. }
  1966.  
  1967.  
  1968. /*****************************************************************************/
  1969. /*  Abstract for function: FixupMenus()                                      */
  1970. /*    This function will set up the pulldown menus for the slide show, by    */
  1971. /*    disabling menus, etc., and then will restore them once the slide show  */
  1972. /*    is over.                                                               */
  1973. /*                                                                           */
  1974. /*    This function will return a handle to the specified window's menu.     */
  1975. /*****************************************************************************/
  1976. HWND FixupMenus(HWND hMenuOwner, BOOL bStartShow)
  1977. {
  1978.   HWND hMenu;
  1979.   USHORT FileAttrib;
  1980.   USHORT SlideAttrib;
  1981.  
  1982.   hMenu = WinWindowFromID(hMenuOwner, FID_MENU);
  1983.   if (bStartShow) {
  1984.     FileAttrib = MIA_DISABLED;
  1985.     SlideAttrib = 0;
  1986.   } else {
  1987.     FileAttrib = 0;
  1988.     SlideAttrib = MIA_DISABLED;
  1989.   }
  1990.  
  1991.   WinSendMsg(hMenu, MM_SETITEMATTR, MPFROM2SHORT(ID_LOADFILE, TRUE),
  1992.              MPFROM2SHORT(MIA_DISABLED, FileAttrib));
  1993.   WinSendMsg(hMenu, MM_SETITEMATTR, MPFROM2SHORT(ID_LOADSLD, TRUE),
  1994.              MPFROM2SHORT(MIA_DISABLED, FileAttrib));
  1995.   WinSendMsg(hMenu, MM_SETITEMATTR, MPFROM2SHORT(ID_RESTART,  TRUE),
  1996.              MPFROM2SHORT(MIA_DISABLED, SlideAttrib));
  1997.   WinSendMsg(hMenu, MM_SETITEMATTR, MPFROM2SHORT(ID_PAUSE,  TRUE),
  1998.              MPFROM2SHORT(MIA_DISABLED, SlideAttrib));
  1999.   WinSendMsg(hMenu, MM_SETITEMATTR, MPFROM2SHORT(ID_TERMINATE, TRUE),
  2000.              MPFROM2SHORT(MIA_DISABLED, SlideAttrib));
  2001.   WinSendMsg(hMenu, MM_SETITEMATTR, MPFROM2SHORT(ID_FORWARD, TRUE),
  2002.              MPFROM2SHORT(MIA_DISABLED, SlideAttrib));
  2003.   WinSendMsg(hMenu, MM_SETITEMATTR, MPFROM2SHORT(ID_REVERSE, TRUE),
  2004.              MPFROM2SHORT(MIA_DISABLED, SlideAttrib));
  2005.   return(hMenu);
  2006. }
  2007.  
  2008.  
  2009. /*****************************************************************************/
  2010. /*  Abstract for function: ParseArgs()                                       */
  2011. /*    This function parses out the command line arguments, filling up the    */
  2012. /*    "InitialSize" structure if ncecessary, and pointing the filename       */
  2013. /*    pointer at the appropriate string.                                     */
  2014. /*                                                                           */
  2015. /*    This function will return a bit value indicating if sizing args where  */
  2016. /*    specified, if the window is to be initially minimized or maximized,    */
  2017. /*    and if a filespec was given, whether or not it is for a .BMP file or a */
  2018. /*    .SLD file.                                                             */
  2019. /*****************************************************************************/
  2020. ULONG ParseArgs(int argc, char *argv[], UCHAR **pFname, PRECTL pInitialSize)
  2021. {
  2022.   UCHAR *pCurrArg;
  2023.   ULONG ReturnVal = 0;
  2024.  
  2025.   *pFname = NULL;
  2026.   while (--argc) {
  2027.     /* Use this to save time! */
  2028.     pCurrArg = argv[argc];
  2029.     strupr(pCurrArg);
  2030.     if (pCurrArg[0] != '/') {
  2031.       *pFname = pCurrArg;
  2032.     } else {
  2033.       switch (pCurrArg[1]) {
  2034.         case 'E':
  2035.           bIgnoreErrors = !bIgnoreErrors;
  2036.           break;
  2037.         case 'F':
  2038.           bFrameEmpty = !bFrameEmpty;
  2039.           break;
  2040.         case 'H':
  2041.           /* Height... */
  2042.           pInitialSize->yTop = atoi(&pCurrArg[3]);
  2043.           ReturnVal |= SWP_SIZE;
  2044.           break;
  2045.         case 'I':
  2046.           ReturnVal |= SWP_MINIMIZE;
  2047.           break;
  2048.         case 'K':
  2049.           bScaleWhileDrawing = !(bScaleWhileDrawing);
  2050.           break;
  2051.         case 'O':
  2052.           pOptions = strdup(&pCurrArg[3]);
  2053.           break;
  2054.         case 'P':
  2055.           bPaletteManager = !bPaletteManager;
  2056.           break;
  2057.        case 'R':
  2058.           bKeepProportion = !bKeepProportion;
  2059.           break;
  2060.         case 'S':
  2061.           ReturnVal |= SLIDE_FILE;
  2062.           break;
  2063.         case 'W':
  2064.           /* Width... */
  2065.           pInitialSize->xRight = atoi(&pCurrArg[3]);
  2066.           ReturnVal |= SWP_SIZE;
  2067.           break;
  2068.         case 'X':
  2069.           pInitialSize->xLeft = atoi(&pCurrArg[3]);
  2070.           ReturnVal |= SWP_SIZE;
  2071.           break;
  2072.         case 'Y':
  2073.           pInitialSize->yBottom = atoi(&pCurrArg[3]);
  2074.           ReturnVal |= SWP_SIZE;
  2075.           break;
  2076.         case 'Z':
  2077.           ReturnVal |= SWP_MAXIMIZE;
  2078.           break;
  2079.       }
  2080.     }
  2081.   }
  2082.   if (*pFname) {
  2083.     if (!(ReturnVal & SLIDE_FILE)) {  /* If they didn't use /S, default is .BMP file! */
  2084.       ReturnVal |= BITMAP_FILE;
  2085.     }
  2086.   } else if (ReturnVal & SLIDE_FILE) { /* Can't specify /S with no filename!!          */
  2087.     ReturnVal &= (~SLIDE_FILE);     /* So remove /S option.                         */
  2088.   }
  2089.  
  2090.   return(ReturnVal);
  2091. }
  2092.