source: branches/branch-1-0/src/helpers/shapewin.c@ 302

Last change on this file since 302 was 222, checked in by umoeller, 23 years ago

Minor adjustments for new static handling.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 53.8 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
310STATIC 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
321STATIC 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
344STATIC 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
371STATIC 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
499STATIC 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
520STATIC 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
593STATIC 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
660STATIC 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 = &rect;
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
708STATIC 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
822STATIC 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
944STATIC 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
1013STATIC 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
1043STATIC 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
1097STATIC 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
1147STATIC 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
1316MRESULT 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
1349BOOL 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
1413VOID 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
1507BOOL 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
1607MRESULT 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
1711BOOL 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
Note: See TracBrowser for help on using the repository browser.