home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / xwphescr.zip / XWPH0208.ZIP / src / helpers / shapewin.c < prev    next >
Text File  |  2002-07-05  |  55KB  |  1,723 lines

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