source: trunk/src/helpers/shapewin.c@ 92

Last change on this file since 92 was 51, checked in by umoeller, 24 years ago

misc. changes.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 53.6 KB
Line 
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
224BOOL 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
234typedef struct _SHPWINCTLDATA *PSHPWINCTLDATA;
235typedef 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
248typedef 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
280typedef 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
294typedef 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
310void 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
321PSHPSPAN 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
344PSHPSPAN 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
371PSHPSPAN 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 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 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
499void 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
520MRESULT 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 return WinDefWindowProc(hwnd, msg, mp1, mp2);
581}
582
583/*
584 * shpmgrWMAdjustWindowPos:
585 * adjust the region windows' positions, visibility etc.
586 * by going thru the whole region windows list and
587 * repositioning all the windows.
588 * This gets called upon receiving WM_ADJUSTWINDOWPOS
589 * in shp_fnwpShapeMgr.
590 */
591
592int shpmgrWMAdjustWindowPos(PSHPWINCTLDATA pCtrl, PSWP pSwp)
593{
594 int i ;
595 PSHPREGION pRgn;
596 ULONG fl ;
597 // HPS hps ;
598
599 PSWP pswpArray;
600
601 // TRACE("shpmgrWMAdjustWindowPos - %d, %08x\n", pCtrl->nRegion, pSwp->fl);
602
603 if (pCtrl->nRegion == 0 || pCtrl->aRegion == NULL)
604 {
605 // TRACE("ShpDrawRegion - no region to open\n");
606 return -1;
607 }
608
609 if ((fl = pSwp->fl) & SWP_MOVE)
610 {
611 pCtrl->x = pSwp->x;
612 pCtrl->y = pSwp->y;
613 }
614
615 pswpArray = (PSWP) malloc(sizeof(SWP) * pCtrl->nRegion);
616
617 // go thru all the "regions" and adjust their sizes
618 for (i = 0, pRgn = pCtrl->aRegion;
619 i < pCtrl->nRegion;
620 i++, pRgn++)
621 {
622 pswpArray[i].fl = fl;
623 pswpArray[i].cy = (pRgn->rect.yTop - pRgn->rect.yBottom);
624 pswpArray[i].cx = (pRgn->rect.xRight - pRgn->rect.xLeft);
625 pswpArray[i].y = (pCtrl->y + pRgn->rect.yBottom);
626 pswpArray[i].x = (pCtrl->x + pRgn->rect.xLeft);
627 pswpArray[i].hwndInsertBehind = pSwp->hwndInsertBehind;
628 pswpArray[i].hwnd = pRgn->hwnd;
629 }
630
631 // set all window positions at once
632 WinSetMultWindowPos(WinQueryAnchorBlock(pCtrl->hwndShape),
633 &pswpArray[0],
634 pCtrl->nRegion);
635 free((void*) pswpArray);
636
637 // calling WinInvalidateRect is not neccessary,
638 // because the windows' update regions are already
639 // properly set by WinSetMultWindowPos (*UM)
640
641 /* for (i = 0, pRgn = pCtrl->aRegion;
642 i < pCtrl->nRegion;
643 i++, pRgn++)
644 {
645 if (fl & (SWP_MOVE | SWP_ZORDER)) {
646 WinInvalidateRect(pRgn->hwnd, NULL, FALSE);
647 }
648 } */
649 return 0;
650}
651
652/*
653 * shpmgrUpdateRegions:
654 * this gets called by shp_fnwpShapeMgr upon receiving
655 * SHAPEWIN_MSG_UPDATE.
656 */
657
658int shpmgrUpdateRegions(PSHPWINCTLDATA pCtrl, PRECTL pRect)
659{
660 RECTL rect, intern;
661 int i ;
662 PSHPREGION pRgn;
663 HAB hab ;
664 // HPS hps ;
665
666 // TRACE("shpmgrUpdateRegions\n");
667
668 hab = WinQueryAnchorBlock(pCtrl->hwndShape);
669
670 if (pRect == NULL) {
671 rect.xLeft = 0 ;
672 rect.yBottom = 0 ;
673 rect.xRight = pCtrl->cx;
674 rect.yTop = pCtrl->cy;
675 pRect = &rect;
676 }
677 for (i = 0, pRgn = pCtrl->aRegion; i < pCtrl->nRegion; i++, pRgn++)
678 {
679 if (WinIntersectRect(hab, &intern, pRect, &pRgn->rect) == FALSE) {
680 continue;
681 } else {
682 WinInvalidateRect(pRgn->hwnd, NULL, FALSE);
683 }
684 }
685 return 0;
686}
687
688/*
689 * shpmgrParseBitmap:
690 * this gets called from shpmgrWMCreate_Bitmap2Regions when the
691 * shape region windows need to be created.
692 * This function does the actual bitmap analysis and
693 * creates a large number of SHPSPAN structures according
694 * to the bitmaps, which can later be turned into
695 * PM windows.
696 * This happens during the processing of WM_CREATE in
697 * shp_fnwpShapeMgr.
698 * CPU usage: relatively low. Maybe 5% of the whole creation
699 * procedure.
700 *
701 *@@changed V0.9.1 (99-12-03): fixed memory leak
702 */
703
704PSHPSPAN shpmgrParseBitmap(HPS hps, PBITMAPINFOHEADER2 bmih2)
705{
706 int blen, hlen;
707 PUCHAR buf;
708 PBITMAPINFO2 pbmi;
709 PSHPSPAN pSpan, pNew;
710 int x, y, k;
711 LONG first, color;
712 BOOL inspan;
713 int left;
714
715 // TRACE("shpmgrParseBitmap\n");
716
717 hlen = sizeof(BITMAPINFO2) + sizeof(RGB) * 256;
718 blen = ((bmih2->cBitCount * bmih2->cx + 31) / 32) * bmih2->cPlanes * 4;
719
720 pbmi = (PBITMAPINFO2)malloc(hlen);
721 buf = (PUCHAR)malloc(blen);
722
723 if (pbmi == NULL || buf == NULL)
724 {
725 // TRACE("shpmgrParseBitmap - failed to alloc %d %d\n", hlen, blen);
726 if (pbmi)
727 free(pbmi);
728 if (buf)
729 free(buf);
730 return NULL;
731 }
732 memcpy(pbmi, bmih2, sizeof(BITMAPINFOHEADER2));
733
734 if ((pSpan = spanCreate()) == NULL)
735 {
736 // TRACE("shpmgrParseBitmap - failed to make\n");
737 free(pbmi);
738 free(buf);
739 return NULL;
740 }
741
742 first = -1;
743
744 for (y = 0; y < bmih2->cy; y++)
745 {
746
747 // TRACE("shpmgrParseBitmap - scan line %d\n", y); fflush(stdout);
748
749 GpiQueryBitmapBits(hps, y, 1, (PBYTE)buf, pbmi);
750
751 for (x = 0, inspan = FALSE; x < bmih2->cx; x++)
752 {
753 k = x * 3;
754 color = ((buf[k] << 16) | (buf[k+1] << 8) | buf[k+2]);
755
756 if (first < 0)
757 {
758 // first iteration: get the very first color (that
759 // is the pixel at (0, 0)), with which we will
760 // compare the others to determine the mask
761 first = color;
762 }
763
764 if (inspan == FALSE && color != first)
765 {
766 inspan = TRUE;
767 left = x;
768 }
769 else if (inspan == TRUE && color == first)
770 {
771 // transparent color found:
772 // create new span
773 inspan = FALSE;
774 if ((pNew = spanAppend(pSpan, y, left, x)) != NULL)
775 {
776 pSpan = pNew;
777 }
778 else
779 {
780 // TRACE("shpmgrParseBitmap - failed to extend\n");
781 break;
782 }
783 }
784 }
785 if (inspan == TRUE)
786 {
787 if ((pNew = spanAppend(pSpan, y, left, x)) != NULL)
788 pSpan = pNew;
789 else
790 // TRACE("shpmgrParseBitmap - failed to extend\n");
791 break;
792 }
793 }
794
795#ifdef SHPDEBUG
796 dumpSpan(pSpan);
797#endif
798
799 // fixed these memory leaks V0.9.1 (99-12-03)
800 if (pbmi)
801 free(pbmi);
802 if (buf)
803 free(buf);
804
805 return pSpan;
806}
807
808/*
809 * shpmgrWMCreate_Bitmap2Regions:
810 * this gets called from shpmgrWMCreate (WM_CREATE) to have a
811 * drawing region created from the bitmap which has been
812 * selected into the given HPS.
813 *
814 * First step in WM_CREATE.
815 */
816
817int shpmgrWMCreate_Bitmap2Regions(PSHPWINCTLDATA pCtrl, // in: shape control data
818 HPS hpsMask) // in: HPS with selected bitmap
819{
820 HAB hab;
821 HDC hdc;
822 HPS hps;
823 SIZEL siz;
824 HBITMAP hbm,
825 hbmPrevious;
826 BITMAPINFOHEADER2 bmi;
827 POINTL apt[3];
828 PSHPSPAN pSpan;
829 PSHPREGION pRegn;
830 int i;
831
832 // TRACE("shpmgrWMCreate_Bitmap2Regions\n");
833
834 hab = WinQueryAnchorBlock(pCtrl->hwndShape);
835
836 /*
837 * Create Memory DC & HPS
838 */
839
840 hdc = DevOpenDC(hab, OD_MEMORY, "*", 0, NULL, NULLHANDLE);
841 siz.cx = siz.cy = 0;
842 hps = GpiCreatePS(hab, hdc, &siz,
843 PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC);
844
845 /*
846 * Create Bitmap and relate to memory PS
847 */
848
849 memset(&bmi, 0, sizeof(bmi));
850
851 bmi.cbFix = sizeof(BITMAPINFOHEADER2);
852 bmi.cx = pCtrl->cx;
853 bmi.cy = pCtrl->cy;
854 bmi.cPlanes = 1 ;
855 bmi.cBitCount = 24;
856 bmi.ulCompression = 0 ;
857 bmi.cclrUsed = 0 ;
858 bmi.cclrImportant = 0 ;
859
860 hbm = GpiCreateBitmap(hps, &bmi, 0, NULL, NULL);
861
862 hbmPrevious = GpiSetBitmap(hps, hbm);
863
864 /*
865 * Copy in Mask Pattern
866 */
867
868 // TRACE("shpmgrWMCreate_Bitmap2Regions - copyin %d x %d mask pattern\n", bmi.cx, bmi.cy);
869
870 apt[0].x = 0; // Target
871 apt[0].y = 0;
872 apt[1].x = bmi.cx;
873 apt[1].y = bmi.cy;
874 apt[2].x = 0; // Source
875 apt[2].y = 0;
876
877 if (GpiBitBlt(hps, pCtrl->hpsDraw, 3, apt, ROP_SRCCOPY, 0) == GPI_ERROR) {
878 // TRACE("MakeRect - BitBlt Failed %08x, hdc %08x, hps %08x, hbm %08x\n",
879 // WinGetLastError(hab), hdc, hps, hbm);
880 }
881
882 /*
883 * Parse Mask Pattern
884 */
885
886 // call shpmgrParseBitmap; this does the actual creation of the
887 // "spans" by comparing all bitmap pixels to the (0, 0)
888 // pixel
889 if ((pSpan = shpmgrParseBitmap(hps, &bmi)) != NULL)
890 {
891 if ((pRegn = (PSHPREGION) malloc(sizeof(SHPREGION) * pSpan->nUsed)) == NULL)
892 {
893 // TRACE("shpmgrWMCreate_Bitmap2Regions - failed to alloc\n");
894 }
895 else
896 {
897 // mask created successfully:
898 pCtrl->nRegion = pSpan->nUsed;
899 pCtrl->aRegion = pRegn;
900
901 for (i = 0; i < pSpan->nUsed; i++)
902 {
903 pRegn[i].pCtrl = pCtrl;
904 pRegn[i].hwnd = NULLHANDLE;
905 pRegn[i].rect.xLeft = pSpan->aSpan[i].xLeft ;
906 pRegn[i].rect.xRight = pSpan->aSpan[i].xRight ;
907 pRegn[i].rect.yTop = pSpan->aSpan[i].yTop ;
908 pRegn[i].rect.yBottom = pSpan->aSpan[i].yBottom;
909 }
910 }
911 spanFree(pSpan);
912 }
913
914 /*
915 * dispose local resources
916 */
917
918 GpiSetBitmap(hps, hbmPrevious); // (*UM)
919 GpiDeleteBitmap(hbm);
920 GpiDestroyPS(hps);
921 DevCloseDC(hdc);
922
923 return 0;
924}
925
926/*
927 * shpmgrWMCreate_Regions2Windows:
928 * this gets called from shpmgrWMCreate (WM_CREATE) to convert
929 * all the "regions" that have been created by shpmgrWMCreate_Bitmap2Regions
930 * in pCtrl to individual rectangular PM windows.
931 *
932 * CPU usage: extremely high, because all the dull PM functions
933 * take so damn long. Calculating the "regions" isn't really
934 * difficult, but it's the PM windows which cause the CPU hog.
935 *
936 * Second step in WM_CREATE.
937 */
938
939int shpmgrWMCreate_Regions2Windows(PSHPWINCTLDATA pCtrl)
940{
941 int i ;
942 PSHPREGION pRgn;
943 ULONG flStyle;
944
945 // TRACE("shpmgrWMCreate_Regions2Windows %d regions\n", pCtrl->nRegion);
946
947 // check if any "regions" exist at all
948 if (pCtrl->nRegion == 0 || pCtrl->aRegion == NULL)
949 {
950 // TRACE("shpmgrWMCreate_Regions2Windows - no region to open\n");
951 return -1;
952 }
953
954 if (G_ShapeRegisteredRegion == FALSE)
955 {
956 // first call: register "shape region" class
957 WinRegisterClass(WinQueryAnchorBlock(pCtrl->hwndShape),
958 WC_SHAPE_REGION,
959 shp_fnwpShapeRegion,
960 CS_PARENTCLIP
961 // use parent's clipping region instead
962 // of the one of the region window
963 | CS_CLIPSIBLINGS
964 // don't allow the subwindows to paint
965 // over siblings (ie. windows with the
966 // same parent); this is neccessary if
967 // HWND_DESKTOP is the parent
968 | CS_SYNCPAINT,
969 // paint immediately
970 sizeof(PVOID));
971 G_ShapeRegisteredRegion = TRUE;
972 }
973
974 flStyle = 0;
975
976 // now go thru the "regions" list
977 for (i = 0, pRgn = pCtrl->aRegion;
978 i < pCtrl->nRegion;
979 i++, pRgn++)
980 {
981 // and create a window for each "region"
982 pRgn->hwnd = WinCreateWindow(
983 pCtrl->hwndParent, // copy parent window from shape window
984 // changed (*UM)
985 // HWND_DESKTOP, // Parent Window
986 WC_SHAPE_REGION, // window class
987 NULL, // window text
988 flStyle, // window style
989 (pCtrl->x + pRgn->rect.xLeft), // x
990 (pCtrl->y + pRgn->rect.yBottom), // y
991 (pRgn->rect.xRight - pRgn->rect.xLeft), // cx
992 (pRgn->rect.yTop - pRgn->rect.yBottom), // cy
993 pCtrl->hwndOwner, // Owner Window
994 HWND_TOP, // Z-Order
995 i, // Window ID
996 pRgn, // Control Data
997 NULL); // Pres. Param.
998 }
999 return 0;
1000}
1001
1002/*
1003 * shpmgrFreeRegion:
1004 * cleanup during WM_DESTROY.
1005 */
1006
1007int shpmgrFreeRegion(PSHPWINCTLDATA pCtrl)
1008{
1009 int i ;
1010 PSHPREGION pRgn;
1011
1012 for (i = 0, pRgn = pCtrl->aRegion;
1013 i < pCtrl->nRegion;
1014 i++, pRgn++)
1015 WinDestroyWindow(pRgn->hwnd);
1016
1017 free(pCtrl->aRegion);
1018
1019 return 0;
1020}
1021
1022/*
1023 * shpmgrWMCreate:
1024 * this initializes the "shape window".
1025 * This gets called upon receiving WM_CREATE in shp_fnwpShapeMgr.
1026 * The procedure is as follows:
1027 * 1) the bitmap in pData->hpsDraw is analyzed pixel by
1028 * pixel to create a number of "regions" from it
1029 * (which are not GPI regions, but an array of SHPREGION
1030 * structures. At least one of these structures is
1031 * created for each line. This is done by calling
1032 * shpmgrWMCreate_Bitmap2Regions.
1033 * 2) We then call shpmgrWMCreate_Regions2Windows to actually create
1034 * PM windows from all these structures.
1035 */
1036
1037PSHPWINCTLDATA shpmgrWMCreate(HWND hwnd, // in: shape window
1038 PCREATESTRUCT pWin, // in: create struct of WM_CREATE
1039 PSHPCTLDATA pData) // in: SHPCTLDATA struct (WM_CREATE mp1)
1040{
1041 PSHPWINCTLDATA pCtrl;
1042
1043 if (pData->hpsDraw == NULLHANDLE || pData->hpsMask == NULLHANDLE) {
1044 return NULL;
1045 }
1046
1047 // create new PSHPWINCTLDATA structure
1048 if ((pCtrl = (PSHPWINCTLDATA) malloc(sizeof(SHPWINCTLDATA))) == NULL) {
1049 return NULL;
1050 }
1051
1052 /*
1053 * Setup Common Window Parameters
1054 */
1055
1056 pCtrl->hwndShape = hwnd;
1057 pCtrl->hwndParent = pWin->hwndParent;
1058 pCtrl->hwndOwner = pWin->hwndOwner ;
1059 pCtrl->id = pWin->id;
1060 pCtrl->x = pWin->x ;
1061 pCtrl->y = pWin->y ;
1062 pCtrl->cx = pWin->cx;
1063 pCtrl->cy = pWin->cy;
1064
1065 /*
1066 * Setup Image Window's Control Data
1067 */
1068
1069 pCtrl->cx = pData->cx;
1070 pCtrl->cy = pData->cy;
1071 pCtrl->hpsDraw = pData->hpsDraw;
1072
1073 // now create "regions" from bitmap;
1074 // this will store the "regions" in pCtrl
1075 shpmgrWMCreate_Bitmap2Regions(pCtrl, pData->hpsMask);
1076
1077 // now create as many rectangular PM
1078 // windows as we have "regions" in pCtrl
1079 shpmgrWMCreate_Regions2Windows(pCtrl);
1080
1081 return pCtrl;
1082}
1083
1084/*
1085 * shpmgrWMDestroy:
1086 * this cleans up the shape's resources.
1087 * Gets called upon receiving WM_DESTROY in
1088 * shp_fnwpShapeMgr.
1089 */
1090
1091void shpmgrWMDestroy(PSHPWINCTLDATA pCtrl)
1092{
1093 if (pCtrl == NULL)
1094 return;
1095
1096 shpmgrFreeRegion(pCtrl);
1097 free(pCtrl);
1098}
1099
1100/*
1101 *@@ shp_fnwpShapeMgr:
1102 * this is the window procedure for the "shape window manager".
1103 * Register this procedure with WinRegisterWindowClass.
1104 *
1105 * This does the transformation of the bitmap into many
1106 * rectangular subwindows upon WM_CREATE, each of which
1107 * will use shp_fnwpShapeRegion as its window proc.
1108 *
1109 * There should be the following window hierarchy (the
1110 * lines signify ownership):
1111 *
1112 + Your owner window
1113 + |
1114 + +-- owns "shape manager" window (this window proc)
1115 + |
1116 + +-- lots of "region" windows (shp_fnwpShapeRegion)
1117 + +-- ...
1118 *
1119 * The "region" windows are owned by the "shape manager" window,
1120 * but have the same parent as the "shape manager" window.
1121 * Normally, this should be set to HWND_DESKTOP when creating the
1122 * "shape" window.
1123 *
1124 * This window procedure forwards the following messages
1125 * to its owner:
1126 * -- WM_MOUSEMOVE
1127 * -- all WM_BUTTONxxx messages
1128 * -- WM_CHAR
1129 * -- WM_VIOCHAR
1130 * -- WM_BEGINDRAG
1131 * -- WM_ENDDRAG
1132 * -- WM_SINGLESELECT
1133 * -- WM_OPEN
1134 * -- WM_CONTEXTMENU
1135 * -- WM_CONTEXTHELP
1136 * -- WM_TEXTEDIT
1137 * -- WM_BEGINSELECT
1138 * -- WM_ENDSELECT
1139 */
1140
1141MRESULT EXPENTRY shp_fnwpShapeMgr(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
1142{
1143 PSHPWINCTLDATA pCtrl;
1144 PSWP pswp ;
1145 // SHORT sx; // , sy;
1146
1147 pCtrl = (PSHPWINCTLDATA) WinQueryWindowPtr(hwnd, 0);
1148
1149 switch (msg)
1150 {
1151
1152 /*
1153 * WM_CREATE:
1154 * shape window is being created.
1155 * Parameters:
1156 * PSHPCTLDATA mp1
1157 * PCREATESTRUCT mp2
1158 * Shaped windows must have a SHPCTLDATA
1159 * structure in mp1.
1160 */
1161
1162 case WM_CREATE:
1163 // TRACE("WM_CREATE\n");
1164 pCtrl = shpmgrWMCreate(hwnd,
1165 (PCREATESTRUCT)PVOIDFROMMP(mp2),
1166 (PSHPCTLDATA)PVOIDFROMMP(mp1));
1167
1168 if (pCtrl == NULL)
1169 return (MRESULT) TRUE;
1170
1171 // store control data in window words
1172 WinSetWindowPtr(hwnd, 0, (PVOID) pCtrl);
1173 return (MRESULT) FALSE;
1174
1175 /*
1176 * WM_DESTROY:
1177 * clean up.
1178 */
1179
1180 case WM_DESTROY:
1181 // TRACE("WM_DESTORY\n");
1182 shpmgrWMDestroy(pCtrl);
1183 return (MRESULT) 0;
1184
1185 /*
1186 * WM_ADJUSTWINDOWPOS:
1187 * this needs to be manipulated to
1188 * adjust the positions of all the
1189 * subwindows instead.
1190 */
1191
1192 case WM_ADJUSTWINDOWPOS:
1193 // TRACE("WM_ADJUSTWINDOWPOS\n");
1194 pswp = (PSWP) PVOIDFROMMP(mp1);
1195 // DUMPSWP(pswp);
1196
1197 // enforce the size which we were given
1198 // in the beginning, because we cannot
1199 // change the size later
1200 pswp->cx = pCtrl->cx;
1201 pswp->cy = pCtrl->cy;
1202
1203 // adjust the sub-windows
1204 shpmgrWMAdjustWindowPos(pCtrl, pswp);
1205
1206 // never show ourselves
1207 pswp->fl &= ~SWP_SHOW;
1208 return (MRESULT) 0;
1209
1210 /*
1211 * SHAPEWIN_MSG_UPDATE:
1212 *
1213 */
1214
1215 case SHAPEWIN_MSG_UPDATE:
1216 shpmgrUpdateRegions(pCtrl, (PRECTL) PVOIDFROMMP(mp1));
1217 return (MRESULT) 0;
1218
1219 /*
1220 * WM_QUERYDLGCODE:
1221 *
1222 */
1223
1224 case WM_QUERYDLGCODE:
1225 // TRACE("WM_QUERYDLGCODE\n");
1226 return (MRESULT)DLGC_STATIC;
1227
1228 /*
1229 * WM_PAINT:
1230 * we just swallow this message because
1231 * there's no "shape window" to be painted;
1232 * instead, all the region windows get
1233 * their own WM_PAINT message
1234 */
1235
1236 case WM_PAINT:
1237 {
1238 // TRACE("WM_PAINT\n");
1239 /* HPS hps = WinBeginPaint(hwnd, NULLHANDLE, NULL);
1240
1241 POINTL apt[3];
1242 RECTL rclWin;
1243 WinQueryWindowRect(hwnd, &rclWin);
1244
1245 // lower left of target
1246 apt[0].x = 0;
1247 apt[0].y = 0;
1248 // upper right of target
1249 apt[1].x = rclWin.xRight;
1250 apt[1].y = rclWin.yTop;
1251 // lower left of source
1252 apt[2].x = 0;
1253 apt[2].y = 0;
1254 GpiBitBlt(hps,
1255 pCtrl->hpsDraw,
1256 3,
1257 apt,
1258 ROP_SRCCOPY,
1259 0); */
1260
1261 // delete update region to stop further
1262 // WM_PAINTs for this window;
1263 // this is faster than WiNBeginPaint
1264 WinValidateRect(hwnd, NULL, FALSE);
1265 // WinEndPaint(hps);
1266 return (MRESULT) 0;
1267 }
1268
1269 /*
1270 * all input-related messages:
1271 * forward these to the owner
1272 */
1273
1274 case WM_MOUSEMOVE :
1275 case WM_BUTTON1DOWN :
1276 case WM_BUTTON1UP :
1277 case WM_BUTTON1CLICK :
1278 case WM_BUTTON1DBLCLK:
1279 case WM_BUTTON2DOWN :
1280 case WM_BUTTON2UP :
1281 case WM_BUTTON2CLICK :
1282 case WM_BUTTON2DBLCLK:
1283 case WM_BUTTON3DOWN :
1284 case WM_BUTTON3UP :
1285 case WM_BUTTON3CLICK :
1286 case WM_BUTTON3DBLCLK:
1287 case WM_CHAR :
1288 case WM_VIOCHAR :
1289 case WM_BEGINDRAG :
1290 case WM_ENDDRAG :
1291 case WM_SINGLESELECT :
1292 case WM_OPEN :
1293 case WM_CONTEXTMENU :
1294 case WM_CONTEXTHELP :
1295 case WM_TEXTEDIT :
1296 case WM_BEGINSELECT :
1297 case WM_ENDSELECT :
1298 return WinSendMsg(pCtrl->hwndOwner, msg, mp1, mp2);
1299
1300 } // end switch (msg)
1301 return WinDefWindowProc(hwnd, msg, mp1, mp2);
1302}
1303
1304/* ******************************************************************
1305 *
1306 * Part 2: Shape frame functions
1307 *
1308 ********************************************************************/
1309
1310MRESULT EXPENTRY fnwpShapeFrame(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
1311
1312/*
1313 *@@ shpLoadBitmap:
1314 * this creates a memory device context/presentation space
1315 * and loads and selects a bitmap into it.
1316 *
1317 * If pszBitmap == NULL, the bitmap is loaded from the
1318 * specified resources, otherwise we attempt to load the
1319 * bitmap file specified in pszBitmap (using gpihLoadBitmapFile).
1320 *
1321 * Output in the given SHAPEFRAME structure:
1322 * -- hab: as passed to this func
1323 * -- hdc: device context handle
1324 * -- hps: presentation space handle
1325 * -- hbm: bitmap handle
1326 * -- bmi: BITMAPINFOHEADER of hbmp
1327 * -- ptlLowerLeft: lower left corner is set so that
1328 * bitmap is centered on screen
1329 *
1330 * All other fields are neither read nor written to.
1331 * Returns TRUE if everything went OK.
1332 *
1333 * You can call this function directly before calling
1334 * shpCreateWindows.
1335 *
1336 * Pass the SHAPEFRAME structure to shpFreeBitmap to clean up.
1337 *
1338 *@@changed V0.9.0 [umoeller]: added default window positioning
1339 *@@changed V0.9.0 [umoeller]: removed GpiSetBitmap here
1340 *@@changed V0.9.9 (2001-03-18) [lafaix]: brc was not set
1341 */
1342
1343BOOL shpLoadBitmap(HAB hab, // in: anchor block
1344 PSZ pszBitmapFile, // in: OS/2 1.3 bmp file or NULL
1345 HMODULE hmodResource, // in: module handle from where the
1346 // resources should be loaded if
1347 // pszBitmapFile == NULL. This can be 0 for
1348 // the current EXE
1349 ULONG idResource, // in: bitmap resource ID in that module
1350 PSHAPEFRAME psb) // out: bitmap info
1351{
1352 SIZEL siz;
1353 BOOL brc = FALSE;
1354
1355 psb->hab = hab;
1356
1357 psb->hdc = DevOpenDC(hab, OD_MEMORY, "*", 0, NULL, NULLHANDLE);
1358 if (psb->hdc)
1359 {
1360 siz.cx = siz.cy = 0;
1361 psb->hps = GpiCreatePS(hab, psb->hdc, &siz,
1362 PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC);
1363
1364 if (psb->hps)
1365 {
1366 if (pszBitmapFile)
1367 {
1368 // load bitmap file
1369 ULONG ulError;
1370 psb->hbm = gpihLoadBitmapFile(psb->hps,
1371 pszBitmapFile,
1372 &ulError);
1373 } else
1374 // load resource bitmap
1375 psb->hbm = GpiLoadBitmap(psb->hps,
1376 hmodResource,
1377 idResource,
1378 0, 0);
1379 if (psb->hbm)
1380 {
1381 SWP swpScreen;
1382 // store bitmap info in structure
1383 psb->bmi.cbFix = sizeof(psb->bmi);
1384 GpiQueryBitmapInfoHeader(psb->hbm, &psb->bmi);
1385
1386 // set ptlLowerLeft so that the bitmap
1387 // is centered on the screen
1388 WinQueryWindowPos(HWND_DESKTOP, &swpScreen);
1389 psb->ptlLowerLeft.x = (swpScreen.cx - psb->bmi.cx) / 2;
1390 psb->ptlLowerLeft.y = (swpScreen.cy - psb->bmi.cy) / 2;
1391
1392 brc = TRUE;
1393 }
1394 }
1395 }
1396 return (brc);
1397}
1398
1399/*
1400 *@@ shpFreeBitmap:
1401 * this cleans up resources allocated by shpLoadBitmap:
1402 * delete the bitmap, destroy the HPS and HDC.
1403 *
1404 *@@changed V0.9.3 (2000-04-11) [umoeller]: fixed major resource leak; the bitmap was never freed
1405 */
1406
1407VOID shpFreeBitmap(PSHAPEFRAME psb)
1408{
1409 if (psb->hbm != NULLHANDLE)
1410 {
1411 // unset bitmap in HPS; it cannot be deleted otherwise...
1412 GpiSetBitmap(psb->hps, NULLHANDLE); // V0.9.3 (2000-04-11) [umoeller]
1413 GpiDeleteBitmap(psb->hbm);
1414 psb->hbm = NULLHANDLE;
1415 }
1416 if (psb->hps != NULLHANDLE)
1417 {
1418 GpiDestroyPS(psb->hps);
1419 psb->hps = NULLHANDLE;
1420 }
1421 if (psb->hdc != NULLHANDLE)
1422 {
1423 DevCloseDC(psb->hdc);
1424 psb->hdc = NULLHANDLE;
1425 }
1426}
1427
1428/*
1429 *@@ shpCreateWindows:
1430 * this is a one-shot function for creating a
1431 * shaped window from a bitmap.
1432 *
1433 * Required fields in SHAPEFRAME for input (those
1434 * are all properly set by shpLoadBitmap):
1435 * -- hab: anchor block
1436 * -- hps: presentation space handle
1437 * -- hbm: bitmap handle
1438 * -- bmi: BITMAPINFOHEADER of hbmp
1439 * -- ptlLowerLeft: lower left corner of where
1440 * to position the shape window (new with V0.9.0).
1441 *
1442 * All other fields are ignored for input and only
1443 * set for output (and for the shape window later).
1444 *
1445 * You can use shpLoadBitmap to have all the fields
1446 * initialized, which will also set ptlLowerLeft
1447 * so that the shape window gets centered on the
1448 * Desktop.
1449 *
1450 * Otherwise you must initialize the above fields for
1451 * yourself.
1452 *
1453 * Obviously, this function uses the same HPS (and
1454 * thus bitmap) for both transparency and drawing.
1455 * If you wish to use two different bitmaps (one for
1456 * transparency, one for drawing), you cannot use
1457 * this function.
1458 *
1459 * Note that the windows are now (V0.9.0) also positioned
1460 * on the screen.
1461 *
1462 * Output in that structure:
1463 * -- hwndShapeFrame: invisible rectangular frame
1464 * window for the shape window
1465 * (fnwpShapeFrame, created here)
1466 * -- hwndShape: "shape" window
1467 * (shp_fnwpShapeMgr, created here)
1468 * -- pfnFrame: original window procedure of
1469 * WC_FRAME (hwndShapeFrame),
1470 * which is subclassed here
1471 * using fnwpShapeFrame
1472 * -- shpctrl: control data for hwndShape
1473 *
1474 * Returns TRUE if everything went OK.
1475 *
1476 * <B>Example</B> for creating a shaped window and
1477 * centering it on the screen:
1478 + SHAPEFRAME sb;
1479 + if (shpLoadBitmap(hab...,
1480 + szBitmapFile...,
1481 + 0, 0,
1482 + &sb))
1483 + {
1484 + // create shape (transparent) windows
1485 + if (shpCreateWindows(habQuickThread, &sb))
1486 + {
1487 * ...
1488 + }
1489 + }
1490 + ...
1491 + // cleanup
1492 + shpFreeBitmap(&sb);
1493 + WinDestroyWindow(sb.hwndShapeFrame) ;
1494 + WinDestroyWindow(sb.hwndShape);
1495 *
1496 *@@changed V0.9.0 [umoeller]: removed hab from function prototype
1497 *@@changed V0.9.0 [umoeller]: added window positioning
1498 *@@changed V0.9.0 [umoeller]: added GpiSetBitmap here (always forget that)
1499 */
1500
1501BOOL shpCreateWindows(PSHAPEFRAME psb)
1502{
1503 BOOL brc = FALSE;
1504
1505 if (psb->hbm)
1506 {
1507 // bitmap seems to be valid:
1508 FRAMECDATA fcd;
1509
1510 GpiSetBitmap(psb->hps, psb->hbm);
1511
1512 memset(&fcd, 0, sizeof(fcd));
1513 fcd.cb = sizeof(fcd);
1514
1515 // create invisible frame
1516 psb->hwndShapeFrame = WinCreateWindow(
1517 HWND_DESKTOP, // Parent window handle
1518 WC_FRAME, // Frame Window Class
1519 "XWorkplaceLogoShape", // title
1520 0, // Window Style
1521 0, 0, 0, 0, // Position & size
1522 NULLHANDLE, // Owner Window
1523 HWND_TOP, // Z-Order
1524 0, // Window ID
1525 &fcd, // Control Data
1526 NULL); // Presentation Parameter
1527
1528 if (psb->hwndShapeFrame)
1529 {
1530 // store the SHAPEFRAME structure in the frame's window words
1531 // so that the subclassed frame can access the data
1532 WinSetWindowULong(psb->hwndShapeFrame, QWL_USER, (ULONG)psb);
1533
1534 // subclass the frame window; store the original wnd proc in
1535 // the SHAPEFRAME structure
1536 psb->pfnFrame = WinSubclassWindow(psb->hwndShapeFrame, fnwpShapeFrame);
1537
1538 if ((psb->hwndShapeFrame) && (psb->hps))
1539 {
1540 // OK, no errors so far
1541
1542 // register shape window class; if this is already
1543 // registered, this won't hurt
1544 WinRegisterClass(psb->hab,
1545 WC_SHAPE_WINDOW,
1546 shp_fnwpShapeMgr,
1547 0L, // class style flags
1548 sizeof(PVOID));
1549
1550 // create shape manager window
1551 psb->shpctrl.cx = psb->bmi.cx;
1552 psb->shpctrl.cy = psb->bmi.cy;
1553 psb->shpctrl.hpsDraw = psb->hps;
1554 psb->shpctrl.hpsMask = psb->hps;
1555
1556 // create the "shape" window
1557 psb->hwndShape = WinCreateWindow(
1558 HWND_DESKTOP, // Parent Window
1559 WC_SHAPE_WINDOW, // Window Class
1560 NULL, // Window Text
1561 0, // Window Style;
1562 // no clip siblings!
1563 0, 0, 0, 0, // Pos & Size
1564 psb->hwndShapeFrame, // Owner Window
1565 HWND_TOP, // Z-Order
1566 0, // Window ID
1567 &psb->shpctrl, // Control Data
1568 NULL); // Pres. Param.
1569
1570 if (psb->hwndShape)
1571 {
1572 // no error: only then return TRUE
1573 brc = TRUE;
1574
1575 // and position the windows
1576 WinSetWindowPos(psb->hwndShapeFrame, NULLHANDLE,
1577 psb->ptlLowerLeft.x, psb->ptlLowerLeft.y,
1578 psb->bmi.cx, psb->bmi.cy,
1579 (SWP_MOVE | SWP_SIZE | SWP_HIDE));
1580 WinSetWindowPos(psb->hwndShape, NULLHANDLE,
1581 psb->ptlLowerLeft.x, psb->ptlLowerLeft.y,
1582 psb->bmi.cx, psb->bmi.cy,
1583 (SWP_MOVE | SWP_SIZE | SWP_SHOW));
1584 }
1585 }
1586 }
1587 }
1588
1589 return (brc);
1590}
1591
1592/*
1593 *@@ fnwpShapeFrame:
1594 * this is the window proc for subclassing the shape frame window
1595 * (shpCreateWindows above).
1596 * The shaped window proc (shp_fnwpShapeMgr) keeps forwarding messages
1597 * to its owner (which is the frame here), so we better handle
1598 * those messages.
1599 */
1600
1601MRESULT EXPENTRY fnwpShapeFrame(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
1602{
1603 MRESULT mrc;
1604
1605 // get the SHAPEFRAME structure from the window words,
1606 // which has been stored there by shpCreateWindows
1607 PSHAPEFRAME psb = (PSHAPEFRAME)WinQueryWindowULong(hwnd, QWL_USER);
1608
1609 // _Pmpf(("frame %08x %08x %08x", msg, mp1, mp2));
1610
1611 switch (msg)
1612 {
1613
1614 /*
1615 * WM_ADJUSTWINDOWPOS:
1616 * forward the data we get here to the shape
1617 * window (which will in turn reposition all
1618 * the region windows);
1619 * afterwards, always delete SHOW and set HIDE
1620 * for ourselves
1621 */
1622
1623 case WM_ADJUSTWINDOWPOS: {
1624 PSWP pswp = (PSWP) PVOIDFROMMP(mp1);
1625 POINTL ptl;
1626 WinQueryPointerPos(HWND_DESKTOP, &ptl);
1627 WinSetWindowPos(psb->hwndShape,
1628 pswp->hwndInsertBehind,
1629 // use current mouse position instead
1630 // of the original ones
1631 ptl.x,
1632 ptl.y,
1633 // pswp->x,
1634 // pswp->y,
1635 pswp->cx,
1636 pswp->cy,
1637 pswp->fl);
1638 pswp->fl &= ~SWP_SHOW;
1639 pswp->fl |= SWP_HIDE;
1640 mrc = (*psb->pfnFrame)(hwnd, msg, mp1, mp2);
1641 break; }
1642
1643 /* the shape window forwards these messages to us:
1644 WM_MOUSEMOVE
1645 WM_BUTTON1DOWN
1646 WM_BUTTON1UP
1647 WM_BUTTON1CLICK
1648 WM_BUTTON1DBLCLK
1649 WM_BUTTON2DOWN
1650 WM_BUTTON2UP
1651 WM_BUTTON2CLICK
1652 WM_BUTTON2DBLCLK
1653 WM_BUTTON3DOWN
1654 WM_BUTTON3UP
1655 WM_BUTTON3CLICK
1656 WM_BUTTON3DBLCLK
1657 WM_CHAR
1658 WM_VIOCHAR
1659 WM_BEGINDRAG
1660 WM_ENDDRAG
1661 WM_SINGLESELECT
1662 WM_OPEN
1663 WM_CONTEXTMENU
1664 WM_CONTEXTHELP
1665 WM_TEXTEDIT
1666 WM_BEGINSELECT
1667 WM_ENDSELECT */
1668
1669 /*
1670 * WM_SINGLESELECT:
1671 * if we are being clicked upon, bring the
1672 * shape window to top instead
1673 */
1674
1675 case WM_SINGLESELECT:
1676 WinSetWindowPos(psb->hwndShape, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER);
1677 mrc = 0;
1678 break;
1679
1680 /*
1681 * WM_BEGINDRAG:
1682 * if we are being dragged with MB2, forward
1683 * this to the shape window
1684 */
1685
1686 case WM_BEGINDRAG:
1687 WinSendMsg(psb->hwndShapeFrame, WM_TRACKFRAME,
1688 MPFROMSHORT(TF_MOVE /* | TF_SETPOINTERPOS*/ ), NULL);
1689 mrc = 0;
1690 break;
1691
1692 default:
1693 mrc = (*psb->pfnFrame)(hwnd, msg, mp1, mp2);
1694 }
1695
1696 return (mrc);
1697}
1698
1699/*
1700 *@@ shp2RegisterClasses:
1701 *
1702 *@@added V0.9.3 (2000-05-03) [umoeller]
1703 */
1704
1705BOOL shp2RegisterClasses(HAB hab)
1706{
1707 // register shape window class; if this is already
1708 // registered, this won't hurt
1709 return(WinRegisterClass(hab,
1710 WC_SHAPE_WINDOW,
1711 shp_fnwpShapeMgr,
1712 0L, // class style flags
1713 sizeof(PVOID)));
1714}
1715
1716
Note: See TracBrowser for help on using the repository browser.