home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v92.tgz / v92.tar / v92 / src / runtime / rpmwin.ri < prev    next >
Text File  |  1996-03-22  |  132KB  |  5,014 lines

  1. /*
  2.  * rpmwin.ri - PresentationManager specific X-Icon support
  3.  */
  4.  
  5. #ifdef PresentationManager
  6.  
  7. void dumpdata(void *data,int len, char *title)
  8. {
  9.     FILE *dlog;
  10.     char *p,*s,*d;
  11.     int i,j;
  12.     char tbuf[17];
  13.     fprintf(stderr,"------<%s>------- Len=%8x\n",title,len);
  14.     for(i=0, s = data;i<len;i+=16,s+=16) {
  15.     p = tbuf;
  16.     for(j = 0; j < 16; j++,p++) {
  17.         *p = ( isprint( *(s+j))) ? *(s+j) : '.';
  18.     }
  19.     *p = '\0';
  20.     fprintf(stderr,"%08X +%04X",s,i);
  21.  
  22.     for(j=0;j<16;j+=4) {
  23.         fprintf(stderr," %02X%02X%02X%02X",
  24.         *(s+0+j),
  25.         *(s+1+j),
  26.         *(s+2+j),
  27.         *(s+3+j));
  28.     }
  29.     fprintf(stderr," *%s*\n",tbuf);
  30.     }
  31.     fflush(stderr);
  32. }
  33.  
  34. #ifdef OS2EMX
  35. int errno;
  36. #endif                    /* OS2EMX */
  37.  
  38. #ifndef min
  39. #define min(x,y) (((x) < (y))?(x):(y))
  40. #define max(x,y) (((x) > (y))?(x):(y))
  41. #endif                    /* min */
  42.  
  43. /*
  44.  * flags for context setting, querying
  45.  */
  46. ULONG lineAttrs = LBB_COLOR    |
  47.           LBB_MIX_MODE |
  48.          /* LBB_WIDTH     | */
  49.           LBB_GEOM_WIDTH |
  50.           LBB_TYPE |
  51.           LBB_JOIN;
  52.  
  53. ULONG areaAttrs = ABB_COLOR    |
  54.           ABB_MIX_MODE |
  55.           ABB_BACK_COLOR |
  56.           ABB_BACK_MIX_MODE |
  57.           ABB_SET |
  58.           ABB_SYMBOL;
  59.  
  60. ULONG charAttrs = CBB_COLOR |
  61.           CBB_BACK_COLOR |
  62.           CBB_MIX_MODE |
  63.           CBB_BACK_MIX_MODE |
  64.           CBB_SET |
  65.           CBB_BOX;
  66.  
  67. ULONG imageAttrs = IBB_COLOR |
  68.            IBB_MIX_MODE |
  69.            IBB_BACK_COLOR |
  70.            IBB_BACK_MIX_MODE;
  71.  
  72. /*
  73.  * the event sem use for parent/child thread sync
  74.  */
  75. HEV HSyncEventSem1;
  76. HEV HSyncEventSem2;
  77.  
  78. /*
  79.  * PMStringBuf, PMStringBufPtr, PMFlags replaced by Console
  80.  * variables in fwindow.r
  81.  */
  82.  
  83.  
  84. /*
  85.  * the system color table - made to match hardware - may not work with
  86.  * all drivers - index into the table is implied by order -> order is *very*
  87.  * important
  88.  */
  89. LONG defClrTable[16] = {
  90.     RGB_BLACK,
  91.     RGB_BLUE,
  92.     RGB_RED,
  93.     RGB_PINK,
  94.     RGB_GREEN,
  95.     RGB_CYAN,
  96.     RGB_YELLOW,
  97.     MAKERGB(190, 190, 190),  /* pale gray */
  98.     MAKERGB(128, 128, 128),  /* dark gray */
  99.     MAKERGB(0, 0, 128),     /* dark blue */
  100.     MAKERGB(128, 0, 0),     /* dark red */
  101.     MAKERGB(128, 0, 128),     /* dark pink */
  102.     MAKERGB(0, 128, 0),     /* dark green */
  103.     MAKERGB(0, 128, 128),     /* dark cyan */
  104.     MAKERGB(128, 128, 0),     /* brown */
  105.     RGB_WHITE
  106.     };
  107.  
  108. /* the color name <-> rgb table. You can add more color names and appropriate
  109.    RGB values here */
  110. stringint siColorNames[] = {
  111.   {0, 33},
  112.   {"beige",             MAKERGB(245, 245, 220)},
  113.   {"black",             RGB_BLACK},
  114.   {"blue",              RGB_BLUE},
  115.   {"brown",             MAKERGB(128, 128, 0)},
  116.   {"chocolate",         MAKERGB(210, 105, 30)},
  117.   {"cyan",              RGB_CYAN},
  118.   {"darkblue",          MAKERGB(0, 0, 128)},
  119.   {"darkcyan",          MAKERGB(0, 128, 128)},
  120.   {"darkgray",          MAKERGB(128, 128, 128)},
  121.   {"darkgreen",         MAKERGB(0, 128, 0)},
  122.   {"darkpink",          MAKERGB(128, 0, 128)},
  123.   {"darkred",           MAKERGB(128, 0, 0)},
  124.   {"firebrick",         MAKERGB(178, 34, 34)},
  125.   {"gold",              MAKERGB(255, 215, 0)},
  126.   {"gray",              MAKERGB(158, 158, 158)},
  127.   {"green",             RGB_GREEN},
  128.   {"ivory",             MAKERGB(255, 255, 240)},
  129.   {"lightgray",         MAKERGB(190, 190, 190)},
  130.   {"magenta",           MAKERGB(255, 0, 255)},
  131.   {"maroon",            MAKERGB(176, 48, 96)},
  132.   {"navy",              MAKERGB(0, 0, 128)},
  133.   {"orange",            MAKERGB(255, 165, 0)},
  134.   {"orchid",            MAKERGB(218, 112, 214)},
  135.   {"palegray",          MAKERGB(190, 190, 190)},
  136.   {"pink",              RGB_PINK},
  137.   {"plum",              MAKERGB(221, 160, 221)},
  138.   {"purple",            MAKERGB(160, 32, 240)},
  139.   {"red",               RGB_RED},
  140.   {"tan",               MAKERGB(210, 180, 140)},
  141.   {"violet",            MAKERGB(238, 130, 238)},
  142.   {"wheat",             MAKERGB(245, 222, 179)},
  143.   {"white",             RGB_WHITE},
  144.   {"yellow",            RGB_YELLOW}
  145.   };
  146.  
  147.  
  148. /*
  149.  * pattern symbols
  150.  */
  151. stringint siPatternSyms[] = {
  152.   {0, 16},
  153.   {"blank",             PATSYM_BLANK},
  154.   {"diagonal1",         PATSYM_DIAG1},
  155.   {"diagonal2",         PATSYM_DIAG2},
  156.   {"diagonal3",         PATSYM_DIAG3},
  157.   {"diagonal4",         PATSYM_DIAG4},
  158.   {"gray1",             PATSYM_DENSE8},
  159.   {"gray2",             PATSYM_DENSE7},
  160.   {"gray3",             PATSYM_DENSE6},
  161.   {"gray4",             PATSYM_DENSE5},
  162.   {"gray5",             PATSYM_DENSE4},
  163.   {"gray6",             PATSYM_DENSE3},
  164.   {"gray7",             PATSYM_DENSE2},
  165.   {"gray8",             PATSYM_DENSE1},
  166.   {"horizontalLines",   PATSYM_HORIZ},
  167.   {"solid",             PATSYM_SOLID},
  168.   {"verticalLines",     PATSYM_VERT}};
  169.  
  170. /*
  171.  * mix modes (draw ops)
  172.  */
  173. stringint siMixModes[] = {
  174.   {0, 17},
  175.   {"and",               ROP_SRCAND},
  176.   {"andInverted",       ROP_SRCERASE},
  177.   {"andReverse",        ROP_SRCERASE},
  178.   {"clear",             ROP_ZERO},
  179.   {"copy",              ROP_SRCCOPY},
  180.   {"copyInverted",      ROP_NOTSRCCOPY},
  181.   {"equiv",             ROP_SRCCOPY},
  182.   {"invert",            ROP_DSTINVERT},
  183.   {"nand",              ROP_SRCERASE},
  184.   {"noop",              ROP_ONE},
  185.   {"nor",               ROP_MERGEPAINT},
  186.   {"or",                ROP_SRCPAINT},
  187.   {"orInverted",        ROP_MERGEPAINT},
  188.   {"orReverse",         0xDD},
  189.   {"reverse",           ROP_USER1},
  190.   {"set",               ROP_ONE},
  191.   {"xor",               ROP_SRCINVERT}};
  192.  
  193. /*
  194.  * line types
  195.  */
  196. stringint siLineTypes[] = {
  197.   {0, 10},
  198.   {"alternate",         LINETYPE_ALTERNATE},
  199.   {"dashdot",           LINETYPE_DASHDOT},
  200.   {"dashdoubledot",     LINETYPE_DASHDOUBLEDOT},
  201.   {"dashed",            LINETYPE_ALTERNATE},
  202.   {"dotted",            LINETYPE_DOT},
  203.   {"doubledot",         LINETYPE_DOUBLEDOT},
  204.   {"longdash",          LINETYPE_LONGDASH},
  205.   {"shortdash",         LINETYPE_SHORTDASH},
  206.   {"solid",             LINETYPE_SOLID},
  207.   {"striped",           LINETYPE_LONGDASH}};
  208.  
  209.  
  210. #define NUMSYSCURSORSYMS    3
  211. #define NUMCURSORSYMS        76
  212.  
  213. /*
  214.  * cursor/pointer symbols
  215.  */
  216. stringint siSysCursorSyms[] = {
  217.   {0, NUMSYSCURSORSYMS},
  218.   {"arrow",             SPTR_ARROW},
  219.   {"clock",             SPTR_WAIT},
  220.   {"xterm",             SPTR_TEXT}};
  221.  
  222. stringint siCursorSyms[] = {
  223.   {0, NUMCURSORSYMS},
  224.   {"X arrow",                   PTR_XARROW},
  225.   {"X cursor",                  PTR_X_CURSOR},
  226.   {"X watch",                   PTR_XWATCH},
  227.   {"based arrow down",          PTR_BASE_ARROW_DOWN},
  228.   {"based arrow up",            PTR_BASE_ARROW_UP},
  229.   {"boat",                      PTR_BOAT},
  230.   {"bogosity",                  PTR_BOGOSITY},
  231.   {"bottom left corner",        PTR_BOTTOM_LEFT_CORNER},
  232.   {"bottom right corner",       PTR_BOTTOM_RIGHT_CORNER},
  233.   {"bottom side",               PTR_BOTTOM_SIDE},
  234.   {"bottom tee",                PTR_BOTTOM_TEE},
  235.   {"box spiral",                PTR_BOX_SPIRAL},
  236.   {"center ptr",                PTR_CENTER_PTR},
  237.   {"circle",                    PTR_CIRCLE},
  238.   {"clock",                     PTR_CLOCK},
  239.   {"coffee mug",                PTR_COFFEE_MUG},
  240.   {"cross",                     PTR_CROSS},
  241.   {"cross reverse",             PTR_CROSS_REVERSE},
  242.   {"crosshair",                 PTR_CROSSHAIR},
  243.   {"diamond cross",             PTR_DIAMOND_CROSS},
  244.   {"dot",                       PTR_DOT},
  245.   {"dot box",                   PTR_DOTBOX},
  246.   {"double arrow",              PTR_DOUBLE_ARROW},
  247.   {"draft large",               PTR_DRAFT_LARGE},
  248.   {"draft small",               PTR_DRAFT_SMALL},
  249.   {"draped box",                PTR_DRAPED_BOX},
  250.   {"exchange",                  PTR_EXCHANGE},
  251.   {"fleur",                     PTR_FLEUR},
  252.   {"gobbler",                   PTR_GOBBLER},
  253.   {"gumby",                     PTR_GUMBY},
  254.   {"hand1",                     PTR_HAND1},
  255.   {"hand2",                     PTR_HAND2},
  256.   {"heart",                     PTR_HEART},
  257.   {"icon",                      PTR_ICON},
  258.   {"iron cross",                PTR_IRON_CROSS},
  259.   {"leftbutton",                PTR_LEFTBUTTON},
  260.   {"left ptr",                  PTR_LEFT_PTR},
  261.   {"left side",                 PTR_LEFT_SIDE},
  262.   {"left tee",                  PTR_LEFT_TEE},
  263.   {"ll angle",                  PTR_LL_ANGLE},
  264.   {"lr angle",                  PTR_LR_ANGLE},
  265.   {"man",                       PTR_MAN},
  266.   {"middlebutton",              PTR_MIDDLEBUTTON},
  267.   {"mouse",                     PTR_MOUSE},
  268.   {"pencil",                    PTR_PENCIL},
  269.   {"pirate",                    PTR_PIRATE},
  270.   {"plus",                      PTR_PLUS},
  271.   {"question arrow",            PTR_QUESTION_ARROW},
  272.   {"right ptr",                 PTR_RIGHT_PTR},
  273.   {"right side",                PTR_RIGHT_SIDE},
  274.   {"right tee",                 PTR_RIGHT_TEE},
  275.   {"rightbutton",               PTR_RIGHTBUTTON},
  276.   {"rtl logo",                  PTR_RTLLOGO},
  277.   {"sailboat",                  PTR_SAILBOAT},
  278.   {"sb down arrow",             PTR_SB_DOWN_ARROW},
  279.   {"sb h double arrow",         PTR_SB_H_DOUBLE_ARROW},
  280.   {"sb left arrow",             PTR_SB_LEFT_ARROW},
  281.   {"sb right arrow",            PTR_SB_RIGHT_ARROW},
  282.   {"sb up arrow",               PTR_SB_UP_ARROW},
  283.   {"sb v double arrow",         PTR_SB_V_DOUBLE_ARROW},
  284.   {"shuttle",                   PTR_SHUTTLE},
  285.   {"sizing",                    PTR_SIZING},
  286.   {"spider",                    PTR_SPIDER},
  287.   {"spraycan",                  PTR_SPRAYCAN},
  288.   {"star",                      PTR_STAR},
  289.   {"target",                    PTR_TARGET},
  290.   {"tcross",                    PTR_TCROSS},
  291.   {"top left arrow",            PTR_TOP_LEFT_ARROW},
  292.   {"top left corner",           PTR_TOP_LEFT_CORNER},
  293.   {"top right corner",          PTR_TOP_RIGHT_CORNER},
  294.   {"top side",                  PTR_TOP_SIDE},
  295.   {"top tee",                   PTR_TOP_TEE},
  296.   {"trek",                      PTR_TREK},
  297.   {"ul angle",                  PTR_UL_ANGLE},
  298.   {"umbrella",                  PTR_UMBRELLA},
  299.   {"ur angle",                  PTR_UR_ANGLE},
  300.   {"xterm",                     PTR_XTERM}};
  301.  
  302. /*
  303.  *
  304.  * Local Prototypes
  305.  *
  306.  */
  307. static lclIdentifier *AllocateLocalID(void);
  308. static void RippleColorAddition(LONG aindx);
  309. static void RippleLocalIdAddition(wcp wc, LONG id);
  310. static void RippleLocalIdRemoval(LONG id);
  311.  
  312. /*
  313.  * main window callback, or should I say, the only window callback
  314.  */
  315. MRESULT_N_EXPENTRY MainWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  316.  
  317. /*
  318.  * PM globals
  319.  */
  320. HAB HInterpAnchorBlock;
  321. HMQ HInterpMessageQueue;
  322. HAB HMainAnchorBlock;
  323. HMQ HMainMessageQueue;
  324.  
  325. /*
  326.  * the color table
  327.  */
  328. colorEntry *ColorTable;
  329. colorEntry *FreeCEntries;
  330. colorEntry *UsedCEntries;
  331.  
  332. /*
  333.  * the local id table
  334.  */
  335. lclIdentifier *LocalIds;
  336. lclIdentifier *FreeIdEntries;
  337. lclIdentifier *FontIdEntries;
  338. lclIdentifier *PatIdEntries;
  339.  
  340. /*
  341.  * device capabilities
  342.  */
  343. LONG FontResX;        /* resolutions used to select image fonts */
  344. LONG FontResY;
  345. ULONG DefFontSize;
  346. LONG ScreenWidth;    /* media (screen) dimensions */
  347. LONG ScreenHeight;
  348. LONG ScreenBitsPerPel;    /* number of bits per pixel for the screen */
  349. LONG MaxPSColors;    /* max color index in logical color table for a PS */
  350.  
  351.  
  352. static void dumplocalids()
  353. {
  354.     register int i;
  355.     FONTMETRICS *fm;
  356.     lclIdentifier *ptr;
  357.  
  358.     int freeid;
  359.     freeid = FreeIdEntries - LocalIds;
  360.     fprintf(stderr,"\n--- Dump of local IDs --- FreeIdEntries = %d (%08lx) Base=%08lx \n",
  361.            freeid,FreeIdEntries,LocalIds);
  362.     fprintf(stderr,"Fonts..\n");
  363.     for( ptr = FontIdEntries; ptr; ptr = ptr->next) {
  364.     i = (ptr - LocalIds) + 1;
  365.     fprintf(stderr,"%3d type=%hd refcount=%hd next=%d (%08lx) prev=%d (%08lx)\n",i,
  366.         ptr->idtype,
  367.         ptr->refcount,
  368.         ptr->next - LocalIds, ptr->next,
  369.         ptr->previous - LocalIds,ptr->previous);
  370.         fm = &ptr->u.font.metrics;
  371.         fprintf(stderr,"FontName=[%s] Base = %d Width=%d\n",fm->szFacename,fm->lMaxBaselineExt,
  372.                                   fm->lAveCharWidth);
  373.     }
  374.     fprintf(stderr,"Patterns..\n");
  375.     for( ptr = PatIdEntries; ptr; ptr = ptr->next) {
  376.     i = (ptr - LocalIds) + 1;
  377.     fprintf(stderr,"%3d type=%hd refcount=%hd next=%d (%08lx) prev=%d (%08lx)\n",i,
  378.         ptr->idtype,
  379.         ptr->refcount,
  380.         ptr->next - LocalIds, ptr->next,
  381.         ptr->previous - LocalIds,ptr->previous);
  382.     }
  383. /*
  384.     fprintf(stderr,"Free..\n");
  385.     for( ptr = FreeIdEntries; ptr; ptr = ptr->next) {
  386.     i = (ptr - LocalIds) + 1;
  387.     fprintf(stderr,"%3d Free\n",i);
  388.     }
  389. */
  390.     fprintf(stderr,"-----\n");
  391.     fflush(stderr);
  392. }
  393.  
  394. /*
  395.  * AddLocalIdToWindow
  396.  *  Parameters - assume id is presentation space relative
  397.  */
  398. void AddLocalIdToWindow(wsp ws, LONG id)
  399. {
  400.    LONG newid;
  401.    lclIdentifier *ptr;
  402.    FATTRS fat;
  403.    int rc;
  404.    newid = id - 1;
  405.  
  406.    if (newid >= 0 && newid < MAXLOCALS) { /* if the id is valid */
  407.       MutexOn(ws);
  408.       ptr = &LocalIds[newid];
  409.       if (ptr->idtype & IS_PATTERN) {    /* if its a pattern... */
  410.      RENDER2(GpiSetBitmapId, ptr->u.hpat, id); /* ok to do win first?#$#$*/
  411.      }
  412.       else {                /* else its a font... */
  413.      memset(&fat, 0, sizeof(FATTRS));
  414.      fat.usRecordLength   = sizeof(FATTRS);
  415.      fat.lMatch          = ptr->u.font.metrics.lMatch;
  416.      strcpy(fat.szFacename, ptr->u.font.metrics.szFacename);
  417.  
  418.      GpiSetCharMode(ws->hpsBitmap,CM_MODE2);
  419.      GpiCreateLogFont(ws->hpsBitmap, NULL, id, &fat);
  420.      if (ws->hpsWin) {
  421.         GpiSetCharMode(ws->hpsWin,CM_MODE2);
  422.         GpiCreateLogFont(ws->hpsWin, NULL, id, &fat);
  423.      }
  424.       }
  425.       MutexOff(ws);
  426.    }
  427. }
  428.  
  429. /*
  430.  * AddContextDep
  431.  */
  432. int AddContextDep(wsp ws, wcp wc)
  433.    {
  434.    int i, first = -1;
  435.    /*
  436.     * Search for the dependency, if its already there, return it, otherwise
  437.     *  find the first open slot.
  438.     */
  439.    for (i = 0; i < ws->maxDeps; i++) {
  440.       if (ws->depContexts[i] == wc) return 1;
  441.       if (first < 0 && !ws->depContexts[i]) first = i;
  442.       }
  443.    /*
  444.     * if there were no free slots, make some more
  445.     */
  446.    if (first < 0) {
  447.       ULONG newsize;
  448.       wcp *newtbl;
  449.       newsize = (ws->maxDeps << 1) * sizeof(wcp);
  450.       /*
  451.        * blow the table up a little bigger, if possible
  452.        */
  453.       if (!(newtbl = realloc(ws->depContexts, newsize))) return 0;
  454.       /*
  455.        * zero out the upper pointers
  456.        */
  457.       memset(&newtbl[ws->maxDeps], 0, sizeof(wcp) * ws->maxDeps);
  458.       ws->depContexts = newtbl;
  459.       first = ws->maxDeps;
  460.       ws->maxDeps <<= 1;
  461.       }
  462.    ws->depContexts[first] = wc;
  463.    ws->numDeps++;
  464.    return 1;
  465.    }
  466.  
  467. /*
  468.  * AddWindowDep - adds a window dependency to a context
  469.  */
  470. int AddWindowDep(wsp ws, wcp wc)
  471.    {
  472.    int i, first = -1;
  473.    /*
  474.     * Search for the dependency, if its already there, return it, otherwise
  475.     *  find the first open slot.
  476.     */
  477.    for (i = 0; i < wc->maxDeps; i++) {
  478.       if (wc->depWindows[i] == ws) /* already there ? */
  479.      return 1;
  480.       if (first < 0 && !wc->depWindows[i]) /* is this slot open? */
  481.      first = i;
  482.       }
  483.    /*
  484.     * if there were no free slots, make some more
  485.     */
  486.    if (first < 0) {
  487.       ULONG newsize;
  488.       wsp *newtbl;
  489.       newsize = (wc->maxDeps << 1) * sizeof(wsp);
  490.       /*
  491.        * blow the table up a little bigger, if possible
  492.        */
  493.       if (!(newtbl = realloc(wc->depWindows, newsize))) return 0;
  494.       /*
  495.        * zero out the upper pointers
  496.        */
  497.       memset(&newtbl[wc->maxDeps], 0, sizeof(wsp) * wc->maxDeps);
  498.       wc->depWindows = newtbl;
  499.       first = wc->maxDeps;
  500.       wc->maxDeps <<= 1;
  501.       }
  502.    wc->depWindows[first] = ws;
  503.    wc->numDeps++;
  504.    return 1;
  505.    }
  506.  
  507. /*
  508.  * Bomb - temp runtime error message reporter
  509.  */
  510. void Bomb(char *mesg, char *place)
  511.    {
  512.    char buf[256];
  513.  
  514.    strcpy(buf, mesg);
  515.    strcat(buf, place);
  516.    WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, buf, NULL, 1,
  517.          MB_OK | MB_ERROR | MB_APPLMODAL);
  518.    DosExit(EXIT_PROCESS, 1);
  519.    }
  520.  
  521. /*
  522.  * ColorInitPS - initializes a new wstate will all the colors in the global
  523.  *  'rainbow'
  524.  */
  525. void ColorInitPS(wbp wb)
  526.    {
  527.    wsp ws = wb->window;
  528.    colorEntry *ce;
  529.    LONG map[2];
  530.  
  531.    /*
  532.     * load the base color tables
  533.     */
  534.  
  535.    RENDER5(GpiCreateLogColorTable, 0, LCOLF_CONSECRGB, 0, 16, defClrTable);
  536.  
  537.  
  538.    for (ce = UsedCEntries; ce; ce = ce->next) {
  539.       if (!(ce->bits & CLR_BASE)) {
  540.      /*
  541.       * figure out next entry
  542.       */
  543.      map[0] = ((ULONG)ce - (ULONG)ColorTable) / sizeof(colorEntry);
  544.      map[1] = (LONG)ce->rgb;
  545.      /*
  546.       * add the rgb-index mapping (color entry) to PS
  547.       */
  548.      RENDER5(GpiCreateLogColorTable, 0, LCOLF_INDRGB, 0, 2, map);
  549.      }
  550.       }
  551.    }
  552.  
  553. /*
  554.  * DestroyWindow
  555.  */
  556. void DestroyWindow(wsp ws)
  557.    {
  558.    QMSG qmsg;
  559.    static int windowid = 0;
  560.    /*
  561.     * send a message to the first thread to destroy the window - since
  562.     * he created it, he has to destroy it.  He'll send back a message
  563.     * saying that he did it.
  564.     */
  565.    if (ws->hwndFrame) {
  566.       /*
  567.        * hdc will be wiped out by window destruction; post notice and
  568.        *  wait for our reply
  569.        */
  570. /* See wopen for explanation of this */
  571. #if 0
  572.       WinPostQueueMsg(HMainMessageQueue, REQUEST_DESTROY, (MPARAM)ws,
  573.               (MPARAM)0);
  574.       /* we may never return from this - if we get a shutdown... */
  575.       WaitForEvent(DESTROYED_WINDOW, &qmsg);
  576. #else                    /* PM Bug?? */
  577.    qmsg.msg = 0;
  578.    for (;;) {
  579.      /* ask for a new window */
  580.      WinPostQueueMsg(HMainMessageQueue, REQUEST_DESTROY, (MPARAM)ws,
  581.              (MPARAM)windowid);
  582.      /* look for our results (cross fingers) */
  583.      ObtainEvents(NULL, NO_WAIT_EVT, DESTROYED_WINDOW, &qmsg);
  584.      /* check what we picked up */
  585.      if (qmsg.msg != DESTROYED_WINDOW) DosSleep(100);
  586.      else break;
  587.      } /* End of for - infinite loop, waiting for reply */
  588.    windowid++;
  589. #endif                    /* PM Bug?? */
  590.  
  591.       /* bye bye presentation space, should have been disassociated by destroy */
  592.       GpiDestroyPS(ws->hpsWin);
  593.       /*
  594.        * knock out the handles so that this can never happen again
  595.        */
  596.       ws->hdcWin = ws->hpsWin = ws->hwndFrame = ws->hwnd = NULLHANDLE;
  597.       }
  598.    }
  599.  
  600. /*
  601.  * EnsureColorAvailable
  602.  */
  603. void EnsureColorAvailable(LONG indx)
  604.    {
  605.    wsp ws;
  606.    LONG map[2];
  607.  
  608.    if (!(ColorTable[indx].bits & CLR_USED)) {
  609.       map[0] = indx;
  610.       /*
  611.        * make up some color to put in the slot
  612.        */
  613.       map[1] = MAKERGB(0, 0, 0);
  614.       for (ws = wstates; ws; ws = ws->next) {
  615.      MutexOn(ws);
  616.      /*
  617.       * add the rgb-index mapping (color entry) to each PS
  618.       */
  619.      RENDER5(GpiCreateLogColorTable, 0, LCOLF_INDRGB, 0, 2, map);
  620.      MutexOff(ws);
  621.      }
  622.       }
  623.    }
  624.  
  625. /*
  626.  * GetColorName
  627.  */
  628. void GetColorName(LONG indx, char *buf, int len)
  629.    {
  630.    char *ptr;
  631.    ULONG rgb;
  632.  
  633.    if (indx >= 0 && indx < MaxPSColors && (ColorTable[indx].bits & CLR_USED)) {
  634.      if (ptr = ColorTable[indx].name)
  635.        mystrncpy(buf, ptr, len - 1);
  636.      else {
  637.        rgb = ColorTable[indx].rgb;
  638.        sprintf(buf, "rgb8:%d,%d,%d", RED(rgb), GREEN(rgb), BLUE(rgb));
  639.        } /* End of else - color has no name */
  640.      } /* End of if - color allocated */
  641.    else strcpy(buf, "error: color not allocated");
  642.    }
  643.  
  644. /*
  645.  * GetFontName
  646.  *  Parameters - the index of the font, PS relative
  647.  */
  648. int GetFontName(LONG id, char *buf, int maxlen)
  649.    {
  650.    LONG newid;
  651.    lclIdentifier *ptr;
  652.    /*
  653.     * sanity check
  654.     */
  655.    if ((newid = id - 1) >= 0 && newid < MAXLOCALS &&
  656.        (LocalIds[newid].idtype & IS_FONT)) {
  657.       ptr = &LocalIds[newid];
  658.  
  659. /*
  660.  * XXX notice, we are ignoring the maxlen here - oooh dangerous :)
  661.  * XXX may have to get the 'long' facename by following the facename atom
  662.  * XXX what if we are simulating italic or bold? - may need flags for that
  663.  */
  664.  
  665. /* XXX this is a hack... change it later */
  666.       sprintf(buf, "%s%s%s,%dx%d", ptr->u.font.metrics.szFamilyname,
  667.           ptr->u.font.metrics.fsSelection & FM_SEL_ITALIC ? ",Italic" : "",
  668.           ptr->u.font.metrics.fsSelection & FM_SEL_BOLD   ? ",Bold"   : "",
  669.           ptr->u.font.metrics.lAveCharWidth,
  670.           ptr->u.font.metrics.lMaxBaselineExt);
  671.       return strlen(buf);
  672.       }
  673.    /* error */
  674.    return 0;
  675.    }
  676.  
  677. /*
  678.  * GetTextWidth
  679.  */
  680. int GetTextWidth(wbp wb, char *text, int len)
  681.    {
  682.    POINTL pts[TXTBOX_COUNT];
  683.    STDLOCALS(wb);
  684.    /*
  685.     * make sure our text context is loaded
  686.     */
  687.    SetCharContext(wb, ws, wc);
  688.    /*
  689.     * calculate the text box
  690.     */
  691.    GpiQueryTextBox(stdbit, len, text, TXTBOX_COUNT, pts);
  692.    return pts[TXTBOX_TOPRIGHT].x - pts[TXTBOX_BOTTOMLEFT].x;
  693.    }
  694.  
  695. /*
  696.  * InitializeColorTable
  697.  */
  698. void InitializeColorTable()
  699.    {
  700.    ULONG i, rgb;
  701.    colorEntry *prev;
  702.    /*
  703.     * grab space for the color table (minus the default colors)
  704.     */
  705.    ColorTable = (colorEntry *)calloc(sizeof(colorEntry), MaxPSColors);
  706.    /*
  707.     * fill in the default colors (system colors)
  708.     */
  709.    UsedCEntries = &ColorTable[0];
  710.    for (i = 0, prev = NULL; i < 16; prev = &ColorTable[i++]) {
  711.       /*
  712.        * lock the color so it cannot be released, then set the color data
  713.        */
  714.       ColorTable[i].bits = CLR_LOCKED | CLR_USED | CLR_BASE;
  715.       rgb = defClrTable[i];
  716.       ColorTable[i].rgb = rgb;
  717.       ColorTable[i].name = salloc(si_i2s(siColorNames, rgb));
  718.       /*
  719.        * link to next color
  720.        */
  721.       if (i < 15) ColorTable[i].next = &ColorTable[i + 1];
  722.       ColorTable[i].previous = prev;
  723.       }
  724.    /*
  725.     * link all the remaining entries together for the free list
  726.     */
  727.    FreeCEntries = &ColorTable[16];
  728.    for (i = 16; i < MaxPSColors - 1; i++) {
  729.       ColorTable[i].next = &ColorTable[i + 1];
  730.       ColorTable[i + 1].previous = &ColorTable[i];
  731.       }
  732.    }
  733.  
  734. /*
  735.  * InitializeIdTable
  736.  */
  737. void InitializeIdTable()
  738.    {
  739.    ULONG i;
  740.    /*
  741.     * allocate the space for the table
  742.     */
  743.    LocalIds = (lclIdentifier *)calloc(sizeof(lclIdentifier), MAXLOCALS);
  744.    /*
  745.     * link all the entries together on the free list
  746.     */
  747.    FreeIdEntries = LocalIds;
  748.    for (i = 0; i < MAXLOCALS - 1; i++) {
  749.       LocalIds[i].next = &LocalIds[i + 1];
  750.       LocalIds[i + 1].previous = &LocalIds[i];
  751.       }
  752.    /*
  753.     * initialize font and pattern list pointers
  754.     */
  755.    FontIdEntries = PatIdEntries = NULL;
  756.    }
  757.  
  758.  
  759. /*
  760.  * LoadDefAttrs
  761.  */
  762. void LoadDefAttrs(wbp wb, wsp ws, wcp wc)
  763.    {
  764.    PLINEBUNDLE lBundle;
  765.    PCHARBUNDLE cBundle;
  766.    PAREABUNDLE aBundle;
  767.    PIMAGEBUNDLE iBundle;
  768.    /*
  769.     * initialize the color table for the new presentation space(s)
  770.     */
  771.    ColorInitPS(wb);
  772.    /*
  773.     * set the defaults for the context attribute bundles
  774.     */
  775.    lBundle = &(wc->lineBundle);
  776.    GpiQueryAttrs(ws->hpsBitmap, PRIM_LINE,
  777.          LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH |
  778.          LBB_GEOM_WIDTH | LBB_END | LBB_TYPE | LBB_JOIN, lBundle);
  779.    cBundle = &(wc->charBundle);
  780.    GpiQueryAttrs(ws->hpsBitmap, PRIM_CHAR,
  781.          CBB_COLOR | CBB_BACK_COLOR | CBB_MIX_MODE |
  782.          CBB_BACK_MIX_MODE | CBB_SET | CBB_MODE | CBB_BOX | CBB_ANGLE |
  783.          CBB_SHEAR | CBB_DIRECTION, cBundle);
  784.    aBundle = &(wc->areaBundle);
  785.    GpiQueryAttrs(ws->hpsBitmap, PRIM_AREA,
  786.          ABB_COLOR | ABB_BACK_COLOR | ABB_MIX_MODE |
  787.          ABB_BACK_MIX_MODE | ABB_SET | ABB_SYMBOL | ABB_REF_POINT,
  788.          aBundle);
  789.    iBundle = &(wc->imageBundle);
  790.    GpiQueryAttrs(ws->hpsBitmap, PRIM_IMAGE, IBB_COLOR | IBB_MIX_MODE |
  791.          IBB_BACK_COLOR | IBB_BACK_MIX_MODE, iBundle);
  792.    /*
  793.     * set the foreground, background, and window background colors
  794.     */
  795.    setfg(wb, "black");
  796.    setbg(wb, "white");
  797.    ws->winbg = aBundle->lBackColor;
  798.    /*
  799.     * set the default drawing mode (for XCopyArea, etc.)
  800.     */
  801.    wc->drawop = ROP_SRCCOPY;
  802.    cBundle->usBackMixMode = aBundle->usBackMixMode = BM_OVERPAINT;
  803.  /*cBundle->usBackMixMode = BM_LEAVEALONE;*/
  804.    cBundle->usMixMode = aBundle->usMixMode = lBundle->usMixMode = FM_OVERPAINT;
  805.    /*
  806.     * default line attributes
  807.     */
  808.    lBundle->lGeomWidth = 1;
  809.    lBundle->usJoin = LINEJOIN_MITRE;
  810.    ws->height = 400;
  811.    ws->width = 400;
  812.    /*
  813.     * load the default font, set the default cursor position RC 1,1
  814.     */
  815.    LoadFont(wb, "System Monospaced", (LONG)0, (ULONG)DefFontSize);
  816.    ws->y = ROWTOY(wb, 1) + wc->dx;
  817.    ws->x = COLTOX(wb, 1) + wc->dy;
  818.    return;
  819.    }
  820.  
  821. /*
  822.  * Name - MainWndProc
  823.  */
  824. MRESULT_N_EXPENTRY MainWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  825.    {
  826.    static SHORT drag_state[3] = { 0, 0, 0 };
  827.    ULONG icon_event, icon_event2, keyval;
  828.    USHORT keyflags;
  829.    int i, button_num = 0;
  830.    RECTL rect;
  831.    HPS hps;
  832.    POINTL pts[4];
  833.    SHORT cx, cy;
  834.    SHORT flag;
  835.    wsp ws;
  836.    HWND caphwnd = NULLHANDLE;
  837.    HRGN hsave, hsave2, hscrap;
  838.    PSWP swp;
  839.    BITMAPINFOHEADER2 bmp;
  840.  
  841.    /*
  842.     * All positional information will be provided by the WinPostQueueMsg
  843.     * when it fills in the QMSG structure
  844.     */
  845.  
  846.    /*
  847.     * get a pointer to the icon window state from the pm window state
  848.     */
  849.    if (ws = (wsp)WinQueryWindowULong(hwnd, QWL_USER)) {
  850.       switch (msg) {
  851.       case WM_SIZE:
  852.      /*
  853.       * don't handle the sizing if already an icon
  854.       */
  855.      if (ws->winState & WS_MIN) break;
  856.  
  857.      TimedMutexOn(ws, "WM_SIZE");
  858.  
  859.      cy = SHORT2FROMMP(mp2);
  860.      /*
  861.       * update the current window cursor position - use the
  862.       * last descender for the positioning
  863.       */
  864.      ws->y = min(ws->y, cy - ws->lastDescender);
  865.      /*
  866.       * change the cursor position
  867.       */
  868.      ws->cursInfo.y += (cy - ws->height);
  869.      if (ISCURSORONW(ws))
  870.         WinCreateCursor(ws->hwnd, ws->cursInfo.x, ws->cursInfo.y, 0, 0,
  871.                 CURSOR_SETPOS, NULL);
  872.      /*
  873.       * update the window state
  874.       */
  875.      ws->width = SHORT1FROMMP(mp2);
  876.      ws->height= cy;
  877.      /*
  878.       * resize the backing bitmap - will only make bigger
  879.       */
  880.      ResizeBackingBitmap(ws, ws->width, ws->height);
  881.      MutexOff(ws);
  882.      /*
  883.       * first time through, just clear the bit - mimic XIcon
  884.       */
  885.      if (ISINITIALW(ws)) CLRINITIALW(ws);
  886.      else WinPostQueueMsg(HInterpMessageQueue, WINDOW_SIZED, (MPARAM)ws,
  887.                   (MPARAM)((UCHAR)RESIZED));
  888.      return (MRESULT)0;
  889.  
  890.       case WM_MOVE:
  891.      /*
  892.       * do the query
  893.       */
  894.      WinQueryWindowRect(ws->hwndFrame, &rect);
  895.      /*
  896.       * map the points relative to us to the desktop
  897.       */
  898.      WinMapWindowPoints(ws->hwndFrame, HWND_DESKTOP, (POINTL *)&rect, 1);
  899.      /* do the change as quickly as possible */
  900.      TimedMutexOn(ws, "WM_MOVE");
  901.      ws->posx = rect.xLeft;
  902.      ws->posy = ScreenHeight - rect.yBottom - rect.yTop;
  903.      MutexOff(ws);
  904.      return (MRESULT)0;
  905.  
  906.       case WM_PAINT:
  907.      TimedMutexOn(ws, "WM_PAINT");
  908.      /*
  909.       * save the current clip region
  910.       */
  911.      GpiSetClipRegion(ws->hpsWin, NULLHANDLE, &hsave);
  912.      hps = WinBeginPaint(hwnd, ws->hpsWin, &rect);
  913.      if (ws->winState & WS_MIN) {
  914.  
  915. /* here is a wonderful hack.  After calling winsetwindowposition,
  916.  *  it seems that PM gives us a paint message even before we are
  917.  *  iconified, it then gives us another one after we are iconified.
  918.  *  This results in the icon bitmap being stretched to the
  919.  *  window before PM iconifies it.  For a brief moment, depending on the
  920.  *  size of the window, the user can see this image.  So, when we do the
  921.  *  iconization, a bit is set, the first paint message is ignored and clears
  922.  *  the bit and the second draws the icon.
  923.  *  Note that this problem still exists if we let winState be changed only
  924.  *  by thread 1 because the WM_MINMAXFRAME is dispatched before the WM_PAINT
  925.  *  message is delivered.
  926.  */
  927.         if (!ISMINPENDW(ws)) {
  928.            /*
  929.         * if icon image is set/defined and not just hiding, blit it
  930.         */
  931.            if (ws->hIconBitmap) {
  932.           /*
  933.            * bottom left target and source
  934.            */
  935.           pts[0].x = pts[0].y = pts[2].x = pts[2].y = 0;
  936.           bmp.cbFix = sizeof(BITMAPINFOHEADER2);
  937.           GpiQueryBitmapInfoHeader(ws->hIconBitmap, &bmp);
  938.           /*
  939.            * top right target
  940.            */
  941.           pts[1].x = rect.xRight;
  942.           pts[1].y = rect.yTop;
  943.           /*
  944.            * top right source
  945.            */
  946.           pts[3].x = bmp.cx;
  947.           pts[3].y = bmp.cy;
  948.           /*
  949.            * carry out the blit
  950.            */
  951.           GpiWCBitBlt(hps, ws->hIconBitmap, 4, pts, ROP_SRCCOPY, BBO_IGNORE);
  952.           }
  953.            /* otherwise, blit the default */
  954.            }
  955.         else CLRMINPENDW(ws);
  956.         }
  957.      else {    /* not minimized */
  958.        /*
  959.         * copy over the affected region - taking into account that
  960.         * the backing bitmap might be larger
  961.         */
  962.  
  963.        /*
  964.         * target lower left corner
  965.         */
  966.        pts[0].x = rect.xLeft; pts[0].y = rect.yBottom;
  967.        /*
  968.         * target upper right corner
  969.         */
  970.        pts[1].x = rect.xRight; pts[1].y = rect.yTop;
  971.  
  972.        /*
  973.         * source lower left corner - this is the one transformed
  974.         */
  975.        pts[2].x = rect.xLeft;
  976.        pts[2].y = rect.yBottom + ws->pixheight - ws->height;
  977.        GpiBitBlt(hps, ws->hpsBitmap, 3, pts, ROP_SRCCOPY, 0UL);
  978.        }
  979.  
  980.      WinEndPaint(hps);
  981.      GpiSetClipRegion(ws->hpsWin, hsave, &hscrap);
  982.      MutexOff(ws);
  983.      return (MRESULT)0;
  984.  
  985.       case WM_MINMAXFRAME:
  986.      swp = (PSWP)mp1;
  987.      TimedMutexOn(ws, "WM_MINMAXFRAME");
  988.      /* since we just flip the pointer on the labels when changed,
  989.         it is an atomic action and needs no mutex protection
  990.         now, the setting of the flags is a different matter */
  991.      /*
  992.       * flip titles if needed..
  993.       */
  994.      if (!(swp->fl & SWP_MINIMIZE)) {
  995.         WinSetWindowText(ws->hwndFrame, ws->windowlabel);
  996.         /*
  997.          * make sure a redraw occurs on the window ps
  998.          */
  999.         WinInvalidateRect(ws->hwndFrame, NULL, TRUE);
  1000.         }
  1001.      else if (ws->iconlabel)
  1002.         WinSetWindowText(ws->hwndFrame, ws->iconlabel);
  1003.  
  1004.      /* set the new flag state */
  1005.      if (swp->fl & SWP_MINIMIZE) ws->winState = (ws->winState & WS_HIDDEN) | WS_MIN;
  1006.      else if (swp->fl & SWP_MAXIMIZE) ws->winState = (ws->winState & WS_HIDDEN) | WS_MAX;
  1007.      else ws->winState = (ws->winState & WS_HIDDEN) | WS_NORMAL;
  1008.  
  1009.      MutexOff(ws);
  1010.      return (MRESULT)FALSE; /* use the swp structure */
  1011.  
  1012.       case WM_CHAR:
  1013.      /*
  1014.       * get the flags out of message parameter 1
  1015.       */
  1016.      keyflags = SHORT1FROMMP(mp1);
  1017.      /*
  1018.       * we will ignore key-ups
  1019.       */
  1020.      if (!(keyflags & KC_KEYUP) && TransKeyMsg(keyflags, mp2, &keyval)) {
  1021.        /* looping through repeat count - break into multiple events */
  1022.        for (i = 0; i < (int)CHAR3FROMMP(mp1); i++)
  1023.           WinPostQueueMsg(HInterpMessageQueue, KEY_PRESS, (MPARAM)ws,
  1024.                   (MPARAM)keyval);
  1025.        return (MRESULT)TRUE;  /* return that we have processed it */
  1026.        }
  1027.     return (MRESULT)FALSE;    /* ignored */
  1028.  
  1029.       case WM_MOUSEMOVE:
  1030.      icon_event = (UCHAR)((drag_state[0]) ? MOUSELEFTDRAG :
  1031.               (drag_state[1]) ? MOUSERIGHTDRAG :
  1032.               (drag_state[2]) ? MOUSEMIDDRAG : 0);
  1033.      /*
  1034.       * combine the event with the control flags, if we have an event
  1035.       */
  1036.      if (icon_event) {
  1037.         keyflags = SHORT2FROMMP(mp2);
  1038.         icon_event |= (keyflags & KC_CTRL) ? ControlMask : 0;
  1039.         icon_event |= (keyflags & KC_ALT) ? Mod1Mask : 0;
  1040.         icon_event |= (keyflags & KC_SHIFT) ? ShiftMask : 0;
  1041.         WinPostQueueMsg(HInterpMessageQueue, MOUSE_EVENT, (MPARAM)ws,
  1042.                 (MPARAM)icon_event);
  1043.         }
  1044.      /*
  1045.       * have to change the cursor based on selected pointer
  1046.       */
  1047.      return (MRESULT)WinSetPointer(HWND_DESKTOP, ws->hPointer);
  1048.  
  1049.       /*
  1050.        * start the drag
  1051.        */
  1052.       case WM_BUTTON3MOTIONSTART:
  1053.      button_num++;
  1054.       case WM_BUTTON2MOTIONSTART:
  1055.      button_num++;
  1056.       case WM_BUTTON1MOTIONSTART:
  1057.      drag_state[button_num] = 1;
  1058.      WinSetCapture(HWND_DESKTOP, hwnd);
  1059.      return (MRESULT)TRUE;
  1060.  
  1061.       /*
  1062.        * end the drag
  1063.        */
  1064.       case WM_BUTTON3MOTIONEND:
  1065.      button_num++;
  1066.       case WM_BUTTON2MOTIONEND:
  1067.      button_num++;
  1068.       case WM_BUTTON1MOTIONEND:
  1069.      drag_state[button_num] = 0;
  1070.      WinSetCapture(HWND_DESKTOP, NULLHANDLE);
  1071.      return (MRESULT)TRUE;
  1072.  
  1073.       case WM_BUTTON1DOWN:
  1074.      /*
  1075.       * combine the event with the control flags
  1076.       */
  1077.      keyflags = SHORT2FROMMP(mp2);
  1078.      icon_event = (UCHAR)MOUSELEFT | ((keyflags & KC_CTRL) ? ControlMask : 0);
  1079.      icon_event |= (keyflags & KC_ALT) ? Mod1Mask : 0;
  1080.      icon_event |= (keyflags & KC_SHIFT) ? ShiftMask : 0;
  1081.      WinPostQueueMsg(HInterpMessageQueue, MOUSE_EVENT, (MPARAM)ws,
  1082.              (MPARAM)icon_event);
  1083.      WinSetActiveWindow(HWND_DESKTOP, hwnd);
  1084.      return (MRESULT)TRUE;
  1085.  
  1086.       case WM_BUTTON2DOWN:
  1087.      /*
  1088.       * combine the event with the control flags
  1089.       */
  1090.      keyflags = SHORT2FROMMP(mp2);
  1091.      icon_event = (UCHAR)MOUSERIGHT | ((keyflags & KC_CTRL) ? ControlMask : 0);
  1092.      icon_event |= (keyflags & KC_ALT) ? Mod1Mask : 0;
  1093.      icon_event |= (keyflags & KC_SHIFT) ? ShiftMask : 0;
  1094.      WinPostQueueMsg(HInterpMessageQueue, MOUSE_EVENT, (MPARAM)ws,
  1095.             (MPARAM)icon_event);
  1096.      WinSetActiveWindow(HWND_DESKTOP, hwnd);
  1097.      return (MRESULT)TRUE;
  1098.  
  1099.       case WM_BUTTON3DOWN:
  1100.      /*
  1101.       * combine the event with the control flags
  1102.       */
  1103.      keyflags = SHORT2FROMMP(mp2);
  1104.      icon_event = (UCHAR)MOUSEMID | ((keyflags & KC_CTRL) ? ControlMask : 0);
  1105.      icon_event |= (keyflags & KC_ALT) ? Mod1Mask : 0;
  1106.      icon_event |= (keyflags & KC_SHIFT) ? ShiftMask : 0;
  1107.      WinPostQueueMsg(HInterpMessageQueue, MOUSE_EVENT, (MPARAM)ws,
  1108.              (MPARAM)icon_event);
  1109.      WinSetActiveWindow(HWND_DESKTOP, hwnd);
  1110.      return (MRESULT)TRUE;
  1111.  
  1112.       case WM_BUTTON1UP:
  1113.      /*
  1114.       * combine the event with the control flags
  1115.       */
  1116.      keyflags = SHORT2FROMMP(mp2);
  1117.      icon_event = (UCHAR)MOUSELEFTUP | ((keyflags & KC_CTRL) ? ControlMask : 0);
  1118.      icon_event |= (keyflags & KC_ALT) ? Mod1Mask : 0;
  1119.      icon_event |= (keyflags & KC_SHIFT) ? ShiftMask : 0;
  1120.      WinPostQueueMsg(HInterpMessageQueue, MOUSE_EVENT, (MPARAM)ws,
  1121.               (MPARAM)icon_event);
  1122.      return (MRESULT)TRUE;
  1123.  
  1124.       case WM_BUTTON2UP:
  1125.      /*
  1126.       * combine the event with the control flags
  1127.       */
  1128.      keyflags = SHORT2FROMMP(mp2);
  1129.      icon_event = (UCHAR)MOUSERIGHTUP | ((keyflags & KC_CTRL) ? ControlMask : 0);
  1130.      icon_event |= (keyflags & KC_ALT) ? Mod1Mask : 0;
  1131.      icon_event |= (keyflags & KC_SHIFT) ? ShiftMask : 0;
  1132.      WinPostQueueMsg(HInterpMessageQueue, MOUSE_EVENT, (MPARAM)ws,
  1133.              (MPARAM)icon_event);
  1134.      return (MRESULT)TRUE;
  1135.  
  1136.       case WM_BUTTON3UP:
  1137.      /*
  1138.       * combine the event with the control flags
  1139.       */
  1140.      keyflags = SHORT2FROMMP(mp2);
  1141.      icon_event = (UCHAR)MOUSEMIDUP | ((keyflags & KC_CTRL) ? ControlMask : 0);
  1142.      icon_event |= (keyflags & KC_ALT) ? Mod1Mask : 0;
  1143.      icon_event |= (keyflags & KC_SHIFT) ? ShiftMask : 0;
  1144.      WinPostQueueMsg(HInterpMessageQueue, MOUSE_EVENT, (MPARAM)ws,
  1145.              (MPARAM)icon_event);
  1146.      return (MRESULT)TRUE;
  1147.  
  1148.       case WM_SETFOCUS:
  1149.      TimedMutexOn(ws, "WM_SETFOCUS");
  1150.      /*
  1151.       * we have the cursor on, do the right thing
  1152.       */
  1153.      if (ISCURSORONW(ws)) {
  1154.         /*
  1155.          * receiving focus, make the cursor
  1156.          */
  1157.         if (SHORT1FROMMP(mp2)) {
  1158.            WinCreateCursor(ws->hwnd, ws->cursInfo.x, ws->cursInfo.y,
  1159.                    ws->cursInfo.cx, ws->cursInfo.cy,
  1160.                    CURSOR_FLASH, NULL);
  1161.            WinShowCursor(ws->hwnd, 1);
  1162.            }
  1163.         /* losing focus.. good bye cursor */
  1164.         else WinDestroyCursor(ws->hwnd);
  1165.         }
  1166.       MutexOff(ws);
  1167.       return (MRESULT)FALSE;
  1168.  
  1169.       case WM_CLOSE:
  1170.      /*
  1171.       * send the quit to the interp thread
  1172.       */
  1173.      WinPostQueueMsg(HInterpMessageQueue, REQUEST_SHUTDOWN, 0, 0);
  1174.      /*
  1175.       * send ourselves the quit
  1176.       */
  1177.      WinPostQueueMsg(HMainMessageQueue, WM_QUIT, (MPARAM)0, (MPARAM)0);
  1178.      return (MRESULT)FALSE;
  1179.  
  1180.       default:;
  1181.       }
  1182.     }
  1183.    return WinDefWindowProc(hwnd, msg, mp1, mp2);
  1184.    }
  1185.  
  1186. /*
  1187.  * OpenConsole
  1188.  */
  1189. FILE *OpenConsole()
  1190.    {
  1191.    struct descrip attrs[4];
  1192.    int eindx;
  1193.  
  1194.    if (!ConsoleBinding) {
  1195.       tended struct b_list *hp;
  1196.       tended struct b_lelem *bp;
  1197.       /*
  1198.        * allocate an empty event queue
  1199.        */
  1200.       hp = alclist(0);
  1201.       bp = alclstb(MinListSlots, (word)0, 0);
  1202.       hp->listhead = hp->listtail = (union block *)bp;
  1203.  
  1204.       /*
  1205.        * build the attribute list
  1206.        */
  1207.       StrLoc(attrs[0]) = "cursor=on";
  1208.       StrLen(attrs[0]) = strlen("cursor=on");
  1209.       StrLoc(attrs[1]) = "rows=24";
  1210.       StrLen(attrs[1]) = strlen("rows=24");
  1211.       StrLoc(attrs[2]) = "columns=80";
  1212.       StrLen(attrs[2]) = strlen("columns=80");
  1213.  
  1214.       StrLoc(attrs[3]) = "reverse=on";
  1215.       StrLen(attrs[3]) = strlen("reverse=on");
  1216.  
  1217.       ConsoleBinding = wopen("Console", hp, attrs, 4, &eindx);
  1218.       /* make sure we are overpainting the background */
  1219.       UnsetCharContext(((wbp)ConsoleBinding)->context);
  1220.       ((wbp)ConsoleBinding)->context->charBundle.usBackMixMode = BM_OVERPAINT;
  1221.       ((wbp)ConsoleBinding)->context->charBundle.usMixMode = FM_OVERPAINT;
  1222.       }
  1223.    return ConsoleBinding;
  1224.    }
  1225.  
  1226. /*
  1227.  * ParseRGBValue - call parsecolor(), convert from 16-bit to 8-bit colors,
  1228.  *  and return a PM-style 32-bit RGB spec.
  1229.  */
  1230. LONG ParseRGBValue(char *buf,double gamma)
  1231.    {
  1232.    int r, g, b;
  1233.  
  1234.    if (parsecolor((wbp)NULL, buf, &r, &g, &b) == Error) return -1;
  1235. /* Apply GAMMA Correction */
  1236.    r = 65535 * pow(r/65535.0,gamma);
  1237.    g = 65535 * pow(g/65535.0,gamma);
  1238.    b = 65535 * pow(b/65535.0,gamma);
  1239.    RGB16TO8(r); RGB16TO8(g); RGB16TO8(b);
  1240.    return MAKERGB(r, g, b);
  1241.    }
  1242.  
  1243. /*
  1244.  * PMfprintf, PMputc - replaced by Consolefprintf, Consoleputc in rwindow.r
  1245.  * (I also added a printf and an fflush for consoles).
  1246.  */
  1247.  
  1248. void PMStartup(void);
  1249. static int PMInited = 0;
  1250. void PMInitialize(void)
  1251. {
  1252.    ULONG htype, flags, tmp;
  1253.    if (PMInited) return;
  1254.  
  1255.    /*
  1256.     * set the flags for I/O redirection
  1257.     */
  1258.    DosQueryHType(0, &htype, &flags);
  1259.    ConsoleFlags |= (htype != 1) ? StdInRedirect : 0;
  1260.    DosQueryHType(1, &htype, &flags);
  1261.    ConsoleFlags |= (htype != 1) ? StdOutRedirect : 0;
  1262.    DosQueryHType(2, &htype, &flags);
  1263.    ConsoleFlags |= (htype != 1) ? StdErrRedirect : 0;
  1264.  
  1265.    /*
  1266.     * get the anchor block
  1267.     */
  1268.    HInterpAnchorBlock = WinInitialize(0);
  1269.    HInterpMessageQueue = WinCreateMsgQueue(HInterpAnchorBlock,MAXMSGS);
  1270.    DosCreateEventSem(NULL, &HSyncEventSem1, 0, 0);
  1271.    DosCreateEventSem(NULL, &HSyncEventSem2, 0, 0);
  1272.  
  1273.    /*
  1274.     * allocate the event semaphore we'll use to synch with child thread on
  1275.     * close.
  1276.     */
  1277.     /* initialize PM and startup interp thread */
  1278.     _beginthread(PMStartup,NULL,THREADSTACKSIZE,NULL);
  1279.  
  1280.     /* Wait for the PM side to finish setting up */
  1281.     DosWaitEventSem(HSyncEventSem1,-1);
  1282.  
  1283.    PMInited = 1;
  1284.  
  1285. }
  1286. /*
  1287.  *  InterpThreadShutdown - shutdown the interpreter thread by synching with
  1288.  *               the primary
  1289.  */
  1290. void InterpThreadShutdown()
  1291. {
  1292.   HMQ hmsgq;
  1293.  
  1294.   /* tell 'dad' to go on and destroy the windows */
  1295.   DosPostEventSem(HSyncEventSem1);
  1296.  
  1297.   /* wait for him to finish so we can remove all resources we created */
  1298.   DosWaitEventSem(HSyncEventSem2, 10000);
  1299.  
  1300.   /* free all the bindings */
  1301.   while (wbndngs) free_binding(wbndngs);
  1302.  
  1303.   /* knock out the handle to our message queue and axe our link */
  1304.   WinDestroyMsgQueue(HInterpMessageQueue);
  1305.  
  1306.   /* done with anything to do with PM now */
  1307.   WinTerminate(HInterpAnchorBlock);
  1308.  
  1309.    /* free the event semaphores */
  1310.    DosCloseEventSem(HSyncEventSem1);
  1311.    DosCloseEventSem(HSyncEventSem2);
  1312.  
  1313.   PMInited = 0;
  1314. } /* End of InterpThreadShutdown */
  1315. /*
  1316.  * PMStartup - This function initializes PM structures (anchor block,
  1317.  *  message queue, etc), starts up the secondary interpreter
  1318.  *  thread and locks thread 1 into retrieving messages and
  1319.  *  dispatching them.
  1320.  *  Since a window is tied to the thread that created it, window
  1321.  *  creation forms a request from the second (interp) thread to
  1322.  *  the first (main) thread.  A window is created and a handle
  1323.  *  to it is passed through the second (interp) thread's queue.
  1324.  */
  1325. void PMStartup(void)
  1326.    {
  1327.    QMSG qmsg;
  1328.    ULONG frame_flags = 0;
  1329.    HWND hwnd, client;
  1330.    HDC hdc;
  1331.    wsp ws;
  1332.    ULONG htype, flags, tmp;
  1333.    static int createwindowid = 0;
  1334.    static int destroywindowid = 0;
  1335.  
  1336.  
  1337.    /*
  1338.     * build a message queue - queue up more than the default
  1339.     */
  1340.    HMainMessageQueue = WinCreateMsgQueue(HMainAnchorBlock, MAXMSGS);
  1341.  
  1342.    /*
  1343.     * register a window class - extra bytes to store pointer to wstate
  1344.     */
  1345.    WinRegisterClass(HMainAnchorBlock, "XIconPM", MainWndProc,
  1346.             CS_MOVENOTIFY, sizeof(wsp));
  1347.  
  1348.    /*
  1349.     * load some device capabilities
  1350.     */
  1351.    hdc = DevOpenDC(HMainAnchorBlock, OD_MEMORY, "*", 0, NULL, NULLHANDLE);
  1352.  
  1353.    /*
  1354.     * get device resolutions used to select image fonts
  1355.     */
  1356.    DevQueryCaps(hdc, CAPS_HORIZONTAL_FONT_RES, 1, &FontResX);
  1357.    DevQueryCaps(hdc, CAPS_VERTICAL_FONT_RES, 1, &FontResY);
  1358.  
  1359.    /*
  1360.     * calculate the default font size - for now, a constant
  1361.     */
  1362.    DefFontSize = 13;
  1363.  
  1364.    /*
  1365.     * load the display resolutions
  1366.     */
  1367.    DevQueryCaps(hdc, CAPS_WIDTH, 1, &ScreenWidth);
  1368.    DevQueryCaps(hdc, CAPS_HEIGHT, 1, &ScreenHeight);
  1369.  
  1370.    /*
  1371.     * load the max color table index
  1372.     */
  1373.    DevQueryCaps(hdc, CAPS_COLOR_INDEX, 1, &MaxPSColors);
  1374.  
  1375.    /*
  1376.     * bump up the max index by one to get the max number of colors
  1377.     */
  1378.    MaxPSColors++;
  1379.  
  1380.    /*
  1381.     * load the bits per pel
  1382.     */
  1383.    DevQueryCaps(hdc, CAPS_COLOR_BITCOUNT, 1, &ScreenBitsPerPel);
  1384.    DevCloseDC(hdc);
  1385.  
  1386.    /*
  1387.     * initialize the global color table
  1388.     */
  1389.    InitializeColorTable();
  1390.  
  1391.    /*
  1392.     * initialize the id table
  1393.     */
  1394.    InitializeIdTable();
  1395.  
  1396.    /*
  1397.     * frame flags for new window
  1398.     */
  1399.    frame_flags = FCF_STANDARD & ~FCF_ICON & ~FCF_MENU & ~FCF_ACCELTABLE;
  1400.    DosPostEventSem(HSyncEventSem1);
  1401.    /*
  1402.     * start processing messages
  1403.     */
  1404.    while (WinGetMsg(HMainAnchorBlock, &qmsg, 0, 0, 0)) {
  1405.       if (qmsg.hwnd == NULLHANDLE) {
  1406.      /*
  1407.       * If the message wasn't a window event, it was from the interpreter.
  1408.       *  Handle the message from the other thread
  1409.       */
  1410.      if (qmsg.msg == REQUEST_WINDOW) {
  1411.         /* if we have already seen this request, ignore */
  1412.         if ((int)(qmsg.mp2) < createwindowid) continue;
  1413.  
  1414.         /* XXX parameter 2 will have the special flags for the new window*/
  1415.  
  1416.         /*
  1417.          * build the window
  1418.          */
  1419.         /* XXX perhaps make it synchronous paint */
  1420.         hwnd = WinCreateStdWindow(HWND_DESKTOP, 0UL,
  1421.                       &frame_flags, "XIconPM", "",
  1422.                       0UL, NULLHANDLE, 256, &client);
  1423.         /*
  1424.          * message param 1 has a pointer to the window state, set that now
  1425.          */
  1426.         WinSetWindowULong(client, QWL_USER, (ULONG)qmsg.mp1);
  1427.         WinSetWindowULong(hwnd, QWL_USER, (ULONG)0);
  1428.         /*
  1429.          * post a reply
  1430.          */
  1431.         WinPostQueueMsg(HInterpMessageQueue, NEW_WINDOW, (MPARAM)client,
  1432.                 (MPARAM)hwnd);
  1433.         /* update the id of the next request we are expecting */
  1434.         createwindowid = (int)(qmsg.mp2) + 1;
  1435.         }
  1436.      else if (qmsg.msg == REQUEST_DESTROY) {
  1437.         /* if we have already seen this request, ignore */
  1438.         if ((int)(qmsg.mp2) < destroywindowid) continue;
  1439.  
  1440.         ws = (wsp)qmsg.mp1;
  1441.         WinDestroyWindow(ws->hwndFrame);
  1442.         /*
  1443.          * tell the secondary thread to remove the window structures
  1444.          */
  1445.         WinPostQueueMsg(HInterpMessageQueue, DESTROYED_WINDOW, qmsg.mp1,0);
  1446.         /* update the id of the next request we are expecting */
  1447.         destroywindowid = (int)(qmsg.mp2) + 1;
  1448.         }
  1449.      }
  1450.       else WinDispatchMsg(HMainAnchorBlock, &qmsg);
  1451.       }
  1452.    /*
  1453.     * destroy any remaining windows and free whatever memory we allocated
  1454.     */
  1455.    for (ws = wstates; ws; ws = ws->next)
  1456.       if (ws->hwndFrame) {
  1457.      GpiDestroyPS(ws->hpsWin);
  1458.      ws->hpsWin = NULLHANDLE;
  1459.      WinDestroyWindow(ws->hwndFrame);
  1460.      ws->hdcWin = ws->hwndFrame = ws->hwnd = NULLHANDLE;
  1461.      }
  1462.  
  1463.    free(ColorTable);
  1464.    free(LocalIds);
  1465.  
  1466.    WinDestroyMsgQueue(HMainMessageQueue);
  1467.  
  1468.    /*
  1469.     * release PM access
  1470.     */
  1471.    WinTerminate(HMainAnchorBlock);
  1472.  
  1473.    /* let the interp thread do its housekeeping */
  1474.    DosPostEventSem(HSyncEventSem2);
  1475.  
  1476.    _endthread();
  1477.    }
  1478.  
  1479. /*
  1480.  *
  1481.  * ReleaseColor - decrements the reference count of the color, if last one,
  1482.  *  the color entry is returned to the free pool.
  1483.  */
  1484. void ReleaseColor(LONG indx)
  1485.    {
  1486.    colorEntry *ptr;
  1487.  
  1488.    if (indx >= 0 && indx < MaxPSColors && (ColorTable[indx].bits & CLR_USED) &&
  1489.        !(ColorTable[indx].bits & CLR_LOCKED) &&
  1490.        --ColorTable[indx].refcount < 1) {
  1491.       ptr = &ColorTable[indx];
  1492.       /*
  1493.        * knock out bits and count
  1494.        */
  1495.       ptr->bits = 0;
  1496.       ptr->refcount = 0;
  1497.       /* free the color name (if avail) */
  1498.       if (ptr->name) free(ptr->name);
  1499.       /*
  1500.        * remove from used list
  1501.        */
  1502.       if (ptr->next) ptr->next->previous = ptr->previous;
  1503.       if (ptr->previous) ptr->previous->next = ptr->next;
  1504.       else UsedCEntries = ptr->next;
  1505.       /*
  1506.        * place on the free list
  1507.        */
  1508.       if (FreeCEntries) FreeCEntries->previous = ptr;
  1509.       ptr->next = FreeCEntries;
  1510.       ptr->previous = NULL;
  1511.       FreeCEntries = ptr;
  1512.       }
  1513.    }
  1514.  
  1515. /*
  1516.  * AllocateLocalID
  1517.  */
  1518. static lclIdentifier *AllocateLocalID()
  1519.    {
  1520.    lclIdentifier *tmp;
  1521.    if (tmp = FreeIdEntries) {
  1522.       FreeIdEntries = tmp->next;
  1523.       if (FreeIdEntries) FreeIdEntries->previous = NULL;
  1524.       memset(tmp, 0, sizeof(lclIdentifier));
  1525.       tmp->refcount = 1;
  1526.       }
  1527.    return tmp;
  1528.    }
  1529.  
  1530. /*
  1531.  * ReleaseLocalId(id) - a lazy release. id is presentation-space relative
  1532.  */
  1533. void ReleaseLocalId(LONG id)
  1534.    {
  1535.    LONG newid;
  1536.    lclIdentifier *ptr, *fptr;
  1537.  
  1538.    newid = id - 1;
  1539.    /*
  1540.     * If an id is within range and an element needs to be removed...
  1541.     */
  1542.    if (newid >= 0 && newid < MAXLOCALS && --LocalIds[newid].refcount < 1) {
  1543.       /*
  1544.        * quick access
  1545.        */
  1546.       ptr = &LocalIds[newid];
  1547.  
  1548.       /*
  1549.        * go change all the PSes
  1550.        */
  1551.       RippleLocalIdRemoval(id);
  1552.  
  1553.       /*
  1554.        * free info and begin removal from list
  1555.        */
  1556.       if (ptr->idtype & IS_PATTERN) {    /* if its a pattern */
  1557.      GpiDeleteBitmap(ptr->u.hpat);
  1558.      if (ptr->previous == NULL) PatIdEntries = ptr->next;
  1559.       }
  1560.       else if (ptr->idtype & IS_FONT)
  1561.      if (ptr->previous == NULL) FontIdEntries = ptr->next;
  1562.  
  1563.       /*
  1564.        * finish removal
  1565.        */
  1566.       if (ptr->previous) ptr->previous->next = ptr->next;
  1567.       if (ptr->next) ptr->next->previous = ptr->previous;
  1568.  
  1569.       /*
  1570.        * put on the end of the free list
  1571.        */
  1572.       if (FreeIdEntries) {
  1573.     for( fptr = FreeIdEntries; fptr->next; fptr = fptr->next);
  1574.     fptr->next = ptr;
  1575.     ptr->previous = fptr;
  1576.     ptr->next = NULL;
  1577.       }
  1578.       else {
  1579.     FreeIdEntries = ptr;
  1580.     ptr->previous = ptr->next = NULL;
  1581.       }
  1582.     }
  1583. }
  1584.  
  1585. /*
  1586.  * ResizeBackingBitmap - Makes the bitmap at least as big as the passed
  1587.  *  in dimensions.
  1588.  */
  1589. void ResizeBackingBitmap(wsp ws, SHORT cx, SHORT cy)
  1590.    {
  1591.    HPS hpsMem = ws->hpsBitmap;
  1592.    HBITMAP hbm, hbmOld;
  1593.    LONG alData[2];
  1594.    BITMAPINFOHEADER2 bmp;
  1595.    POINTL pt;
  1596.    HRGN hsave, hscrap;
  1597.    AREABUNDLE abundle;
  1598.    POINTL pts[2];
  1599.  
  1600.    /*
  1601.     * if the bitmap is large enough, just return
  1602.     */
  1603.    if (cx <= ws->pixwidth && cy <= ws->pixheight) return;
  1604.    /*
  1605.     * take the clip region off
  1606.     */
  1607.    GpiSetClipRegion(hpsMem, NULLHANDLE, &hsave);
  1608.    /*
  1609.     * find out about formats  (plane/bit count)
  1610.     */
  1611.    GpiQueryDeviceBitmapFormats(hpsMem, 2, alData);
  1612.    /*
  1613.     * etake the old bitmap out - if there was one
  1614.     */
  1615.    hbmOld = GpiSetBitmap(hpsMem, NULLHANDLE);
  1616.    /*
  1617.     * build the bitmap header
  1618.     */
  1619.    memset(&bmp, 0, sizeof(BITMAPINFOHEADER2));
  1620.    bmp.cbFix = sizeof(BITMAPINFOHEADER2);
  1621.    bmp.cx = max(cx, ws->pixwidth);
  1622.    bmp.cy = max(cy, ws->pixheight);
  1623.    bmp.cPlanes = alData[0];
  1624.    bmp.cBitCount = alData[1];
  1625.  
  1626.    /*
  1627.     * build the bitmap
  1628.     */
  1629.    if (!(ws->hBitmap = GpiCreateBitmap(hpsMem, &bmp, 0, NULL, NULL)))
  1630.       Bomb("Couldn't build a backing bitmap", NULL);
  1631.    /*
  1632.     * select into the bitmap presentation space
  1633.     */
  1634.    GpiSetBitmap(hpsMem, ws->hBitmap);
  1635.    /*
  1636.     * clear the background with the appropriate color
  1637.     */
  1638.    memset(&abundle, 0, sizeof(AREABUNDLE));   /* clear out the bundle */
  1639.    abundle.lColor = ws->winbg;
  1640.    /*
  1641.     * set up the rectangle values
  1642.     */
  1643.    pt.x = pt.y = 0;
  1644.    GpiMove(hpsMem, &pt);
  1645.    pt.x = bmp.cx;
  1646.    pt.y = bmp.cy;
  1647.    /*
  1648.     * knock out the context currently selected
  1649.     */
  1650.    ws->areaContext = NULL;
  1651.    /*
  1652.     * clear area using window background color
  1653.     */
  1654.    GpiSetAttrs(hpsMem, PRIM_AREA, ABB_COLOR, ABB_SYMBOL | ABB_SET, &abundle);
  1655.    GpiBox(hpsMem, DRO_FILL, &pt, 0, 0);
  1656.    /*
  1657.     * if an old bitmap exists, copy over the information from it
  1658.     */
  1659.    if (hbmOld) {
  1660.       pt.x = 0;
  1661.       pt.y = bmp.cy - ws->pixheight;
  1662.       WinDrawBitmap(hpsMem, hbmOld, NULL, &pt, CLR_BLACK, CLR_WHITE,
  1663.             DBM_NORMAL);
  1664.       /*
  1665.        * destroy the old bitmap
  1666.        */
  1667.       GpiDeleteBitmap(hbmOld);
  1668.       }
  1669.    else if (ws->hInitialBitmap) {
  1670.       pt.x = 0;
  1671.       pt.y = 0;
  1672.       WinDrawBitmap(hpsMem, ws->hInitialBitmap, NULL, &pt,
  1673.             CLR_BLACK, CLR_WHITE, DBM_NORMAL);
  1674.       /* XXX could probably get rid of the initial bitmap here */
  1675.       }
  1676.    /*
  1677.     * update the dimensions
  1678.     */
  1679.    ws->pixwidth = bmp.cx;
  1680.    ws->pixheight = bmp.cy;
  1681.    /*
  1682.     * put the clip region back on
  1683.     */
  1684.    GpiSetClipRegion(hpsMem, hsave, &hscrap);
  1685.    }
  1686.  
  1687.  
  1688. /*
  1689.  * RippleColorAddition() - adds a color to all presentation spaces.
  1690.  *  Parameters - the index of the color to 'ripple'
  1691.  */
  1692. static void RippleColorAddition(LONG indx)
  1693.    {
  1694.    wsp ws;
  1695.    LONG map[2];
  1696.  
  1697.    map[0] = indx;
  1698.    map[1] = (LONG)ColorTable[indx].rgb;
  1699.    for (ws = wstates; ws; ws = ws->next) {
  1700.       MutexOn(ws);
  1701.       /*
  1702.        * add the rgb-index mapping (color entry) to each PS
  1703.        */
  1704.       RENDER5(GpiCreateLogColorTable, 0, LCOLF_INDRGB, 0, 2, map);
  1705.       MutexOff(ws);
  1706.       }
  1707.    }
  1708.  
  1709. /*
  1710.  * RuntimeErrorDlgProc - callback for runtime error dialog box
  1711.  */
  1712. MRESULT_N_EXPENTRY RuntimeErrorDlgProc(HWND hwnd, ULONG msg,
  1713.                      MPARAM mp1, MPARAM mp2)
  1714. {
  1715.    HWND hwndMLE;
  1716.    int extent;
  1717.  
  1718.    switch (msg) {
  1719.    case WM_INITDLG:
  1720.       sprintf(ConsoleStringBuf, "%d", k_errornumber);
  1721.       WinSetDlgItemText(hwnd, DID_ERRNO, ConsoleStringBuf);
  1722.       WinSetDlgItemText(hwnd, DID_FILE, findfile(ipc.opnd));
  1723.       sprintf(ConsoleStringBuf, "%d", (long)findline(ipc.opnd));
  1724.       WinSetDlgItemText(hwnd, DID_LINE, ConsoleStringBuf);
  1725.       WinSetDlgItemText(hwnd, DID_MSG, k_errortext);
  1726.       /* make sure our output goes to the buffer */
  1727.       ConsoleFlags |= OutputToBuf;
  1728.       /* just in case someone has changed it */
  1729.       ConsoleStringBufPtr = ConsoleStringBuf;
  1730.       if (have_errval) {
  1731.     outimage(stderr, &k_errorvalue, 0);
  1732.     WinSetDlgItemText(hwnd, DID_OFFEND, ConsoleStringBuf);
  1733.     } /* End of if - have an offending value to display */
  1734.       else WinSetDlgItemText(hwnd, DID_OFFEND, "?");
  1735.       if (debug_info && pfp) {
  1736.     hwndMLE = WinWindowFromID(hwnd, DID_TRACE);
  1737.     tracebk(NULL, argp, hwndMLE);
  1738.     } /* End of if - info and not startup problem */
  1739.       /* reset */
  1740.       ConsoleFlags &= ~OutputToBuf;
  1741.       break;
  1742.    case WM_COMMAND:
  1743.       WinDismissDlg(hwnd, 1);
  1744.       break;
  1745.    default:
  1746.      break;
  1747.    } /* endswitch */
  1748.    return WinDefDlgProc(hwnd, msg, mp1, mp2);
  1749. } /* End of RuntimeErrorDlgProc */
  1750.  
  1751. /*
  1752.  * RippleLocalIdAddition
  1753.  *  Parameters - assume id is presentation space relative id and valid
  1754.  */
  1755. static void RippleLocalIdAddition(wcp wc, LONG id)
  1756.    {
  1757.    wsp ws;
  1758.    int i;
  1759.    int num;
  1760.    num = wc->numDeps;
  1761.    for (i = 0; i < wc->maxDeps && num > 0; i++)
  1762.       if (ws = wc->depWindows[i]) {
  1763.      num--;
  1764.      AddLocalIdToWindow(ws, id);
  1765.      } /* End of if - found a dependant */
  1766.    }
  1767.  
  1768. /*
  1769.  * RippleLocalIdRemoval
  1770.  *  Parameters - assumes id is index with respect to presentation space
  1771.  */
  1772. static void RippleLocalIdRemoval(LONG id)
  1773.    {
  1774.    wsp ws;
  1775.  
  1776.    for (ws = wstates; ws; ws = ws->next) {
  1777.       MutexOn(ws);
  1778.       RENDER1(GpiDeleteSetId, id);
  1779.       MutexOff(ws);
  1780.       }
  1781.    }
  1782.  
  1783.  
  1784. /*
  1785.  * SetClipContext
  1786.  */
  1787. void SetClipContext(wbp w, wsp ws, wcp wc)
  1788.    {
  1789.    HRGN hscrap;
  1790.    RECTL rect;
  1791.    int diff;
  1792.  
  1793.    /*
  1794.     * If this context is not already loaded
  1795.     */
  1796.    if (ws->clipContext != wc) {
  1797.       ws->hClipBitmap = ws->hClipWindow = NULLHANDLE;
  1798.  
  1799.       /*
  1800.        * if clip is even set
  1801.        */
  1802.       if (wc->cliph > 0 || wc->clipw > 0 ||
  1803.       wc->clipx > 0 || wc->clipy > 0 ) {
  1804.      rect.xLeft = wc->clipx;
  1805.      rect.xRight = (wc->clipw) ? wc->clipx + wc->clipw : ws->width;
  1806.      rect.yTop = ws->pixheight - wc->clipy;
  1807.      rect.yBottom = (wc->cliph) ? rect.yTop - wc->cliph : 0;
  1808.      ws->hClipBitmap = GpiCreateRegion(ws->hpsBitmap, 1, &rect);
  1809.      if (ws->hpsWin) {
  1810.         diff = ws->pixheight - ws->height;
  1811.         rect.yTop -= diff;
  1812.         rect.yBottom -= diff;
  1813.         ws->hClipWindow = GpiCreateRegion(ws->hpsWin, 1, &rect);
  1814.         }
  1815.      }
  1816.       GpiSetClipRegion(ws->hpsBitmap, ws->hClipBitmap, &hscrap);
  1817.       GpiDestroyRegion(ws->hpsBitmap, hscrap);
  1818.       if (ws->hpsWin) {
  1819.      GpiSetClipRegion(ws->hpsWin, ws->hClipWindow, &hscrap);
  1820.      GpiDestroyRegion(ws->hpsWin, hscrap);
  1821.      }
  1822.       /*
  1823.        * Install the newly-loaded context
  1824.        */
  1825.       ws->clipContext = wc;
  1826.       }
  1827.    }
  1828.  
  1829. static FONTMETRICS afm[20];
  1830.  
  1831. int fontcompare(char *f1, char *f2)
  1832. {
  1833.     char *n1, *n2;
  1834.     char *s1, *s2;
  1835.     int nl1, nl2;
  1836.  
  1837.     n1 = strchr(f1,',');
  1838.     n2 = strchr(f2,',');
  1839.     if (n1) nl1 = n1 - f1;
  1840.     else nl1 = strlen(f1);
  1841.     if (n2) nl2 = n2 - f2;
  1842.     else nl2 = strlen(f2);
  1843.     s1 = n1 + 1;
  1844.     s2 = n2 + 1;
  1845.  
  1846.     /* Compare the face names first */
  1847.     if (nl2 >= nl1 ) {
  1848.     if (nl2 == nl1) {
  1849.      if (strnicmp(f1,f2,nl1)) return 0;
  1850.     }
  1851.     if (nl2 > nl1) {
  1852.         if (strnicmp(f1,f2,nl1) || strcmpi(f2+nl1," Non-ISO"))
  1853.         return 0;
  1854.     }
  1855.     }
  1856.     else     return 0;
  1857.  
  1858.     if (n1 && n2 && strcmpi(s1,s2)) return 0;
  1859.     if (n1 == NULL || n2 == NULL) return 0;
  1860.  
  1861.     return 1;
  1862. }
  1863. /*
  1864.  * LoadFont
  1865.  *  Returns - the index of the font, PS relative
  1866.  */
  1867. int LoadFont(wbp wb, char *family, LONG attrs, ULONG fsize)
  1868.    {
  1869.  
  1870.    int rc;
  1871.  
  1872.    lclIdentifier *ptr;
  1873.    LONG newid;
  1874.    SIZEF sizef;
  1875.    HDC hdc;
  1876.    char name1[128];
  1877.    char name2[128];
  1878.    char attstr[32];
  1879.    FATTRS fat;
  1880.    LONG cfonts;
  1881.    LONG i;
  1882.    int fwidth, fheight;
  1883.    SIZEL size = {0, 0};
  1884.    STDLOCALS(wb);
  1885.  
  1886.    /*
  1887.     * break out the selection attributes
  1888.     */
  1889.  
  1890.    if ((signed long)fsize < 0 ) fsize = DefFontSize;
  1891.    i = fsize;
  1892.    fsize = MAKEFNTSIZE(i,i);
  1893.  
  1894.    fwidth = FNTWIDTH(fsize);
  1895.    fheight = FNTHEIGHT(fsize);
  1896.    attstr[0] = '\0';
  1897.  
  1898. #ifndef CSET2
  1899. #define FATTR_SEL_BOLD            FM_SEL_BOLD
  1900. #define FATTR_SEL_ITALIC        FM_SEL_ITALIC
  1901. #define FATTR_FONTUSE_OUTLINE        FM_SEL_OUTLINE
  1902. #define FATTR_FONTUSE_TRANSFORMABLE FM_SEL_ISO9241_TESTED
  1903. #endif                    /* CSET2 */
  1904.  
  1905.    if (attrs & FONTFLAG_BOLD) strcat(attstr, " Bold");
  1906.    if (attrs & FONTFLAG_ITALIC) strcat(attstr, " Italic");
  1907.  
  1908.    /*
  1909.     * build the name to search for
  1910.     */
  1911.    sizef.cx = MAKEFIXED(fwidth, 0);
  1912.    sizef.cy = MAKEFIXED(fheight, 0);
  1913.    sprintf(name1, "%s%s%s,%dx%d", family,
  1914.     attrs & FONTFLAG_ITALIC ? ",Italic" : "",
  1915.     attrs & FONTFLAG_BOLD   ? ",Bold"   : "",
  1916.    fwidth, fheight);
  1917.    /*
  1918.     * search through font entries... - try to find matching name
  1919.     */
  1920.    for (ptr = FontIdEntries; ptr; ptr = ptr->next) {
  1921.       newid = (ptr - LocalIds)+1;
  1922.       GetFontName(newid, name2, 128);
  1923.       if (fontcompare(name1, name2)) break;
  1924.       }
  1925.  
  1926.    /*
  1927.     * if we found one, simply bump up the reference.  Else, make a new one.
  1928.     */
  1929.    if (ptr) {
  1930.       AddFontDependant(newid);
  1931.       }
  1932.    else {
  1933.       newid = (FreeIdEntries - LocalIds) + 1;
  1934.       GpiDeleteSetId(stdwin,newid);
  1935.       /*
  1936.        * try to create a font
  1937.        *
  1938.        * build the font request
  1939.        */
  1940.       memset(&fat, 0, sizeof(FATTRS));
  1941.       fat.usRecordLength = sizeof(FATTRS);
  1942.       fat.fsFontUse = 0;
  1943.  
  1944.       if (attrs & FONTFLAG_BOLD) fat.fsSelection |= FATTR_SEL_BOLD;
  1945.       if (attrs & FONTFLAG_ITALIC) fat.fsSelection |= FATTR_SEL_ITALIC;
  1946.  
  1947.  
  1948.       /*
  1949.        * make the facename to look for
  1950.        */
  1951.       strcpy(fat.szFacename, family);
  1952.       strcat(fat.szFacename,attstr);
  1953.       fat.lMaxBaselineExt = fheight;
  1954.       fat.lAveCharWidth   = fwidth;
  1955.       fat.fsSelection = 0;
  1956.       /*
  1957.        * request the font
  1958.        */
  1959.  
  1960.       if (rc = GpiCreateLogFont(stdwin, NULL, newid, &fat) != FONT_MATCH) {
  1961.  
  1962.     if ( rc != GPI_ERROR )
  1963.         GpiDeleteSetId(stdwin,newid);
  1964.      /*
  1965.       * couldn't get an outline font, try for an image
  1966.       */
  1967.      cfonts = 20;  /* maximum fonts to get info on */
  1968.  
  1969.      /*
  1970.       * notice we query the memory PS since it may have fewer fonts
  1971.       * than the display
  1972.       */
  1973.      GpiQueryFonts(stdwin, QF_PUBLIC, family, &cfonts,
  1974.                sizeof(FONTMETRICS), afm);
  1975.  
  1976. /* XXX
  1977.  *  this will cause a problem when trying to implement the WxH format -
  1978.  *  seems that memory DCs only have one monospaced font per resolution
  1979.  *  in the 32bit Graphics Enging (GA+SPP) - check back on this in OS/2 2.1
  1980.  *  and see if the situation improves.    If not - checking for width and
  1981.  *  height below is pretty much useless
  1982.  */
  1983.  
  1984.      /* try to match one with the exact attributes */
  1985.      for (i = 0;
  1986.           i < cfonts &&
  1987.           (afm[i].sXDeviceRes != FontResX ||
  1988.            afm[i].sYDeviceRes != FontResY ||
  1989.            afm[i].lEmHeight != fheight ||
  1990.            afm[i].lMaxCharInc != fwidth ||
  1991.            strcmpi(afm[i].szFacename, fat.szFacename)); i++);
  1992.  
  1993.      /*
  1994.       * see if we got one
  1995.       */
  1996.      if (i >= cfonts) {
  1997.         /*
  1998.          * ok, didn't find an exact match, this time search for just
  1999.          * the height - go for broke
  2000.          */
  2001.         for (i = 0; i < cfonts && afm[i].lEmHeight > fheight; i++);
  2002.  
  2003.         /*
  2004.          * couldn't find an appropriate font - sorry charlie
  2005.          */
  2006.         if (i >= cfonts) return 0;
  2007.         /* else - we made it */
  2008.         }
  2009.      memset(&fat, 0, sizeof(FATTRS));
  2010.      fat.usRecordLength = sizeof(FATTRS);
  2011.      fat.lMatch = afm[i].lMatch;
  2012.      strcpy(fat.szFacename, afm[i].szFacename);
  2013.  
  2014.      /*
  2015.       * try once again to make the font
  2016.       */
  2017.      if (rc = GpiCreateLogFont(stdwin, NULL, newid, &fat) != FONT_MATCH) {
  2018.           if ( rc != GPI_ERROR ) GpiDeleteSetId(stdwin,newid);
  2019.           return 0;
  2020.      }
  2021.       }
  2022.  
  2023.       /*
  2024.        * grab a new font node
  2025.        */
  2026.       if (!(ptr = AllocateLocalID())) return 0;
  2027.       ptr->idtype = IS_FONT;
  2028.  
  2029.       /*
  2030.        * set the box on the presentation space - in case we have an outline
  2031.        */
  2032.       GpiSetCharBox(stdwin, &sizef);
  2033.  
  2034.       /*
  2035.        * set the new set
  2036.        */
  2037.       GpiSetCharSet(stdwin, newid);
  2038.       GpiQueryFontMetrics(stdwin, sizeof(FONTMETRICS), &(ptr->u.font.metrics));
  2039.       GpiDeleteSetId(stdwin,newid);
  2040.  
  2041.       /*
  2042.        * add this font to the font list
  2043.        */
  2044.       ptr->next = FontIdEntries;
  2045.       if (FontIdEntries) FontIdEntries->previous = ptr;
  2046.       ptr->previous = NULL;
  2047.       FontIdEntries = ptr;
  2048.       }
  2049.  
  2050.    /*
  2051.     * before we release the font, subtract out the leading
  2052.     */
  2053.    if (wc->font) wc->fntLeading -=
  2054.        (wc->font->metrics.lMaxBaselineExt +
  2055.     wc->font->metrics.lExternalLeading);
  2056.    /*
  2057.     * release the previous font
  2058.     */
  2059.    ReleaseFont(wc->charBundle.usSet);
  2060.  
  2061.    /*
  2062.     * Set the cell in case we got an outline font,
  2063.     * the new character set,
  2064.     * the new font, and
  2065.     * our new leading.
  2066.     */
  2067.    wc->charBundle.sizfxCell = sizef;
  2068.    wc->charBundle.usSet = newid;
  2069.    wc->font = &(ptr->u.font);
  2070.    wc->fntLeading += (wc->font->metrics.lMaxBaselineExt+
  2071.               wc->font->metrics.lExternalLeading);
  2072.  
  2073.    /*
  2074.     * ripple the change -> put this log font on all our wstate PSes
  2075.     */
  2076.    RippleLocalIdAddition(wc, newid);
  2077.  
  2078.    /*
  2079.     * unset us from everyone
  2080.     */
  2081.    UnsetCharContext(wc);
  2082.    return 1;
  2083.    }
  2084.  
  2085.  
  2086. /*
  2087.  * SetNewPattern
  2088.  *  Returns - id of the newly created pattern or -1 on error.
  2089.  */
  2090. int SetNewBitPattern(wcp wc, PBYTE bits)
  2091.    {
  2092.    lclIdentifier *ptr;
  2093.    int i;
  2094.    SHORT id;
  2095.    wsp ws;
  2096.    HBITMAP hbm;
  2097.    HDC hdcMem;
  2098.    HPS hpsMem;
  2099.    SIZEL size = {0, 0};
  2100.    BITMAPINFOHEADER2 bmp;
  2101.    PBITMAPINFO2 pbmi;
  2102.    PRGB2 prgb;
  2103.  
  2104.    /* XXX for now, each pattern will be separate */
  2105.  
  2106.    /*
  2107.     * try to find it first
  2108.     */
  2109.  
  2110.    /*
  2111.     * grab a new local id
  2112.     */
  2113.    if (ptr = AllocateLocalID()) {
  2114.       /*
  2115.        * initialize some data
  2116.        */
  2117.       ptr->idtype = IS_PATTERN;
  2118.       /*
  2119.        * if there was a different stipple before destroy it
  2120.        */
  2121.       ReleasePattern(wc->currPattern);
  2122.       /*
  2123.        * make the bitmap for the pattern
  2124.        *
  2125.        * grab a memory DC
  2126.        */
  2127.       hdcMem = DevOpenDC(HInterpAnchorBlock, OD_MEMORY, "*", 0, NULL,
  2128.              NULLHANDLE);
  2129.       /*
  2130.        * make a presentation space
  2131.        */
  2132.       hpsMem = GpiCreatePS(HInterpAnchorBlock, hdcMem, &size, GPIT_MICRO |
  2133.                GPIA_ASSOC | PU_PELS);
  2134.  
  2135.       /*
  2136.        * initialize the bitmap structure
  2137.        */
  2138.       memset(&bmp, 0, sizeof(BITMAPINFOHEADER2));
  2139.       bmp.cbFix = sizeof(BITMAPINFOHEADER2);
  2140.       bmp.cPlanes = 1;
  2141.       bmp.cBitCount = 1;
  2142.       bmp.cx = bmp.cy = 8;
  2143.  
  2144.       pbmi = (PBITMAPINFO2)calloc(1,sizeof(BITMAPINFO2) + (sizeof(RGB2) << 1));
  2145.       pbmi->cbFix = bmp.cbFix;
  2146.       pbmi->cx = pbmi->cy = 8;
  2147.       pbmi->cPlanes = 1;
  2148.       pbmi->cBitCount = 1;
  2149.  
  2150.       /*
  2151.        * set up the color info
  2152.        */
  2153.       prgb = (PRGB2)(pbmi->argbColor);
  2154.       prgb[1].bBlue = prgb[1].bRed = prgb[1].bGreen = 255;  /* white */
  2155.  
  2156.       /*
  2157.        * build the bitmap
  2158.        */
  2159.       hbm = GpiCreateBitmap(hpsMem, &bmp, CBM_INIT, (PBYTE)bits, pbmi);
  2160.  
  2161.       /*
  2162.        * store the handle to the pattern bitmap
  2163.        */
  2164.       ptr->u.hpat = hbm;
  2165.       /* shouldn't need this anymore ... */
  2166.       free(pbmi);
  2167.  
  2168.       /*
  2169.        * dump the hps, then get rid of the dc
  2170.        */
  2171.       GpiAssociate(hpsMem, NULLHANDLE);
  2172.       GpiDestroyPS(hpsMem);
  2173.  
  2174.       DevCloseDC(hdcMem);
  2175.  
  2176.       /*
  2177.        * set the current stipple pattern
  2178.        */
  2179.       id = (ptr - LocalIds) + 1;
  2180.       wc->currPattern = id;
  2181.  
  2182.       /*
  2183.        * if we are currently 'stippled', update the area bundle
  2184.        */
  2185.       if (!(wc->fillstyle & FS_SOLID)) {
  2186.      wc->areaBundle.usSet = id;
  2187.      wc->areaBundle.usSymbol = PATSYM_DEFAULT;
  2188.  
  2189.      UnsetAreaContext(wc);
  2190.      }
  2191.  
  2192.       /*
  2193.        * update all the PSes
  2194.        */
  2195.       RippleLocalIdAddition(wc, id);
  2196.       /*
  2197.        * add the pattern to the pattern list
  2198.        */
  2199.       ptr->next = PatIdEntries;
  2200.       if (PatIdEntries) PatIdEntries->previous = ptr;
  2201.       ptr->previous = NULL;
  2202.       PatIdEntries = ptr;
  2203.       return 1;
  2204.       }
  2205.    return 0;
  2206.    }
  2207.  
  2208. /*
  2209.  * SetPattern
  2210.  */
  2211. int patbits[] = {
  2212.   0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  2213.   0xFE,0xFF,0xEF,0xFF,0xFE,0xFF,0xEF,0xFF,
  2214.   0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,
  2215.   0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,
  2216.   0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,
  2217.   0x01,0x00,0x10,0x00,0x01,0x00,0x10,0x00,
  2218.   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  2219.   0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
  2220.   0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01,
  2221.   0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,
  2222.   0x10,0x10,0x10,0xFF,0x10,0x10,0x10,0x10,
  2223.   0x82,0x44,0x28,0x10,0x28,0x44,0x82,0x01,
  2224.   0x0F,0x0F,0x0F,0x0F,0xF0,0xF0,0xF0,0xF0,
  2225.   0x1B,0x18,0x81,0xB1,0x36,0x06,0x60,0x63,
  2226.   0x02,0x02,0x05,0xF8,0x20,0x20,0x50,0x8F,
  2227.   0x03,0x84,0x48,0x30,0x03,0x84,0x48,0x30,
  2228.  
  2229. };
  2230. /*
  2231.  * pattern symbols
  2232.  */
  2233. stringint siPatternSyms2[] = {
  2234.   {0,        16},
  2235.   { "black",     0},
  2236.   { "checkers",  12},
  2237.   { "darkgray",  2},
  2238.   { "diagonal",  8},
  2239.   { "grains",    13},
  2240.   { "gray",      3},
  2241.   { "grid",      10},
  2242.   { "horizontal",9},
  2243.   { "lightgray", 4},
  2244.   { "scales",    14},
  2245.   { "trellis",   11},
  2246.   { "vertical",  7},
  2247.   { "verydark",  1},
  2248.   { "verylight", 5},
  2249.   { "waves",     15},
  2250.   { "white",     6},
  2251. };
  2252. int SetPattern(wbp w, char *name, int len)
  2253.    {
  2254.    C_integer buf[64];
  2255.    int symbol;
  2256.    int width, nbits = 64;
  2257.    STDLOCALS(w);
  2258.  
  2259.    if (w->context->patternname != NULL)
  2260.       free(w->context->patternname);
  2261.    w->context->patternname = malloc(len+1);
  2262.    mystrncpy(w->context->patternname, name, len);
  2263.  
  2264.   /*
  2265.    * If the pattern starts with a number it is a width , bits encoding
  2266.    */
  2267.   if ((len > 0) && ((name[0] == '#') || isdigit(name[0]))) {
  2268.      if (parsepattern(name, len, &width, &nbits, buf) == Error)
  2269.     ReturnErrNum(144, 0);
  2270.      return SetPatternBits(w, width, buf, nbits);
  2271.      }
  2272.    /*
  2273.     * find the symbol id
  2274.     */
  2275.    if ((symbol = si_s2i(siPatternSyms, w->context->patternname)) >= 0) {
  2276.       /*
  2277.        * release the previous pattern
  2278.        */
  2279.       ReleasePattern(wc->currPattern);
  2280.       wc->currPattern = -symbol;
  2281.       /*
  2282.        * if we are currently stippled, change the bundle
  2283.        */
  2284.       if (!(wc->fillstyle & FS_SOLID)) {
  2285.      wc->areaBundle.usSet = LCID_DEFAULT;
  2286.      wc->areaBundle.usSymbol = symbol;
  2287.      UnsetAreaContext(wc);
  2288.      }
  2289.       return Succeeded;
  2290.       }
  2291.    /*
  2292.     * find the symbol id
  2293.     */
  2294.    if ((symbol = si_s2i(siPatternSyms2, w->context->patternname)) >= 0) {
  2295.       return SetPatternBits(w,8,&patbits[ symbol * 8] ,8);
  2296.       }
  2297.    ReturnErrNum(144,0);
  2298.    }
  2299.  
  2300. int SetPatternBits(w, width, bits, nbits)
  2301. wbp w;
  2302. int width;
  2303. C_integer *bits;
  2304. int nbits;
  2305.    {
  2306.    int i, j, k, val, height;
  2307.    BYTE data[32];
  2308.    STDLOCALS(w);
  2309.    /*
  2310.     * zero out the bits
  2311.     */
  2312.    memset(data, 0, sizeof(data));
  2313.    /*
  2314.     * bitmaps are aligned on word (32bit) boundaries.  So, with an 8x8
  2315.     * pattern, you need 32 bytes (1 bit per pel).
  2316.     *
  2317.     * fill in the bits, flipping over because of PM way of doing things.
  2318.     * In PM, patterns *must* be 8x8.  if the user supplies fewer bits,
  2319.     * we'll blow the pattern 'out' for them to fill in the remainder
  2320.     */
  2321.    for (i = 0, j = 28; i < nbits && j >= 0; j -= 4, i++) {
  2322.       val = bits[i];
  2323.       /*
  2324.        * if they specified a smaller than 8 width, blow the pattern out
  2325.        * to fill in the missing
  2326.        */
  2327.       data[j] = (BYTE)val;
  2328.       if (width < 8)
  2329.      for (k = 0; k < (8 / width) + ((8 % width != 0) ? 0 : -1); k++)
  2330.         data[j] = (data[j] << width) | (BYTE)val;
  2331.       }
  2332.    /*
  2333.     * have to blow out the height too - if j > 0, some left to do
  2334.     */
  2335.    for (k = 28; j >= 0; j -= 4, k -= 4)
  2336.       data[j] = data[k];
  2337.  
  2338.    /* this function will do all the work */
  2339.    if (!SetNewBitPattern(w->context, data))
  2340.       return Error;
  2341.    return Succeeded;
  2342.    }
  2343.  
  2344.  
  2345. /*
  2346.  * TransKeyMsg -
  2347.  *  Parameters - the broken out flags, and the two identifying words
  2348.  *  Returns - an icon event code equivalent or -1 if the event should
  2349.  *          be dropped
  2350.  */
  2351. int TransKeyMsg(USHORT flags, MPARAM mp, ULONG *keyval)
  2352.    {
  2353.    SHORT tmp;
  2354.  
  2355.    /* set the key modifier flags */
  2356.    *keyval = (flags & KC_CTRL) ? ControlMask : 0;
  2357.    *keyval |= (flags & KC_ALT) ? Mod1Mask : 0;
  2358.    *keyval |= (flags & KC_SHIFT) ? ShiftMask : 0;
  2359.  
  2360.    if (flags & KC_VIRTUALKEY) {
  2361.       switch(tmp = SHORT2FROMMP(mp)) {
  2362.       case VK_F1: *keyval |= 65470; break;
  2363.       case VK_F2: *keyval |= 65471; break;
  2364.       case VK_F3: *keyval |= 65472; break;
  2365.       case VK_F4: *keyval |= 65473; break;
  2366.       case VK_F5: *keyval |= 65474; break;
  2367.       case VK_F6: *keyval |= 65475; break;
  2368.       case VK_F7: *keyval |= 65476; break;
  2369.       case VK_F8: *keyval |= 65477; break;
  2370.       case VK_F9: *keyval |= 65478; break;
  2371.       case VK_F10: *keyval |= 65479; break;
  2372.       case VK_F11: *keyval |= 65480; break;
  2373.       case VK_F12: *keyval |= 65481; break;
  2374.       case VK_LEFT: *keyval |= 65361; break;
  2375.       case VK_UP: *keyval |= 65362; break;
  2376.       case VK_RIGHT: *keyval |= 65363; break;
  2377.       case VK_DOWN: *keyval |= 65364; break;
  2378.       case VK_HOME: *keyval |= 65360; break;
  2379.       case VK_PAGEUP: *keyval |= 65365; break;
  2380.       case VK_END: *keyval |= 65367; break;
  2381.       case VK_PAGEDOWN: *keyval |= 65366; break;
  2382.       case VK_ALTGRAF: *keyval |= 0; break;
  2383.       case VK_PAUSE: *keyval |= 65299; break;
  2384.       case VK_PRINTSCRN: *keyval |= 65377; break;
  2385.       case VK_SCRLLOCK: *keyval |= 65300; break;
  2386.       case VK_NUMLOCK: *keyval |= 65407; break;
  2387.       case VK_INSERT: *keyval |= 65379; break;
  2388.       /* this is the control key going down by itself */
  2389.       case VK_CTRL: return 0;
  2390.       case VK_ESC:
  2391.     /* ASCII value for escape is 27 */
  2392.     *keyval |= 0x1B;
  2393.     return 1;
  2394.       case VK_DELETE:
  2395.     /* ASCII value for delete is 16 */
  2396.     *keyval |= 0x10;
  2397.     return 1;
  2398.       default:;
  2399.      }
  2400.       /* see if we set the lower 16 bits */
  2401.       if ((*keyval) & 0xFFFF) {
  2402.     *keyval |= VirtKeyMask;
  2403.     return 1;
  2404.     } /* End of if - recognized virtual key */
  2405.       }
  2406.  
  2407.    /*
  2408.     * make sure we don't get some garbage in the upper 8
  2409.     */
  2410.    tmp = (SHORT1FROMMP(mp) & 0xFF);
  2411.    /*
  2412.     * check for a control character (modify keycode if CTRL pressed)
  2413.     */
  2414.    if (((flags & KC_CHAR) || (flags & KC_CTRL)) && tmp > 0) {
  2415.       *keyval |= (flags & KC_CTRL) ? tmp % 32 : tmp;
  2416.       return 1;
  2417.       }
  2418.    /*
  2419.     * drop everything else
  2420.     */
  2421.    return 0;
  2422.    }
  2423.  
  2424.  
  2425. /*
  2426.  * UpdateCursorPos
  2427.  */
  2428. void UpdateCursorPos(wsp ws, wcp wc)
  2429.    {
  2430.    PCURSORINFO ptr;
  2431.  
  2432.    if (ws->hpsWin) {
  2433.       ptr = &(ws->cursInfo);
  2434.       MutexOn(ws);
  2435.       ptr->x = ws->x;
  2436.       ptr->y = ws->height - ws->y ;
  2437.       if (ISCURSORONW(ws) && ws->hwnd == WinQueryFocus(HWND_DESKTOP))
  2438.      WinCreateCursor(ws->hwnd, ptr->x, ptr->y, 0, 0, CURSOR_SETPOS, NULL);
  2439.       MutexOff(ws);
  2440.       }
  2441.    }
  2442.  
  2443. /*
  2444.  * wopen
  2445.  */
  2446. FILE *wopen(char *name, struct b_list *lp, dptr attr, int n, int *err_index)
  2447.    {
  2448.    wbp wb;
  2449.    wsp ws;
  2450.    wcp wc;
  2451.    char answer[128];
  2452.    ULONG frame_flags = 0, showflags;
  2453.    static HWND client;
  2454.    QMSG qmsg;
  2455.    HDC hdc;
  2456.    POINTL pt;
  2457.    HDC hdcMem;
  2458.    HPS hps, hpsMem;
  2459.    SIZEL size = { 0, 0 };
  2460.    SHORT height, width, tmp;
  2461.    int i;
  2462.    tended struct b_list *tlp;
  2463.    tended struct descrip attrrslt;
  2464.    static windowid = 0;
  2465.  
  2466.    tlp = lp;
  2467.  
  2468.    /*
  2469.     * allocate a binding, a window state, and a context
  2470.     */
  2471.    Protect(wb = alc_wbinding(), return NULL);
  2472.    Protect(wb->window = alc_winstate(), { free_binding(wb); return NULL; });
  2473.    Protect(wb->context = alc_context(wb), { free_binding(wb); return NULL; });
  2474.    ws = wb->window;
  2475.    ws->listp.dword = D_List;
  2476.    BlkLoc(ws->listp) = (union block *)lp;
  2477.    wc = wb->context;
  2478.  
  2479.    /*
  2480.     * add the context to the window's context pointer array, and
  2481.     * add the window to the context's window pointer array
  2482.     */
  2483.    AddContextDep(ws, wc);
  2484.    AddWindowDep(ws, wc);
  2485.  
  2486.    /*
  2487.     * make a mutex semaphore and grab it
  2488.     */
  2489.    DosCreateMutexSem(NULL, &(ws->mutex), 0, TRUE);
  2490.  
  2491.    /*
  2492.     * send the request for a new window to be made, and wait for a reply
  2493.     */
  2494. /* I wanted to do the simple two liner below.  However, it seems that there is
  2495.    a bug in PM.  If the user is moving or sizing a window when this post happens,
  2496.    the message is lost, even though WinPostQueueMsg reports no error (ie - says
  2497.    it posted the event).  This causes the secondary thread (us) to block
  2498.    indefinately waiting for a reply from thread 1 that will never come.
  2499.    The workaround below solves this by polling our queue, waiting for the
  2500.    response to come back.  If no response in 100 milliseconds, the request is
  2501.    sent again.    The request for a new window is tagged with a window ID.  After
  2502.    creating a window with a specific 'request ID', thread 1 ignores all requests
  2503.    for window creations tagged with that ID (so our request won't be fullfilled
  2504.    multiple times).
  2505.    Yes, this is ugly, but it works.  Any better ideas?
  2506.    I plan to report this behavior when I get a chance to write a little program
  2507.    exhibiting the behavior.  However, since queue managment is being completely
  2508.    rewritten for the next release (> 2.1), I doubt this will be fixed for me.
  2509.    Oh, there'll be something like this in wclose as well.
  2510. */
  2511. #if 0
  2512.    /* ask for a new window */
  2513.    WinPostQueueMsg(HMainMessageQueue, REQUEST_WINDOW, (MPARAM)ws, (MPARAM)0);
  2514.    /* wait for our response from thread 1 */
  2515.    WaitForEvent(NEW_WINDOW, &qmsg);
  2516. #else                    /* PM Bug?? */
  2517.   qmsg.msg = 0;
  2518.   for (;;) {
  2519.      /* ask for a new window */
  2520.      WinPostQueueMsg(HMainMessageQueue, REQUEST_WINDOW, (MPARAM)ws, (MPARAM)windowid);
  2521.      /* look for our results (cross fingers) - this may never return (on close) */
  2522.      ObtainEvents(NULL, NO_WAIT_EVT, NEW_WINDOW, &qmsg);
  2523.      /* check out what we nabbed (if anything), if not what we want sleep for a bit */
  2524.      if (qmsg.msg != NEW_WINDOW) DosSleep(100);
  2525.      else break;
  2526.      } /* End of for - infinite loop waiting for reply */
  2527.    windowid++;
  2528. #endif                    /* PM Bug?? */
  2529.  
  2530.    ws->hwnd = (HWND)qmsg.mp1;        /* mp1 is the client handle */
  2531.    ws->hwndFrame = (HWND)qmsg.mp2;    /* mp2 is the frame window handle */
  2532.    /*
  2533.     * set the initial flag - first size message will clear the initial
  2534.     */
  2535.    SETINITIAL(wb);
  2536.  
  2537.    /*
  2538.     * get the device context for the window, and
  2539.     * build a presentation space for the window
  2540.     */
  2541.    hdc = ws->hdcWin = WinOpenWindowDC(ws->hwnd);
  2542.    ws->hpsWin = GpiCreatePS(HInterpAnchorBlock, hdc, &size,
  2543.                 PU_PELS | GPIA_ASSOC | GPIT_MICRO);
  2544.    /*
  2545.     * setup the backing bitmap
  2546.     */
  2547.    hdcMem = ws->hdcBitmap = DevOpenDC(HInterpAnchorBlock, OD_MEMORY, "*", 0,
  2548.                       NULL, NULLHANDLE);
  2549.    hpsMem = ws->hpsBitmap = GpiCreatePS(HInterpAnchorBlock, hdcMem, &size,
  2550.                     PU_PELS | GPIA_ASSOC | GPIT_MICRO);
  2551.    /*
  2552.     * load the default attributes into the bundles in context
  2553.     */
  2554.    LoadDefAttrs(wb, ws, wc);
  2555.  
  2556.    /* set the system pointer - copy it because we may have to destroy it */
  2557.    ws->hPointer = WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, TRUE);
  2558.    ws->theCursor = SPTR_ARROW;
  2559.  
  2560.    /*
  2561.     * process the passed in attributes - by calling wattrib
  2562.     */
  2563.    for(i = 0; i < n; i++)
  2564.       switch (wattrib(wb, StrLoc(attr[i]), StrLen(attr[i]), &attrrslt,
  2565.               answer)) {
  2566.       case Failed:
  2567.      DosReleaseMutexSem(ws->mutex);
  2568.      wclose(wb);
  2569.      return NULL;
  2570.       case Error:
  2571.      DosReleaseMutexSem(ws->mutex);
  2572.      /* think of something to do here */
  2573.      break;
  2574.      }
  2575.  
  2576.    /*
  2577.     * set the title, defaulting to the "filename" supplied to open()
  2578.     */
  2579.    if (ws->windowlabel == NULL) ws->windowlabel = salloc(name);
  2580.    WinSetWindowText(ws->hwndFrame,
  2581.             ((ws->winState & WS_MIN) ? ws->iconlabel :
  2582.              ws->windowlabel));
  2583.    /*
  2584.     * query system settings to find out size of borders and title bar -
  2585.     * make the window the exact size the customer wanted (ie - size frame)
  2586.     */
  2587.    height = ws->height + TITLEHEIGHT + (BORDERHEIGHT << 1);
  2588.    width = ws->width + (BORDERWIDTH << 1);
  2589.  
  2590.    /*
  2591.     * the window background is taken from the context background
  2592.     */
  2593.    ws->winbg = wc->areaBundle.lBackColor;
  2594.  
  2595.    /*
  2596.     * preload our contexts - only char context is really neede for the
  2597.     * cursor display, but lets load them all for the fun of it
  2598.     */
  2599.  
  2600.    SetCharContext(wb, ws, wc);
  2601.    SetLineContext(wb, ws, wc);
  2602.    SetAreaContext(wb, ws, wc);
  2603.    SetImageContext(wb, ws, wc);
  2604.  
  2605.    MutexOff(ws);
  2606.    ResizeBackingBitmap(ws, ws->width, ws->height);
  2607.  
  2608.    /* size, make visible, place and bring the window to the top  */
  2609.    showflags = SWP_SIZE | SWP_MOVE;
  2610.  
  2611.    if (ws->winState & WS_MIN) showflags |= SWP_MINIMIZE;
  2612.    else if(ws->winState & WS_MAX) showflags |= SWP_MAXIMIZE;
  2613.  
  2614.    if (!(ws->winState & WS_HIDDEN)) showflags |= SWP_ZORDER | SWP_SHOW | SWP_ACTIVATE;
  2615.  
  2616.    WinSetWindowPos(ws->hwndFrame, HWND_TOP,
  2617.            ws->posx, ScreenHeight - ws->posy - height,
  2618.            width, height, showflags);
  2619.  
  2620.    return (FILE *)wb;
  2621.    }
  2622.  
  2623. /*
  2624.  * wclose - make sure the window goes away - no questions asked
  2625.  */
  2626. int wclose(wbp w)
  2627.    {
  2628.    /*
  2629.     * Ask primary to close the window for us
  2630.     */
  2631.    DestroyWindow(w->window);
  2632.  
  2633.    free_binding(w);
  2634.    return 1;
  2635.    }
  2636.  
  2637. /*
  2638.  * write some text to both the window and the pixmap
  2639.  */
  2640. novalue xdis(w,s,n)
  2641. register wbp w;
  2642. char *s;
  2643. int n;
  2644.    {
  2645.    POINTL pt;
  2646.    STDLOCALS(w);
  2647.  
  2648.    pollctr>>=1; pollctr++;
  2649.  
  2650.    MutexOn(ws);
  2651.    /*
  2652.     * load the character context
  2653.     */
  2654.  
  2655.    SetCharContext(w, ws, wc);
  2656.    /*
  2657.     * fixup the current position
  2658.     */
  2659.    pt.x = ws->x;
  2660.    /*
  2661.     * draw to the window
  2662.     */
  2663.    if (stdwin && !(ws->winState & WS_MIN)) {
  2664.       /*
  2665.        * move the position, then draw the stuff on the window
  2666.        */
  2667.       pt.y = ws->height - (ws->y);
  2668.       GpiCharStringAt(stdwin, &pt, n, s);
  2669.       }
  2670.    /*
  2671.     * draw to the bitmap
  2672.     */
  2673.    pt.y = ws->pixheight - ws->y;
  2674.    GpiCharStringAt(stdbit, &pt, n, s);
  2675.    /*
  2676.     * update the current position
  2677.     */
  2678.    GpiQueryCurrentPosition(stdbit, &pt);
  2679.    ws->x = pt.x;
  2680.    ws->y = ws->pixheight - pt.y;
  2681.  
  2682.    MutexOff(ws);
  2683.    }
  2684. /*
  2685.  * wputc
  2686.  */
  2687. int wputc(int ci, wbp wb)
  2688.    {
  2689.    char c = (char)ci;
  2690.    POINTL pt, pt2;
  2691.    HPS hps, hpsb;
  2692.    wsp ws;
  2693.    POINTL pts[3];
  2694.    int diff;
  2695.    wcp wc;
  2696.    int scrollamt;
  2697.    FONTMETRICS *metrics;
  2698.  
  2699.  
  2700.    wc = wb->context;
  2701.    ws = wb->window;
  2702.    hps = ws->hpsWin;
  2703.    hpsb = ws->hpsBitmap;
  2704.  
  2705.    /*
  2706.     * turn off the cursor
  2707.     */
  2708.    hidecrsr(ws);
  2709.    switch (c) {
  2710.    case '\n':
  2711.  
  2712.       MutexOn(ws);
  2713.       /*
  2714.        * load the current character context
  2715.        */
  2716.       SetCharContext(wb, ws, wc);
  2717.       metrics = &(wc->font->metrics);
  2718.       /*
  2719.        * check if we need to clear to end of line
  2720.        */
  2721.       if (ISCEOLON(wb)) {
  2722.     pts[0].x = 0;
  2723.     pts[0].y = ws->height - (ws->y + metrics->lMaxDescender);
  2724.     pts[1].x = ws->width;
  2725.     pts[1].y = pts[0].y - metrics->lMaxBaselineExt;
  2726.     WinFillRect(hps, (PRECTL)pts, ws->winbg);
  2727.     pts[0].y = ws->pixheight - (ws->y + metrics->lMaxDescender);
  2728.     pts[1].y = pts[0].y + metrics->lMaxBaselineExt;
  2729.     WinFillRect(hpsb, (PRECTL)pts, ws->winbg);
  2730.     }
  2731.  
  2732.       /*
  2733.        * if at the end of the window (currpos.y - height < 0)
  2734.        */
  2735. /* CCW
  2736.       scrollamt = metrics->lMaxDescender + wc->fntLeading +
  2737.           metrics->lMaxBaselineExt + ws->y + wc->dy - ws->height;
  2738. */
  2739.       scrollamt = wc->fntLeading + ws->y - ws->height;
  2740.  
  2741.       if (scrollamt > 0) {
  2742.      /*
  2743.       * common calculation done once
  2744.       */
  2745.      diff = ws->pixheight - ws->height;
  2746.      /*
  2747.       * determine the points for the region to be scrolled
  2748.       */
  2749.      pts[0].x = 0;
  2750.      pts[0].y = diff + scrollamt;
  2751.      pts[1].x = ws->width;
  2752.      pts[1].y = ws->pixheight;
  2753.      pts[2].x = 0;
  2754.      pts[2].y =  diff;
  2755.      /*
  2756.       * move a portion of the bitmap 'up'
  2757.       */
  2758.      GpiBitBlt(ws->hpsBitmap, ws->hpsBitmap, 3, pts, ROP_SRCCOPY, 0UL);
  2759.      /*
  2760.       * paint over the exposed area - make point array look like rect
  2761.       */
  2762.      pts[1].y = pts[0].y;
  2763.      pts[0].y = diff;
  2764.      WinFillRect(hpsb, (PRECTL)pts, ws->winbg);
  2765.      /*
  2766.       * blit to the window
  2767.       */
  2768.      pts[0].y = 0;
  2769.      pts[1].x = ws->width;
  2770.      pts[1].y = ws->height;
  2771.      pts[2].y = diff;
  2772.      GpiBitBlt(hps, hpsb, 3, pts, ROP_SRCCOPY, 0UL);
  2773.      ws->y += wc->fntLeading - scrollamt;
  2774.      }
  2775.       else
  2776.      /*
  2777.       * update the cursor position
  2778.       */
  2779.      ws->y += wc->fntLeading;
  2780.       /* intended fall-through */
  2781.     case '\r':
  2782.       /*
  2783.        * set the new x position
  2784.        */
  2785.       ws->x = wc->dx;
  2786.       MutexOff(ws);
  2787.       break;
  2788.    case '\t':
  2789.       xdis(wb, "        ", 8 - (XTOCOL(wb,ws->x) & 7));
  2790.       break;
  2791.       /*
  2792.        * Handle backspaces.  This implements cooked mode echo handling.
  2793.        */
  2794.    case '\177':
  2795.    case '\010': {
  2796.       int i = 0, pre_x;
  2797.       LONG cwid;
  2798.  
  2799.       MutexOn(ws);
  2800.       /*
  2801.        * grab the current character context
  2802.        */
  2803.       SetCharContext(wb, ws, wc);
  2804.       MutexOff(ws);
  2805.       /*
  2806.        * Start with the last character queued up.
  2807.        */
  2808.       i--;
  2809.       /*
  2810.        * Trot back to the control-H itself.
  2811.        */
  2812.       while ((i>-EQUEUELEN) && (EVQUESUB(wb,i) != c)) i--;
  2813.       if (i == -EQUEUELEN) break;
  2814.       /*
  2815.        * Go past the control-H.
  2816.        */
  2817.       i--;
  2818.       /*
  2819.        * Go back through any number of control-H's from prior lifetimes.
  2820.        */
  2821.       while((i > -EQUEUELEN) && !isprint(EVQUESUB(wb,i))) i--;
  2822.       if (i == -EQUEUELEN) break;
  2823.  
  2824.       /*
  2825.        * OK, here's the character we're actually rubbing out.  Back up.
  2826.        */
  2827.       c = EVQUESUB(wb,i);
  2828.       pre_x = ws->x;
  2829.  
  2830.       /* get the width of the character to rub out */
  2831.       GpiQueryWidthTable(hps, (LONG)c, 1, &cwid);
  2832.       ws->x -= cwid;
  2833.       /*
  2834.        * Physically erase the character from the queue.  This results in
  2835.        * two control-H's present in the queue.
  2836.        */
  2837.       *evquesub(wb,i) = '\010';
  2838.       /*
  2839.        * Save the backed-up position, and draw spaces through the erased.
  2840.        */
  2841.       i = ws->x;
  2842.       while(ws->x < pre_x) xdis(wb, " ",1);
  2843.       ws->x = i;
  2844.       break;
  2845.       }
  2846.     /*
  2847.      * bell (control-G)
  2848.      */
  2849.     case '\007':
  2850.       DosBeep(800, 200);
  2851.       break;
  2852.    default:
  2853.       xdis(wb, &c, 1);
  2854.       }
  2855.    /*
  2856.     * turn the cursor back on
  2857.     */
  2858.    UpdateCursorPos(ws, wc);
  2859.    showcrsr(ws);
  2860.    return 0;
  2861.    }
  2862.  
  2863. /*
  2864.  * Get a window that has an event pending (queued)
  2865.  */
  2866. wsp getactivewindow(void)
  2867. {
  2868.   static LONG next = 0;
  2869.   LONG i;
  2870.   wsp ws, ptr, stdws = NULL;
  2871.  
  2872.   /* cache the console window value, if exists */
  2873.   if (ConsoleBinding) stdws = ((wbp)ConsoleBinding)->window;
  2874.   /* make sure we are still in bounds */
  2875.   next %= NumWindows;
  2876.   /* gather any new events */
  2877.   ObtainEvents(NULL, NO_WAIT_EVT, 0, NULL);
  2878.   /* position ptr on the next window to get events from (fairness) */
  2879.   for (ws = wstates, i = 0; i < next; i++, ws = ws->next);
  2880.   /* now, see if any events pending on windows */
  2881.   for (i = 0; i < NumWindows; ws = (ws->next) ? ws->next : wstates, i++)
  2882.     if (ws != stdws && BlkLoc(ws->listp)->list.size > 0) {
  2883.       next += i + 1;
  2884.       return ws;
  2885.       } /* End of if - found one with events pending */
  2886.   /* well, we'll just have to wait I guess (and don't wait for console) */
  2887.   while ((ws = ObtainEvents(NULL, WAIT_EVT, 0, NULL)) == stdws && stdws);
  2888.   /* reset 'next' */
  2889.   for (next = 1, ptr = wstates; ptr != ws; next++, ptr = ptr->next);
  2890.   return ws;
  2891. }
  2892.  
  2893. /*
  2894.  * ObtainEvents
  2895.  */
  2896. wsp ObtainEvents(wsp ws, SHORT blockflag, ULONG messg, QMSG *msgout)
  2897.    {
  2898.    static QMSG msg;
  2899.    static QMSG *qmsg;
  2900.    static struct descrip evt;
  2901.    static ULONG evt_x, evt_y;
  2902.    wsp msg_ws = NULL;
  2903.  
  2904.    /*
  2905.     * if block flag set, go for the block
  2906.     */
  2907.    qmsg = (msgout) ? msgout : &msg;
  2908.    while (WinPeekMsg(HInterpAnchorBlock, qmsg, NULLHANDLE, 0, 0, PM_REMOVE) ||
  2909.       (blockflag && WinGetMsg(HInterpAnchorBlock, qmsg, NULLHANDLE, 0, 0))) {
  2910.  
  2911.       /* decipher the window state pointer */
  2912.       msg_ws = (wsp)qmsg->mp1;
  2913.  
  2914.       /* Events that don't get passed on to the icon prog */
  2915.       if (qmsg->msg == REQUEST_SHUTDOWN)
  2916.      InterpThreadShutdown();  /* never return */
  2917.  
  2918.       /* short circuit - if we match and they passed in a structure to fill,
  2919.              break out */
  2920.       else if ((!ws || ws == msg_ws) && (!messg || qmsg->msg == messg) && msgout)
  2921.     return msg_ws;
  2922.  
  2923.       /* catch some errors - we should never see these events getting this far */
  2924.       else if (qmsg->msg == DESTROYED_WINDOW || qmsg->msg == NEW_WINDOW)
  2925.     Bomb("Received and event that shouldn't have happened.", "");
  2926.  
  2927.       /* Events that get passed on to the icon program */
  2928.       else {
  2929.      /*
  2930.       * update pointerx, and pointery in window state.
  2931.       * map the point to our window
  2932.       */
  2933.      WinMapWindowPoints(HWND_DESKTOP, msg_ws->hwnd, &(qmsg->ptl), 1);
  2934.      msg_ws->pointerx = (SHORT)qmsg->ptl.x;
  2935.      msg_ws->pointery = msg_ws->height - (SHORT)msg.ptl.y;
  2936.  
  2937.      /* message data is formatted as follows: (mp2)
  2938.         [byte 3] - unused
  2939.         [byte 2] - keyboard modifier flags, virtual key flag
  2940.         [byte 1] - extended keyboard spills over into this byte (VIRT_KEY)
  2941.         [byte 0] - ASCII code if KEY_PRESS, part of VIRT_KEY or window
  2942.                event otherwise (like mouse move, resize...)
  2943.      */
  2944.  
  2945.      /*
  2946.       * take the event and shove it onto the window's icon list
  2947.       */
  2948.      if (qmsg->msg == KEY_PRESS) {
  2949.         /* check for virtual key flag */
  2950.         if (((ULONG)qmsg->mp2) & VirtKeyMask) {
  2951.           MakeInt(0xFFFF & (int)qmsg->mp2, &evt);
  2952.           } /* End of if - virt key */
  2953.         else {
  2954.           StrLen(evt) = 1;
  2955.           StrLoc(evt) = &allchars[((int)qmsg->mp2) & 0xFF];
  2956.           } /* End of else - ascii char (vs. virtual key) */
  2957.         } /* End of if - event is a key press */
  2958.      else {
  2959.         MakeInt((signed char)(0xFF & ((int)qmsg->mp2)), &evt);
  2960.         } /* End of else - all other events (like mouse click, ...) */
  2961.      /*
  2962.       * send the event to be queued up
  2963.       */
  2964.      qevent(&(msg_ws->listp), &evt, msg_ws->pointerx, msg_ws->pointery,
  2965.         qmsg->time, (((ULONG)qmsg->mp2) & 0x00FF0000));
  2966.  
  2967.      /* if the event matches up to what we want, get out */
  2968.      if ((!messg || messg == qmsg->msg) && (!ws || ws == msg_ws))
  2969.        return msg_ws;
  2970.      }
  2971.       }
  2972.    return msg_ws;
  2973.    }
  2974.  
  2975. /*
  2976.  * wgetq - get event from pending queue
  2977.  */
  2978. int wgetq(wbp w, dptr res)
  2979.    {
  2980.    wsp ws;
  2981.    int first = 0;
  2982.  
  2983.    if (!w || !(ws = w->window) || !(ws->hpsWin)) return -1;
  2984.    while (1) {
  2985.       /*
  2986.        * grab the built up queue
  2987.        */
  2988.       if (!EVQUEEMPTY(ws)) {
  2989.      EVQUEGET(ws, *res);
  2990.      return 1;
  2991.      }
  2992.       ObtainEvents(ws, WAIT_EVT, 0, NULL);
  2993.       }
  2994.    return -1;
  2995.    }
  2996.  
  2997. int do_config(wbp w, int status)
  2998.    {
  2999.    int wid = w->window->width, ht = w->window->height;
  3000.    int posx = w->window->posx, posy = w->window->posy;
  3001.  
  3002.    STDLOCALS(w);
  3003.  
  3004.    if (ws->hwndFrame) {
  3005.       pollevent();
  3006.       if (status == 3) {
  3007.      if (moveResizeWindow(w, posx, posy, wid, ht) == Failed) return Failed;
  3008.      }
  3009.       else if (status == 2)
  3010.      resizeWindow(w,wid, ht);
  3011.       else if (status == 1)
  3012.      moveWindow(w, posx, posy);
  3013.       }
  3014.    return Succeeded;
  3015.    }
  3016. /*
  3017.  * determine the new size of the client
  3018.  */
  3019. int setheight(wbp w,SHORT height)
  3020.    {
  3021.    wsp ws = w->window;
  3022.    ws->height = height;
  3023.  
  3024.    /*
  3025.     * If this is not an initial sizing specification, change the
  3026.     *  existing window.
  3027.     */
  3028.    if (!ISINITIAL(w)) {
  3029.       /*
  3030.        * if we are dealing with a window
  3031.        */
  3032.       if (ws->hwndFrame) {
  3033.      if (ws->winState & WS_MIN)
  3034.         WinSetWindowUShort(ws->hwndFrame, QWS_CYRESTORE,
  3035.                    height + TITLEHEIGHT + (BORDERHEIGHT << 1));
  3036.      else
  3037.         WinSetWindowPos(ws->hwndFrame, 0, 0, 0,
  3038.                 ws->width + (BORDERWIDTH << 1),
  3039.                 height + TITLEHEIGHT + (BORDERHEIGHT << 1),
  3040.                 SWP_SIZE);
  3041.      }
  3042.       /*
  3043.        * make sure the bitmap is big enough
  3044.        */
  3045.       if (ws->hBitmap) ResizeBackingBitmap(ws, ws->width, height);
  3046.       }
  3047.    return Succeeded;
  3048.    }
  3049.  
  3050. /*
  3051.  * determine new size of client
  3052.  */
  3053. int setwidth(wbp w,SHORT width)
  3054.    {
  3055.    wsp ws = w->window;
  3056.    ws->width = width;
  3057.    /*
  3058.     * If this is not an initial sizing specification, change the
  3059.     *  existing window.
  3060.     */
  3061.    if (!ISINITIAL(w)) {
  3062.       /*
  3063.        * if we are dealing with a window
  3064.        */
  3065.       if (ws->hwndFrame) {
  3066.      if (ws->winState & WS_MIN)
  3067.         WinSetWindowUShort(ws->hwndFrame, QWS_CXRESTORE,
  3068.                    width + (BORDERWIDTH << 1));
  3069.      else
  3070.         WinSetWindowPos(ws->hwndFrame, 0, 0, 0,
  3071.                 width + (BORDERWIDTH << 1),
  3072.                 ws->height + TITLEHEIGHT + (BORDERHEIGHT << 1),
  3073.                 SWP_SIZE);
  3074.      }
  3075.       /*
  3076.        * make sure the bitmap is big enough
  3077.        */
  3078.       if (ws->hBitmap) ResizeBackingBitmap(ws, width, ws->height);
  3079.       }
  3080.    }
  3081.  
  3082. int setgeometry(w, geo)
  3083. wbp w;
  3084. char *geo;
  3085.    {
  3086.    wsp ws = w->window;
  3087.    LONG stat;
  3088.    SHORT x, y, width, height;
  3089.  
  3090.    /*
  3091.     * load some defaults
  3092.     */
  3093.    MutexOn(ws);
  3094.    y = ws->posy; x = ws->posx;
  3095.    width = ws->width; height = ws->height;
  3096.    MutexOff(ws);
  3097.    /*
  3098.     * figure out what we are dealing with
  3099.     */
  3100.    if ((stat = parsegeometry(geo, &x, &y, &width, &height)) == 0) {
  3101.       return Error;
  3102.     }
  3103.    else {
  3104.       /*
  3105.        * correct for neg positional values
  3106.        */
  3107.       if (x != ws->posx && x < 0)
  3108.     x += ScreenWidth - width - (BORDERWIDTH << 1);
  3109.       if (y != ws->posy && y < 0)
  3110.     y += ScreenHeight - height - (BORDERHEIGHT << 1) - TITLEHEIGHT;
  3111.       /*
  3112.        * make the changes stick
  3113.        */
  3114.       if (stat & 1) {
  3115.      ws->width = width;
  3116.      ws->height = height;
  3117.      }
  3118.       if (stat & 2) {
  3119.      ws->posx = x;
  3120.      ws->posy = y;
  3121.      }
  3122.       if (!ISINITIAL(w)) {
  3123.      if (ws->hwndFrame) {
  3124.         if (ws->winState & WS_MIN) {
  3125.            WinSetWindowUShort(ws->hwndFrame, QWS_CXRESTORE,
  3126.                   width + (BORDERWIDTH << 1));
  3127.            WinSetWindowUShort(ws->hwndFrame, QWS_CYRESTORE,
  3128.                   height + TITLEHEIGHT + (BORDERWIDTH << 1));
  3129.            WinSetWindowUShort(ws->hwndFrame, QWS_XRESTORE, x);
  3130.            WinSetWindowUShort(ws->hwndFrame, QWS_YRESTORE,
  3131.                   ScreenHeight - y -
  3132.                   (height + (BORDERHEIGHT << 1) + TITLEHEIGHT));
  3133.            }
  3134.         else
  3135.            WinSetWindowPos(ws->hwndFrame, 0, x,
  3136.                    ScreenHeight - y -
  3137.                    (height + (BORDERHEIGHT << 1) + TITLEHEIGHT),
  3138.                    width + (BORDERWIDTH << 1),
  3139.                    height + TITLEHEIGHT + (BORDERHEIGHT << 1),
  3140.                    SWP_SIZE | SWP_MOVE);
  3141.         }
  3142.      /*
  3143.       * make sure the bitmap is big enough - dont bother on the initial
  3144.       */
  3145.      if (ws->hBitmap) ResizeBackingBitmap(ws, width, height);
  3146.      }
  3147.       }
  3148.    return Succeeded;
  3149.    }
  3150.  
  3151. novalue getcanvas(wbp w,char *s)
  3152.    {
  3153.    STDLOCALS(w);
  3154.       if (!WinIsWindowVisible(stdwin)) {
  3155.     sprintf(s,"hidden");
  3156.       }
  3157.       else switch (w->window->winState) {
  3158.       case WS_NORMAL:
  3159.      sprintf(s, "normal");
  3160.      break;
  3161.       case WS_MIN:
  3162.      sprintf(s, "iconic");
  3163.      break;
  3164.       case WS_MAX:
  3165.      sprintf(s, "maximal");
  3166.      break;
  3167.       default:
  3168.      sprintf(s, "hidden");
  3169.       }
  3170.    }
  3171.  
  3172. int setcanvas(wbp w,char *s)
  3173.    {
  3174.    ULONG cmd;
  3175.    STDLOCALS(w);
  3176.    cmd = SWP_SHOW;
  3177.    if (!strcmp(s, "iconic")) {
  3178.     cmd |= SWP_MINIMIZE;
  3179.     w->window->winState = (w->window->winState & WS_HIDDEN) | WS_MIN;
  3180.       }
  3181.    else if (!strcmp(s, "normal")) {
  3182.     cmd != SWP_RESTORE;
  3183.     w->window->winState = (w->window->winState & WS_HIDDEN) | WS_NORMAL;
  3184.       }
  3185.    else if (!strcmp(s, "maximal")) {
  3186.     cmd != SWP_MAXIMIZE;
  3187.     w->window->winState = (w->window->winState & WS_HIDDEN) | WS_MAX;
  3188.       }
  3189.    else if (!strcmp(s, "hidden")) {
  3190.     w->window->winState |= WS_HIDDEN;
  3191.     WinShowWindow(stdwin,FALSE);
  3192.     return Succeeded;
  3193.       }
  3194.    else return Error;
  3195.    WinSetWindowPos(stdwin,HWND_TOP,0,0,0,0,cmd);
  3196.    return Succeeded;
  3197.    }
  3198.  
  3199. int seticonicstate(w, val)
  3200. wbp w;
  3201. char *val;
  3202.    {
  3203.    int height;
  3204.    ULONG flags = SWP_SIZE | SWP_MOVE | SWP_ACTIVATE | SWP_ZORDER;
  3205.    wsp ws = w->window;
  3206.    int already = 0;
  3207.    /*
  3208.     * doesn't apply to bitmap
  3209.     */
  3210.    if (!ws->hwndFrame) return Failed;
  3211.    /*
  3212.     * break out what we mean
  3213.     */
  3214.    if (!strcmp(val, "icon")) {
  3215.       already = (ws->winState & WS_MIN);
  3216.       ws->winState = (ws->winState & WS_HIDDEN) | WS_MIN;
  3217.       flags |= SWP_MINIMIZE;
  3218.       }
  3219.    else if (!strcmp(val, "window")) {
  3220.       already = (ws->winState & WS_NORMAL);
  3221.       ws->winState = (ws->winState & WS_HIDDEN) | WS_NORMAL;
  3222.       flags |= SWP_RESTORE;
  3223.       }
  3224.    else if (!strcmp(val, "fullscreen")) {
  3225.       already = (ws->winState & WS_MAX);
  3226.       ws->winState = (ws->winState & WS_HIDDEN) | WS_MAX;
  3227.       flags |= SWP_MAXIMIZE;
  3228.       }
  3229.    else return Error;
  3230.    if( !(ws->winState & WS_HIDDEN)) flags |= SWP_SHOW;
  3231.  
  3232.    height = ws->height + TITLEHEIGHT + (BORDERHEIGHT << 1);
  3233.    if (!already && !ISINITIAL(w)) {
  3234.         /*
  3235.          * dumb hack - see WM_PAINT in rxwindw.r
  3236.          */
  3237.       if (flags & SWP_MINIMIZE) SETMINPEND(w);
  3238.       WinSetWindowPos(ws->hwndFrame, HWND_TOP,
  3239.               ws->posx, ScreenHeight - ws->posy - height,
  3240.               ws->width + (BORDERWIDTH << 1), height, flags);
  3241.       }
  3242.    return Succeeded;
  3243.    }
  3244.  
  3245. int seticonlabel(w, val)
  3246. wbp w;
  3247. char *val;
  3248.    {
  3249.    wsp ws = w->window;
  3250.    /*
  3251.     * doesn't make sense for a bitmap
  3252.     */
  3253.    if (!ws->hpsWin) return Failed;
  3254.    /*
  3255.     * plug in the new string
  3256.     */
  3257.    free(ws->iconlabel);
  3258.    ws->iconlabel = salloc(val);
  3259.    /*
  3260.     * if we have to update, do it
  3261.     */
  3262.    if (!ISINITIAL(w) && (ws->winState & WS_MIN))
  3263.       WinSetWindowText(ws->hwndFrame, ws->iconlabel);
  3264.    return Succeeded;
  3265.    }
  3266.  
  3267. int seticonpos(w, val)
  3268. wbp w;
  3269. char *val;
  3270.    {
  3271.    return Failed;
  3272.    }
  3273.  
  3274. int setwindowlabel(w, val)
  3275. wbp w;
  3276. char *val;
  3277.    {
  3278.    wsp ws = w->window;
  3279.    char *tmp;
  3280.  
  3281.    if (!ws->hpsWin) return Failed;   /* doesn't make sense for a bitmap */
  3282.    /*
  3283.     * plug in the new string
  3284.     */
  3285.    /* done (flip) this way to avoid a race condition */
  3286.    tmp = ws->windowlabel;
  3287.    ws->windowlabel = salloc(val);
  3288.    free(tmp);
  3289.    /*
  3290.     * if we have to update, do it
  3291.     */
  3292.    MutexOn(ws);
  3293.    if (!ISINITIAL(w) && !(ws->winState & WS_MIN))
  3294.       WinSetWindowText(ws->hwndFrame, ws->windowlabel);
  3295.    MutexOff(ws);
  3296.    return Succeeded;
  3297.    }
  3298.  
  3299. int setcursor(w, on)
  3300. wbp w;
  3301. int on;
  3302.    {
  3303.    wsp ws = w->window;
  3304.    if (!ws->hpsWin) return Failed;
  3305.    MutexOn(ws);
  3306.    if (on) {
  3307.      SETCURSORON(w);
  3308.      if (WinQueryFocus(HWND_DESKTOP) == ws->hwnd) {
  3309.        WinCreateCursor(ws->hwnd, ws->cursInfo.x, ws->cursInfo.y,
  3310.                ws->cursInfo.cx, ws->cursInfo.cy, CURSOR_FLASH, NULL);
  3311.        WinShowCursor(ws->hwnd, 1);
  3312.        } /* End of if - we have the focus */
  3313.      } /* End of if - turning it on */
  3314.    else {
  3315.      CLRCURSORON(w);
  3316.      WinDestroyCursor(ws->hwnd);
  3317.      } /* End of else - turnin off */
  3318.    MutexOff(ws);
  3319.    return Succeeded;
  3320.    }
  3321.  
  3322. /*
  3323.  * Set the window's font by name.
  3324.  */
  3325. int setfont(w, s)
  3326. wbp w;
  3327. char **s;
  3328.    {
  3329.    int flags;
  3330.    int size;
  3331.  
  3332.    char family[256];
  3333.    char *stdfam;
  3334.  
  3335.    if( parsefont(*s,family,&flags,&size) ) {
  3336.       /*
  3337.        * This is a legal Icon font spec (and it's not an unadorned "fixed").
  3338.        * Check first for special "standard" family names.
  3339.        */
  3340.       if (!strcmp(family, "mono")) {
  3341.      stdfam = "System Monospaced";
  3342.      flags |= FONTFLAG_MONO + FONTFLAG_SANS;
  3343.      }
  3344.       else if (!strcmp(family, "fixed")) {
  3345.      stdfam = "System Monospaced";
  3346.      flags |= FONTFLAG_MONO + FONTFLAG_SANS;
  3347.      }
  3348.       else if (!strcmp(family, "typewriter")) {
  3349.      stdfam = "Courier";
  3350.      flags |= FONTFLAG_MONO + FONTFLAG_SERIF;
  3351.      }
  3352.       else if (!strcmp(family, "sans")) {
  3353.      stdfam = "Helvetica";
  3354.      flags |= FONTFLAG_PROPORTIONAL + FONTFLAG_SANS;
  3355.      }
  3356.       else if (!strcmp(family, "serif")) {
  3357.      stdfam = "Times New Roman";
  3358.      flags |= FONTFLAG_PROPORTIONAL + FONTFLAG_SERIF;
  3359.      }
  3360.       else if (!strcmp(family, "proportional")) {
  3361.      stdfam = "System Proportional";
  3362.      }
  3363.       else stdfam = NULL;
  3364.  
  3365.       if (stdfam) {
  3366.      /*
  3367.       * Standard name: first try preferred family, then generalize.
  3368.       */
  3369.      if (LoadFont(w, stdfam, flags,size) )
  3370.          return Succeeded;
  3371.       }
  3372.       else {
  3373.      /*
  3374.       * Any other name: must match as specified.
  3375.       */
  3376.      if (LoadFont(w, family, flags,size) )
  3377.          return Succeeded;
  3378.      else {
  3379.         strcpy(family,*s);
  3380.         stdfam = strchr(family,',');
  3381.         if (stdfam) *stdfam = '\0';
  3382.         if (LoadFont(w,family,flags,size) )
  3383.          return Succeeded;
  3384.      }
  3385.       }
  3386.  
  3387.  
  3388.       }
  3389.    return Failed;
  3390.  
  3391.    }
  3392.  
  3393. /*
  3394.  * rebind() - bind w's context to that of w2.
  3395.  */
  3396. int rebind(w, w2)
  3397. wbp w, w2;
  3398.    {
  3399.    wsp ws = w->window;
  3400.    wcp wc;
  3401.    w->context = wc = w2->context;
  3402.    /*
  3403.     * Make sure font and such are loaded for that window
  3404.     */
  3405.    AddPatternToWindow(ws, wc->currPattern);
  3406.    AddFontToWindow(ws, wc->charBundle.usSet);
  3407.    /*
  3408.     * make the dependencies
  3409.     */
  3410.    if (!AddWindowDep(ws, wc) || !AddContextDep(ws, wc))
  3411.       return Error;
  3412.    return Succeeded;
  3413.    }
  3414.  
  3415. novalue setclip(w)
  3416. wbp w;
  3417.    {
  3418.    UnsetClipContext(w->context);
  3419.    MutexOn(w->window);
  3420.    SetClipContext(w, w->window, w->context);
  3421.    MutexOff(w->window);
  3422.    }
  3423.  
  3424. novalue unsetclip(w)
  3425. wbp w;
  3426.    {
  3427.    HRGN hscrap;
  3428.    STDLOCALS(w);
  3429.    GpiSetClipRegion(stdwin,NULL,&hscrap);
  3430.    GpiSetClipRegion(stdbit,NULL,&hscrap);
  3431.    UnsetClipContext(w->context);
  3432.    /* ?? */
  3433.    }
  3434.  
  3435. /*
  3436.  * if the window exists and is visible, set its position to (x,y)
  3437.  */
  3438. novalue moveWindow(wbp w,int x, int y)
  3439.    {
  3440.    STDLOCALS(w);
  3441.    if (stdwin && WinIsWindowVisible(ws->hwndFrame))
  3442.       /* won't protect with mutex since only 1 state var is accessed - atomic */
  3443.       WinSetWindowPos(ws->hwndFrame, 0, x,
  3444.              ScreenHeight - y -
  3445.              (ws->height + (BORDERHEIGHT << 1) + TITLEHEIGHT),
  3446.              0, 0, SWP_MOVE);
  3447.    else if (stdwin) {
  3448.       /* only time this will happen is when invisible, shouldn't have to
  3449.      protect with mutex */
  3450.       ws->posx = x;
  3451.       ws->posy = y;
  3452.       }
  3453.    }
  3454.  
  3455. int resizeWindow(w,width,height)
  3456. wbp w;
  3457. int width, height;
  3458.    {
  3459.    STDLOCALS(w);
  3460.    if (stdwin && WinIsWindowVisible(ws->hwndFrame))
  3461.       WinSetWindowPos(ws->hwndFrame, 0, 0, 0, width + (BORDERWIDTH << 1),
  3462.               height + (BORDERHEIGHT << 1) + TITLEHEIGHT, SWP_SIZE);
  3463.    else {
  3464.       /* win is either invisible or is jsut bitmap, either case, user cannot
  3465.      adjust size and therefore this needs not be protected */
  3466.       ws->width = width;
  3467.       ws->height = height;
  3468.       }
  3469.    }
  3470.  
  3471. int moveResizeWindow(wbp w,int x, int y, int width, int height)
  3472.    {
  3473.    STDLOCALS(w);
  3474.    if (stdwin && WinIsWindowVisible(ws->hwndFrame))
  3475.       WinSetWindowPos(ws->hwndFrame, 0, x,
  3476.               ScreenHeight - y -
  3477.               (ws->height + (BORDERHEIGHT << 1) + TITLEHEIGHT),
  3478.               width + (BORDERWIDTH << 1),
  3479.               height + (BORDERHEIGHT << 1) + TITLEHEIGHT,
  3480.               SWP_SIZE | SWP_MOVE);
  3481.    else {
  3482.       ws->posx = x;
  3483.       ws->posy = y;
  3484.       ws->width = width;
  3485.       ws->height = height;
  3486.       }
  3487.    }
  3488.  
  3489. int lowerWindow(wbp w)
  3490.    {
  3491.    STDLOCALS(w);
  3492.  
  3493.    return (!ws->hpsWin ||
  3494.        !WinSetWindowPos(ws->hwndFrame, HWND_BOTTOM, 0, 0, 0, 0,
  3495.        SWP_ZORDER)) ? Failed : Succeeded;
  3496.    }
  3497.  
  3498. int raiseWindow(wbp w)
  3499.    {
  3500.    STDLOCALS(w);
  3501.  
  3502.    return (!ws->hpsWin ||
  3503.        !WinSetWindowPos(ws->hwndFrame, HWND_TOP, 0, 0, 0, 0,
  3504.        SWP_ZORDER)) ? Failed : Succeeded;
  3505.    }
  3506.  
  3507. int lookup_color(wbp w,char *s,SysColor *rgbreturn)
  3508.    {
  3509.    return ((*rgbreturn = si_s2i(siColorNames, s)) >= 0);
  3510.    }
  3511.  
  3512. int nativecolor(wbp w,char *s,int *r, int *g, int *b)
  3513.    {
  3514.    SysColor rgb;
  3515.    double invgamma;
  3516.    if(w && w->context)
  3517.     invgamma = 1.0 / w->context->gamma;
  3518.    else invgamma = 1.0;
  3519.  
  3520.    rgb = si_s2i(siColorNames, s);
  3521.    if (rgb < 0)
  3522.       return 0;
  3523.  
  3524.  
  3525.    *r = RED(rgb)   * 257;
  3526.    *g = GREEN(rgb) * 257;
  3527.    *b = BLUE(rgb)  * 257;
  3528.  
  3529.    *r = 65535 * pow(*r / 65535.0, invgamma);
  3530.    *g = 65535 * pow(*g / 65535.0, invgamma);
  3531.    *b = 65535 * pow(*b / 65535.0, invgamma);
  3532.  
  3533.    return 1;
  3534.    }
  3535.  
  3536. novalue warpPointer(wbp w,int x, int y)
  3537.    {
  3538.    POINTL pt;
  3539.  
  3540.    pt.x = x;
  3541.    /*
  3542.     * Fixup the y with respect to the window - ie. flip it, then
  3543.     *  convert coordinates to desktop (i.e. root) coordinates, and
  3544.     *  finally, set the pointer position.
  3545.     */
  3546.    pt.y = w->window->height - y;
  3547.    WinMapWindowPoints(w->window->hwnd, HWND_DESKTOP, &pt, 1);
  3548.    WinSetPointerPos(HWND_DESKTOP, pt.x, pt.y);
  3549.    }
  3550. int warpAbsolute(int x, int y)
  3551.    {
  3552.    y = ScreenHeight - y;
  3553.    WinSetPointerPos(HWND_DESKTOP, x, y);
  3554.    }
  3555.  
  3556. /*
  3557.  * Set the context's fill style by name.
  3558.  */
  3559. int setfillstyle(wbp w,char *s)
  3560.    {
  3561.    STDLOCALS(w);
  3562.  
  3563.    if (!strcmp(s, "solid")) {
  3564.       wc->fillstyle = FS_SOLID;
  3565.       wc->areaBundle.usSet = LCID_DEFAULT;
  3566.       wc->areaBundle.usSymbol = PATSYM_SOLID;
  3567.       wc->areaBundle.usBackMixMode = BM_LEAVEALONE;
  3568.       }
  3569.    else {
  3570.       if (!strcmp(s, "masked")
  3571.        || !strcmp(s, "stippled") ||
  3572.       !strcmp(s, "patterned")) {
  3573.      wc->fillstyle = FS_STIPPLE;
  3574.      wc->areaBundle.usBackMixMode = BM_LEAVEALONE;
  3575.      }
  3576.       else if (!strcmp(s, "textured")
  3577.         || !strcmp(s, "opaquestippled") ||
  3578.            !strcmp(s, "opaquepatterned")) {
  3579.      wc->fillstyle = FS_OPAQUESTIPPLE;
  3580.      wc->areaBundle.usBackMixMode = BM_OVERPAINT;
  3581.      }
  3582.       else return Error;
  3583.       /*
  3584.        * fixup the bundle
  3585.        */
  3586.       if (wc->currPattern >= 0) { /* pattern currently bitmap or default */
  3587.      wc->areaBundle.usSet = wc->currPattern;
  3588.      wc->areaBundle.usSymbol = PATSYM_DEFAULT;
  3589.      }
  3590.       else { /* pattern specifies symbol */
  3591.      wc->areaBundle.usSet = LCID_DEFAULT;
  3592.      wc->areaBundle.usSymbol = abs(wc->currPattern);
  3593.      }
  3594.       }
  3595.    /*
  3596.     * cause a lazy update
  3597.     */
  3598.    UnsetAreaContext(wc);
  3599.    return Succeeded;
  3600.    }
  3601.  
  3602. /*
  3603.  * Set the context's line style by name.
  3604.  */
  3605. int setlinestyle(wbp w,char *s)
  3606.    {
  3607.    SHORT ltype;
  3608.    STDLOCALS(w);
  3609.  
  3610.    if ((ltype = si_s2i(siLineTypes, s)) < 0)
  3611.       return Error;
  3612.    wc->lineBundle.usType = ltype;
  3613.    UnsetLineContext(wc);
  3614.    return Succeeded;
  3615.    }
  3616.  
  3617. /*
  3618.  * Set the context's line width
  3619.  */
  3620. int setlinewidth(wbp w, LONG linewid)
  3621.    {
  3622.    STDLOCALS(w);
  3623.  
  3624.    if (linewid < 0)
  3625.       return Error;
  3626.    if (linewid == 0) wc->lineBundle.lGeomWidth = LINEWIDTH_DEFAULT;
  3627.    else wc->lineBundle.lGeomWidth = linewid - 1;
  3628.    UnsetLineContext(wc);
  3629.    return Succeeded;
  3630.    }
  3631.  
  3632.  
  3633. /*
  3634.  * Set the foreground to draw in a mutable color (not supported under PM)
  3635.  */
  3636. int isetfg(wbp w, int i)
  3637.    {
  3638.    return Failed;
  3639.    }
  3640.  
  3641.  
  3642. /*
  3643.  * Builds a color and returns its index
  3644.  */
  3645. LONG GetColorIndex(char *buf,double gamma)
  3646. {
  3647.   char *ptr;
  3648.   int r, g, b;
  3649.   ULONG rgb;
  3650.   colorEntry *ce;
  3651.   LONG indx;
  3652.  
  3653.   /* trim the color name */
  3654.   while (isspace(*buf)) buf++;
  3655.   for (ptr = buf + strlen(buf) - 1; isspace(*ptr) && ptr > buf; ptr--) *ptr = '\0';
  3656.   /* is it a real name or an RGB spec */
  3657.   ptr = (isalpha(*buf)) ? buf : NULL;
  3658.  
  3659.   rgb = ParseRGBValue(buf,gamma);
  3660.  
  3661.   if ((LONG)rgb < 0)
  3662.      return -1;
  3663.  
  3664.  
  3665.   /* let's see if we can find it already allocated and placed */
  3666.   for (ce = UsedCEntries; ce; ce = ce->next)
  3667.     if (ce->rgb == rgb) {
  3668.       /* check if we need to set the name */
  3669.       if (!ce->name && ptr) ce->name = salloc(ptr);
  3670.       /* one more person using this color */
  3671.       ce->refcount++;
  3672.       return ((ULONG)ce - (ULONG)ColorTable) / sizeof(colorEntry);
  3673.       } /* End of if - we found a match */
  3674.  
  3675.   /* did not find it... allocate a new color and ripple effect */
  3676.   if (FreeCEntries) {
  3677.     /* remove the node from the list */
  3678.     ce = FreeCEntries;
  3679.     FreeCEntries = ce->next;
  3680.     if (FreeCEntries) FreeCEntries->previous = NULL;
  3681.     /* put it in the used list */
  3682.     ce->next = UsedCEntries;
  3683.     if (UsedCEntries) UsedCEntries->previous = ce;
  3684.     UsedCEntries = ce;
  3685.     /* fill the entry in */
  3686.     ce->refcount = 1;
  3687.     ce->rgb = rgb;
  3688.     ce->bits = CLR_USED;
  3689.     /* try to set the color name */
  3690.     if (ptr) ce->name = salloc(ptr);
  3691.     /* update all the presentation spaces */
  3692.     indx = ((ULONG)ce - (ULONG)ColorTable) / sizeof(colorEntry);
  3693.     RippleColorAddition(indx);
  3694.     return indx;
  3695.     } /* End of if - have some space to use still */
  3696.    return -1;
  3697. } /* End of GetColorIndex */
  3698.  
  3699. /*
  3700.  * Set the context's foreground color
  3701.  */
  3702. int setfg(wbp w, char *s)
  3703. {
  3704.   int indx, tmpindx;
  3705.   wcp wc = w->context;
  3706.  
  3707.   if ((indx = GetColorIndex(s,wc->gamma)) >= 0) {
  3708.     /* if we are in mode reverse, xor the index for the new color */
  3709.     if (ISXORREVERSE(w)) {
  3710.       /* construct the new foreground color */
  3711.       indx ^= wc->charBundle.lBackColor;
  3712.       /* make sure it is available for PS loading */
  3713.       EnsureColorAvailable(indx);
  3714.       /* release the previous foreground color */
  3715.       tmpindx = wc->charBundle.lColor ^ wc->charBundle.lBackColor;
  3716.       ReleaseColor(tmpindx);
  3717.       }
  3718.     else /* just free the old color */
  3719.       ReleaseColor(wc->charBundle.lColor);
  3720.     /* set the color attribute in the context */
  3721.     wc->areaBundle.lColor = indx;
  3722.     wc->charBundle.lColor = indx;
  3723.     wc->lineBundle.lColor = indx;
  3724.     /* This context needs to be unloaded and subsequently reload for our change
  3725.        to take    effect. */
  3726.     UnsetAllContext(wc);
  3727.     return Succeeded;
  3728.     } /* End of if - got the color */
  3729.   return Failed;
  3730. } /* End of setfg */
  3731.  
  3732. /*
  3733.  * Set the window context's background color
  3734.  */
  3735. int setbg(wbp w, char *s)
  3736. {
  3737.   int indx, findx;
  3738.   wcp wc = w->context;
  3739.  
  3740.   if ((indx = GetColorIndex(s,wc->gamma)) >= 0) {
  3741.     /* release the current background color */
  3742.     ReleaseColor(wc->charBundle.lBackColor);
  3743.     /* if we are in reverse mode, have to change the foreground color */
  3744.     if (ISXORREVERSE(w)) {
  3745.       /* break the real foreground color back out */
  3746.       findx = (wc->charBundle.lColor ^ wc->charBundle.lBackColor);
  3747.       /* the new index for the foreground */
  3748.       findx ^= indx;
  3749.       /* make sure new foreground color is available */
  3750.       EnsureColorAvailable(findx);
  3751.       /* set the new foreground color */
  3752.       wc->areaBundle.lColor = findx;
  3753.       wc->lineBundle.lColor = findx;
  3754.       wc->charBundle.lColor = findx;
  3755.       /* have to unset the line bundle here too */
  3756.       UnsetLineContext(wc);
  3757.       } /* End of if - mode reverse */
  3758.     /* set the color attribute in the context */
  3759.     wc->areaBundle.lBackColor = indx;
  3760.     wc->charBundle.lBackColor = indx;
  3761.     /* unset us */
  3762.     UnsetCharContext(wc);
  3763.     UnsetAreaContext(wc);
  3764.     /* if we are initializing, also set the window background color */
  3765.     if (ISINITIAL(w)) w->window->winbg = wc->areaBundle.lBackColor;
  3766.     return Succeeded;
  3767.     } /* End of if - got the color */
  3768.   return Failed;
  3769. } /* End of setbg */
  3770.  
  3771. /*
  3772.  * Set the context's background color by color cell.
  3773.  */
  3774. int isetbg(wbp w,int bg)
  3775.    {
  3776.    return 0;
  3777.    }
  3778.  
  3779. /*
  3780.  * Set the gamma correction factor  (not supported yet).
  3781.  */
  3782. int setgamma(wbp w,double gamma)
  3783.    {
  3784.    char colorname[65];
  3785.    w->context->gamma = gamma;
  3786.    GetColorName(w->context->charBundle.lColor,colorname,64);
  3787.    setfg(w, colorname);         /* reinterpret current Fg/Bg spec */
  3788.    GetColorName(w->context->charBundle.lBackColor,colorname,64);
  3789.    setbg(w, colorname);
  3790.    return 1;
  3791.    }
  3792.  
  3793. /*
  3794.  * setpointer() - define a mouse pointer shape
  3795.  */
  3796. int setpointer(wbp w,char *val)
  3797.    {
  3798.    wsp ws = w->window;
  3799.    int id;
  3800.    HPOINTER oldPtr, newPtr;
  3801.    POINTL ptl;
  3802.    /*
  3803.     * if we are trying to set the pointer on a bitmap- fail
  3804.     */
  3805.    if (!ws->hpsWin) return Failed;
  3806.  
  3807.    if ((id = si_s2i(siSysCursorSyms, val)) >= 0) {
  3808.       ws->theCursor = id;
  3809.       newPtr = WinQuerySysPointer(HWND_DESKTOP, id, TRUE);
  3810.       } /* End of if - a system cursor */
  3811.    else if ((id = si_s2i(siCursorSyms, val)) >= 0) {
  3812.       /* make it negative so we know that we had to load it */
  3813.       ws->theCursor = -id;
  3814.       newPtr = WinLoadPointer(HWND_DESKTOP, NULLHANDLE, id);
  3815.       } /* End of elseif - a loadable cursor? */
  3816.    else return Failed;
  3817.  
  3818.    /* make sure we got the new pointer */
  3819.    if (!newPtr) return Failed;
  3820.  
  3821.    /* store the old handle */
  3822.    oldPtr = ws->hPointer;
  3823.    /* place the new -> atomic change */
  3824.    ws->hPointer = newPtr;
  3825.    /* if the pointer is within our window's boundaries and we have focus,
  3826.       make the change now */
  3827.    WinQueryPointerPos(HWND_DESKTOP, &ptl);
  3828.    if (WinQueryFocus(HWND_DESKTOP) == ws->hwnd &&
  3829.        WinWindowFromPoint(HWND_DESKTOP, &ptl, FALSE) == ws->hwndFrame)
  3830.      WinSetPointer(HWND_DESKTOP, ws->hPointer);
  3831.    /* destroy the previous pointer */
  3832.    if (oldPtr) WinDestroyPointer(oldPtr);
  3833.    return Succeeded;
  3834.    }
  3835.  
  3836. /*
  3837.  * setdrawop() - set the drawing operation
  3838.  */
  3839. int setdrawop(wbp w,char *val)
  3840.    {
  3841.    wcp wc = w->context;
  3842.    int dop;
  3843.    LONG clrindex;
  3844.    USHORT foreground = FM_OVERPAINT;
  3845.  
  3846.    if ((dop = si_s2i(siMixModes, val)) < 0)
  3847.       return Error;
  3848.  
  3849.    /* check if we really need to change - dop != wc->drawop */
  3850.  
  3851.    /*
  3852.     * if we were in mode reverse before, change things back
  3853.     */
  3854.    if (ISXORREVERSE(w)) {
  3855.       /*
  3856.        * put the color back
  3857.        */
  3858.       clrindex = (wc->charBundle.lColor ^ wc->charBundle.lBackColor);
  3859.       wc->charBundle.lColor = clrindex;
  3860.       wc->lineBundle.lColor = clrindex;
  3861.       wc->areaBundle.lColor = clrindex;
  3862.       /*
  3863.        * unset the reverse mode
  3864.        */
  3865.       CLRXORREVERSE(w);
  3866.       }
  3867.  
  3868.    /* set the other, drawing mix modes */
  3869.    switch(dop) {
  3870.    case ROP_USER1: /* mode reverse */
  3871.       /*
  3872.        * find the new foreground color index and set it
  3873.        */
  3874.       clrindex = (wc->charBundle.lColor ^ wc->charBundle.lBackColor);
  3875.       /*
  3876.        * ensure that some color is loaded at clrindex
  3877.        */
  3878.       EnsureColorAvailable(clrindex);
  3879.       /*
  3880.        * set the flag
  3881.        */
  3882.       SETXORREVERSE(w);
  3883.       wc->charBundle.lColor = clrindex;
  3884.       wc->lineBundle.lColor = clrindex;
  3885.       wc->areaBundle.lColor = clrindex;
  3886.       /*
  3887.        * foreground mix will be XOR
  3888.        */
  3889.       foreground = FM_XOR;
  3890.       break;
  3891.    case ROP_SRCAND:
  3892.       foreground = FM_AND;
  3893.       break;
  3894.    case ROP_ZERO:
  3895.       foreground = FM_ZERO;
  3896.       break;
  3897.    case ROP_SRCINVERT:
  3898.       foreground = FM_XOR;
  3899.       break;
  3900.    case ROP_DSTINVERT:
  3901.       foreground = FM_INVERT;
  3902.       break;
  3903.    case ROP_SRCERASE:
  3904.       foreground = FM_MASKSRCNOT;
  3905.       break;
  3906.    case ROP_ONE:
  3907.       foreground = FM_ONE;
  3908.       break;
  3909.    case ROP_MERGEPAINT:
  3910.       foreground = FM_MERGENOTSRC;
  3911.       break;
  3912.    case ROP_SRCPAINT:
  3913.       foreground = FM_OR;
  3914.       break;
  3915.    case ROP_NOTSRCCOPY:
  3916.       foreground = FM_NOTCOPYSRC;
  3917.       break;
  3918.    case ROP_SRCCOPY:
  3919.    default:;
  3920.       }
  3921.    /*
  3922.     * bitblt mix mode
  3923.     */
  3924.    wc->drawop = (dop == ROP_USER1) ? ROP_SRCINVERT : dop;
  3925.  
  3926.    wc->areaBundle.usMixMode = foreground;
  3927.    wc->lineBundle.usMixMode = foreground;
  3928.    wc->charBundle.usMixMode = foreground;
  3929.    UnsetAllContext(wc);
  3930.    return Succeeded;
  3931.    }
  3932.  
  3933. setdisplay(wbp w, char *s)
  3934.    {
  3935.    return Succeeded;    /* Nop under OS/2 */
  3936.    }
  3937.  
  3938. int setimage(wbp w,char *val)
  3939.    {
  3940.    wsp ws = w->window;
  3941.    int width, height;
  3942.    HBITMAP hbm;
  3943.    /*
  3944.     * ensure that we are only called at initialization
  3945.     */
  3946.    if (!ISINITIAL(w)) return Failed;
  3947.    /*
  3948.     * grab the bitmap
  3949.     */
  3950.    if (hbm = loadimage(w, val, &width, &height)) {
  3951.       GpiDeleteBitmap(ws->hInitialBitmap);
  3952.       ws->hInitialBitmap = hbm;
  3953.       /*
  3954.        * set the window size
  3955.        */
  3956.       ws->width = width;
  3957.       ws->height = height;
  3958.       }
  3959.    else return Failed;
  3960.    return Succeeded;
  3961.    }
  3962.  
  3963. int setleading(wbp w,int i)
  3964.    {
  3965.    wcp wc = w->context;
  3966.    wc->fntLeading = wc->font->metrics.lMaxBaselineExt +
  3967.             wc->font->metrics.lExternalLeading + i;
  3968.    }
  3969.  
  3970. novalue toggle_fgbg(wbp w)
  3971.    {
  3972.    LONG tmp;
  3973.    wcp wc = w->context;
  3974.    /*
  3975.     * swap the colors in the character bundle
  3976.     */
  3977.    tmp = wc->charBundle.lColor;
  3978.    wc->charBundle.lColor = wc->charBundle.lBackColor;
  3979.    wc->charBundle.lBackColor = tmp;
  3980.    tmp = wc->areaBundle.lColor;
  3981.    wc->areaBundle.lColor = wc->areaBundle.lBackColor;
  3982.    wc->areaBundle.lBackColor = tmp;
  3983.    tmp = wc->imageBundle.lColor;
  3984.    wc->imageBundle.lColor = wc->imageBundle.lBackColor;
  3985.    wc->imageBundle.lBackColor = tmp;
  3986.    /*
  3987.     * unmark this context as being current (since it has to be
  3988.     * reloaded with new values)
  3989.     */
  3990.    UnsetCharContext(wc);
  3991.    UnsetAreaContext(wc);
  3992.    UnsetImageContext(wc);
  3993.    }
  3994.  
  3995. int getvisual(wbp w,char *answer)
  3996.    {
  3997.    return Failed;
  3998.    }
  3999.  
  4000. /*
  4001.  * getpos() - update the window state's notion of its current position
  4002.  *  (a no-op under OS/2).
  4003.  */
  4004. int getpos(wbp w)
  4005.    {
  4006.    if (!w->window->hpsWin) return Failed;
  4007.    return Succeeded;
  4008.    }
  4009.  
  4010. novalue getfg(wbp w,char *answer)
  4011.    {
  4012. /* strcpy(answer, "fg="); */
  4013.    GetColorName(w->context->charBundle.lColor, answer, 64);
  4014.    }
  4015.  
  4016. novalue getbg(wbp w,char *answer)
  4017.    {
  4018. /* strcpy(answer, "bg="); */
  4019.    GetColorName(w->context->charBundle.lBackColor, answer, 64);
  4020.    }
  4021.  
  4022. novalue getlinestyle(wbp w,char *answer)
  4023.    {
  4024.    char *ptr;
  4025.    if (ptr = si_i2s(siLineTypes, w->context->lineBundle.usType))
  4026. /*    sprintf(answer, "linestyle=%s", ptr); */
  4027.       sprintf(answer, "%s", ptr);
  4028.    else strcpy(answer, "solid");
  4029.    }
  4030.  
  4031. novalue getfntnam(wbp w,char *answer)
  4032.    {
  4033. /* strcpy(answer, "font="); */
  4034.    GetFontName(w->context->charBundle.usSet, answer, 128);
  4035.    }
  4036.  
  4037. novalue getpointername(wbp w,char *answer)
  4038.    {
  4039.    char *s;
  4040.    wsp ws = w->window;
  4041.  
  4042.    if (ws->theCursor < 0)
  4043.      s = si_i2s(siCursorSyms, abs(ws->theCursor));
  4044.    else
  4045.      s = si_i2s(siSysCursorSyms, ws->theCursor);
  4046.    if (s) sprintf(answer, "%s", s);
  4047. /* if (s) sprintf(answer, "pointer=%s", s); */
  4048.    else strcpy(answer, "???");
  4049.    }
  4050.  
  4051. novalue getdisplay(wbp w, char *answer)
  4052.    {
  4053.    strcpy(answer, "local");
  4054.    }
  4055.  
  4056. novalue getdrawop(wbp w,char *answer)
  4057.    {
  4058.    char *s;
  4059.    if (ISXORREVERSE(w)) s = "reverse";
  4060.    else s = si_i2s(siMixModes, w->context->drawop);
  4061.    if (s) sprintf(answer, "%s", s);
  4062. /* if (s) sprintf(answer, "drawop=%s", s); */
  4063.    else strcpy(answer, "copy");
  4064.    }
  4065.  
  4066. novalue geticonic(wbp w,char *answer)
  4067.    {
  4068. /* sprintf(answer, "iconic=%s", */
  4069.    sprintf(answer, "%s",
  4070.        ((w->window->winState & WS_MIN) ? "icon" :
  4071.         (w->window->winState & WS_MAX) ? "fullscreen" : "window"));
  4072.    }
  4073.  
  4074. int geticonpos(wbp w,char *val)
  4075.    {
  4076.    return Failed;
  4077.    }
  4078.  
  4079. /*
  4080.  * erase an area
  4081.  */
  4082. novalue eraseArea(wbp w,int x, int y, int width, int height)
  4083.    {
  4084.    AREABUNDLE abundle;
  4085.    POINTL pts[2];
  4086.    STDLOCALS(w);
  4087.    /*
  4088.     * clear out the bundle
  4089.     */
  4090.    memset(&abundle, 0, sizeof(AREABUNDLE));
  4091.    abundle.lColor = wc->areaBundle.lBackColor;
  4092.    /*
  4093.     * set up the rectangle values
  4094.     */
  4095.    pts[0].x = x;
  4096.    pts[1].x = (width > 0) ? pts[0].x + width - 1 : ws->width - pts[0].x;
  4097.  
  4098.    MutexOn(ws);
  4099.    /*
  4100.     * knock out the context currently selected
  4101.     */
  4102.    ws->areaContext = NULL;
  4103.    /*
  4104.     * clear area using window background color
  4105.     */
  4106.    if (stdwin && !(ws->winState & WS_MIN)) {
  4107.      GpiSetAttrs(stdwin, PRIM_AREA, ABB_COLOR, ABB_SYMBOL | ABB_SET, &abundle);
  4108.      pts[1].y = ws->height - y - 1;
  4109.      pts[0].y = (height > 0) ? pts[1].y - height + 1: 0;
  4110.      GpiMove(stdwin, &pts[0]);
  4111.      GpiBox(stdwin, DRO_FILL, &pts[1], 0, 0);
  4112.      }
  4113.  
  4114.    GpiSetAttrs(stdbit, PRIM_AREA, ABB_COLOR, ABB_SYMBOL | ABB_SET, &abundle);
  4115.    pts[1].y = ws->pixheight - y - 1;
  4116.    /*
  4117.     * if the height is 0.. clear to the bottom of the window
  4118.     */
  4119.    pts[0].y = (height > 0) ? pts[1].y - height + 1 : 0;
  4120.    GpiMove(stdbit, &pts[0]);
  4121.    GpiBox(stdbit, DRO_FILL, &pts[1], 0, 0);
  4122.  
  4123.    MutexOff(ws);
  4124.    }
  4125.  
  4126. /*
  4127.  * copy an area
  4128.  */
  4129. int copyArea(wbp w, wbp w2, int x, int y, int width, int height, int x2, int y2)
  4130.    {
  4131.    POINTL pts[3];
  4132.    wsp src_ws = w->window;
  4133.    HPS src_hps = src_ws->hpsBitmap;
  4134.    STDLOCALS(w2);
  4135.  
  4136.    /*
  4137.     * have to do the copies in the order they are.. from bmp to window
  4138.     * and *then* bmp to bmp.  This is because of the source=destination
  4139.     * problem.    If you do it the other way around, you will get an inconsistent
  4140.     * bmp<->window state
  4141.     */
  4142.    /*
  4143.     * grab both mutexes
  4144.     */
  4145.    MutexOn(ws);
  4146.    MutexOn(src_ws);
  4147.    /*
  4148.     * fix up the points..
  4149.     */
  4150.    pts[0].x = x2;                 /* lower left - target */
  4151.    pts[1].x = x2 + width;             /* upper right - target */
  4152.    pts[2].x = x;                 /* lower left - src */
  4153.    pts[2].y = src_ws->pixheight - y - height;
  4154.    /*
  4155.     * if window is around, blit to it too
  4156.     */
  4157.    if (stdwin && !(ws->winState & WS_MIN)) {
  4158.      /*
  4159.       * fixup the points
  4160.       */
  4161.      pts[1].y = pts[0].y = ws->height - y2;
  4162.      pts[0].y -= height;
  4163.      GpiBitBlt(stdwin, src_hps, 3, pts, wc->drawop, 0UL);
  4164.      }
  4165.    /*
  4166.     * fixup the points for the bitmap
  4167.     */
  4168.    pts[1].y = pts[0].y = ws->pixheight - y2;
  4169.    pts[0].y -= height;
  4170.    /*
  4171.     * blit from src bitmap to destination bitmap
  4172.     */
  4173.    GpiBitBlt(stdbit, src_hps, 3, pts, wc->drawop, 0UL);
  4174.    /*
  4175.     * release the mutexes
  4176.     */
  4177.    MutexOff(ws);
  4178.    MutexOff(src_ws);
  4179.    return Succeeded;
  4180.    }
  4181.  
  4182. int getdefault(wbp w,char *prog, char *opt, char *answer)
  4183.    {
  4184.    return Failed;
  4185.    }
  4186.  
  4187. /*
  4188.  * Draw a bilevel image.
  4189.   */
  4190. int blimage(wbp w, int x, int y, int width, int hgt,
  4191.         int ch, unsigned char *s, word len)
  4192.    {
  4193.    POINTL pt;
  4194.    POINTL pts[3];
  4195.  
  4196.    int c, v, ret;
  4197.  
  4198.    unsigned int m, msk1;
  4199.    unsigned int r, g, b, ix, iy;
  4200.    unsigned int fg, bg;
  4201.  
  4202.    long colorndx[256], i;
  4203.  
  4204.    char tmp[24];
  4205.  
  4206.    STDLOCALS(w);
  4207.  
  4208.    MutexOn(ws);
  4209.  
  4210.  
  4211.    m = width % 4;
  4212.    if (m == 0)
  4213.       msk1 = 8;
  4214.    else
  4215.       msk1 = 1 << (m - 1);        /* mask for first byte of row */
  4216.  
  4217.    fg = wc->areaBundle.lColor;
  4218.    bg = ws->winbg;
  4219.    ix = width;
  4220.    iy = 0;
  4221.    m = msk1;
  4222.  
  4223.    while (len--) {
  4224.       if (isxdigit(c = *s++)) {     /* if hexadecimal character */
  4225.      if (!isdigit(c))        /* fix bottom 4 bits if necessary */
  4226.         c += 9;
  4227.      while (m > 0) {        /* set (usually) 4 pixel values */
  4228.         --ix;
  4229.         if (c & m) {
  4230.            GpiSetColor(stdbit,fg);
  4231.            pt.x = ix + x;
  4232.            pt.y = ws->pixheight - (iy + y);
  4233.            GpiSetPel(stdbit,&pt);
  4234.         }
  4235.         else if (ch != TCH1) {    /* if zeroes aren't transparent */
  4236.            GpiSetColor(stdbit,bg);
  4237.            pt.x = ix + x;
  4238.            pt.y = ws->pixheight - (iy + y);
  4239.            GpiSetPel(stdbit,&pt);
  4240.         }
  4241.         m >>= 1;
  4242.         }
  4243.      if (ix == 0) {         /* if end of row */
  4244.         ix = width;
  4245.         iy++;
  4246.         m = msk1;
  4247.         }
  4248.      else
  4249.         m = 8;
  4250.      }
  4251.       }
  4252.    if (ix > 0) {            /* pad final row if incomplete */
  4253.       GpiSetColor(stdbit,bg);
  4254.       pt.y = ws->pixheight - (iy + y);
  4255.       while (ix < width) {
  4256.            pt.x = ix++ + x;
  4257.            GpiSetPel(stdbit,&pt);
  4258.       }
  4259.    }
  4260.  
  4261.    if (stdwin && !(ws->winState & WS_MIN)) {
  4262.  
  4263.        pts[0].x = pts[2].x = x;
  4264.        pts[0].y = pts[2].y = ws->pixheight - (y+hgt);
  4265.        pts[1].x = x+width;
  4266.        pts[1].y = ws->pixheight - y;
  4267.  
  4268.        GpiBitBlt(stdwin,stdbit,3,pts,ROP_SRCCOPY, 0UL);
  4269.  
  4270.    }
  4271.  
  4272.    MutexOff(ws);
  4273.  
  4274.    return ret;
  4275.    }
  4276.  
  4277. /*
  4278.  * Draw a character-per-pixel image.
  4279.  */
  4280. int strimage(wbp w, int x, int y, int width,
  4281.          int height, struct palentry *e,
  4282.          unsigned char *s, word len, int on_icon)
  4283.    {
  4284.  
  4285.    POINTL pt;
  4286.    POINTL pts[3];
  4287.  
  4288.    int c, v, ret;
  4289.  
  4290.    unsigned int r, g, b, ix, iy;
  4291.  
  4292.    long colorndx[256], i;
  4293.  
  4294.    char tmp[24];
  4295.  
  4296.    STDLOCALS(w);
  4297.  
  4298.    MutexOn(ws);
  4299.    ret = 0;
  4300.    for( c = 0; c < 256; c++) {
  4301.     if (e[c].used && e[c].valid) {
  4302.         r = e[c].clr.red;
  4303.         g = e[c].clr.green;
  4304.         b = e[c].clr.blue;
  4305.         sprintf(tmp,"%d,%d,%d",r,g,b);
  4306.         i = GetColorIndex(tmp,wc->gamma);
  4307.         if( i < 0) {
  4308.         ret++;
  4309.         if ((0.299 * r + 0.587 * g + 0.114 * b) > 32767)
  4310.            i = CLR_WHITE;
  4311.         else
  4312.            i = CLR_BLACK;
  4313.         }
  4314.         colorndx[c] = i;
  4315.     }
  4316.     else colorndx[c] = CLR_BLACK;
  4317.     }
  4318.  
  4319.    /*
  4320.     * Read the image string and set the pixel values.
  4321.     */
  4322.    ix = iy = 0;
  4323.    while (len--) {
  4324.       c = *s++;
  4325.       v = e[c].valid;
  4326.       if (v) {                    /* put char if valid */
  4327.      GpiSetColor(stdbit,colorndx[c]);
  4328.      pt.x = ix + x;
  4329.      pt.y = ws->pixheight - (iy + y);
  4330.      GpiSetPel(stdbit,&pt);
  4331.       }
  4332.       if (v || c == TCH1 || c == TCH2) {    /* advance if valid or txpt */
  4333.      if (++ix >= width) {
  4334.         ix = 0;                /* reset for new row */
  4335.         iy++;
  4336.         }
  4337.      }
  4338.       }
  4339.    if (ix > 0) {            /* pad final row if incomplete */
  4340.       GpiSetColor(stdbit,ws->winbg);
  4341.       pt.y = ws->pixheight - (iy + y);
  4342.       while (ix < width) {
  4343.      pt.x = ix + x;
  4344.      GpiSetPel(stdbit,&pt);
  4345.  
  4346.       }
  4347.    }
  4348.    if (stdwin && !(ws->winState & WS_MIN)) {
  4349.  
  4350.        pts[0].x = pts[2].x = x;
  4351.        pts[0].y = pts[2].y = ws->pixheight - (y+height);
  4352.        pts[1].x = x+width;
  4353.        pts[1].y = ws->pixheight - y;
  4354.  
  4355.        GpiBitBlt(stdwin,stdbit,3,pts,ROP_SRCCOPY, 0UL);
  4356.  
  4357.    }
  4358.  
  4359.    MutexOff(ws);
  4360.  
  4361.    return ret;
  4362.    }
  4363.  
  4364. /*
  4365.  * Get an image as a string.  (stub)
  4366.  */
  4367. int getimstr(wbp w, int x, int y, int width, int hgt,
  4368.          struct palentry *ptbl, unsigned char *data)
  4369.    {
  4370.    return 0;
  4371.    }
  4372.  
  4373. readimage(wbp w,char *filename,int x, int y, int *status)
  4374.    {
  4375.    HBITMAP hbm;
  4376.    POINTL pt;
  4377.    int width, height;
  4378.    STDLOCALS(w);
  4379.    if (hbm = loadimage(w, filename, &width, &height)) {
  4380.       pt.x = x;
  4381.       pt.y = ws->height - y - height;
  4382.       MutexOn(ws);
  4383.       if (stdwin)
  4384.      WinDrawBitmap(stdwin, hbm, NULL, &pt, CLR_WHITE, CLR_BLACK, DBM_NORMAL);
  4385.       pt.y = ws->pixheight - y - height;
  4386.       WinDrawBitmap(stdbit, hbm, NULL, &pt, CLR_WHITE, CLR_BLACK, DBM_NORMAL);
  4387.       MutexOff(ws);
  4388.       GpiDeleteBitmap(hbm);
  4389.       *status = 0;
  4390.       return Succeeded;
  4391.       }
  4392.    return Failed;
  4393.    }
  4394.  
  4395. int pixmap_open(w, attribs, argc)
  4396. wbp w;
  4397. dptr attribs;
  4398. int argc;
  4399.    {
  4400.    SIZEL size = {0, 0};
  4401.    wcp wc;
  4402.    wsp ws;
  4403.  
  4404.    w->context = wc = alc_context(w);
  4405.    w->window = ws = alc_winstate();
  4406.    /*
  4407.     * make the dependencies
  4408.     */
  4409.    if (!AddWindowDep(ws, wc) || !AddContextDep(ws, wc))
  4410.       return Error;
  4411.    /*
  4412.     * build the presentation space and DC for the bitmap
  4413.     */
  4414.    ws->hdcBitmap = DevOpenDC(HInterpAnchorBlock, OD_MEMORY, "*", 0, NULL,
  4415.                  NULLHANDLE);
  4416.    ws->hpsBitmap = GpiCreatePS(HInterpAnchorBlock, ws->hdcBitmap, &size,
  4417.                    PU_PELS | GPIA_ASSOC | GPIT_MICRO);
  4418.    /*
  4419.     * load the default attributes
  4420.     */
  4421.    LoadDefAttrs(w, ws, wc);
  4422.    SETINITIAL(w);
  4423.    return Succeeded;
  4424.    }
  4425.  
  4426. int pixmap_init(w)
  4427. wbp w;
  4428.    {
  4429.    wsp ws = w->window;
  4430.    CLRINITIAL(w);
  4431.    ResizeBackingBitmap(ws, ws->width, ws->height);
  4432.    return Succeeded;
  4433.    }
  4434.  
  4435. /*
  4436.  * Initialize client for producing pixels from a window, a
  4437.  * no-op under OS/2.
  4438.  */
  4439. int getpixel_init(wbp w,int x, int y, int width, int height)
  4440.    {
  4441.    return Succeeded;
  4442.    }
  4443.  
  4444. /*
  4445.  * Return pixel (x,y) from a window
  4446.  */
  4447. int getpixel(wbp w, int x, int y, long *rv, char *s)
  4448.    {
  4449.    ULONG clrindex;
  4450.    int r,g,b;
  4451.    long rgb;
  4452.    double invgamma = 1.0 / w->context->gamma;
  4453.  
  4454.    HPS stdbit = w->window->hpsBitmap;
  4455.    POINTL pt;
  4456.    pt.x = x;
  4457.    pt.y = w->window->pixheight - y;
  4458.    clrindex = GpiQueryPel(stdbit, &pt);
  4459.    GpiQueryLogColorTable(stdbit, 0, clrindex, 1, &rgb);
  4460.    r = RED(rgb) * 257;
  4461.    g = GREEN(rgb) * 257;
  4462.    b = BLUE(rgb) * 257;
  4463.    r = 65535 * pow(r/65535.0,invgamma);
  4464.    g = 65535 * pow(g/65535.0,invgamma);
  4465.    b = 65535 * pow(b/65535.0,invgamma);
  4466.    *rv = 1;
  4467.    sprintf(s,"%d,%d,%d",r,g,b);
  4468.    return Succeeded;
  4469.    }
  4470.  
  4471. int query_pointer(wbp w,XPoint *pp)
  4472.    {
  4473.    wsp ws = w->window;
  4474.    if (ws->hwnd == NULLHANDLE) return Failed;
  4475.    /*
  4476.     * get the current pointer position
  4477.     */
  4478.    WinQueryPointerPos(HWND_DESKTOP, pp);
  4479.    /*
  4480.     * map the points to window coordinates and flip y by the window's height
  4481.     */
  4482.    WinMapWindowPoints(HWND_DESKTOP, ws->hwnd, pp, 1);
  4483.    pp->y = ws->height - pp->y;
  4484.    /*
  4485.     * save the state
  4486.     */
  4487.    ws->pointerx = pp->x;
  4488.    ws->pointery = pp->y;
  4489.    return Succeeded;
  4490.    }
  4491.  
  4492. query_rootpointer(XPoint *pp)
  4493.    {
  4494.    /*
  4495.     * Get the current pointer position, and flip y by the root window's height.
  4496.     */
  4497.    WinQueryPointerPos(HWND_DESKTOP, pp);
  4498.    pp->y = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN) - pp->y;
  4499.    }
  4500.  
  4501. int seticonimage(w, dp)
  4502. wbp w;
  4503. dptr dp;
  4504.    {
  4505.    tended char *tmp;
  4506.    HBITMAP hbm;
  4507.    wsp ws = w->window;
  4508.    /*
  4509.     * get the preloaded (in another window value) pixmap image
  4510.     */
  4511.    if (is:file(*dp) && (BlkLoc(*dp)->file.status & Fs_Window)) {
  4512.       wbp w2;
  4513.       wsp ws2;
  4514.       ULONG size;
  4515.       BITMAPINFOHEADER2 bmp;
  4516.       PBITMAPINFO2 pbmi;
  4517.       PBYTE data;
  4518.       /*
  4519.        * locate the second window
  4520.        */
  4521.       w2 = (wbp)BlkLoc(*dp)->file.fd;
  4522.       ws2 = w2->window;
  4523.       /*
  4524.        * knock out the previous bitmap and the previous filename
  4525.        */
  4526.       GpiDeleteBitmap(ws->hIconBitmap);
  4527.       free(ws->iconimage);
  4528.       ws->iconimage = NULL;
  4529.       /*
  4530.        * load the bitmap data and create a new bitmap
  4531.        */
  4532.       memset(&bmp, 0, sizeof(BITMAPINFOHEADER2));
  4533.       bmp.cbFix = sizeof(BITMAPINFOHEADER2);
  4534.       GpiQueryBitmapInfoHeader(ws2->hBitmap, &bmp);
  4535.       /*
  4536.        * make the info table
  4537.        */
  4538.       size = sizeof(RGB2) * (1 << (bmp.cPlanes * bmp.cBitCount));
  4539.       pbmi = calloc(sizeof(BITMAPINFO2) + size, 1);
  4540.       pbmi->cbFix = bmp.cbFix;
  4541.       pbmi->cPlanes = bmp.cPlanes;
  4542.       pbmi->cBitCount = bmp.cBitCount;
  4543.       /*
  4544.        * allocate space for the data
  4545.        */
  4546.       size = ((bmp.cx * bmp.cPlanes * bmp.cBitCount) + 31) / 32 * 4 * bmp.cy;
  4547.       data = calloc(size, 1);
  4548.       /*
  4549.        * query the data from the bitmap
  4550.        */
  4551.       GpiQueryBitmapBits(ws2->hpsBitmap, 0, ws2->pixheight, data, pbmi);
  4552.       /*
  4553.        * build the new bitmap
  4554.        */
  4555.       ws->hIconBitmap = GpiCreateBitmap(ws->hpsBitmap, &bmp, CBM_INIT, data, pbmi);
  4556.       /*
  4557.        * free the garbage
  4558.        */
  4559.       free(data);
  4560.       free(pbmi);
  4561.       }
  4562.    /*
  4563.     * get the pixmap file named by x
  4564.     */
  4565.    else if (is:string(*dp)) {
  4566.       int height, width;
  4567.       if (!cnv:C_string(*dp,tmp))
  4568.      ReturnErrVal(103, *dp, Error);
  4569.       /*
  4570.        * try to load the bitmap
  4571.        */
  4572.       if (hbm = loadimage(w, tmp, &width, &height)) {
  4573.      GpiDeleteBitmap(ws->hIconBitmap);
  4574.      ws->hIconBitmap = hbm;
  4575.      /*
  4576.       * dup the filename
  4577.       */
  4578.      free(ws->iconimage);
  4579.      ws->iconimage = salloc(tmp);
  4580.      /*
  4581.       * if we are iconic, force a redraw
  4582.       */
  4583.      if (ws->winState & WS_MIN) WinInvalidateRect(ws->hwndFrame, NULL, TRUE);
  4584.      }
  4585.       else return Failed;
  4586.       }
  4587.    else
  4588.       return Failed;
  4589.    return Succeeded;
  4590.    }
  4591.  
  4592. /*
  4593.  * dumpimage -- write an image to a disk file.
  4594.  * PM version accepts .bmp filenames and rejects others with NoCvt return.
  4595.  * This whole routine needs to be revamped - very hackish.
  4596.  */
  4597. int dumpimage(wbp wb, char *filename, unsigned int x, unsigned int y, unsigned int width,int unsigned height)
  4598.    {
  4599.    FILE *fp;
  4600.    BITMAPINFOHEADER2 bmp;
  4601.    PBITMAPINFOHEADER2 pbmp2;
  4602.    BITMAPARRAYFILEHEADER2 afhdr;
  4603.    BITMAPFILEHEADER2 *fhdr;
  4604.    PBITMAPINFO2 pbmi;
  4605.    int result = Failed;
  4606.    ULONG ctblsize, datasize;
  4607.    unsigned char *tdata, *data, *ptr, *cloc;
  4608.    int lshift, rshift, i, j, startbit, startbyte;
  4609.    unsigned char emask;
  4610.    ULONG bytewidth, twidth;
  4611.    LONG tmp;
  4612.    STDLOCALS(wb);
  4613.  
  4614.    if (strcmp(".bmp", filename + strlen(filename) - 4) &&
  4615.        strcmp(".BMP", filename + strlen(filename) - 4))
  4616.       return NoCvt;
  4617.  
  4618.    /*
  4619.     * open the file - binary mode
  4620.     */
  4621.    if (fp = fopen(filename, "wb")) {
  4622.       /*
  4623.        * initialize the header
  4624.        */
  4625.       memset(&afhdr, 0, sizeof(BITMAPARRAYFILEHEADER2));
  4626.       fhdr = &(afhdr.bfh2);
  4627.       pbmp2 = &(fhdr->bmp2);
  4628.       afhdr.cbSize = sizeof(BITMAPARRAYFILEHEADER2);
  4629.       afhdr.usType = BFT_BITMAPARRAY;
  4630.       afhdr.cxDisplay = ScreenWidth;
  4631.       afhdr.cyDisplay = ScreenHeight;
  4632.       /*
  4633.        * get the info about the source bitmap
  4634.        */
  4635.       memset(&bmp, 0, sizeof(BITMAPINFOHEADER2));
  4636.       bmp.cbFix = sizeof(BITMAPINFOHEADER2);
  4637.       GpiQueryBitmapInfoHeader(ws->hBitmap, &bmp);
  4638.  
  4639.       /*
  4640.        * make the info (color) table
  4641.        */
  4642.       ctblsize = sizeof(RGB2) * (1 << (bmp.cPlanes * bmp.cBitCount));
  4643.       pbmi = (PBITMAPINFO2)calloc(sizeof(BITMAPINFO2) + ctblsize, 1);
  4644.       pbmi->cbFix = bmp.cbFix;
  4645.       /*
  4646.        * convert it to one plane if different
  4647.        */
  4648.       pbmi->cBitCount = bmp.cBitCount * bmp.cPlanes;
  4649.       pbmi->cPlanes = 1;
  4650.  
  4651.       /*
  4652.        * allocate space for the data
  4653.        */
  4654.       twidth = (pbmi->cBitCount * bmp.cx + 31) / 32 * 4;
  4655.       datasize = twidth * height;
  4656.       tdata = (PBYTE)calloc(datasize, 1);
  4657.       /*
  4658.        * query the data from the bitmap
  4659.        */
  4660.       GpiQueryBitmapBits(ws->hpsBitmap, ws->pixheight - y - height, height,
  4661.              tdata, pbmi);
  4662.       /*
  4663.        * write the header
  4664.        */
  4665.       fhdr->usType = BFT_BMAP;
  4666.       fhdr->cbSize = sizeof(BITMAPFILEHEADER2);
  4667.       fhdr->offBits = afhdr.cbSize + ctblsize;
  4668.       *pbmp2 = *((PBITMAPINFOHEADER2)pbmi);
  4669.       pbmp2->cclrImportant = 0;
  4670.       pbmp2->cbImage = (pbmi->cBitCount * width + 31) / 32 * 4 * height;
  4671.       pbmp2->cx = width;
  4672.       pbmp2->cy = height;
  4673.       fwrite((void *)&afhdr, 1, sizeof(BITMAPARRAYFILEHEADER2), fp);
  4674.       /*
  4675.        * write the color table
  4676.        */
  4677.       fwrite((void *)pbmi->argbColor, 1, ctblsize, fp);
  4678.       /*
  4679.        * write the bitmap data
  4680.        */
  4681.       if (width != bmp.cx) {
  4682.      /*
  4683.       * width is different than scanned width - shift.
  4684.       *
  4685.       * allocate space for the new bitmap
  4686.       */
  4687.      bytewidth = (pbmi->cBitCount * width + 31) / 32 * 4;
  4688.      datasize = bytewidth * height;
  4689.      data = (PBYTE)calloc(datasize, 1);
  4690.  
  4691.      /* starting bit in first byte */
  4692.      startbit = x * pbmi->cBitCount;
  4693.      /* and the starting byte */
  4694.      startbyte = startbit / 8;
  4695.      /* make mask to chop off unneeded bits */
  4696.      emask = 0xFF << (((tmp = 8 - ((width * pbmi->cBitCount) % 8)) < 8) ? tmp : 0);
  4697.  
  4698.      /*
  4699.       * figure out how much we need to shift the data so that we can
  4700.       * make the first pel start at a byte boundary (and thus all
  4701.       * subsequent bytes also..)
  4702.       */
  4703.      lshift = startbit % 8;
  4704.      rshift = 8 - lshift;
  4705.  
  4706.      for (i = 0; i < height; i++) { /* for every scan line */
  4707.         /* set the pointer into data to fill */
  4708.         cloc = data + bytewidth * i;
  4709.         /* pointer into data to read */
  4710.         ptr = tdata + startbyte + twidth * i;
  4711.         /* assemble the bytes */
  4712.         for (j = 1; j < bytewidth; j++, ptr++, cloc++)
  4713.           *cloc = (lshift) ? ((*ptr << lshift) | (*(ptr + 1) >> rshift)) : *ptr;
  4714.         /* if width didn't fall on byte bounds, have to knock some data off */
  4715.         *cloc = ((*ptr << lshift) & emask);
  4716.         }
  4717.      }
  4718.       else {
  4719.      data = tdata;
  4720.      tdata = NULL;
  4721.      } /* End of else - same widths, use the data we scanned */
  4722.       /*
  4723.        * finally do the write in one big sum, and close the file
  4724.        */
  4725.       fwrite((void *)data, 1, datasize, fp);
  4726.       fclose(fp);
  4727.       free(pbmi);
  4728.       free(data);
  4729.       free(tdata);
  4730.       result = Succeeded;
  4731.       }
  4732.    return result;
  4733.    }
  4734. /*
  4735.  * LoadColorTable
  4736.  */
  4737. static PBITMAPINFO2 LoadColorTable(FILE *fp, PBITMAPINFOHEADER2 pbmp,int oflag)
  4738.    {
  4739.    RGB2 *ctbl;
  4740.    RGB *tctbl;
  4741.    PBITMAPINFO2 pbmi;
  4742.    ULONG cbits, ctblsize, nclrs;
  4743.    int i;
  4744.  
  4745.    cbits = pbmp->cPlanes * pbmp->cBitCount;
  4746.    nclrs = 1 << cbits;
  4747.    ctblsize = (cbits < 24) ? sizeof(RGB2) * nclrs : 0;
  4748.    pbmi = (PBITMAPINFO2)calloc(sizeof(BITMAPINFO2) + ctblsize, 1);
  4749.    pbmi->cx = pbmp->cx;
  4750.    pbmi->cy = pbmp->cy;
  4751.    pbmi->cbFix = sizeof(BITMAPINFOHEADER2);
  4752.    pbmi->cPlanes = pbmp->cPlanes;
  4753.    pbmi->cBitCount = pbmp->cBitCount;
  4754.    ctbl = pbmi->argbColor;
  4755.    /*
  4756.     * if we are true color, we are done
  4757.     */
  4758.    if (cbits < 24) {
  4759.       /*
  4760.        * if we are not the old form, just read in the table..
  4761.        */
  4762.       if (!oflag)
  4763.      return (!fread(ctbl, 1, ctblsize, fp)) ? (free(pbmi), NULL) : pbmi;
  4764.       else {
  4765.      /*
  4766.       * figure the size of table on disk
  4767.       */
  4768.      ctblsize = sizeof(RGB) * nclrs;
  4769.      tctbl = calloc(ctblsize, 1);
  4770.      /*
  4771.       * read the old format table in
  4772.       */
  4773.      if (!fread(tctbl, 1, ctblsize, fp))
  4774.         return (free(pbmi), free(tctbl), NULL);
  4775.      /*
  4776.       * run through the colors, moving them to new format
  4777.       */
  4778.      for (i = 0; i < nclrs; i++)
  4779.         memcpy(&ctbl[i], &tctbl[i], sizeof(RGB));
  4780.      free(tctbl);
  4781.      }
  4782.       }
  4783.    return pbmi;
  4784.    }
  4785.  
  4786. #define FHEADSIZE    ((sizeof(ULONG) << 1) + 3 * sizeof(USHORT))
  4787.  
  4788. /*
  4789.  * loadimage
  4790.  */
  4791. HBITMAP loadimage(wbp wb, char *filename, int *width, int *height)
  4792.    {
  4793.    FILE *fp;
  4794.    HBITMAP hbm = NULLHANDLE;
  4795.    PBITMAPINFOHEADER2 pbmp2;
  4796.    BITMAPINFOHEADER2 bmp2;
  4797.    PBITMAPINFOHEADER pbmp;
  4798.    PBITMAPINFO2 pbmi;
  4799.    PBYTE data;
  4800.    BITMAPFILEHEADER2 fhdr;
  4801.    BITMAPARRAYFILEHEADER2 afhdr;
  4802.    ULONG offset, defoffset;
  4803.    int found;
  4804.    int oldformat = 0;
  4805.    STDLOCALS(wb);
  4806.  
  4807.    /*
  4808.     * zero out the header
  4809.     */
  4810.    memset(&bmp2, 0, sizeof(BITMAPINFOHEADER2));
  4811.    bmp2.cbFix = sizeof(BITMAPINFOHEADER2);
  4812.  
  4813.    if (fp = fopen(filename, "rb")) {
  4814.       /*
  4815.        * read the header to figure out what we are dealing with
  4816.        */
  4817.       if (!fread((void *)&fhdr, 1, sizeof(BITMAPFILEHEADER2), fp))
  4818.      return (fclose(fp), NULLHANDLE);
  4819.       /*
  4820.        * check for a single bitmap in this file
  4821.        */
  4822.       if (fhdr.usType == BFT_BMAP) {
  4823.      if (fhdr.bmp2.cbFix == sizeof(BITMAPINFOHEADER)) {
  4824.         oldformat = 1; /* old 1.X format */
  4825.         pbmp = (PBITMAPINFOHEADER)&(fhdr.bmp2);
  4826.         }
  4827.      else if (fhdr.bmp2.cbFix == sizeof(BITMAPINFOHEADER2))
  4828.         pbmp2 = &(fhdr.bmp2);
  4829.      else return (fclose(fp), NULLHANDLE);
  4830.      /*
  4831.       * reset the file ptr to right after the header - to read clr table
  4832.       */
  4833.      fseek(fp, fhdr.bmp2.cbFix + FHEADSIZE, SEEK_SET);
  4834.      offset = fhdr.offBits;
  4835.      }
  4836.       /*
  4837.        * check for an array of bitmaps
  4838.        */
  4839.       else if (fhdr.usType == BFT_BITMAPARRAY) {
  4840.      offset = defoffset = found = 0;
  4841.      while (!found) {
  4842.         /*
  4843.          * read in a header
  4844.          */
  4845.         if (fseek(fp, offset, SEEK_SET) ||
  4846.         !fread((void *)&afhdr, sizeof(BITMAPARRAYFILEHEADER2), 1, fp)||
  4847.         afhdr.bfh2.usType != BFT_BMAP)
  4848.            return (fclose(fp), NULLHANDLE);
  4849.         /*
  4850.          * check it for the resolution match - 0 will set the default
  4851.          */
  4852.         if (afhdr.cxDisplay==ScreenWidth && afhdr.cyDisplay== ScreenHeight)
  4853.            found = 1;
  4854.         else {
  4855.            /*
  4856.         * res independant, don't match the resolution
  4857.         */
  4858.            if (!afhdr.cxDisplay) defoffset = offset;
  4859.            if (!(offset = afhdr.offNext)) break;
  4860.            }
  4861.         }
  4862.      /*
  4863.       * check if we got anything, if not read in default
  4864.       */
  4865.      if (!found) {
  4866.         offset = defoffset;
  4867.         fseek(fp, offset, SEEK_SET);
  4868.         fread((void *)&afhdr, sizeof(BITMAPARRAYFILEHEADER2), 1, fp);
  4869.         }
  4870.      if (afhdr.cbSize == sizeof(BITMAPARRAYFILEHEADER2))
  4871.         pbmp2 = &(afhdr.bfh2.bmp2);
  4872.      else if (afhdr.cbSize == sizeof(BITMAPARRAYFILEHEADER)) {
  4873.         oldformat = 1;
  4874.         pbmp = (PBITMAPINFOHEADER)&(afhdr.bfh2.bmp2);
  4875.         /*
  4876.          * reset the file pointer to right after the header,
  4877.          * since we read past it
  4878.          */
  4879.         fseek(fp, offset + afhdr.cbSize, SEEK_SET);
  4880.         }
  4881.      else return (fclose(fp), NULLHANDLE);
  4882.      offset = afhdr.bfh2.offBits;
  4883.      }
  4884.       else return (fclose(fp), NULLHANDLE);
  4885.  
  4886.       if (oldformat) {
  4887.      /*
  4888.       * load the values for the 'old' format bitmap
  4889.       */
  4890.      pbmp2 = &bmp2;
  4891.      pbmp2->cx = pbmp->cx;
  4892.      pbmp2->cy = pbmp->cy;
  4893.      pbmp2->cPlanes = pbmp->cPlanes;
  4894.      pbmp2->cBitCount = pbmp->cBitCount;
  4895.      pbmp2->cbImage = ((pbmp->cx * pbmp->cBitCount * pbmp->cPlanes) + 31) /
  4896.         32 * 4 * pbmp->cy;
  4897.      }
  4898.       if (pbmi = LoadColorTable(fp, pbmp2, oldformat)) {
  4899.      /*
  4900.       * store the dimensions for return
  4901.       */
  4902.      *width = pbmi->cx;
  4903.      *height = pbmi->cy;
  4904.      /*
  4905.       * set up space for the data
  4906.       */
  4907.      data = (PBYTE)calloc(pbmp2->cbImage, 1);
  4908.      if (data && !fseek(fp, offset, SEEK_SET) &&
  4909.          fread((void *)data, 1, pbmp2->cbImage, fp))
  4910.         /*
  4911.          * build the bitmap compatible with backing bitmap PS
  4912.          */
  4913.         hbm = GpiCreateBitmap(stdbit, pbmp2, CBM_INIT, data, pbmi);
  4914.      free(data);
  4915.      }
  4916.       free(pbmi);
  4917.  
  4918.       fclose(fp);
  4919.     }
  4920.    /*
  4921.     * return the presentation space
  4922.     */
  4923.    return hbm;
  4924.    }
  4925.  
  4926. /*
  4927.  * Context unsetting mechanism - disassociates all dependent windows from
  4928.  * various contexts - thus forcing them to 'reload' upon the next use.  This
  4929.  * is a form of lazy updating mechanism.  The primary function, UnsetContext,
  4930.  * goes through the dependency list and calls a helper function on each
  4931.  * window in the dependency list.
  4932.  */
  4933. void UnsetContext(wcp wc, void (*f)(wcp, wsp))
  4934.    {
  4935.    int i, num;
  4936.    wsp ws;
  4937.    if (wc) {
  4938.       num = wc->numDeps;
  4939.       for (i = 0; i < wc->maxDeps && num > 0; i++)
  4940.      if (ws = wc->depWindows[i]) {
  4941.         num--;
  4942.         f(wc, ws);
  4943.         }
  4944.       }
  4945.    }
  4946.  
  4947. /*
  4948.  * Helper functions for UnsetContext remove wc from fields of ws.
  4949.  */
  4950. void UAllContext(wcp wc, wsp ws)
  4951.    {
  4952.    if (ws->lineContext == wc) ws->lineContext = NULL;
  4953.    if (ws->charContext == wc) ws->charContext = NULL;
  4954.    if (ws->areaContext == wc) ws->areaContext = NULL;
  4955.    }
  4956. void UCharContext(wcp wc, wsp ws)
  4957.    {
  4958.    if (ws->charContext == wc) ws->charContext = NULL;
  4959.    }
  4960. void ULineContext(wcp wc, wsp ws)
  4961.    {
  4962.    if (ws->lineContext == wc) ws->lineContext = NULL;
  4963.    }
  4964. void UAreaContext(wcp wc, wsp ws)
  4965.    {
  4966.    if (ws->areaContext == wc) ws->areaContext = NULL;
  4967.    }
  4968. void UImageContext(wcp wc, wsp ws)
  4969.    {
  4970.    if (ws->imageContext == wc) ws->imageContext = NULL;
  4971.    }
  4972. void UClipContext(wcp wc, wsp ws)
  4973.    {
  4974.    if (ws->clipContext == wc) {
  4975.     ws->clipContext = NULL;
  4976.     GpiDestroyRegion(ws->hpsWin,ws->hClipWindow);
  4977.     GpiDestroyRegion(ws->hpsBitmap,ws->hClipBitmap);
  4978.     ws->hClipWindow = NULLHANDLE;
  4979.     ws->hClipBitmap = NULLHANDLE;
  4980.     }
  4981.    }
  4982.  
  4983. char *get_mutable_name(wbp w, int mute_index)
  4984.    {
  4985.    return NULL;
  4986.    }
  4987.  
  4988. set_mutable(wbp w, int i, char *s)
  4989.    {
  4990.    return Failed;
  4991.    }
  4992.  
  4993. novalue free_mutable(wbp w, int mute_index)
  4994.    {
  4995.    }
  4996.  
  4997. int mutable_color(wbp w, dptr argv, int argc, int *retval)
  4998.    {
  4999.    return Failed;
  5000.    }
  5001.  
  5002. novalue freecolor(wbp w, char *s)
  5003.    {
  5004.    }
  5005.  
  5006. int walert(wbp w,int volume)
  5007. {
  5008.   STDLOCALS(w);
  5009.   return Failed;
  5010.   }
  5011. #else                    /* PresentationManager */
  5012. static char cxc;            /* avoid empty module */
  5013. #endif                    /* PresentationManager */
  5014.