home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: WPS_PM / WPS_PM.zip / xfld085s.zip / helpers / shapewin.c < prev    next >
C/C++ Source or Header  |  1999-03-15  |  48KB  |  1,513 lines

  1.  
  2. /*
  3.  *@@sourcefile shapewin.c:
  4.  *      contains helper functions for PM windows which do not have a
  5.  *      rectangular shape, but are defined using GPI regions.
  6.  *
  7.  *      This file is new with V0.85.
  8.  *
  9.  *      Function prefixes:
  10.  *      --  shp*    shape window functions
  11.  *
  12.  *      This file consists of two parts:
  13.  *
  14.  *  *** Part 1 ***
  15.  *
  16.  *  The code in Part 1 implements the "Shape" window. This is used
  17.  *  to display a bitmap on the screen with transparency.
  18.  *
  19.  *  Really, it is not the "Shape" window which displays the bitmap.
  20.  *  Since PM can only handle rectangular windows, as many subwindows
  21.  *  as required are created, which are only managed by the "Shape"
  22.  *  window.
  23.  *
  24.  *  If you are not using the frame window functions in Part 2, the
  25.  *  shape window class must be registered like this (the declarations
  26.  *  are in shapein.h):
  27.  *
  28.  +      WinRegisterClass(
  29.  +                     hab,                // anchor block handle
  30.  +                     SHAPE_WINDOW_CLASS, // class name (shapewin.h)
  31.  +                     fnwpShapeWindow,    // window procedure (in this file)
  32.  +                     0L,                 // default window style
  33.  +                     sizeof(PVOID)) ;    // class data size
  34.  *
  35.  *  You can then create shape windows using WinCreateWindow():
  36.  +      hwndShape = WinCreateWindow(
  37.  +                     hwndParent,      // see remark (2)
  38.  +                     SHAPE_WINDOW_CLASS, // class name (shapewin.h)
  39.  +                     pszName,         // doesn't matter
  40.  +                     flStyle,         // can be 0
  41.  +                     x, y, cx, cy,    // can all be 0; shape window
  42.  +                                      // size depends on bitmap
  43.  +                     hwndOwner,       // see remark (2)
  44.  +                     hwndInsertBehind, // should be HWND_TOP
  45.  +                     id,
  46.  +                     pCtlData,        // *SHPCTLDATA, see remark (1)
  47.  +                     pPresParams);    // NULL
  48.  *
  49.  *  Remarks:
  50.  *
  51.  *  1)  Shape windows _require_ a SHPCTLDATA structure for input with
  52.  *      the pCtlData parameter of WinCreateWindow. This structure
  53.  *      must contain the following:
  54.  +          SHORT   cx, cy ;       // bitmap size
  55.  +          HPS     hpsMask;       // HPS with bitmap selected into
  56.  +          HPS     hpsDraw;       // HPS used for drawing the bitmap
  57.  *
  58.  *      Note that hpsMask determines the drawing mask of the bitmap,
  59.  *      while hpsDraw determines the bitmap to be drawn. You can set
  60.  *      both to the same HPS, but you can also use a different bitmap
  61.  *      for the "shape" (in hpsMask).
  62.  *
  63.  *      You _must_ select the bitmap to be displayed into the HPS's,
  64.  *      using GpiSetBitmap, or nothing will work. shpLoadBitmap
  65.  *      in Part 2 of this file offers you a one-shot function for
  66.  *      loading a bitmap either from resources or a PM 1.3 *.BMP
  67.  *      file.
  68.  *
  69.  *      Transparency is determined according to the most lower-left
  70.  *      pixel of the bitmap in hpsMask. That is, all bitmap pixels
  71.  *      which have the same color as pixel (0, 0) will be made
  72.  *      transparent.
  73.  *
  74.  *      During window creation, the shape window analyzes the bitmap
  75.  *      which was selected into hpsMask and creates lots of
  76.  *      rectangular PM windows as neccessary. This is dependent on
  77.  *      the "transparency" pixels of the bitmap.
  78.  *
  79.  *      There is no limit for the size of the bitmap (in the HPS's).
  80.  *      But you should be very careful with large bitmaps, because
  81.  *      this can block the system forever. Shape windows are real
  82.  *      CPU hogs. The number of PM subwindows created depends on the
  83.  *      size of the bitmap and on the transparency. The calculations
  84.  *      are line-based:
  85.  *      --  each line is examined, and a PM window is created for
  86.  *          each line of the input bitmap;
  87.  *      --  if this line contains "transparency" pixels, more PM
  88.  *          windows are created accordingly for that line.
  89.  *      --  However, if several vertically adjacent subwindows have
  90.  *          the same left and right coordinates, they are combined
  91.  *          into one window.
  92.  *
  93.  *      As a result, the more single transparent pixels you have,
  94.  *      the more windows need to be created. The more rectangular
  95.  *      transparent areas you have, the less windows need to be
  96.  *      created.
  97.  *
  98.  *  2)  Shape window requires both a parent and an owner window. As
  99.  *      always, the parent window determines the visibility, while
  100.  *      the owner window requires a more abstract relationship. With
  101.  *      shape windows, the owner window is important because all the
  102.  *      input messages (for mouse and keyboard input) are forwarded
  103.  *      to the owner.
  104.  *
  105.  *      So it's best to set the parent to HWND_DESKTOP and specify
  106.  *      a frame window for the owner. If you don't already have a
  107.  *      frame window in your application, you can create an invisible
  108.  *      frame window just for message handling. That's what the shp*
  109.  *      functions in Part 2 of this file do (Akira Hatakeyama calls
  110.  *      this the "Voodoo" feature).
  111.  *
  112.  *      Never use the shape window as a top-level window.
  113.  *
  114.  *      Note that the keyboard and mouse input messages which are
  115.  *      forwarded to the owner contain mouse coordinates relative
  116.  *      to the rectangular shape subwindow which actually received
  117.  *      the message, not relative to the frame window. So you better
  118.  *      determine the real mouse position using WinQueryPointerPos().
  119.  *
  120.  *  Note that the size of the shape window is defined once upon
  121.  *  creation and cannot be changed later because this would conflict
  122.  *  with all the subwindows which were created. For the same reason,
  123.  *  you cannot alter the bitmap of the shape window after creation.
  124.  *  You must create a second shape bitmap for that.
  125.  *  Thus all the size parameters in WinSetWindowPos are swallowed and
  126.  *  ignored.
  127.  *
  128.  *  *** Part 2 ***
  129.  *
  130.  *  This implements a proper invisible frame window for displaying
  131.  *  shaped bitmap windows directly on the desktop.
  132.  *  See shpLoadBitmap, shpFreeBitmap, and shpCreateWindows for more.
  133.  *
  134.  *@@include #define INCL_GPIBITMAPS // or INCL_GPIPRIMITIVES
  135.  *@@include #include <os2.h>
  136.  *@@include #include "shapewin.h"
  137.  */
  138.  
  139. /*
  140.  *  Credits:
  141.  *      1)  Functions for shaped windows.
  142.  *          This is based on the ShapeWin library 1.01 (SHAPEWIN.ZIP at
  143.  *          Hobbes), (C) 1998, 1999 Software Research Associates, Inc.
  144.  *          This has been written by Akira Hatakeyama (akira@sra.co.jp).
  145.  *          Updated by Takayuki Suwa (jjsuwa@ibm.net).
  146.  *          The original was placed under the GPL.
  147.  *
  148.  *          Changes made by Ulrich Möller (February 1999):
  149.  *          --  some speedup (marked with *UM)
  150.  *          --  renamed and commented out almost all of the functions
  151.  *              and structures to make their use more lucid.
  152.  *
  153.  *      2)  Functions for easily creating shape frame windows from a
  154.  *          given HBITMAP. This has been written by me, after getting
  155.  *          some inspiration from the sample programs in SHAPEWIN.ZIP.
  156.  *
  157.  *      Copyright (C) 1998-99
  158.  *                  Ulrich Möller,
  159.  *                  Akira Hatakeyama,
  160.  *                  Takayuki Suwa.
  161.  *      This file is part of the XFolder source package.
  162.  *      XFolder is free software; you can redistribute it and/or modify
  163.  *      it under the terms of the GNU General Public License as published
  164.  *      by the Free Software Foundation, in version 2 as it comes in the
  165.  *      "COPYING" file of the XFolder main distribution.
  166.  *      This program is distributed in the hope that it will be useful,
  167.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  168.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  169.  *      GNU General Public License for more details.
  170.  *
  171.  */
  172.  
  173. #define INCL_DOS
  174. #define INCL_DOSERRORS
  175. #define INCL_WIN
  176. #define INCL_WINSYS
  177. #define INCL_GPILOGCOLORTABLE
  178. #define INCL_GPIPRIMITIVES
  179. #include <os2.h>
  180.  
  181. #include <stdlib.h>
  182. #include <stdio.h>
  183. #include <string.h>
  184.  
  185. #include "gpih.h"
  186. #include "shapewin.h"
  187.  
  188. /* ******************************************************************
  189.  *                                                                  *
  190.  *   Part 1: Shape window functions                                 *
  191.  *                                                                  *
  192.  ********************************************************************/
  193.  
  194. // forward declarations for structures, because
  195. // the structures are referenced from each other
  196. typedef struct  _SHPWINCTLDATA  *PSHPWINCTLDATA;
  197. typedef struct  _SHPREGION  *PSHPREGION;
  198.  
  199. /*
  200.  * SHPWINCTLDATA:
  201.  *      internal shape window control data.
  202.  *      This is the shape-window-internal structure
  203.  *      to allow the shape window to manage itself.
  204.  *      This is created in WM_CREATE with the data
  205.  *      passed in the mp1 and mp2 parameters
  206.  *      (CREATESTRUCT and SHPCTLDATA).
  207.  *      This is stored in a shape window's window words.
  208.  */
  209.  
  210. typedef struct _SHPWINCTLDATA
  211. {
  212.     // common window parameters
  213.     // (copied from CREATESTRUCT in WM_CREATE)
  214.     HWND        hwndShape ;    // main shape window handle
  215.     HWND        hwndParent;    // shape window's parent (should be HWND_DESKTOP)
  216.     HWND        hwndOwner ;    // shape window's owner, to whom we'll forward all
  217.                                // all the input messages
  218.     USHORT      id        ;    // window ID
  219.     SHORT       x         ;    // x - horz. position
  220.     SHORT       y         ;    // y - vert. position
  221.     SHORT       cx        ;    // horz. size
  222.     SHORT       cy        ;    // vert. size
  223.     PSZ         pszText   ;    // window text
  224.  
  225.     // additional window parameters
  226.     HPS         hpsDraw;       // the input HPS with the bitmap
  227.     ULONG       nRegion;       // number of "regions"
  228.     PSHPREGION  aRegion;       // array of "regions"
  229.  
  230. } SHPWINCTLDATA;
  231.  
  232. /*
  233.  * SHPREGION:
  234.  *      this is the structure for shape window
  235.  *      "regions". Note that has nothing to do
  236.  *      with GPI regions, but is simply a structure
  237.  *      for each rectangular area in the shape
  238.  *      window's bitmap which can be displayed
  239.  *      as a rectangular PM window.
  240.  */
  241.  
  242. typedef struct _SHPREGION
  243. {
  244.     PSHPWINCTLDATA   pCtrl;   // link to parent
  245.     HWND        hwnd ;         // drawing window
  246.     RECTL       rect ;         // rectangle of sub-bitmap
  247. } SHPREGION;
  248.  
  249. /*
  250.  * SHPSPAN:
  251.  *      this is a temporary structure used during
  252.  *      the creation of SHPREGION's from the
  253.  *      input bitmap.
  254.  */
  255.  
  256. typedef struct _SHPSPAN {
  257.     ULONG   nSize   ;
  258.     ULONG   nUsed   ;
  259.     RECTL   aSpan[1];
  260. } SHPSPAN, *PSHPSPAN;
  261.  
  262. // the following defines how many SHPSPAN structures
  263. // will be initially created and afterwards for span
  264. // expansions by spanExpand
  265. #define SPAN_ALLOC_STEP    1024
  266.  
  267. /*
  268.  * spanFree:
  269.  *
  270.  */
  271.  
  272. static void spanFree(PSHPSPAN pSpan)
  273. {
  274.     if (pSpan != NULL) {
  275.         free(pSpan);
  276.     }
  277. }
  278.  
  279. /*
  280.  * spanCreate:
  281.  *      this creates SPAN_ALLOC_STEP SHPSPAN structures.
  282.  */
  283.  
  284. static PSHPSPAN spanCreate(void)
  285. {
  286.     PSHPSPAN pSpan;
  287.     int     len  ;
  288.  
  289.     len = sizeof(SHPSPAN) + sizeof(RECTL) * SPAN_ALLOC_STEP;
  290.  
  291.     if ((pSpan = (PSHPSPAN) malloc(len)) == NULL) {
  292.         return NULL;
  293.     }
  294.     memset(pSpan, 0, len);
  295.     pSpan->nSize = SPAN_ALLOC_STEP;
  296.     pSpan->nUsed = 0   ;
  297.     return pSpan;
  298. }
  299.  
  300. /*
  301.  * spanExpand:
  302.  *      this expands the memory used for the SHPSPAN
  303.  *      structures if more spans need to be appended.
  304.  *      Another SPAN_ALLOC_STEP SHPSPAN structures are created.
  305.  */
  306.  
  307. static PSHPSPAN spanExpand(PSHPSPAN pOld)
  308. {
  309.     PSHPSPAN pNew;
  310.     int     len ;
  311.  
  312.     // TRACE("spanExpand\n");
  313.  
  314.     len = sizeof(SHPSPAN) + sizeof(RECTL) * (pOld->nSize + SPAN_ALLOC_STEP);
  315.  
  316.     if ((pNew = (PSHPSPAN) malloc(len)) == NULL) {
  317.         return NULL;
  318.     }
  319.     memset(pNew, 0, len);
  320.     pNew->nSize = pOld->nSize + SPAN_ALLOC_STEP;
  321.     pNew->nUsed = pOld->nUsed;
  322.     memcpy(pNew->aSpan, pOld->aSpan, sizeof(RECTL) * pOld->nUsed);
  323.     spanFree(pOld);
  324.  
  325.     return pNew;
  326. }
  327.  
  328. /*
  329.  * spanAppend:
  330.  *      this adds a new SHPSPAN to the list of spans.
  331.  *
  332.  */
  333.  
  334. static PSHPSPAN spanAppend(PSHPSPAN pSpan,
  335.                            int y,       // bottom y; top y = y+1
  336.                            int x1,      // left x
  337.                            int x2)      // right x
  338. {
  339.     int     i;
  340.     PRECTL  p;
  341.     PSHPSPAN pNew;
  342.  
  343.     // TRACE("spanAppend %d (%d %d)\n", y, x1, x2);
  344.  
  345.     /*
  346.      * check if continuous one
  347.      */
  348.  
  349.     for (i = 0; i < pSpan->nUsed; i++) {
  350.         p = &pSpan->aSpan[i];
  351.         if (p->yTop == y && p->xLeft == x1 && p->xRight == x2)
  352.         {
  353.             p->yTop += 1;
  354.             return pSpan;      // merged
  355.         }
  356.     }
  357.  
  358.     /*
  359.      * if not enough space, expand
  360.      */
  361.  
  362.     if ((pSpan->nUsed + 1) >= pSpan->nSize)
  363.     {
  364.         if ((pNew = spanExpand(pSpan)) == NULL)
  365.             return NULL;
  366.  
  367.         pSpan = pNew;
  368.     }
  369.  
  370.     /*
  371.      * append a rectangle
  372.      */
  373.  
  374.     pSpan->aSpan[pSpan->nUsed].yTop = y + 1;
  375.     pSpan->aSpan[pSpan->nUsed].yBottom = y ;
  376.     pSpan->aSpan[pSpan->nUsed].xLeft   = x1;
  377.     pSpan->aSpan[pSpan->nUsed].xRight  = x2;
  378.     pSpan->nUsed += 1;
  379.  
  380.     return pSpan;
  381. }
  382.  
  383. #ifdef  SHPDEBUG
  384.  
  385.     /*
  386.      * ptisin:
  387.      *
  388.      */
  389.  
  390.     static BOOL ptisin(PSHPSPAN pSpan, int x, int y)
  391.     {
  392.         int     i;
  393.  
  394.         for (i = 0; i < pSpan->nUsed; i++)
  395.         {
  396.             if (y >= pSpan->aSpan[i].yTop) {
  397.                 continue;
  398.             }
  399.             if (y < pSpan->aSpan[i].yBottom) {
  400.                 continue;
  401.             }
  402.             if (x < pSpan->aSpan[i].xLeft) {
  403.                 continue;
  404.             }
  405.             if (x >= pSpan->aSpan[i].xRight) {
  406.                 continue;
  407.             }
  408.             return TRUE;
  409.         }
  410.         return FALSE;
  411.     }
  412.  
  413.     /*
  414.      * dumpSpan:
  415.      *
  416.      */
  417.  
  418.     static void dumpSpan(PSHPSPAN pSpan)
  419.     {
  420.         int     i, maxx, maxy, x, y;
  421.  
  422.         TRACE("dumpSpan %d\n", pSpan->nUsed);
  423.  
  424.         maxx = maxy = 0;
  425.  
  426.         for (i = 0; i < pSpan->nUsed; i++) {
  427.             if (pSpan->aSpan[i].yTop > maxy) {
  428.             maxy = pSpan->aSpan[i].yTop;
  429.         }
  430.         if (pSpan->aSpan[i].xRight > maxx) {
  431.             maxx = pSpan->aSpan[i].xRight;
  432.         }
  433.         }
  434.  
  435.         for (y = maxy - 1; y >= 0; y--) {
  436.             printf("%03d : ", y);
  437.             for (x = 0; x < maxx; x++) {
  438.             if (ptisin(pSpan, x, y)) {
  439.                 printf("#");
  440.             } else {
  441.                 printf("_");
  442.             }
  443.             }
  444.         printf("\n");
  445.         }
  446.     }
  447.  
  448. #endif  // SHPDEBUG
  449.  
  450. /*
  451.  * spanParseBitmap:
  452.  *      this gets called from shapeBitmap2Regions when the
  453.  *      shape region windows need to be created.
  454.  *      This function does the actual bitmap analysis and
  455.  *      creates a large number of SHPSPAN structures according
  456.  *      to the bitmaps, which can later be turned into
  457.  *      PM windows.
  458.  *      This happens during the processing of WM_CREATE in
  459.  *      fnwpShapeWindow.
  460.  *      CPU usage: relatively low. Maybe 5% of the whole creation
  461.  *      procedure.
  462.  */
  463.  
  464. static PSHPSPAN spanParseBitmap(HPS hps, PBITMAPINFOHEADER2 bmih2)
  465. {
  466.     int     blen, hlen ;
  467.     PUCHAR          buf;
  468.     PBITMAPINFO2    pbm;
  469.     PSHPSPAN pSpan, pNew;
  470.     int     x, y, k    ;
  471.     LONG    first, color;
  472.     BOOL    inspan;
  473.     int     left  ;
  474.  
  475.     // TRACE("spanParseBitmap\n");
  476.  
  477.     hlen = sizeof(BITMAPINFO2) + sizeof(RGB) * 256;
  478.     blen = ((bmih2->cBitCount * bmih2->cx + 31) / 32) * bmih2->cPlanes * 4;
  479.  
  480.     pbm = (PBITMAPINFO2) malloc(hlen);
  481.     buf = (PUCHAR) malloc(blen);
  482.  
  483.     if (pbm == NULL || buf == NULL) {
  484.         // TRACE("spanParseBitmap - failed to alloc %d %d\n", hlen, blen);
  485.         if (pbm)
  486.             free(pbm);
  487.         if (buf)
  488.             free(buf);
  489.         return NULL;
  490.     }
  491.     memcpy(pbm, bmih2, sizeof(BITMAPINFOHEADER2));
  492.  
  493.     if ((pSpan = spanCreate()) == NULL)
  494.     {
  495.         // TRACE("spanParseBitmap - failed to make\n");
  496.         free(pbm);
  497.         free(buf);
  498.         return NULL;
  499.     }
  500.  
  501.     first = -1;
  502.  
  503.     for (y = 0; y < bmih2->cy; y++)
  504.     {
  505.  
  506.         // TRACE("spanParseBitmap - scan line %d\n", y); fflush(stdout);
  507.  
  508.         GpiQueryBitmapBits(hps, y, 1, buf, pbm);
  509.  
  510.         for (x = 0, inspan = FALSE; x < bmih2->cx; x++)
  511.         {
  512.             k = x * 3;
  513.             color = ((buf[k] << 16) | (buf[k+1] << 8) | buf[k+2]);
  514.  
  515.             if (first < 0) {
  516.                 // first iteration: get the very first color (that
  517.                 // is the pixel at (0, 0)), with which we will
  518.                 // compare the others to determine the mask
  519.                 first = color;
  520.             }
  521.  
  522.             if (inspan == FALSE && color != first)
  523.             {
  524.                 inspan = TRUE;
  525.                 left = x;
  526.             }
  527.             else if (inspan == TRUE && color == first)
  528.             {
  529.                 // transparent color found:
  530.                 // create new span
  531.                 inspan = FALSE;
  532.                 if ((pNew = spanAppend(pSpan, y, left, x)) != NULL)
  533.                 {
  534.                     pSpan = pNew;
  535.                 } else {
  536.                     // TRACE("spanParseBitmap - failed to extend\n");
  537.                     break;
  538.                 }
  539.             }
  540.         }
  541.         if (inspan == TRUE) {
  542.                 if ((pNew = spanAppend(pSpan, y, left, x)) != NULL) {
  543.                 pSpan = pNew;
  544.             } else {
  545.                 // TRACE("spanParseBitmap - failed to extend\n");
  546.                     break;
  547.             }
  548.         }
  549.     }
  550.  
  551. #ifdef  SHPDEBUG
  552.     dumpSpan(pSpan);
  553. #endif
  554.  
  555.     return pSpan;
  556. }
  557.  
  558. /*
  559.  * shapeBitmap2Regions:
  560.  *      this gets called from shapeWMCreate (WM_CREATE) to have a
  561.  *      drawing region created from the bitmap which has been
  562.  *      selected into the given HPS.
  563.  */
  564.  
  565. static int shapeBitmap2Regions(PSHPWINCTLDATA pCtrl,  // in: shape control data
  566.                          HPS hpsMask)      // in: HPS with selected bitmap
  567. {
  568.     HAB     hab;
  569.     HDC     hdc;
  570.     HPS     hps;
  571.     SIZEL   siz;
  572.     HBITMAP hbm;
  573.     BITMAPINFOHEADER2   bmi;
  574.     POINTL  apt[3];
  575.     PSHPSPAN     pSpan;
  576.     PSHPREGION   pRegn;
  577.     int         i    ;
  578.  
  579.     // TRACE("shapeBitmap2Regions\n");
  580.  
  581.     hab = WinQueryAnchorBlock(pCtrl->hwndShape);
  582.  
  583.     /*
  584.      * Create Memory DC & HPS
  585.      */
  586.  
  587.     hdc = DevOpenDC(hab, OD_MEMORY, "*", 0, NULL, NULLHANDLE);
  588.     siz.cx = siz.cy = 0;
  589.     hps = GpiCreatePS(hab, hdc, &siz,
  590.             PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC);
  591.  
  592.     /*
  593.      * Create Bitmap and relate to memory PS
  594.      */
  595.  
  596.     memset(&bmi, 0, sizeof(bmi));
  597.  
  598.     bmi.cbFix = sizeof(BITMAPINFOHEADER2);
  599.     bmi.cx = pCtrl->cx;
  600.     bmi.cy = pCtrl->cy;
  601.     bmi.cPlanes       = 1 ;
  602.     bmi.cBitCount     = 24;
  603.     bmi.ulCompression = 0 ;
  604.     bmi.cclrUsed      = 0 ;
  605.     bmi.cclrImportant = 0 ;
  606.  
  607.     hbm = GpiCreateBitmap(hps, &bmi, 0, NULL, NULL);
  608.  
  609.     GpiSetBitmap(hps, hbm);
  610.  
  611.     /*
  612.      * Copy in Mask Pattern
  613.      */
  614.  
  615.     // TRACE("shapeBitmap2Regions - copyin %d x %d mask pattern\n", bmi.cx, bmi.cy);
  616.  
  617.     apt[0].x = 0;          // Target
  618.     apt[0].y = 0;
  619.     apt[1].x = bmi.cx;
  620.     apt[1].y = bmi.cy;
  621.     apt[2].x = 0;          // Source
  622.     apt[2].y = 0;
  623.  
  624.     if (GpiBitBlt(hps, pCtrl->hpsDraw, 3, apt, ROP_SRCCOPY, 0) == GPI_ERROR) {
  625.         // TRACE("MakeRect - BitBlt Failed %08x, hdc %08x, hps %08x, hbm %08x\n",
  626.                 // WinGetLastError(hab), hdc, hps, hbm);
  627.     }
  628.  
  629.     /*
  630.      * Parse Mask Pattern
  631.      */
  632.  
  633.     // call spanParseBitmap; this does the actual creation of the
  634.     // "spans" by comparing all bitmap pixels to the (0, 0)
  635.     // pixel
  636.     if ((pSpan = spanParseBitmap(hps, &bmi)) != NULL)
  637.     {
  638.         if ((pRegn = (PSHPREGION) malloc(sizeof(SHPREGION) * pSpan->nUsed)) == NULL)
  639.         {
  640.         // TRACE("shapeBitmap2Regions - failed to alloc\n");
  641.         } else
  642.         {
  643.             // mask created successfully:
  644.             pCtrl->nRegion = pSpan->nUsed;
  645.             pCtrl->aRegion = pRegn;
  646.  
  647.             for (i = 0; i < pSpan->nUsed; i++)
  648.             {
  649.                 pRegn[i].pCtrl    = pCtrl;
  650.                 pRegn[i].hwnd = NULLHANDLE;
  651.                 pRegn[i].rect.xLeft   = pSpan->aSpan[i].xLeft  ;
  652.                 pRegn[i].rect.xRight  = pSpan->aSpan[i].xRight ;
  653.                 pRegn[i].rect.yTop    = pSpan->aSpan[i].yTop   ;
  654.                 pRegn[i].rect.yBottom = pSpan->aSpan[i].yBottom;
  655.             }
  656.         }
  657.         spanFree(pSpan);
  658.     }
  659.  
  660.     /*
  661.      * dispose local resources
  662.      */
  663.  
  664.     GpiDeleteBitmap(hbm);
  665.     GpiDestroyPS(hps);
  666.     DevCloseDC(hdc);
  667.  
  668.     return 0;
  669. }
  670.  
  671. /*
  672.  * regnDraw:
  673.  *      this gets called upon receiving WM_PAINT in
  674.  *      fnwpRegionSubwindow. We simply draw the
  675.  *      subrectangle from the shape window's bitmap
  676.  *      which corresponds to our region rectangle.
  677.  */
  678.  
  679. static void regnDraw(HPS hps, PSHPREGION pRgn)
  680. {
  681.     POINTL      apt[3];
  682.  
  683.     apt[0].x = 0;
  684.     apt[0].y = 0;
  685.     apt[1].x = (pRgn->rect.xRight - pRgn->rect.xLeft);
  686.     apt[1].y = (pRgn->rect.yTop - pRgn->rect.yBottom);
  687.     apt[2].x = pRgn->rect.xLeft  ;
  688.     apt[2].y = pRgn->rect.yBottom;
  689.     GpiBitBlt(hps, pRgn->pCtrl->hpsDraw, 3, apt, ROP_SRCCOPY, 0);
  690. }
  691.  
  692. /*
  693.  *@@ fnwpRegionSubwindow:
  694.  *      this is the window procedure for each of the
  695.  *      shape window's rectangular subwindows.
  696.  */
  697.  
  698. static MRESULT EXPENTRY fnwpRegionSubwindow(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  699. {
  700.     PSHPREGION   pRgn;
  701.     HPS         hps ;
  702.  
  703.     pRgn = (PSHPREGION) WinQueryWindowPtr(hwnd, 0);
  704.  
  705.     switch (msg)
  706.     {
  707.         /*
  708.          * WM_CREATE:
  709.          *      store the SHPREGION pointer in our
  710.          *      window words.
  711.          */
  712.  
  713.         case WM_CREATE:
  714.             // TRACE("WM_CREATE\n");
  715.             pRgn = (PSHPREGION) PVOIDFROMMP(mp1);
  716.             WinSetWindowPtr(hwnd, 0, (PVOID) pRgn);
  717.         return (MRESULT) FALSE;
  718.  
  719.         /*
  720.          * WM_PAINT:
  721.          *      draw our subrectangle of the main bitmap.
  722.          */
  723.  
  724.         case WM_PAINT:
  725.             // TRACE("WM_PAINT (%d %d) (%d %d)\n", pRgn->rect.yBottom, pRgn->rect.xLeft, pRgn->rect.yTop, pRgn->rect.xRight);
  726.             hps = WinBeginPaint(hwnd, NULLHANDLE, NULL);
  727.             regnDraw(hps, pRgn);
  728.             WinEndPaint(hps)  ;
  729.         return (MRESULT) 0;
  730.  
  731.         case WM_MOUSEMOVE    :
  732.         case WM_BUTTON1DOWN  :
  733.         case WM_BUTTON1UP    :
  734.         case WM_BUTTON1CLICK :
  735.         case WM_BUTTON1DBLCLK:
  736.         case WM_BUTTON2DOWN  :
  737.         case WM_BUTTON2UP    :
  738.         case WM_BUTTON2CLICK :
  739.         case WM_BUTTON2DBLCLK:
  740.         case WM_BUTTON3DOWN  :
  741.         case WM_BUTTON3UP    :
  742.         case WM_BUTTON3CLICK :
  743.         case WM_BUTTON3DBLCLK:
  744.         case WM_CHAR         :
  745.         case WM_VIOCHAR      :
  746.         case WM_BEGINDRAG    :
  747.         case WM_ENDDRAG      :
  748.         case WM_SINGLESELECT :
  749.         case WM_OPEN         :
  750.         case WM_CONTEXTMENU  :
  751.         case WM_CONTEXTHELP  :
  752.         case WM_TEXTEDIT     :
  753.         case WM_BEGINSELECT  :
  754.         case WM_ENDSELECT    :
  755.             // forward all these to the shape window
  756.             return WinSendMsg(pRgn->pCtrl->hwndShape, msg, mp1, mp2);
  757.     }
  758.     return WinDefWindowProc(hwnd, msg, mp1, mp2);
  759. }
  760.  
  761. static BOOL    ShapeRegisteredRegion = FALSE;
  762.  
  763. /*
  764.  * shapeRegions2Windows:
  765.  *      this gets called from shapeWMCreate (WM_CREATE) to convert
  766.  *      all the "regions" that have been created by shapeBitmap2Regions
  767.  *      in pCtrl to individual rectangular PM windows.
  768.  *      CPU usage: extremely high, because all the dull PM functions
  769.  *      take so damn long. Calculating the "regions" isn't really
  770.  *      difficult, but it's the PM windows which cause the CPU hog.
  771.  */
  772.  
  773. static int shapeRegions2Windows(PSHPWINCTLDATA pCtrl)
  774. {
  775.     int         i   ;
  776.     PSHPREGION   pRgn;
  777.     ULONG       flStyle;
  778.  
  779.     // TRACE("shapeRegions2Windows %d regions\n", pCtrl->nRegion);
  780.  
  781.     // check if any "regions" exist at all
  782.     if (pCtrl->nRegion == 0 || pCtrl->aRegion == NULL)
  783.     {
  784.         // TRACE("shapeRegions2Windows - no region to open\n");
  785.         return -1;
  786.     }
  787.  
  788.     if (ShapeRegisteredRegion == FALSE) {
  789.         // first call: register "shape region" class
  790.         WinRegisterClass(WinQueryAnchorBlock(pCtrl->hwndShape),
  791.                         "ShapeWinRegion",
  792.                         fnwpRegionSubwindow,
  793.                         CS_PARENTCLIP
  794.                             // use parent's clipping region instead
  795.                             // of the one of the region window
  796.                         | CS_CLIPSIBLINGS
  797.                             // don't allow the subwindows to paint
  798.                             // over siblings (ie. windows with the
  799.                             // same parent); this is neccessary if
  800.                             // HWND_DESKTOP is the parent
  801.                         | CS_SYNCPAINT
  802.                             // paint immediately
  803.                         ,
  804.                         sizeof(PVOID));
  805.         ShapeRegisteredRegion = TRUE;
  806.     }
  807.  
  808.     flStyle = 0;
  809.  
  810.     // now go thru the "regions" list
  811.     for (i = 0, pRgn = pCtrl->aRegion;
  812.          i < pCtrl->nRegion;
  813.          i++, pRgn++)
  814.     {
  815.         // and create a window for each "region"
  816.         pRgn->hwnd = WinCreateWindow(
  817.                 pCtrl->hwndParent,      // copy parent window from shape window
  818.                             // changed (*UM)
  819.                         // HWND_DESKTOP,           // Parent Window
  820.                 "ShapeWinRegion",       // Window Class
  821.                 NULL,                   // Window Text
  822.                 flStyle,                // Window Style
  823.                 (pCtrl->x + pRgn->rect.xLeft),              // x
  824.                 (pCtrl->y + pRgn->rect.yBottom),            // y
  825.                 (pRgn->rect.xRight - pRgn->rect.xLeft),     // cx
  826.                 (pRgn->rect.yTop - pRgn->rect.yBottom),     // cy
  827.                 pCtrl->hwndOwner,       // Owner Window
  828.                 HWND_TOP,               // Z-Order
  829.                 i,                      // Window ID
  830.                 pRgn,                   // Control Data
  831.                 NULL);                  // Pres. Param.
  832.     }
  833.     return 0;
  834. }
  835.  
  836. /*
  837.  * shapeFreeRegion - Dispose Region Window and Related Resources
  838.  */
  839.  
  840. static int shapeFreeRegion(PSHPWINCTLDATA pCtrl)
  841. {
  842.     int         i   ;
  843.     PSHPREGION   pRgn;
  844.  
  845.     for (i = 0, pRgn = pCtrl->aRegion; i < pCtrl->nRegion; i++, pRgn++) {
  846.         WinDestroyWindow(pRgn->hwnd);
  847.     }
  848.     free(pCtrl->aRegion);
  849.  
  850.     return 0;
  851. }
  852.  
  853. /*
  854.  * shapeWMAdjustWindowPos:
  855.  *      adjust the region windows' positions, visibility etc.
  856.  *      by going thru the whole region windows list and
  857.  *      repositioning all the windows.
  858.  *      This gets called upon receiving WM_ADJUSTWINDOWPOS
  859.  *      in fnwpShapeWindow.
  860.  */
  861.  
  862. static int shapeWMAdjustWindowPos(PSHPWINCTLDATA pCtrl, PSWP pSwp)
  863. {
  864.     int         i   ;
  865.     PSHPREGION   pRgn;
  866.     ULONG       fl  ;
  867.     HPS         hps ;
  868.  
  869.     PSWP pswpArray;
  870.  
  871.     // TRACE("shapeWMAdjustWindowPos - %d, %08x\n", pCtrl->nRegion, pSwp->fl);
  872.  
  873.     if (pCtrl->nRegion == 0 || pCtrl->aRegion == NULL)
  874.     {
  875.         // TRACE("ShpDrawRegion - no region to open\n");
  876.         return -1;
  877.     }
  878.  
  879.     if ((fl = pSwp->fl) & SWP_MOVE)
  880.     {
  881.         pCtrl->x = pSwp->x;
  882.         pCtrl->y = pSwp->y;
  883.     }
  884.  
  885.     pswpArray = (PSWP) malloc(sizeof(SWP) * pCtrl->nRegion);
  886.  
  887.     // go thru all the "regions" and adjust their sizes
  888.     for (i = 0, pRgn = pCtrl->aRegion; i < pCtrl->nRegion; i++, pRgn++)
  889.     {
  890.         pswpArray[i].fl = fl;
  891.         pswpArray[i].cy = (pRgn->rect.yTop - pRgn->rect.yBottom);
  892.         pswpArray[i].cx = (pRgn->rect.xRight - pRgn->rect.xLeft);
  893.         pswpArray[i].y = (pCtrl->y + pRgn->rect.yBottom);
  894.         pswpArray[i].x = (pCtrl->x + pRgn->rect.xLeft);
  895.         pswpArray[i].hwndInsertBehind = pSwp->hwndInsertBehind;
  896.         pswpArray[i].hwnd = pRgn->hwnd;
  897.     }
  898.  
  899.     // set all window positions at once
  900.     WinSetMultWindowPos(WinQueryAnchorBlock(pCtrl->hwndShape),
  901.                         &pswpArray[0],
  902.                         pCtrl->nRegion);
  903.     free((void*) pswpArray);
  904.  
  905.     // calling WinInvalidateRect is not neccessary,
  906.     // because the windows' update regions are already
  907.     // properly set by WinSetMultWindowPos (*UM)
  908.  
  909.     /* for (i = 0, pRgn = pCtrl->aRegion;
  910.          i < pCtrl->nRegion;
  911.          i++, pRgn++)
  912.     {
  913.         if (fl & (SWP_MOVE | SWP_ZORDER)) {
  914.             WinInvalidateRect(pRgn->hwnd, NULL, FALSE);
  915.         }
  916.     } */
  917.     return 0;
  918. }
  919.  
  920. /*
  921.  * shapeUpdateRegions:
  922.  *      this gets called by fnwpShapeWindow upon receiving
  923.  *      SHAPEWIN_MSG_UPDATE.
  924.  */
  925.  
  926. static int shapeUpdateRegions(PSHPWINCTLDATA pCtrl, PRECTL pRect)
  927. {
  928.     RECTL       rect, intern;
  929.     int         i   ;
  930.     PSHPREGION   pRgn;
  931.     HAB         hab ;
  932.     HPS         hps ;
  933.  
  934.     // TRACE("shapeUpdateRegions\n");
  935.  
  936.     hab = WinQueryAnchorBlock(pCtrl->hwndShape);
  937.  
  938.     if (pRect == NULL) {
  939.         rect.xLeft   = 0       ;
  940.         rect.yBottom = 0       ;
  941.         rect.xRight = pCtrl->cx;
  942.         rect.yTop   = pCtrl->cy;
  943.         pRect = ▭
  944.     }
  945.     for (i = 0, pRgn = pCtrl->aRegion; i < pCtrl->nRegion; i++, pRgn++)
  946.     {
  947.         if (WinIntersectRect(hab, &intern, pRect, &pRgn->rect) == FALSE) {
  948.             continue;
  949.         } else {
  950.             WinInvalidateRect(pRgn->hwnd, NULL, FALSE);
  951.         }
  952.     }
  953.     return 0;
  954. }
  955.  
  956. /*
  957.  * shapeWMCreate:
  958.  *      this initializes the "shape window".
  959.  *      This gets called upon receiving WM_CREATE in fnwpShapeWindow.
  960.  *      The procedure is as follows:
  961.  *      1)  the bitmap in pData->hpsDraw is analyzed pixel by
  962.  *          pixel to create a number of "regions" from it
  963.  *          (which are not GPI regions, but an array of SHPREGION
  964.  *          structures. At least one of these structures is
  965.  *          created for each line. This is done by calling
  966.  *          shapeBitmap2Regions.
  967.  *      2)  We then call shapeRegions2Windows to actually create
  968.  *          PM windows from all these structures.
  969.  */
  970.  
  971. static PSHPWINCTLDATA shapeWMCreate(HWND hwnd, // in: shape window
  972.                          PCREATESTRUCT pWin,    // in: create struct of WM_CREATE
  973.                          PSHPCTLDATA pData)       // in: SHPCTLDATA struct (WM_CREATE mp1)
  974. {
  975.     PSHPWINCTLDATA   pCtrl;
  976.  
  977.     if (pData->hpsDraw == NULLHANDLE || pData->hpsMask == NULLHANDLE) {
  978.         return NULL;
  979.     }
  980.  
  981.     // create new PSHPWINCTLDATA structure
  982.     if ((pCtrl = (PSHPWINCTLDATA) malloc(sizeof(SHPWINCTLDATA))) == NULL) {
  983.         return NULL;
  984.     }
  985.  
  986.     /*
  987.      * Setup Common Window Parameters
  988.      */
  989.  
  990.     pCtrl->hwndShape  = hwnd;
  991.     pCtrl->hwndParent = pWin->hwndParent;
  992.     pCtrl->hwndOwner  = pWin->hwndOwner ;
  993.     pCtrl->id         = pWin->id;
  994.     pCtrl->x          = pWin->x ;
  995.     pCtrl->y          = pWin->y ;
  996.     pCtrl->cx         = pWin->cx;
  997.     pCtrl->cy         = pWin->cy;
  998.  
  999.     /*
  1000.      * Setup Image Window's Control Data
  1001.      */
  1002.  
  1003.     pCtrl->cx = pData->cx;
  1004.     pCtrl->cy = pData->cy;
  1005.     pCtrl->hpsDraw = pData->hpsDraw;
  1006.  
  1007.     // now create "regions" from bitmap;
  1008.     // this will store the "regions" in pCtrl
  1009.     shapeBitmap2Regions(pCtrl, pData->hpsMask);
  1010.  
  1011.     // now create as many rectangular PM
  1012.     // windows as we have "regions" in pCtrl
  1013.     shapeRegions2Windows(pCtrl);
  1014.  
  1015.     return pCtrl;
  1016. }
  1017.  
  1018. /*
  1019.  * shapeWMDestroy:
  1020.  *      this cleans up the shape's resources.
  1021.  *      Gets called upon receiving WM_DESTROY in
  1022.  *      fnwpShapeWindow.
  1023.  */
  1024.  
  1025. static void shapeWMDestroy(PSHPWINCTLDATA pCtrl)
  1026. {
  1027.     if (pCtrl == NULL) {
  1028.         return;
  1029.     }
  1030.     shapeFreeRegion(pCtrl);
  1031.     free(pCtrl);
  1032. }
  1033.  
  1034. /*
  1035.  *@@ fnwpShapeWindow:
  1036.  *      this is the window procedure for the "shape window".
  1037.  *      Register this procedure with WinRegisterWindowClass.
  1038.  *      This does the transformation of the bitmap into many
  1039.  *      rectangular subwindows upon WM_CREATE, each of which
  1040.  *      will use fnwpRegionSubwindow as the window proc.
  1041.  *      This window procedure forwards the following messages
  1042.  *      to its owner:
  1043.  *      --  WM_MOUSEMOVE
  1044.  *      --  WM_BUTTON1xxx
  1045.  *      --  WM_BUTTON2xxx
  1046.  *      --  WM_BUTTON3xxx
  1047.  *      --  WM_CHAR
  1048.  *      --  WM_VIOCHAR
  1049.  *      --  WM_BEGINDRAG
  1050.  *      --  WM_ENDDRAG
  1051.  *      --  WM_SINGLESELECT
  1052.  *      --  WM_OPEN
  1053.  *      --  WM_CONTEXTMENU
  1054.  *      --  WM_CONTEXTHELP
  1055.  *      --  WM_TEXTEDIT
  1056.  *      --  WM_BEGINSELECT
  1057.  *      --  WM_ENDSELECT
  1058.  */
  1059.  
  1060. MRESULT EXPENTRY fnwpShapeWindow(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1061. {
  1062.     PSHPWINCTLDATA   pCtrl;
  1063.     HPS         hps  ;
  1064.     PSWP        pswp ;
  1065.     SHORT       sx, sy;
  1066.  
  1067.     pCtrl = (PSHPWINCTLDATA) WinQueryWindowPtr(hwnd, 0);
  1068.  
  1069.     switch (msg)
  1070.     {
  1071.  
  1072.         /*
  1073.          * WM_CREATE:
  1074.          *      shape window is being created.
  1075.          *      Parameters:
  1076.          *          PSHPCTLDATA mp1
  1077.          *          PCREATESTRUCT mp2
  1078.          *      Shaped windows must have a SHPCTLDATA
  1079.          *      structure in mp1.
  1080.          */
  1081.  
  1082.         case WM_CREATE:
  1083.             // TRACE("WM_CREATE\n");
  1084.             pCtrl = shapeWMCreate(hwnd,
  1085.                 (PCREATESTRUCT)PVOIDFROMMP(mp2),
  1086.                 (PSHPCTLDATA)PVOIDFROMMP(mp1));
  1087.  
  1088.             if (pCtrl == NULL)
  1089.                 return (MRESULT) TRUE;
  1090.  
  1091.             // store control data in window words
  1092.             WinSetWindowPtr(hwnd, 0, (PVOID) pCtrl);
  1093.             return (MRESULT) FALSE;
  1094.  
  1095.         /*
  1096.          * WM_DESTROY:
  1097.          *      clean up.
  1098.          */
  1099.  
  1100.         case WM_DESTROY:
  1101.             // TRACE("WM_DESTORY\n");
  1102.             shapeWMDestroy(pCtrl);
  1103.             return (MRESULT) 0;
  1104.  
  1105.         /*
  1106.          * WM_ADJUSTWINDOWPOS:
  1107.          *      this needs to be manipulated to
  1108.          *      adjust the positions of all the
  1109.          *      subwindows instead.
  1110.          */
  1111.  
  1112.         case WM_ADJUSTWINDOWPOS:
  1113.             // TRACE("WM_ADJUSTWINDOWPOS\n");
  1114.             pswp = (PSWP) PVOIDFROMMP(mp1);
  1115.             // DUMPSWP(pswp);
  1116.  
  1117.             // enforce the size which we were given
  1118.             // in the beginning, because we cannot
  1119.             // change the size later
  1120.             pswp->cx = pCtrl->cx;
  1121.             pswp->cy = pCtrl->cy;
  1122.  
  1123.             // adjust the sub-windows
  1124.             shapeWMAdjustWindowPos(pCtrl, pswp);
  1125.  
  1126.             // never show ourselves
  1127.             pswp->fl &= ~SWP_SHOW;
  1128.             return (MRESULT) 0;
  1129.  
  1130.         /*
  1131.          * SHAPEWIN_MSG_UPDATE:
  1132.          *
  1133.          */
  1134.  
  1135.         case SHAPEWIN_MSG_UPDATE:
  1136.             shapeUpdateRegions(pCtrl, (PRECTL) PVOIDFROMMP(mp1));
  1137.             return (MRESULT) 0;
  1138.  
  1139.         /*
  1140.          * WM_QUERYDLGCODE:
  1141.          *
  1142.          */
  1143.  
  1144.         case WM_QUERYDLGCODE:
  1145.             // TRACE("WM_QUERYDLGCODE\n");
  1146.             return (MRESULT) DLGC_STATIC;
  1147.  
  1148.         /*
  1149.          * WM_PAINT:
  1150.          *      we just swallow this message because
  1151.          *      there's no "shape window" to be painted;
  1152.          *      instead, all the region windows get
  1153.          *      their own WM_PAINT message
  1154.          */
  1155.  
  1156.         case WM_PAINT:
  1157.             // TRACE("WM_PAINT\n");
  1158.             hps = WinBeginPaint(hwnd, NULLHANDLE, NULL);
  1159.             WinEndPaint(hps);
  1160.             return (MRESULT) 0;
  1161.  
  1162.         /*
  1163.          * all input-related messages:
  1164.          *      forward these to the owner
  1165.          */
  1166.  
  1167.         case WM_MOUSEMOVE    :
  1168.         case WM_BUTTON1DOWN  :
  1169.         case WM_BUTTON1UP    :
  1170.         case WM_BUTTON1CLICK :
  1171.         case WM_BUTTON1DBLCLK:
  1172.         case WM_BUTTON2DOWN  :
  1173.         case WM_BUTTON2UP    :
  1174.         case WM_BUTTON2CLICK :
  1175.         case WM_BUTTON2DBLCLK:
  1176.         case WM_BUTTON3DOWN  :
  1177.         case WM_BUTTON3UP    :
  1178.         case WM_BUTTON3CLICK :
  1179.         case WM_BUTTON3DBLCLK:
  1180.         case WM_CHAR         :
  1181.         case WM_VIOCHAR      :
  1182.         case WM_BEGINDRAG    :
  1183.         case WM_ENDDRAG      :
  1184.         case WM_SINGLESELECT :
  1185.         case WM_OPEN         :
  1186.         case WM_CONTEXTMENU  :
  1187.         case WM_CONTEXTHELP  :
  1188.         case WM_TEXTEDIT     :
  1189.         case WM_BEGINSELECT  :
  1190.         case WM_ENDSELECT    :
  1191.             return WinSendMsg(pCtrl->hwndOwner, msg, mp1, mp2);
  1192.  
  1193.     } // end switch (msg)
  1194.     return WinDefWindowProc(hwnd, msg, mp1, mp2);
  1195. }
  1196.  
  1197. /* ******************************************************************
  1198.  *                                                                  *
  1199.  *   Part 2: Shape frame functions                                  *
  1200.  *                                                                  *
  1201.  ********************************************************************/
  1202.  
  1203. static MRESULT EXPENTRY fnwpShapeFrame(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  1204.  
  1205. /*
  1206.  *@@ shpLoadBitmap:
  1207.  *      this creates a memory device context/presentation space
  1208.  *      and loads and selects a bitmap into it.
  1209.  *
  1210.  *      If pszBitmap == NULL, the bitmap is loaded from the
  1211.  *      specified resources, otherwise we attempt to load the
  1212.  *      bitmap file specified in pszBitmap (using gpihLoadBitmapFile).
  1213.  *
  1214.  *      Output in the given SHAPEFRAME structure:
  1215.  *      --  hdc                 device context handle
  1216.  *      --  hps                 presentation space handle
  1217.  *      --  hbm                 bitmap handle
  1218.  *      --  bmi                 BITMAPINFOHEADER of hbmp
  1219.  *
  1220.  *      All other fields are neither read nor written to.
  1221.  *      Returns TRUE if everything went OK.
  1222.  *      You can call this function directly before calling
  1223.  *      shpCreateWindows.
  1224.  *      Pass the SHAPEFRAME structure to shpFreeBitmap to clean up.
  1225.  */
  1226.  
  1227. BOOL shpLoadBitmap(HAB hab, // in: anchor block
  1228.                    PSZ pszBitmapFile, // in: OS/2 1.3 bmp file or NULL
  1229.                    HMODULE hmodResource, // in: module handle from where the
  1230.                             // resources should be loaded if
  1231.                             // pszBitmapFile == NULL. This can be 0 for
  1232.                             // the current EXE
  1233.                    ULONG idResource, // in: bitmap resource ID in that module
  1234.                    PSHAPEFRAME psb) // out: bitmap info
  1235. {
  1236.     SIZEL       siz;
  1237.     BOOL        brc;
  1238.  
  1239.     psb->hdc = DevOpenDC(hab, OD_MEMORY, "*", 0, NULL, NULLHANDLE);
  1240.     if (psb->hdc)
  1241.     {
  1242.         siz.cx = siz.cy = 0;
  1243.         psb->hps = GpiCreatePS(hab, psb->hdc, &siz,
  1244.                 PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC);
  1245.  
  1246.         if (psb->hps)
  1247.         {
  1248.             // hbm = bitmapLoadFile(hab, *phps, pszBitmap);
  1249.  
  1250.             if (pszBitmapFile)
  1251.             {
  1252.                 // load bitmap file
  1253.                 ULONG ulError;
  1254.                 psb->hbm = gpihLoadBitmapFile(psb->hps,
  1255.                                               pszBitmapFile,
  1256.                                               &ulError);
  1257.             } else
  1258.                 // load resource bitmap
  1259.                 psb->hbm = GpiLoadBitmap(psb->hps,
  1260.                                              hmodResource,
  1261.                                              idResource,
  1262.                                              0, 0);
  1263.             if (psb->hbm)
  1264.             {
  1265.                 // store bitmap info in structure
  1266.                 psb->bmi.cbFix = sizeof(psb->bmi);
  1267.                 GpiQueryBitmapInfoHeader(psb->hbm, &psb->bmi);
  1268.  
  1269.                 GpiSetBitmap(psb->hps, psb->hbm);
  1270.                 brc = TRUE;
  1271.             }
  1272.         }
  1273.     }
  1274.     return (brc);
  1275. }
  1276.  
  1277. /*
  1278.  *@@ shpFreeBitmap:
  1279.  *      this cleans up resources allocated by shpLoadBitmap:
  1280.  *      delete the bitmap, destroy the HPS and HDC.
  1281.  */
  1282.  
  1283. VOID shpFreeBitmap(PSHAPEFRAME psb)
  1284. {
  1285.     if (psb->hbm != NULLHANDLE) {
  1286.         GpiDeleteBitmap(psb->hbm);
  1287.         psb->hbm = NULLHANDLE;
  1288.     }
  1289.     if (psb->hps != NULLHANDLE) {
  1290.         GpiDestroyPS(psb->hps);
  1291.         psb->hps = NULLHANDLE;
  1292.     }
  1293.     if (psb->hdc != NULLHANDLE) {
  1294.         DevCloseDC(psb->hdc);
  1295.         psb->hdc = NULLHANDLE;
  1296.     }
  1297. }
  1298.  
  1299. /*
  1300.  *@@ shpCreateWindows:
  1301.  *      this is a one-shot function for creating a
  1302.  *      shaped window from a bitmap. Before calling
  1303.  *      this function, you should call shpLoadBitmap
  1304.  *      to have the neccessary fields initialized.
  1305.  *      Otherwise you must initialize those fields for
  1306.  *      yourself.
  1307.  *
  1308.  *      Required fields in SHAPEFRAME for input:
  1309.  *      --  hps                 presentation space handle
  1310.  *      --  hbmp                bitmap handle
  1311.  *      --  bmi                 BITMAPINFOHEADER of hbmp
  1312.  *
  1313.  *      Output in that structure:
  1314.  *      --  hwndShapeFrame      invisible rectangular frame
  1315.  *                              window for the shape window
  1316.  *      --  hwndShape           visible shape window
  1317.  *      --  pfnFrame            original window procedure of
  1318.  *                              WC_FRAME (hwndShapeFrame),
  1319.  *                              which is subclassed here
  1320.  *                              using fnwpShapeFrame
  1321.  *      --  shpctrl             control data for hwndShape
  1322.  *
  1323.  *      Returns TRUE if everything went OK.
  1324.  *
  1325.  *      Note that the windows are only created; they are
  1326.  *      neither positioned nor shown on the screen. If you
  1327.  *      use WinSetWindowPos on the shape, you must always
  1328.  *      issue that twice: once for hwndShapeFrame without
  1329.  *      SWP_SHOW set, once for hwndShape with SWP_SHOW set.
  1330.  */
  1331.  
  1332. BOOL shpCreateWindows(HAB hab, PSHAPEFRAME psb)
  1333. {
  1334.     BOOL        brc = FALSE;
  1335.  
  1336.     if (psb->hbm)
  1337.     {
  1338.         // bitmap seems to be valid:
  1339.         FRAMECDATA  fcd;
  1340.         UCHAR       title[256];
  1341.  
  1342.         memset(&fcd, 0, sizeof(fcd));
  1343.         fcd.cb = sizeof(fcd);
  1344.  
  1345.         sprintf(title, "XFolderLogoShape"); // , ProgramName, pszBitmap);
  1346.  
  1347.         // create invisible frame
  1348.         psb->hwndShapeFrame = WinCreateWindow(
  1349.                 HWND_DESKTOP,           // Parent window handle
  1350.                 WC_FRAME,               // Frame Window Class
  1351.                 title,                  // as Title
  1352.                 0,                      // Window Style
  1353.                 0, 0, 0, 0,             // Position & size
  1354.                 NULLHANDLE,             // Owner Window
  1355.                 HWND_TOP,               // Z-Order
  1356.                 0,                      // Window ID
  1357.                 &fcd,                   // Control Data
  1358.                 NULL);                  // Presentation Parameter
  1359.  
  1360.         if (psb->hwndShapeFrame)
  1361.         {
  1362.             // store the SHAPEFRAME structure in the frame's window words
  1363.             // so that the subclassed frame can access the data
  1364.             WinSetWindowULong(psb->hwndShapeFrame, QWL_USER, (ULONG)psb);
  1365.  
  1366.             // subclass the frame window; store the original wnd proc in
  1367.             // the SHAPEFRAME structure
  1368.             psb->pfnFrame = WinSubclassWindow(psb->hwndShapeFrame, fnwpShapeFrame);
  1369.  
  1370.             if ((psb->hwndShapeFrame) && (psb->hps))
  1371.             {
  1372.                 // OK, no errors so far
  1373.  
  1374.                 // register shape window class; if this is already
  1375.                 // registered, this won't hurt
  1376.                 WinRegisterClass(hab, SHAPE_WINDOW_CLASS, fnwpShapeWindow, 0L, sizeof(PVOID));
  1377.  
  1378.                 // create shape (image) window
  1379.                 psb->shpctrl.cx = psb->bmi.cx;
  1380.                 psb->shpctrl.cy = psb->bmi.cy;
  1381.                 psb->shpctrl.hpsDraw = psb->hps;
  1382.                 psb->shpctrl.hpsMask = psb->hps;
  1383.  
  1384.                 // create the "shape" window
  1385.                 psb->hwndShape = WinCreateWindow(
  1386.                         HWND_DESKTOP,           // Parent Window
  1387.                         SHAPE_WINDOW_CLASS,     // Window Class
  1388.                         NULL,                   // Window Text
  1389.                         0,                      // Window Style
  1390.                         0, 0, 0, 0,             // Pos & Size
  1391.                         psb->hwndShapeFrame,    // Owner Window
  1392.                         HWND_TOP,               // Z-Order
  1393.                         0,                      // Window ID
  1394.                         &psb->shpctrl,          // Control Data
  1395.                         NULL);                  // Pres. Param.
  1396.  
  1397.                 if (psb->hwndShape)
  1398.                     // no error: only then return TRUE
  1399.                     brc = TRUE;
  1400.             }
  1401.         }
  1402.     }
  1403.  
  1404.     return (brc);
  1405. }
  1406.  
  1407. /*
  1408.  *@@ fnwpShapeFrame:
  1409.  *      this is the window proc for subclassing the shape frame window
  1410.  *      (shpCreateWindows above).
  1411.  *      The shaped window proc (fnwpShapeWindow) keeps forwarding messages
  1412.  *      to its owner (which is the frame here), so we better handle
  1413.  *      those messages.
  1414.  */
  1415.  
  1416. MRESULT EXPENTRY fnwpShapeFrame(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1417. {
  1418.     MRESULT mrc;
  1419.  
  1420.     // get the SHAPEFRAME structure from the window words,
  1421.     // which has been stored there by shpCreateWindows
  1422.     PSHAPEFRAME psb = (PSHAPEFRAME)WinQueryWindowULong(hwnd, QWL_USER);
  1423.  
  1424.     // _Pmpf(("frame %08x %08x %08x", msg, mp1, mp2));
  1425.  
  1426.     switch (msg) {
  1427.  
  1428.         /*
  1429.          * WM_ADJUSTWINDOWPOS:
  1430.          *      forward the data we get here to the shape
  1431.          *      window (which will in turn reposition all
  1432.          *      the region windows);
  1433.          *      afterwards, always delete SHOW and set HIDE
  1434.          *      for ourselves
  1435.          */
  1436.  
  1437.         case WM_ADJUSTWINDOWPOS: {
  1438.             PSWP pswp = (PSWP) PVOIDFROMMP(mp1);
  1439.             POINTL ptl;
  1440.             WinQueryPointerPos(HWND_DESKTOP, &ptl);
  1441.             WinSetWindowPos(psb->hwndShape,
  1442.                             pswp->hwndInsertBehind,
  1443.                             // use current mouse position instead
  1444.                             // of the original ones
  1445.                             ptl.x,
  1446.                             ptl.y,
  1447.                             // pswp->x,
  1448.                             // pswp->y,
  1449.                             pswp->cx,
  1450.                             pswp->cy,
  1451.                             pswp->fl);
  1452.             pswp->fl &= ~SWP_SHOW;
  1453.             pswp->fl |=  SWP_HIDE;
  1454.             mrc = (*psb->pfnFrame)(hwnd, msg, mp1, mp2);
  1455.         break; }
  1456.  
  1457.         /* the shape window forwards these messages to us:
  1458.             WM_MOUSEMOVE
  1459.             WM_BUTTON1DOWN
  1460.             WM_BUTTON1UP
  1461.             WM_BUTTON1CLICK
  1462.             WM_BUTTON1DBLCLK
  1463.             WM_BUTTON2DOWN
  1464.             WM_BUTTON2UP
  1465.             WM_BUTTON2CLICK
  1466.             WM_BUTTON2DBLCLK
  1467.             WM_BUTTON3DOWN
  1468.             WM_BUTTON3UP
  1469.             WM_BUTTON3CLICK
  1470.             WM_BUTTON3DBLCLK
  1471.             WM_CHAR
  1472.             WM_VIOCHAR
  1473.             WM_BEGINDRAG
  1474.             WM_ENDDRAG
  1475.             WM_SINGLESELECT
  1476.             WM_OPEN
  1477.             WM_CONTEXTMENU
  1478.             WM_CONTEXTHELP
  1479.             WM_TEXTEDIT
  1480.             WM_BEGINSELECT
  1481.             WM_ENDSELECT */
  1482.  
  1483.         /*
  1484.          * WM_SINGLESELECT:
  1485.          *      if we are being clicked upon, bring the
  1486.          *      shape window to top instead
  1487.          */
  1488.  
  1489.         case WM_SINGLESELECT:
  1490.             WinSetWindowPos(psb->hwndShape, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER);
  1491.             mrc = 0;
  1492.         break;
  1493.  
  1494.         /*
  1495.          * WM_BEGINDRAG:
  1496.          *      if we are being dragged with MB2, forward
  1497.          *      this to the shape window
  1498.          */
  1499.  
  1500.         case WM_BEGINDRAG:
  1501.             WinSendMsg(psb->hwndShapeFrame, WM_TRACKFRAME,
  1502.                 MPFROMSHORT(TF_MOVE /* | TF_SETPOINTERPOS*/ ), NULL);
  1503.             mrc = 0;
  1504.         break;
  1505.  
  1506.         default:
  1507.             mrc = (*psb->pfnFrame)(hwnd, msg, mp1, mp2);
  1508.     }
  1509.  
  1510.     return (mrc);
  1511. }
  1512.  
  1513.